La infraestructura gestionada a mano —clicks en la consola de AWS, scripts sueltos, cambios que nadie documenta— tiene un nombre poco halagador: "servidores copo de nieve", cada uno único e imposible de reproducir. Infrastructure as Code resuelve esto convirtiendo la infraestructura en código versionado, auditable y reproducible. Terraform es hoy la herramienta más extendida para esto, muy por delante de alternativas como CloudFormation.
El problema de la infraestructura manual
El flujo típico sin IaC: entrar a la consola de AWS, crear VPC, subredes y grupos de seguridad a golpe de clic, configurar una instancia RDS ajustando parámetros uno a uno, desplegar la app con scripts bash improvisados. El problema no es solo el tiempo que lleva —es que nadie puede responder con certeza quién cambió qué, cuándo, ni por qué, cuando algo deja de funcionar.
Con Terraform, la misma infraestructura se declara como código:
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
}
resource "aws_db_instance" "db" {
allocated_storage = 20
storage_type = "gp2"
engine = "postgres"
engine_version = "14.7"
}
resource "aws_autoscaling_group" "app" {
desired_capacity = 3
}
terraform apply # reproducible y auditable
Cada cambio pasa por commit y revisión de PR antes de aplicarse. Se acaba la "infraestructura sorpresa".
Lo básico: providers, resources, state
Un provider es la plataforma cloud contra la que trabajas (AWS, Azure, GCP...):
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "eu-west-1"
}
Un resource es cada unidad de infraestructura:
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
tags = {
Name = "web-server"
}
}
El state es la base de datos donde Terraform guarda qué infraestructura existe realmente:
terraform init # crea .terraform/ y el fichero de estado
terraform plan # previsualiza los cambios antes de aplicarlos
terraform apply # ejecuta los cambios
terraform destroy # elimina todo (peligroso)
El fichero de estado contiene información sensible —incluidas contraseñas de bases de datos en texto plano en algunos casos. Nunca debe acabar en el repositorio de git.
Gestión del estado: el error más caro que se puede cometer
Añadir terraform.tfstate al .gitignore después de haberlo commiteado ya no sirve de nada: si el secreto quedó en el historial de git, sigue ahí. La solución correcta es no depender nunca de un state local, sino usar un backend remoto desde el principio:
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "eu-west-1"
dynamodb_table = "terraform-lock"
encrypt = true
}
}
Un backend S3 con cifrado, historial de versiones y bloqueo vía DynamoDB evita que dos personas apliquen cambios al mismo tiempo y corrompan el estado.
Terraform vs CloudFormation
Terraform usa HCL, un lenguaje bastante más legible que el JSON/YAML verboso de CloudFormation, y funciona con cualquier proveedor cloud, no solo AWS. Su ecosistema de módulos reutilizables es también mucho más amplio. La única razón real para elegir CloudFormation en vez de Terraform es estar completamente atado a AWS y preferir la integración nativa sin depender de una herramienta de terceros.
Compara el mismo recurso en ambos:
# CloudFormation
Resources:
MyInstance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-0c55b159cbfafe1f0
InstanceType: t3.medium
# Terraform, mismo recurso
resource "aws_instance" "web" {
ami = "ami-0c55b159cbfafe1f0"
instance_type = "t3.medium"
}
Múltiples entornos: dev, staging, prod
Un patrón habitual es usar workspaces con variables condicionales:
variable "instance_count" {
default = {
dev = 1
staging = 2
prod = 5
}
}
resource "aws_autoscaling_group" "app" {
desired_capacity = lookup(var.instance_count, var.environment)
}
terraform workspace select prod
terraform apply
Un patrón más explícito, y que previene accidentes con más margen de seguridad, es tener directorios separados por entorno (terraform/dev, terraform/staging, terraform/prod), cada uno con su propio main.tf.
Los errores que de verdad rompen infraestructuras
Secretos hardcodeados:
# Mal: queda en git para siempre
resource "aws_db_instance" "db" {
password = "super-secret-123"
}
# Bien: viene de una variable, inyectada desde un secrets manager
resource "aws_db_instance" "db" {
password = var.db_password
}
Destruir sin protección. Cualquiera con acceso puede ejecutar terraform destroy si no hay salvaguardas. Protege los recursos críticos explícitamente:
resource "aws_s3_bucket" "prod_data" {
lifecycle {
prevent_destroy = true
}
}
Aplicar en paralelo desde dos sitios a la vez. El backend remoto con bloqueo (visto arriba) es justamente la solución a esto.
Aplicar sin revisar el plan primero. Un pipeline de CI/CD que muestre el plan y requiera aprobación manual antes de aplicar evita sorpresas:
plan:
script:
- terraform plan -out=tfplan
- terraform show tfplan
apply:
script:
- terraform apply tfplan
when: manual
No fijar la versión de Terraform. Un plan generado con una versión y aplicado con otra puede comportarse de forma inesperada:
terraform {
required_version = "~> 1.5"
}
Un flujo de despliegue razonable
- El ingeniero crea una rama y escribe el Terraform
- Push a GitHub
- El pipeline de CI ejecuta
terraform plany muestra los cambios - Revisión por PR
- Aprobación manual en el CI/CD
terraform applysolo tras la aprobación- El estado se actualiza en S3, bloqueado durante el apply
- Alertas de monitoring si algo se rompe tras el despliegue
Herramientas
Terraform es open source y gratuito. Terraform Cloud añade gestión de estado y una interfaz de ejecución por una tarifa mensual modesta. Terragrunt es un wrapper útil para mantener configuraciones DRY entre entornos.
Fuentes:






Comentarios (0)
Deja un comentario
No hay comentarios aún. ¡Sé el primero en comentar!