Introdução ao uso otimizado do Backend S3 no Terraform: boas práticas e configurações essenciais
- Cloud e Infraestrutura
- Artigo
O estado do Terraform é um dos pilares da ferramenta, fundamental para gerenciar infraestrutura como código. Se você já utilizou o Terraform, certamente se deparou com o estado. Mas você sabia que ele vai além do básico?
Neste artigo, vamos explorar as melhores práticas para gerenciar o estado através de um backend S3, garantindo segurança, integridade e confiabilidade. Abordaremos tópicos como:
- Uso do S3 para o backend: descubra como o S3 pode ser utilizado para armazenar o estado do Terraform de forma segura e escalável.
- Solução do “ovo e da galinha”: aprenda a lidar com o problema da criação da infraestrutura do backend em si.
- Migração do estado local: migre seu estado local para o backend S3 sem complicações.
Com base no repositório, este artigo te ajudará a usar o estado do Terraform de forma eficiente e segura, implementando melhores práticas para gerenciar sua infraestrutura.
Venha comigo e vamos juntos aprender sobre as boas práticas de uso do Terraform com backend S3.
Boas práticas Backend S3
Vale a pena um rápido lembrete do que é estado e o que é backend. O estado do terraform é uma estrutura de dados que representa toda a infraestrutura com sua configuração que foi provisionada até então. Por sua vez o backend nada mais é do que um mecanismo de persistência para armazenar esse estado.
Dito isso, quando se trata de backend na AWS, o S3 é o serviço mais usado para essa finalidade. Usando o S3, ganhamos um ambiente seguro e centralizado e naturalmente distribuído para compartilhar o estado entre os membros da equipe. Deste modo, surgem necessidades específicas de configuração e cuidados para garantir a segurança e integridade do estado da infraestrutura que serão descritos a seguir.
Configuração da política de acesso
É importante configurar a política de acesso para garantir que apenas as pessoas e service accounts autorizadas possam acessar e modificar o estado da infraestrutura. Imaginando o cenário, desenvolvedores acessam o estado do ambiente de desenvolvimento para leitura identificando as alterações realizadas em códigos, porém somente a service account destinada para a ferramenta de continuous integration (CI) realiza o deploy no ambiente após merge do código. Considerando esse cenário, será utilizado o AWS Identity and Access Management (IAM) para criar usuários, grupos, roles e políticas de acesso conforme a necessidade do projeto e ambientes.
Segue um exemplo para a política de acesso que realiza a separação de usuários para somente leitura, leitura e escrita e negação total para não vinculados. Deste modo, você consegue realizar o controle de acesso de forma granular.
# file: iam.tf
data "aws_iam_policy_document" "backend_infra" {
statement {
sid = "ReadOnlyUsers"
actions = [
"s3:GetObject",
"s3:GetObjectAcl",
"s3:ListBucket",
]
resources = [
aws_s3_bucket.backend_infra.arn,
"${aws_s3_bucket.backend_infra.arn}/*"
]
principals {
type = "AWS"
identifiers = var.users_ready_only
}
}
statement {
sid = "ReadWriteUsers"
actions = [
"s3:*Object"
]
resources = [
aws_s3_bucket.backend_infra.arn,
"${aws_s3_bucket.backend_infra.arn}/*"
]
principals {
type = "AWS"
identifiers = var.users_write_permissions
}
}
statement {
sid = "AllExceptUser"
effect = "Deny"
actions = [
"s3:GetObject"
]
resources = [
aws_s3_bucket.backend_infra.arn,
"${aws_s3_bucket.backend_infra.arn}/*"
]
not_principals {
identifiers = concat(var.users_write_permissions, var.users_ready_only)
type = "AWS"
}
}
}
# file: s3.tf
resource "aws_s3_bucket_policy" "backend_infra" {
bucket = aws_s3_bucket.backend_infra.id
policy = data.aws_iam_policy_document.backend_infra.json
}
Configuração do versionamento do S3
Suponha que no momento do deploy houve uma instabilidade no CI que resultou no corrompimento e perda do arquivo de estado atual.
Para prevenir ou ajudar a resolver esse tipo de situação, existem duas possibilidades para auxiliar neste processo. A primeira é a utilização do versionamento do AWS S3 e a segunda é a utilização do AWS DynamoDB para lockstate.
O S3 permite o versionamento de objetos, o que significa que cada vez que o estado da infraestrutura é alterado, uma nova versão é criada. Isso permite que as diferentes versões possam ser comparadas e revertidas de forma rápida, se necessário.
Esta configuração é muito útil, além disso, a implementação é simples e pode ser realizada através do código abaixo.
# file: s3.tf
resource "aws_s3_bucket_versioning" "backend_infra" {
bucket = aws_s3_bucket.backend_infra.id
versioning_configuration {
status = "Enabled"
}
}
Utilização DynamoDB para lockstate
O DynamoDB pode ser usado pelo Terraform para armazenar o lockstate do backend, o que garante que o estado não seja modificado por mais de um usuário ao mesmo tempo.
Realizar lock do estado é recomendado para ambientes de produção, onde o estado da infraestrutura é mais crítico e não pode ser modificado por mais de um usuário ao mesmo tempo. Para ambientes de desenvolvimento e homologação, o lockstate pode ser desabilitado, já que o estado da infraestrutura tem uma necessidade de deploy constante para testes e validações.
A implementação do DynamoDB para lockstate é simples e pode ser realizada através do código abaixo.
# file: dynamodb.tf
resource "aws_dynamodb_table" "backend_infra" {
name = "terraform-state-lock"
billing_mode = "PAY_PER_REQUEST"
hash_key = "LockID"
attribute {
name = "LockID"
type = "S"
}
}
Utilização de criptografia
O S3 oferece suporte à criptografia de dados em repouso, o que significa que é possível criptografar o estado da infraestrutura armazenado no S3. Deve-se ressaltar a importância de criptografar o estado, já que várias informações sensíveis podem estar armazenadas no estado do Terraform, como senhas ou informações como número da sua conta AWS utilizada, entre outros dados.
Por padrão, o serviço do S3 utiliza a criptografia por AES-256, mas é possível customizar essa criptografia com outros serviços, inclusive com o AWS KMS, usado para gerenciamento de chaves de criptografia.
A implementação da criptografia utilizando o AWS KMS é simples e pode ser realizada através do código abaixo.
# file: kms.tf
resource "aws_kms_key" "encrypt_state" {
count = var.activate_kms ? 1 : 0
description = "Key to protect S3 objects"
key_usage = "ENCRYPT_DECRYPT"
deletion_window_in_days = 7
is_enabled = true
tags = merge(
{ Name = "${local.deployment_project}-kms-custom-key" },
var.tags
)}
resource "aws_kms_alias" "kms_s3_key_alias" {
count = var.activate_kms ? 1 : 0
name = "alias/${var.project_name}/${var.environment}/s3-state-key"
target_key_id = aws_kms_key.encrypt_state[0].key_id
}
# file: s3.tf
resource "aws_s3_bucket_server_side_encryption_configuration" "backend_infra" {
bucket = aws_s3_bucket.backend_infra.bucket
rule {
dynamic "apply_server_side_encryption_by_default" {
for_each = var.activate_kms ? [1] : []
content {
kms_master_key_id = aws_kms_key.encrypt_state[0].arn
sse_algorithm = "aws:kms"
}
}
dynamic "apply_server_side_encryption_by_default" {
for_each = var.activate_kms ? [] : [1]
content {
sse_algorithm = "aws:kms"
}
}
}
}
Utilização de logging no S3
Uma boa auditoria é essencial para garantir a segurança. A AWS oferece uma boa rastreabilidade através do CloudTrail, mas para obter melhor rastreabilidade e controle é recomendado o uso de logging com o S3.
Segue um exemplo de recursos para adicionar um bucket de logging ao S3 principal.
# file: s3_logging.tf
resource "aws_s3_bucket" "logging" {
bucket = "${local.deployment_project}-bucket-logging"
[...]
}
resource "aws_s3_bucket_acl" "logging" {
bucket = aws_s3_bucket.logging.id
acl = "private"
}
resource "aws_s3_bucket_public_access_block" "logging" {
bucket = aws_s3_bucket.logging.id
[...]
}
resource "aws_s3_bucket_lifecycle_configuration" "logging" {
bucket = aws_s3_bucket.logging.bucket
[...]
}
# file: s3.tf
resource "aws_s3_bucket_logging" "backend_infra" {
bucket = aws_s3_bucket.backend_infra.id
target_bucket = aws_s3_bucket.logging.id
target_prefix = "${local.deployment_project}/"
}
Até aqui foram apresentados alguns recursos que podem ser utilizados para configurar e otimizar o backend S3 do Terraform. Lembrando que para conferir na integra esses códigos encontram-se neste repositório.
Infraestrutura Backend S3
Todas as práticas mencionados podem ser usadas para configurar o backend S3 e podem ser adaptadas a qualquer projeto. Porém podemos ponderar sobre duas situações: qual a infraestrutura mínima necesssária em termos custo/benefício e qual o ideal para um ambiente produtivo.
Para uma infraestrutura mínima, pode ser suficiente apenas criar um bucket S3 e usá-lo como backend. Porém para um ambiente produtivo, vale a pena adicionar outros recursos para dar mais robustez e segurança ao seu backend. Por exemplo, podemos usar o mecanismo de locking de state com o Dynamo e adicionar logging via S3.
Caso você ainda esteja com dúvidas, a infraestrutura inicial proposta possui uma base de recursos para seu projeto que contempla criptografia e logs. Segue o link do código para criação da infraestrutura inicial proposta neste artigo.
Após a criação do backend S3, você deve estar se perguntando, mas e o estado da infraestrutura do backend do Terraform que acabei de criar, vai ficar local? A resposta é sim, mas tem maneiras de se contornar isso, pensando que essa infraestrutura não será alterada após sua criação, é possível configurar o projeto Terraform para utilizar os recursos de backend criados e realizar a migração desses estados para o bucket S3.
No próximo tópico vamos abordar esse cenário, considerando que você já possui um projeto criado no Terraform, como fazer a migração do estado local para o backend S3.
Migrando o estado local para o S3
Executei meu código Terraform e só vi esse artigo agora, o que fazer? Calma, não se desespere, é possível migrar o estado do seu projeto Terraform para o backend S3. Após executar a sua infraestrutura backend conforme descrito anteriormente, é possível configurar o seu projeto Terraform para utilizar o backend S3 e migrar o estado local para o bucket S3.
Uma das maneiras de realizar esse tipo de configuração é através de um arquivo de que contém as informações necessárias, no caso apresentado é o backend.hcl, que pode ser carregado pelo Terraform através da inclusão de dois parâmetro através do comando terraform init , são eles: -backend=true e -backend-config=backend.hcl.
Todas as variáveis utilizadas para esse arquivo de configuração, é possível ser encontradas neste link da documentação do Terraform. A seguir será apresentado um exemplo de arquivo de configuração para o backend S3 em relação a variáveis obrigatórias.
bucket = nome-do-meu-bucket-s3-de-estado-terraform
key = terraform.tfstate
# Lembre-se que o S3 não possui o conceito de pastas. O prefixo é uma analogia.
Considerando o repositório de exemplo, o arquivo de configuração do backend S3 para o projeto Terraform utilizado, encontra-se neste link.
Uma vez que as configurações de backend estão corretas, basta executar o comando abaixo. Neste momento, será solicitado a migração do estado local para o bucket S3, basta digitar yes e aguardar a migração e inicialização.
terraform init -backend=true -backend-config=backend.hcl
Pronto! Se a inicialização ocorreu sem erros, você terá os seus arquivos de estado sendo carregados para o S3.
Conclusão
Neste artigo, foram apresentadas boas práticas para utilização do backend S3 em projetos Terraform, além da importancia de cada uma delas, focando em auditoria e proteção de dados. Vale ressaltar que os recursos aqui apresentados são específicos da cloud AWS e cada recurso utilizado tem custos atualizados por região, sempre antes de iniciar um projeto de infraestrutura verifique os custos de todos os componentes necessários, backend remoto e projeto principal.
Após a definição dos componentes da infraestrutura, realize a utilização de estado remoto para seu projeto Terraform, pois além de ser uma boa prática, é uma maneira de garantir a segurança e integridade do seu projeto. Além disso, como uma boa prática bônus, é possível realizar o gerenciamento por workspaces, sendo uma maneira de separar os ambientes de seu projeto.
Foi demonstrado o procedimento detalhado para configurar o backend em projetos Terraform por meio de um arquivo de configuração específico. Adicionalmente, foi explicado de maneira abrangente o processo de migração do estado local para o backend S3, garantindo uma transição eficiente e segura.
Lembrando que os códigos apresentados neste artigo encontram-se no repositório por meio do link.