Terraform
Herramienta de Infrastructure as Code de HashiCorp que permite definir, provisionar y gestionar infraestructura multi-cloud mediante archivos declarativos en HCL.
Terraform es la herramienta de IaC más adoptada del mercado. Usa un lenguaje declarativo (HCL) para definir infraestructura y un modelo de estado para rastrear qué recursos existen y cómo actualizarlos.
¿Cómo funciona?
Write (.tf files) → Plan (preview changes) → Apply (execute changes)
Ciclo de vida
terraform init # Descargar providers y módulos
terraform validate # Verificar sintaxis
terraform plan # Ver qué va a cambiar
terraform apply # Aplicar cambios
terraform destroy # Eliminar toda la infraestructuraConceptos fundamentales
Providers
Plugins que conectan Terraform con APIs de servicios:
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}Más de 4,000 providers: AWS, Azure, GCP, Kubernetes, GitHub, Datadog, Cloudflare, etc.
Resources
Unidad básica — un recurso de infraestructura:
resource "aws_s3_bucket" "data" {
bucket = "my-app-data-${var.environment}"
tags = {
Environment = var.environment
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "data" {
bucket = aws_s3_bucket.data.id
versioning_configuration {
status = "Enabled"
}
}Variables
# variables.tf
variable "environment" {
description = "Deployment environment"
type = string
validation {
condition = contains(["dev", "staging", "prod"], var.environment)
error_message = "Must be dev, staging, or prod."
}
}
variable "instance_count" {
description = "Number of instances"
type = number
default = 2
}# terraform.tfvars
environment = "prod"
instance_count = 3Outputs
output "bucket_arn" {
description = "ARN of the S3 bucket"
value = aws_s3_bucket.data.arn
}
output "api_url" {
description = "API Gateway URL"
value = aws_apigatewayv2_api.main.api_endpoint
sensitive = false
}Data sources
Leer información de recursos existentes (no gestionados por Terraform):
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
}State
El state file es la fuente de verdad sobre qué recursos existen:
# Backend remoto (obligatorio para equipos)
terraform {
backend "s3" {
bucket = "company-terraform-state"
key = "services/api/terraform.tfstate"
region = "us-east-1"
dynamodb_table = "terraform-locks" # Locking
encrypt = true # Encryption at rest
}
}Comandos de state
terraform state list # Listar recursos
terraform state show aws_instance.web # Detalle de un recurso
terraform state mv aws_instance.old aws_instance.new # Renombrar
terraform state rm aws_instance.legacy # Dejar de gestionar
terraform import aws_instance.web i-1234567890 # Importar existenteMódulos
Paquetes reutilizables de infraestructura:
# Módulo propio
module "api" {
source = "./modules/lambda-api"
function_name = "my-api"
runtime = "nodejs20.x"
memory_size = 256
environment = var.environment
}
# Módulo del registry
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
version = "5.5.0"
name = "production"
cidr = "10.0.0.0/16"
}Estructura de un módulo
modules/lambda-api/
├── main.tf # Resources
├── variables.tf # Inputs
├── outputs.tf # Outputs
├── versions.tf # Provider requirements
└── README.md # Documentation
Patrones avanzados
Workspaces
Múltiples entornos con el mismo código:
terraform workspace new staging
terraform workspace new production
terraform workspace select staging
terraform apply -var-file="staging.tfvars"for_each y count
# Crear múltiples recursos
resource "aws_iam_user" "team" {
for_each = toset(["alice", "bob", "carol"])
name = each.key
}
# Condicional
resource "aws_cloudwatch_log_group" "api" {
count = var.enable_logging ? 1 : 0
name = "/api/${var.environment}"
}Moved blocks (refactoring seguro)
moved {
from = aws_instance.server
to = aws_instance.web
}Terraform vs alternativas
| Aspecto | Terraform | Pulumi | AWS CDK | CloudFormation |
|---|---|---|---|---|
| Lenguaje | HCL | TS, Python, Go | TS, Python | YAML/JSON |
| Multi-cloud | Sí | Sí | No (AWS) | No (AWS) |
| State | Self-managed/Cloud | Managed/self | AWS-managed | AWS-managed |
| Ecosistema | 4,000+ providers | 100+ providers | AWS only | AWS only |
| Licencia | BSL 1.1 | Apache 2.0 | Apache 2.0 | Propietario |
| Fork OSS | OpenTofu | — | — | — |
Seguridad
# Nunca hardcodear secretos
variable "db_password" {
type = string
sensitive = true # No aparece en logs ni plan
}
# Usar data sources para secretos
data "aws_secretsmanager_secret_version" "db" {
secret_id = "prod/db/password"
}Anti-patrones
- State local — compartir state por Slack/email. Usar backend remoto con locking.
- Mega-monolito — toda la infra en un solo
main.tf. Dividir por dominio. - Sin pinear versiones — providers y módulos sin versión fija rompen builds.
- Apply sin plan — siempre revisar el plan antes de aplicar.
- Secretos en .tf — usar variables sensitive, secret managers, o Vault.
- Ignorar
terraform fmt— formateo consistente facilita code review.
¿Por qué importa?
Terraform se ha convertido en el estándar de facto para infraestructura como código. Dominarlo no es opcional para equipos que operan en la nube — es la diferencia entre infraestructura reproducible y auditable, y configuración manual que nadie puede reconstruir cuando falla.
Referencias
- Terraform Documentation — HashiCorp, 2024. Documentación oficial.
- Terraform: Up & Running, 3rd Edition — Yevgeniy Brikman, 2022. La guía práctica más completa.
- Terraform Best Practices — Anton Babenko, 2024. Mejores prácticas de la comunidad.
- Terraform Registry — HashiCorp, 2024. Catálogo de providers y módulos.
- Spacelift Blog: Terraform Patterns — Spacelift, 2024. Patrones avanzados y anti-patrones.