CI/CD Terraform con GitHub Actions: validar y planificar
Automatizar la validación y la planificación de Terraform con GitHub Actions acelera las revisiones y reduce errores humanos. Este tutorial muestra cómo configurar una pipeline que ejecuta terraform fmt, init, validate y terraform plan y publica el resultado como comentario en el Pull Request. Al automatizar estos pasos, se pueden detectar problemas antes del merge y dar contexto a las decisiones de infraestructura a los revisores — por ejemplo, saber que un terraform plan prevé la creación de 3 recursos y la modificación de 1, sin tener que ejecutar comandos localmente.
Prerrequisitos
- Cuenta GitHub con repositorio (público o privado). Se recomienda repositorio con rama protegida y políticas de revisión.
- Conocimientos básicos de Terraform (ficheros .tf). Saber ejecutar
terraform init,terraform plane interpretar la salida. - Git y GitHub CLI básicos para crear ramas y Pull Requests. Un flujo típico: rama con hasta 10 cambios .tf por PR es más fácil de revisar.
- Secrets en GitHub (providers/credentials) cuando sea necesario. Para un repositorio con 1-2 providers, añada las variables necesarias como secrets.
Paso 1: Estructura mínima del repositorio Terraform
Cree una estructura simple con un main.tf de ejemplo. Mantenemos el backend local por simplicidad — en producción use un backend remoto (S3, Azure Storage, etc.). Una estructura mínima para un módulo o entorno puede ser:
# main.tf
resource "null_resource" "exemplo" {
provisioner "local-exec" {
command = "echo Hello"
}
}
Sugerencia práctica: mantenga el repositorio organizado por carpetas por entorno (por ejemplo, environments/dev, environments/prod) y limite cada PR a un entorno cuando sea posible. Para un repositorio con 20-50 ficheros .tf, la pipeline sigue funcionando — el tiempo de ejecución aumenta según el número de providers y módulos, típicamente entre 10s y 2min para init+validate en proyectos pequeños.
Paso 2: Crear el workflow de GitHub Actions
Crear un workflow en .github/workflows/terraform.yml que ejecute los pasos: checkout, setup-terraform, terraform fmt, terraform init, terraform validate, terraform plan y publicar el plan en el PR. Usamos actions oficiales para simplificar y garantizar versiones estables.
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 del plan (abrir)
```
${{ steps.plan.outputs.plan-body }}
```
Notas prácticas: usar -no-color facilita la lectura en comentarios. El paso terraform plan está usando || true para garantizar que, incluso con exit code>0, capturamos la salida y comentamos en el PR — ideal para diagnosticar errores sin bloquear la publicación del comentario.
Paso 3: Configurar secrets y providers
Si su Terraform usa providers que requieren credenciales (AWS, Azure, GCP), añada los secrets en GitHub (Settings > Secrets > Actions). Ejemplo 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
Ejemplo práctico: para un proyecto pequeño, defina 3 secrets (ACCESS_KEY, SECRET_KEY y REGION). Verifique que el token de GitHub Actions tiene permisos para comentar PRs (GITHUB_TOKEN tiene permisos por defecto, pero para repositorios con restricciones puede ser necesario un token personal con permisos limitados).
Paso 4: Manejar errores comunes
Errores típicos y soluciones rápidas:
- terraform fmt -check falla: ejecutar
terraform fmtlocalmente o ajustar el CI para corregir automáticamente usandoterraform fmt -recursive. En equipos, configure un pre-commit hook para evitar estos errores — puede reducir fallos en CI en ~30%. - Fallo de autenticación del provider: confirmar secrets en el repositorio y variables de entorno en el workflow. Verifique también el tiempo de vida de las claves (rutina de rotación cada 90 días es común).
- terraform plan falla con exit code >0: capturamos la salida y continuamos el job con
|| truepara poder comentar el plan; analice la salida en el comentario. Si el plan falla por falta de state remoto, verifique backend y locks.
Verificar el resultado
Abra una rama, haga cambios en los .tf y cree un Pull Request. Acceda a la pestaña Actions del PR y verifique que el workflow se ejecutó con éxito. En el propio Pull Request debería aparecer un comentario con la salida del terraform plan — si el comentario no aparece, verifique los logs del paso Comment plan on PR y el permiso del GITHUB_TOKEN. En proyectos con CI medio, el tiempo total desde el push hasta el comentario es típicamente 30s–3min.
Conclusión
Con esta pipeline básica de CI para Terraform, gana automatización en las revisiones y reduce riesgos de regresión. Próximos pasos recomendados: mover el state a un backend remoto (S3/Backend de Azure), añadir job de terraform fmt automático que corrija ficheros, y condicionar terraform apply a ramas protegidas con aprobación manual. Pequeñas mejoras, como bloquear merges sin comentarios de plan o añadir análisis de drift, pueden reducir incidentes en producción en decenas de porcentajes. Consejo: ¿quiere que incluya un ejemplo con backend remoto (S3/Consul/Azure Storage) y locks en el workflow?