La Transición de "ClickOps" a Infraestructura como Código (IaC)
Aprovisionar recursos en nubes públicas como Amazon Web Services (AWS) a través de la consola web (ClickOps) introduce vulnerabilidades sistémicas en entornos corporativos: falta de trazabilidad histórica, ausencia de revisiones por pares, discrepancias de configuración (drift) imposibles de auditar y un alto índice de errores humanos accidentales que exponen bases de datos o abren puertos de gestión a Internet.
La Infraestructura como Código (IaC) resuelve estos problemas al definir la infraestructura de forma declarativa y reproducible mediante código versionado en Git. En este ecosistema, Terraform y su bifurcación de código abierto bajo la Linux Foundation, OpenTofu, representan los estándares dominantes del sector.
Sin embargo, adoptar IaC sin controles rigurosos de seguridad introduce nuevos vectores de ataque críticos:
- Exposición del archivo de estado (
terraform.tfstate): El state de Terraform contiene un mapa completo de los recursos desplegados y almacena en texto plano cualquier secreto procesado (contraseñas maestras de RDS, certificados TLS, claves de acceso y tokens de servicios). - Inexistencia de bloqueos de concurrencia: Múltiples pipelines de CI/CD o ingenieros ejecutando
applyconcurrentemente sin bloqueo pueden corromper el estado de la infraestructura. - Configuraciones permisivas no auditadas: Despliegue inadvertido de Security Groups con
0.0.0.0/0, buckets S3 públicos o instancias sin cifrado KMS por falta de análisis estático en los pipelines de entrega continua. - *Deriva de configuración (Configuration Drift):* Modificaciones manuales fuera de la pipeline que desalinean la infraestructura real respecto al código fuente.
Hacer IaC de nivel empresarial exige asegurar el ciclo de vida completo: desde el almacenamiento cifrado del estado hasta el análisis estático automatizado con herramientas como Checkov.
Pipeline DevSecOps para IaC: De la Pull Request al Despliegue
La seguridad en IaC debe implementarse como un pipeline automatizado de análisis estático y puertas de calidad (quality gates), tal como exploramos en los fundamentos de qué es DevSecOps:
graph TD
subgraph Dev_Environment ["👨💻 Entorno de Desarrollo"]
Dev["Ingeniero / SRE"]
Git["Git Commit & Push"]
end
subgraph CI_Pipeline ["⚙️ Pipeline CI/CD (GitHub Actions / GitLab CI)"]
Lint["terraform fmt & validate"]
SecretScan["Escaneo de Secretos: Gitleaks"]
IaCScan["Escaneo de Seguridad IaC: Checkov / Trivy"]
Plan["terraform plan -out=tfplan"]
Gate{"¿Pasa Reglas de Seguridad?"}
end
subgraph Approval_Gate ["🛡️ Aprobación y Gobernanza"]
Review["Revisión de Plan por Pares (PR Approval)"]
end
subgraph CD_Deployment ["🚀 Despliegue en AWS Cloud"]
LockDB["DynamoDB: Adquirir State Lock"]
Apply["terraform apply tfplan"]
StateS3["S3 Bucket: Guardar tfstate (SSE-KMS)"]
UnlockDB["DynamoDB: Liberar State Lock"]
end
Dev --> Git
Git --> Lint
Lint --> SecretScan
SecretScan --> IaCScan
IaCScan --> Plan
Plan --> Gate
Gate -->|Fallo: Bloqueo crítico| Dev
Gate -->|Aprobado| Review
Review --> LockDB
LockDB --> Apply
Apply --> StateS3
StateS3 --> UnlockDB
classDef dev fill:#e1f5fe,stroke:#0288d1,stroke-width:2px;
classDef ci fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px;
classDef gate fill:#fff3e0,stroke:#f57c00,stroke-width:2px;
classDef deploy fill:#e8f5e9,stroke:#388e3c,stroke-width:2px;
class Dev,Git dev;
class Lint,SecretScan,IaCScan,Plan,Gate ci;
class Review gate;
class LockDB,Apply,StateS3,UnlockDB deploy;
1. Hardening del Backend Remoto: S3 y DynamoDB
Por defecto, Terraform almacena el estado localmente en el archivo terraform.tfstate. En entornos de equipo o producción, el estado debe persistirse en un backend remoto seguro en AWS, combinando Amazon S3 para el almacenamiento cifrado y Amazon DynamoDB para el bloqueo de concurrencia.
Requisitos de Hardening del Bucket S3:
- Bloqueo Total de Acceso Público:
BlockPublicAccess = truepara todas las políticas de lista de control de acceso (ACLs) y políticas de bucket. - Versionado de Objetos: Activado para permitir revertir a estados anteriores ante corrupción accidental.
- Cifrado en Reposo Obligatorio (SSE-KMS): Cifrado mediante una clave KMS gestionada por el cliente (CMK), evitando el uso de claves compartidas por defecto.
- Política de Transporte Seguro: Exigir
aws:SecureTransport = truepara forzar todas las operaciones sobre TLS 1.3/1.2.
A continuación se muestra la configuración del backend en Terraform/OpenTofu:
terraform {
required_version = ">= 1.6.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.40"
}
}
backend "s3" {
bucket = "corp-production-terraform-state-eu-west-1"
key = "core-infra/vpc-rds.tfstate"
region = "eu-west-1"
encrypt = true
kms_key_id = "arn:aws:kms:eu-west-1:123456789012:key/b2c3d4e5-6789-01ab-cdef-222222222222"
dynamodb_table = "terraform-state-lock-production"
}
}
La tabla de DynamoDB requiere únicamente una clave primaria de tipo String denominada LockID. Cuando un operador o pipeline ejecuta terraform apply o terraform plan, Terraform inserta temporalmente un registro en DynamoDB; si otro proceso intenta ejecutarse simultáneamente, es bloqueado con el error Error: Error acquiring the state lock, previniendo colisiones catastróficas.
2. Gestión Segura de Secretos: El Dilema del tfstate
Uno de los problemas más incomprendidos en Terraform es que cualquier valor referenciado en un recurso o proveedor queda guardado en texto plano dentro del archivo .tfstate, incluso si la variable está marcada con sensitive = true.
El atributo sensitive = true solo oculta el valor en la salida estándar de la consola (stdout) durante plan y apply; no cifra el contenido dentro del archivo JSON del estado.
Antipatrones Comunes:
- Definir contraseñas de bases de datos mediante variables estáticas en archivos
terraform.tfvars. - Generar contraseñas aleatorias con el proveedor
randompasswordy pasarlas al recursoawsdb_instance: la contraseña se escribe íntegra en el estado.
Solución de Arquitectura: Generación y Rotación Fuera de Terraform
La práctica recomendada consiste en delegar la generación de secretos a servicios especializados como AWS Secrets Manager con rotación automática, o consumir credenciales generadas de forma efímera:
# Crear el contenedor del secreto en AWS Secrets Manager gestionado por KMS
resource "aws_secretsmanager_secret" "db_credentials" {
name = "production/rds/mysql-app"
kms_key_id = aws_kms_key.infrastructure_key.arn
recovery_window_in_days = 0 # Eliminación inmediata en caso de baja controlada
}
# La contraseña NO se define en Terraform, se gestiona mediante RDS auto-generation
resource "aws_db_instance" "production_database" {
identifier = "corp-production-db"
allocated_storage = 100
engine = "mysql"
engine_version = "8.0"
instance_class = "db.r6g.large"
manage_master_user_password = true # AWS RDS gestiona y rota la contraseña en Secrets Manager
master_user_secret_kms_key_id = aws_kms_key.infrastructure_key.arn
username = "dbadmin"
vpc_security_group_ids = [aws_security_group.db_sg.id]
db_subnet_group_name = aws_db_subnet_group.private.name
publicly_accessible = false
storage_encrypted = true
kms_key_id = aws_kms_key.infrastructure_key.arn
skip_final_snapshot = false
final_snapshot_identifier = "corp-production-db-final-snapshot"
}
Al activar managemasteruser_password = true, AWS RDS crea automáticamente el secreto en AWS Secrets Manager, rota la clave periódicamente y la contraseña jamás pasa por Terraform ni se escribe en el archivo de estado.
3. Análisis Estático de Seguridad IaC con Checkov en CI/CD
El análisis estático de código de infraestructura (Static Application Security Testing - SAST para IaC) permite detectar malas prácticas antes de que los recursos sean creados en la nube. Checkov (de Palo Alto Networks / Bridgecrew) analiza archivos HCL, CloudFormation, Kubernetes y Terraform Plans frente a más de 1.000 políticas de seguridad alineadas con CIS Benchmarks.
Integración en GitHub Actions:
El siguiente flujo ejecuta validaciones automáticas ante cualquier Pull Request que modifique código Terraform:
name: "Terraform DevSecOps Quality Gate"
on:
pull_request:
paths:
- 'terraform/**'
permissions:
contents: read
pull-requests: write
jobs:
security-scan:
name: "Checkov Security & Compliance Scan"
runs-on: ubuntu-latest
steps:
- name: "Checkout Code"
uses: actions/checkout@v4
- name: "Run Gitleaks Secret Detector"
uses: gitleaks/gitleaks-action@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Set up Python & Install Checkov"
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: "Run Checkov Static Analysis"
run: |
pip install checkov
checkov --directory terraform/ \
--framework terraform \
--output cli \
--output github_failed_only \
--soft-fail false \
--skip-check CKV_AWS_144 # Justificación documentada si aplica
Si un desarrollador introduce una regla de Security Group con cidr_blocks = ["0.0.0.0/0"] en el puerto 3306 o crea un bucket S3 sin cifrado KMS, Checkov falla el pipeline con código de salida 1, impidiendo que el código se fusione a la rama principal.
4. OpenTofu: Cifrado Nativo del Estado y Compatibilidad
Tras el cambio de licencia de Terraform por parte de HashiCorp en 2023 hacia la licencia BSL (Business Source License), la comunidad de código abierto y la Linux Foundation lanzaron OpenTofu.
OpenTofu mantiene compatibilidad drop-in con el lenguaje HCL y los proveedores existentes, pero introduce una funcionalidad de seguridad largamente demandada por los equipos de ciberseguridad: Cifrado nativo del archivo de estado desde el cliente.
Configuración del Cifrado de Estado en OpenTofu:
A diferencia de Terraform tradicional, donde el estado viaja en texto plano hacia S3 y depende exclusivamente del cifrado de S3 en reposo, OpenTofu puede cifrar el estado antes de enviarlo al backend, utilizando claves AES-GCM o claves de AWS KMS:
# Exclusivo de OpenTofu (v1.7+)
terraform {
encryption {
key_provider "aws_kms" "production_kms" {
kms_key_id = "arn:aws:kms:eu-west-1:123456789012:key/b2c3d4e5-6789-01ab-cdef-222222222222"
region = "eu-west-1"
}
method "aes_gcm" "state_encryption" {
keys = key_provider.aws_kms.production_kms
}
state {
method = method.aes_gcm.state_encryption
enforced = true
}
plan {
method = method.aes_gcm.state_encryption
enforced = true
}
}
}
Con esta directiva, incluso si un atacante obtiene acceso de lectura al bucket S3 del backend o descarga un archivo de plan tfplan, no puede descifrar los datos sin permisos explícitos de kms:Decrypt sobre la clave KMS designada.
5. Buenas Prácticas para la Gobernanza de Infraestructura en Producción
Para alcanzar un nivel de madurez elevado en IaC corporativa, se recomienda consolidar las siguientes prácticas operativas:
- Despliegues Exclusivos vía CI/CD: Revocar permisos de
Applymanual a los ingenieros en sus cuentas individuales de AWS. Solo los runners de CI/CD autenticados mediante OIDC (OpenID Connect federado con GitHub Actions o GitLab) deben tener permisos para modificar recursos de producción. - Pipelines Basadas en
PlanCifrado: El comandoterraform applynunca debe ejecutarse a ciegas. Debe consumir un archivo de plan pre-generado y aprobado (terraform plan -out=tfplan), garantizando que lo que se aplica es idéntico a lo que fue revisado en la Pull Request. - *Control de Deriva Automatizado (Drift Detection):* Ejecutar un job programado (cron nocturno) que ejecute
terraform plan -detailed-exitcode. Si detecta modificaciones manuales no declaradas en código, alerta automáticamente al equipo de seguridad en Slack o PagerDuty. - Principio de Mínimo Privilegio en Roles de Aprovisionamiento: Segmentar los pipelines por capas arquitectónicas (red, base de datos, cómputo) para que el runner de Terraform encargado de la capa de datos no tenga permisos sobre la capa de identidad ni sobre los clústeres de Kubernetes.
Resumen y Checklist de Seguridad para Terraform y OpenTofu
- [x] Backend remoto S3 configurado con bloqueo de acceso público, versionado y cifrado SSE-KMS.
- [x] Concurrencia de despliegues protegida mediante tabla de bloqueo en DynamoDB.
- [x] Secretos y contraseñas delegados a AWS Secrets Manager con
managemasteruser_password = true, evitando su persistencia en el archivotfstate. - [x] Escaneo estático SAST obligatorio en CI/CD con Checkov y detección de credenciales con Gitleaks.
- [x] Despliegues ejecutados exclusivamente mediante pipelines automatizados federados vía OIDC, sin credenciales estáticas de AWS en runners.
- [x] Detección programada de deriva de configuración (drift detection) para revertir cambios manuales fuera de código.
Si necesitas auditar la infraestructura como código de tu organización, implementar pipelines DevSecOps seguros en AWS o migrar tus despliegues a OpenTofu con cifrado nativo, puedes consultar mis Servicios de Ciberseguridad y Consultoría o ponerte en contacto conmigo a través de Sobre mí.