CI/CD Terraform com GitHub Actions: validar e planear
Automatizar a validação e o planeamento de Terraform com GitHub Actions acelera revisões e reduz erros humanos. Este tutorial mostra como configurar uma pipeline que faz terraform fmt, init, validate e terraform plan e publica o resultado como comentário no Pull Request. Ao automatizar estes passos, consegue detetar problemas antes do merge e dar contexto às decisões de infraestrutura aos revisores — por exemplo, saber que um terraform plan prevê a criação de 3 recursos e a modificação de 1, sem ter de executar comandos localmente.
Pré-requisitos
- Conta GitHub com repositório (público ou privado). Recomenda-se repositório com branch protegida e políticas de revisão.
- Conhecimentos básicos de Terraform (ficheiros .tf). Saber executar
terraform init,terraform plane interpretar a saída. - Git e GitHub CLI básicos para criar branches e Pull Requests. Um fluxo típico: branch com até 10 alterações .tf por PR é mais fácil de rever.
- Segredos no GitHub (providers/credentials) quando necessário. Para um repositório com 1-2 providers, adicione as variáveis necessárias como secrets.
Passo 1: Estrutura mínima do repositório Terraform
Crie uma estrutura simples com um main.tf de exemplo. Mantemos o backend local para simplicidade — em produção use um backend remoto (S3, Azure Storage, etc.). Uma estrutura mínima para um módulo ou ambiente pode ser:
# main.tf
resource "null_resource" "exemplo" {
provisioner "local-exec" {
command = "echo Hello"
}
}
Sugestão prática: mantenha o repositório organizado por pastas por ambiente (por exemplo, environments/dev, environments/prod) e limite cada PR a um ambiente quando possível. Para um repositório com 20-50 ficheiros .tf, a pipeline continua a funcionar — o tempo de execução sobe conforme o número de providers e módulos, tipicamente entre 10s a 2min para init+validate em pequenos projectos.
Passo 2: Criar o workflow do GitHub Actions
Criar um workflow em .github/workflows/terraform.yml que execute os passos: checkout, setup-terraform, terraform fmt, terraform init, terraform validate, terraform plan e publicar o plan no PR. Usamos actions oficiais para simplificar e garantir versões estáveis.
name: Terraform CI
on:
pull_request:
paths:
- '**/*.tf'
jobs:
terraform:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
- name: Terraform fmt
run: terraform fmt -check -recursive
- name: Terraform init
run: terraform init -input=false
- name: Terraform validate
run: terraform validate
- name: Terraform plan
id: plan
run: |
terraform plan -no-color -out=plan.tfplan || true
terraform show -no-color plan.tfplan > plan.txt || true
echo "plan-body<> $GITHUB_OUTPUT
cat plan.txt >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Comment plan on PR
uses: peter-evans/create-or-update-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
body: |
**Terraform Plan**
Mostrar output do plan (abrir)
```
${{ steps.plan.outputs.plan-body }}
```
Notas práticas: usar -no-color facilita a leitura em comentários. O passo terraform plan está a usar || true para garantir que, mesmo com exit code>0, capturamos a saída e comentamos no PR — ideal para diagnosticar erros sem bloquear a publicação do comentário.
Passo 3: Configurar segredos e providers
Se o seu Terraform usa providers que requerem credenciais (AWS, Azure, GCP), adicione os segredos no GitHub (Settings > Secrets > Actions). Exemplo para AWS:
- name: Configure AWS creds
if: env.AWS_REQUIRED == 'true'
run: |
echo "AWS_ACCESS_KEY_ID=${{ secrets.AWS_ACCESS_KEY_ID }}" >> $GITHUB_ENV
echo "AWS_SECRET_ACCESS_KEY=${{ secrets.AWS_SECRET_ACCESS_KEY }}" >> $GITHUB_ENV
Exemplo prático: para um pequeno projeto, defina 3 secrets (ACCESS_KEY, SECRET_KEY e REGION). Verifique que o token do GitHub Actions tem permissões para comentar PRs (GITHUB_TOKEN tem permissões por defeito, mas para repositórios com restrições pode ser necessário um token pessoal com permissões limitadas).
Passo 4: Lidar com erros comuns
Erros típicos e soluções rápidas:
- terraform fmt -check falha: executar
terraform fmtlocalmente ou ajustar CI para corrigir automaticamente usandoterraform fmt -recursive. Em equipas, configure um pre-commit hook para evitar estes erros — pode reduzir falhas em CI em ~30%. - Provider auth falha: confirmar segredos no repositório e variáveis de ambiente no workflow. Verifique também o tempo de vida das chaves (rotina de rotação a cada 90 dias é comum).
- terraform plan a falhar com exit code >0: capturamos a saída e continuamos a job com
|| truepara poder comentar o plan; analise a saída no comentário. Se o plano falhar por falta de state remoto, verifique backend e locks.
Verificar o resultado
Abra um branch, faça alterações nos .tf e crie um Pull Request. Aceda ao separador Actions do PR e verifique que o workflow correu com sucesso. No próprio Pull Request deverá aparecer um comentário com a saída do terraform plan — se o comentário não aparecer, verifique os logs do passo Comment plan on PR e a permissão do GITHUB_TOKEN. Em projetos com CI médio, o tempo total desde o push até ao comentário é tipicamente 30s–3min.
Conclusão
Com esta pipeline básica de CI para Terraform, ganha automatização nas revisões e reduz riscos de regressão. Próximos passos recomendados: mover o state para um backend remoto (S3/Backend do Azure), adicionar job de terraform fmt automático que corrige ficheiros, e condicionar terraform apply a branches protegidos com aprovação manual. Pequenas melhorias, como bloquear merges sem comentários de plan ou adicionar análise de drift, podem reduzir incidentes em produção em dezenas de percentuais. Dica: quer que inclua um exemplo com backend remoto (S3/Consul/Azure Storage) e locks no workflow?