kb.erickguedes.com
Terraform: Infraestrutura como Código

Boas Práticas em Produção

Aula 7 de 7

Estrutura Recomendada

terraform/
├── environments/
│   ├── dev/
│   │   ├── main.tf
│   │   ├── variables.tf
│   │   ├── outputs.tf
│   │   └── terraform.tfvars
│   ├── staging/
│   └── prod/
├── modules/
│   ├── networking/
│   ├── compute/
│   ├── database/
│   └── security/
├── live/
│   ├── global/          # IAM, Route53, CloudTrail
│   ├── us-east-1/
│   │   ├── network/
│   │   ├── services/
│   │   └── monitoring/
│   └── eu-west-1/
└── scripts/
    └── ci.sh

Terragrunt para Produção

# prod/terragrunt.hcl
locals {
  env_vars = yamldecode(file("${get_terragrunt_dir()}/../env.yaml"))
}

inputs = {
  environment = "prod"
  vpc_cidr    = "10.100.0.0/16"
  instance_type = "m6i.xlarge"
  min_capacity  = 3
  max_capacity  = 20
}

remote_state {
  backend = "s3"
  config = {
    encrypt        = true
    bucket         = "terraform-state-prod"
    key            = "${path_relative_to_include()}/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
  }
}

Sentinel — Policy as Code

# Restringir tipos de instância
policy "restrict-instance-type" {
  enforcement_level = "advisory"
}

main = rule {
  all tfplan.resources_changed as _, instance {
    instance.applied.instance_type in ["t3.micro", "t3.small", "m6i.large"]
  }
}

Pre-commit Hooks

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/antonbabenko/pre-commit-terraform
    rev: v1.88.0
    hooks:
      - id: terraform_fmt
      - id: terraform_validate
      - id: terraform_tflint
      - id: terraform_docs
      - id: terraform_tfsec
pre-commit install

TFSec — Security Scanning

tfscan .
# ou
tfsec terraform/

# Exemplo de saída:
# Result: FAIL (critical)
# filename: main.tf:10-15
# Description: AWS S3 bucket has public ACL enabled

Checklist de Produção

  • Remote state com S3 + DynamoDB lock
  • Backend configurado antes de qualquer apply
  • Nenhuma secret hardcoded (use vars/env)
  • prevent_destroy em resources críticos (RDS, S3)
  • create_before_destroy onde possível
  • Workspaces ou diretórios para ambientes
  • CI/CD com plan em PR, apply apenas em main
  • Formatting com terraform fmt --check no CI
  • Snyk/tfsec scanning de segurança
  • Budget alerts nos recursos provisionados
  • Pinned provider version (~> x.y)
  • Módulos com versão fixa (não usar "latest")
  • outputs sensíveis marcados como sensitive = true
  • Lifecycle ignore_changes onde apropriado
  • Documentação gerada com terraform-docs

Drift Detection Automática

# drift.yaml — GitHub Action semanal
name: Drift Detection
on:
  schedule:
    - cron: '0 6 * * 1'  # Segunda 6h

jobs:
  detect:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: |
          terraform init
          terraform plan -detailed-exitcode
          echo "exit=$?" >> $GITHUB_OUTPUT
      - if: steps.plan.outputs.exit == 2
        run: echo "Drift detectado! Criar issue..."

TFLint

# .tflint.hcl
config {
  module = true
}

rule "terraform_unused_declarations" {
  enabled = true
}

rule "terraform_comment_syntax" {
  enabled = true
}

rule "terraform_documented_outputs" {
  enabled = true
}

rule "terraform_documented_variables" {
  enabled = true
}

plugin "aws" {
  enabled = true
  version = "0.30.0"
  source  = "github.com/terraform-linters/tflint-ruleset-aws"
}

Produção exige rigor: CI/CD, validação automática, scanning de segurança e detecção de drift. Invista em pre-commit hooks e tfsec desde o primeiro dia. Nunca aplique sem revisão.