Si gestionas infraestructura en dos o más nubes, sabes que el problema no es escribir recursos — es mantenerlos consistentes, seguros y auditables cuando los equipos crecen.
Este artículo no es un tutorial de Terraform básico. Es una guía de patrones de producción para equipos que operan infraestructura multi-cloud (AWS + OCI como caso central), extraídos de proyectos reales donde el costo del error —un state corrupto, un secreto expuesto, un recurso huérfano— se mide en downtime o facturas inesperadas.
1. State Management: El Talón de Aquiles del Multi-Cloud
En un solo proveedor, el state es un archivo remoto. En multi-cloud, es el mapa de tu negocio. Si se corrompe o se desincroniza, pierdes visibilidad de lo que tienes desplegado y dónde.
Backend centralizado con aislamiento por entorno
Usa un backend único (S3 con DynamoDB para locking, o un bucket OCI con bloqueo OCI Object Storage) pero con keys por entorno y por proveedor:
| Entorno | Proveedor | Key de State |
|---|---|---|
| dev | AWS | env:/dev/aws/terraform.tfstate |
| dev | OCI | env:/dev/oci/terraform.tfstate |
| prod | AWS | env:/prod/aws/terraform.tfstate |
| prod | OCI | env:/prod/oci/terraform.tfstate |
Esto permite aplicar cambios en un entorno sin bloquear el resto, y mantiene separación clara entre proveedores. Usa OpenTofu en lugar de Terraform si prefieres licencia MPL y evitar cambios unilaterales de licencia.
2. Diseño Modular por Capas
Un solo directorio con 2000 recursos es insostenible. Divide por capas, no por proveedor:
infrastructure/
└── modules/
│ └── networking/
│ └── compute/
│ └── database/
│ └── storage/
│ └── monitoring/
└── environments/
│ └── dev/
│ │ └── aws/
│ │ └── oci/
│ └── staging/
│ │ └── aws/
│ │ └── oci/
│ └── prod/
│ └── aws/
│ └── oci/
└── terragrunt.hcl Terragrunt como orquestador
Terragrunt (o Terramate) resuelve el problema de la repetición entre entornos. Cada entorno hereda configuraciones base y solo sobreescribe lo que varía:
# environments/prod/terragrunt.hcl
terraform {
source = "../../modules//networking"
}
inputs = {
environment = "prod"
vpc_cidr = "10.0.0.0/16"
region = "us-east-1"
} El mismo módulo se reusa en dev, staging y prod con distintos inputs. Esto reduce drásticamente la duplicación de código.
3. Gestión de Secretos: Fuera del State, Fuera del Código
Terraform state contiene todos los valores de recursos, incluidos secretos si los pasas como variables planas. Un bucket S3 con state expuesto filtra credenciales de base de datos, API keys y tokens.
Reglas de producción:
- Nunca uses variables
sensitive = truecomo protección — solo ocultan en output, no en el state. - Usa
vault(HashiCorp Vault, AWS Secrets Manager, OCI Vault) como backend de variables sensibles. - Con Terragrunt: usa
dependencyblocks para obtener outputs de otros módulos sin hardcodear. - Con OpenTofu:
tofu init -backend-config=backend.hclcon backend config nunca en el repo.
# Ejemplo con AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/database/credentials"
}
locals {
db_creds = jsondecode(data.aws_secretsmanager_secret_version.db.secret_string)
}
resource "aws_db_instance" "main" {
username = local.db_creds.username
password = local.db_creds.password
} 4. CI/CD: El Pipeline como Único Punto de Verdad
Si alguien puede ejecutar terraform apply desde su terminal, eventualmente va a romper algo. El pipeline de CI/CD debe ser la única vía de despliegue.
| Fase | Qué ocurre | Duración típica |
|---|---|---|
| Plan | tofu plan -out=tfplan + comentario en PR | 30-60s |
| Review | Humano revisa diff en PR. Aprobar = trigger apply | variable |
| Apply | Merge a main → GitHub Actions ejecuta apply automático | 2-5 min |
| Drift | Cron diario detecta cambios manuales no trackeados | programado |
GitHub Actions multi-proveedor
name: "IaC - Apply"
on:
push:
branches: [main]
paths: ["environments/prod/**"]
jobs:
terraform:
strategy:
matrix:
provider: [aws, oci]
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: tofu init -backend-config=backend-$}{{ matrix.provider }}.hcl
- run: tofu apply -auto-approve tfplan 5. Control de Costos desde IaC
El momento más barato para evitar un gasto innecesario es antes de crear el recurso. Integra políticas de costos directamente en tu pipeline de IaC:
- Sentinel / OPA policies: Bloquea deploys que creen instancias sin etiquetas de costos, o que excedan thresholds de tamaño.
- Infracost: Corre en cada PR y estima el costo del cambio propuesto. Los equipos ven el impacto financiero antes de aprobar.
- Tagging obligatorio: El módulo base de cada recurso debe forzar tags como
Environment,CostCenter,Owner.
# Política OPA: bloquear instancias mayores a t3.large en dev
deny[msg] {
input.resource_changes[_].type == "aws_instance"
instance_type := input.resource_changes[_].change.after.instance_type
instance_type in ["t3.xlarge", "t3.2xlarge", "m5.xlarge"]
msg := sprintf("Instancia %v no permitida en dev", [instance_type])
} 6. Drift Detection y Remediation
En multi-cloud, alguien siempre va a tocar algo desde la consola web. El drift es inevitable; la detección automatizada no es opcional.
Recomendación: un pipeline diario que ejecute tofu plan en cada entorno y notifique si detecta cambios no trackeados. Si el drift supera un threshold, un human revisa; si es menor, remediación automática con tofu apply para restaurar el estado deseado.
Resumen: Checklist de IaC Multi-Cloud
- ☑ State remoto con locking y keys por entorno/proveedor
- ☑ Diseño modular: módulos reusables, entornos como instancias
- ☑ Secretos fuera del state (Vault / Secrets Manager)
- ☑ Pipeline único de CI/CD para deploys
- ☑ Cost estimation en cada PR (Infracost)
- ☑ Políticas OPA/Sentinel para gobernanza
- ☑ Drift detection diario
- ☑ OpenTofu > Terraform para evitar lock-in de licencia
- ☑ Sin terraform apply local — solo desde CI/CD
La infraestructura como código es la base de cualquier operación multi-cloud que no quiera convertirse en un dolor de cabeza. Implementar estos patrones desde el día uno —o corregirlos gradualmente— separa a los equipos que controlan su infraestructura de los que son controlados por ella.