Infraestructura como código
La infraestructura como código (IaC) consiste en definir tus servidores, redes y bases de datos en ficheros de texto versionados, en lugar de crearlos pinchando en una consola web.
El cambio que produce es más profundo de lo que parece: la infraestructura pasa a tener las mismas propiedades que el código. Historial, revisión por pares, capacidad de volver atrás y posibilidad de recrearla desde cero.
Lo que sustituye
El modelo manual tiene un problema que no se ve hasta que es tarde:
1. Documentar la infraestructura en un Excel
2. Crear los servidores a mano en la consola
3. Configurarlos entrando por SSH
4. Rezar para poder replicarlo
5. Descubrir que staging y producción no se parecen
El paso 5 es el que duele. Cuando staging y producción divergen, staging deja de servir para lo único que sirve: predecir qué pasará en producción.
Con IaC, ambos entornos salen de la misma definición.
Qué te da
- Repetible. El mismo código produce la misma infraestructura, siempre.
- Versionado.
git logsobre tu infraestructura, ygit revertcuando hace falta. - Revisable. Los cambios pasan por un pull request antes de tocar producción.
- Documentada por definición. El código es la documentación, y no se queda obsoleto.
- Recuperable. Perder una región deja de ser una catástrofe y pasa a ser un
apply.
Las herramientas
| Terraform / OpenTofu | Pulumi | CloudFormation | |
|---|---|---|---|
| Lenguaje | HCL (declarativo) | Python, TypeScript, Go | YAML / JSON |
| Nubes | Todas | Todas | Solo AWS |
| Estado | Fichero propio | Fichero propio | Gestionado por AWS |
| Ecosistema | Enorme | Medio | Solo AWS |
Terraform es el estándar de facto y con lo que trabajaremos aquí. OpenTofu es su bifurcación open source tras el cambio de licencia de HashiCorp en 2023, y es compatible. Pulumi interesa si prefieres un lenguaje de programación real con bucles y condicionales de verdad. CloudFormation solo tiene sentido si vives exclusivamente en AWS.
Lo básico de Terraform
provider "aws" {
region = "eu-west-1"
}
resource "aws_vpc" "principal" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
tags = {
Name = "vpc-principal"
Environment = var.entorno
}
}
El flujo de trabajo son tres comandos, y el del medio es el importante:
terraform init # descarga los proveedores
terraform plan # ¿QUÉ va a cambiar?
terraform apply # aplícalo
plan es la razón por la que Terraform funciona. Te enseña exactamente qué va a crear, modificar o destruir antes de tocar nada. Léelo siempre, y especialmente busca la palabra destroy — algunos cambios aparentemente inocentes obligan a recrear un recurso, y "recrear" una base de datos significa perderla.
El fichero de estado
Terraform guarda en un fichero .tfstate qué recursos ha creado y cómo se corresponden con tu código. Es lo que le permite saber que el aws_vpc.principal de tu fichero es esa VPC concreta que existe en AWS.
Es la pieza más delicada de todo el sistema:
- Nunca en Git. Contiene valores en claro, contraseñas incluidas.
- Siempre remoto y compartido, o cada miembro del equipo tendrá una versión distinta de la realidad.
- Con bloqueo, para que dos
applysimultáneos no lo corrompan.
terraform {
backend "s3" {
bucket = "mi-empresa-terraform-state"
key = "produccion/terraform.tfstate"
region = "eu-west-1"
encrypt = true
use_lockfile = true
}
}
Y una regla que ahorra disgustos: un estado por entorno. Si dev y producción comparten estado, un error en dev puede destruir producción.
Módulos
Un módulo es infraestructura empaquetada y parametrizada, igual que una función:
# modules/vpc/main.tf
resource "aws_vpc" "this" {
cidr_block = var.cidr_block
tags = merge(var.tags, { Name = "${var.prefijo}-vpc" })
}
output "vpc_id" {
value = aws_vpc.this.id
}
# environments/produccion/main.tf
module "vpc" {
source = "../../modules/vpc"
prefijo = "produccion"
cidr_block = "10.0.0.0/16"
}
Un aviso por experiencia ajena: no crees un módulo hasta que tengas el mismo patrón dos o tres veces. Abstraer demasiado pronto produce módulos con veinte variables que nadie entiende, y que acaban siendo más difíciles de usar que copiar y pegar.
Antes de escribir el tuyo, mira el Terraform Registry: los módulos de VPC y EKS de la comunidad están mucho más pulidos que lo que vas a escribir la primera vez.
Organizar el proyecto
infrastructure/
├── modules/ # piezas reutilizables
│ ├── vpc/
│ └── rds/
└── environments/ # una carpeta y un estado por entorno
├── dev/
├── staging/
└── produccion/
La estructura debe ser idéntica entre entornos; lo único que cambia son los valores de las variables. En cuanto producción tiene recursos que staging no tiene, has perdido la capacidad de probar antes de desplegar.
IaC en el pipeline
name: Terraform
on: [pull_request]
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- run: terraform fmt -check -recursive
- run: terraform init
- run: terraform validate
- run: terraform plan -no-color
El patrón que usa casi todo el mundo:
- En el pull request —
plan, y publicar el resultado como comentario para que se revise - Al hacer merge a main —
apply, con aprobación manual si es producción
Nunca un apply automático a producción sin que un humano haya leído el plan. Es la diferencia entre un error corregido en dos minutos y un incidente.
Además del plan, aquí encaja el análisis de seguridad de la infraestructura: buckets públicos, puertos abiertos, recursos sin cifrar. Lo tienes con laboratorio en el capítulo de seguridad en IaC del curso de DevSecOps.
Errores habituales
- Cambios manuales en la consola. Rompen la correspondencia con el estado y el siguiente
applylos deshace o falla. - Un único estado gigante. Un
plantarda diez minutos y cualquier error afecta a todo. Divide por entorno y por dominio. - Secretos en los ficheros
.tf. Acaban en Git y en el estado. Usa el gestor de secretos de tu nube. - No fijar la versión del proveedor. Un
applyque funcionaba hace un mes deja de funcionar sin que nadie haya tocado nada.
Resumen
- IaC da a tu infraestructura las propiedades del código: historial, revisión y reversión
- Terraform es el estándar; OpenTofu es su bifurcación libre y compatible
planantes deapply, siempre, y busca la palabradestroy- El estado va remoto, cifrado, con bloqueo y uno por entorno
- No abstraigas en módulos hasta repetir el patrón dos o tres veces
- En el pull request se hace
plan; elapplya producción lo aprueba una persona - Los cambios manuales en la consola rompen todo el modelo
Recursos adicionales
- Documentación de Terraform
- Terraform Registry
- Seguridad en IaC con Checkov
- Gestión de configuraciones — la otra mitad
💡 Recuerda: si tu infraestructura no se puede recrear desde cero con un comando, no la tienes como código. Tienes documentación con suerte.
En el próximo capítulo vemos qué hacer con lo que hay dentro de esas máquinas.