Seguridad en Terraform: Mejores Prácticas para una Infraestructura Segura
Mejores prácticas de seguridad en Terraform para state, secretos, IAM, módulos y CI para que tu infraestructura como código llegue a producción de forma segura.
La seguridad en Terraform es la disciplina de asegurarse de que la infraestructura que defines como código sea segura cuando llega a una cuenta de nube, y no solo cómoda de escribir. Terraform es una manera excelente de describir infraestructura de forma declarativa y reproducible, pero construirá exactamente lo que le indiques, incluido un security group completamente abierto o una base de datos pública si eso es lo que dice la configuración. La buena noticia es que, como todo es código, cada riesgo se puede revisar, probar y detectar antes de aprovisionar cualquier cosa. Este análisis a fondo recorre las prácticas específicas de Terraform que más importan, desde el state file hasta el CI, y encaja dentro de nuestra guía más amplia de seguridad en infraestructura como código.
Ayuda tener presente una idea a lo largo de todo el proceso: con Terraform, un problema de seguridad y un cambio de código son lo mismo. Una configuración incorrecta es una línea en un pull request, un rol con privilegios excesivos es un bloque de recurso, un secreto filtrado es un archivo que se subió. Eso es un regalo, porque significa que puedes aplicar las mismas herramientas en las que ya confías para el código de aplicación, control de versiones, revisión, pruebas automatizadas y gates de CI, a la propia infraestructura. Las prácticas de abajo son simplemente los puntos de mayor apalancamiento donde apuntar esas herramientas. Ninguna de ellas requiere frenar a tu equipo; la mayoría es una configuración única que luego protege automáticamente cada cambio futuro.
El state file es tu mayor riesgo
Toda conversación sobre seguridad en Terraform debería comenzar por el state. Terraform registra los recursos del mundo real que gestiona en un state file, y ese archivo no es solo metadato: puede contener secretos en texto plano. Contraseñas de bases de datos, access keys generadas, claves privadas y cualquier atributo sensible que Terraform lea de vuelta de un provider pueden terminar en el state exactamente como son. Cualquiera que pueda leer el state puede leer esos secretos.
La primera regla se desprende directamente: nunca subas el state al control de versiones. Un archivo terraform.tfstate en Git es una filtración de credenciales esperando a ser clonada, y permanece en el historial incluso después de que lo borres. Agrégalo al .gitignore desde el primer día.
En su lugar, usa un backend remoto con cifrado en reposo, locking de state y un control de acceso estricto. El locking evita que dos ejecuciones corrompan el state simultáneamente, el cifrado protege los secretos que hay dentro y el control de acceso mantiene el state legible solo para los pipelines y las personas que realmente lo necesitan.
terraform {
backend "s3" {
bucket = "acme-tfstate-prod"
key = "network/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "tf-locks"
}
}
Protege también el propio backend: bloquea el acceso público al bucket de almacenamiento, restringe quién puede leerlo con una policy de alcance acotado y activa el versionado para poder recuperarte de un apply fallido. Trata el almacén de state como el datastore de joyas de la corona que es.
Dos hábitos relacionados hacen una gran diferencia. Primero, audita quién y qué puede leer el state, y revisa esa lista periódicamente; el acceso tiende a acumularse a medida que los equipos crecen, y un permiso amplio de lectura sobre un bucket de state se convierte silenciosamente en un permiso amplio de lectura sobre todos los secretos que hay dentro. Segundo, si de verdad no quieres un valor en el state en absoluto, evita que Terraform gestione el recurso que lo produce, o genera el secreto fuera de Terraform y solo referéncialo, para que el material sensible nunca pase por el state file en primer lugar. El cifrado del state protege el archivo en reposo, pero reducir lo que llega al state es el control más fuerte.
Mantén los secretos fuera del código y de las variables
El segundo problema recurrente de seguridad en Terraform son los secretos hardcodeados. Resulta tentador poner un token de API directamente en un archivo .tf o en un terraform.tfvars, pero esos archivos suelen subirse al repositorio, y todo lo que se sube es, en la práctica, público dentro de tu organización.
No hardcodees secretos ni subas archivos .tfvars que los contengan. En su lugar, obtén los secretos en tiempo de ejecución desde un secrets manager dedicado o un provider de vault, para que el valor viva en un sistema hecho para ese fin y no en tu repositorio.
data "vault_kv_secret_v2" "db" {
mount = "secret"
name = "prod/database"
}
resource "aws_db_instance" "main" {
username = "app"
password = data.vault_kv_secret_v2.db.data["password"]
}
Cuando de verdad aceptes una entrada sensible, márcala como tal. Definir sensitive = true en una variable o un output evita que su valor se imprima en la salida del plan y del apply, que es una forma habitual en que los secretos terminan pegados en logs de CI y canales de chat.
variable "db_password" {
type = string
sensitive = true
}
Marcar los valores como sensibles reduce la exposición, pero no cifra el state, así que esta práctica funciona junto con un backend protegido, no en su lugar.
Otorga a los providers el menor privilegio
Terraform actúa sobre tu nube mediante credenciales de provider, y esas credenciales suelen ser mucho más potentes de lo que cualquier configuración individual necesita. Un pipeline que solo gestiona redes no necesita permiso para eliminar bases de datos o rotar usuarios IAM.
Acota la identidad de cada provider a los recursos que realmente gestiona. Prefiere credenciales de corta duración y federadas, como OpenID Connect desde tu sistema de CI, en lugar de claves estáticas de larga duración, y separa los roles por entorno para que un pipeline de desarrollo comprometido no pueda tocar producción. El menor privilegio aquí limita el radio de impacto si alguna vez se compromete una ejecución, un runner o un conjunto de credenciales.
Acertar el alcance exacto al primer intento es difícil, así que trátalo como algo iterativo. Empieza deliberadamente estrecho, ejecuta un plan y amplía los permisos solo para las acciones específicas que Terraform realmente necesita, en lugar de otorgar un rol administrativo amplio y prometer ajustarlo más adelante, una promesa que rara vez se cumple. También vale la pena ser explícito sobre dónde residen las credenciales: una clave de larga duración incrustada en la laptop de un desarrollador o en una variable de CI es, en sí misma, un secreto que hay que proteger, lo cual es otra razón para que las credenciales federadas y con expiración sean la opción predeterminada más segura.
Cuida la cadena de suministro de módulos
Los módulos son una de las mejores funcionalidades de Terraform y uno de sus riesgos más silenciosos. Cuando traes un módulo de un registry público, estás ejecutando el código de otra persona con tus credenciales, y una referencia sin fijar significa que el código puede cambiar bajo tus pies sin previo aviso.
Fija tanto las versiones de módulos como las de providers a releases específicas y comprobadamente buenas, en lugar de rangos flotantes, para que un cambio upstream nunca entre en tu plan sin revisar. Evalúa las fuentes del registry antes de adoptarlas y, para cualquier cosa sensible o ampliamente reutilizada, aloja módulos verificados en un registry privado bajo tu control.
module "vpc" {
source = "app.private-registry.acme.com/networking/vpc/aws"
version = "3.4.1"
}
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.40"
}
}
}
El archivo de lock de dependencias, .terraform.lock.hcl, complementa esto registrando versiones exactas de providers y checksums. Súbelo al repositorio para que cada ejecución y cada compañero de equipo resuelvan los mismos binarios de provider, verificados.
Detecta valores predeterminados inseguros con análisis estático
La mayoría de los incidentes reales de seguridad en Terraform no son exóticos. Son configuraciones incorrectas comunes: un bucket de almacenamiento dejado público, un security group abierto a 0.0.0.0/0, un volumen o base de datos creado sin cifrado, una base de datos expuesta a internet. Los proveedores de nube a menudo facilitan la opción insegura, y una pequeña omisión en el HCL se convierte en una exposición real.
# Riesgoso: abierto a toda internet
resource "aws_security_group_rule" "ssh" {
type = "ingress"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
Esto es exactamente lo que el análisis estático, a veces llamado IaC scanning, está hecho para encontrar. Un scanner analiza tu Terraform antes de que se aplique y señala el bucket público, el puerto abierto al mundo, el disco sin cifrar y la configuración de logging ausente, asignando cada uno al recurso y a la línea que lo causaron. Como lee el plan en lugar de la nube en ejecución, detecta los problemas mientras aún son una corrección de una línea en un pull request y no un incidente en producción. Muchas de estas configuraciones incorrectas se relacionan con los riesgos de control de acceso y de configuración incorrecta que destaca el OWASP Top 10 (2025), lo que los convierte en un lenguaje común y sencillo entre los equipos de seguridad y de plataforma.
Aplica policy as code
El análisis estático te dice qué está mal configurado respecto a un baseline general. Policy as code te permite codificar las reglas propias de tu organización y aplicarlas automáticamente. Usando un motor al estilo OPA o Sentinel, escribes guardrails como código verificable: todo bucket debe estar cifrado, ningún security group puede permitir acceso de entrada sin restricciones, los recursos de producción deben llevar una etiqueta de centro de costos, solo se permiten las regiones aprobadas.
La clave es evaluar estas policies en el momento del plan, antes del apply, para que una violación bloquee el cambio en lugar de documentarlo después del hecho. Policy as code convierte el conocimiento tribal y las páginas de wiki en gates automatizados que se aplican de forma consistente a cada cambio, de cada ingeniero, en cada ejecución.
Detecta el drift
Incluso un Terraform perfectamente protegido puede quedar socavado después del hecho cuando alguien hace un cambio directamente en la consola de la nube. Esa divergencia entre tu código y la realidad se llama drift, y es una preocupación de seguridad tanto como operativa: un puerto abierto manualmente o una configuración de cifrado desactivada no aparecerán en tu configuración revisada.
Ejecuta terraform plan con regularidad contra producción, idealmente de forma programada, y trata los diffs inesperados como señales para investigar. Detectar el drift temprano mantiene tu código como la verdadera fuente de registro y evita que los cambios fuera de banda debiliten silenciosamente tu postura. Combina la detección de drift con una regla cultural de que la consola es para leer, no para cambiar: cuando todo cambio en producción pasa por un pull request revisado, el drift se convierte en la excepción que resalta en lugar de la norma que has aprendido a ignorar.
Analiza tu Terraform en el CI
Todas estas prácticas se unen en tu pipeline. Una etapa de CI sólida para Terraform ejecuta terraform fmt -check y terraform validate para detectar problemas de formato y sintaxis, genera un terraform plan y luego corre un análisis de seguridad de IaC y tus verificaciones de policy contra ese plan.
El detalle crucial es el comportamiento ante fallos: configura el pipeline para que falle ante hallazgos críticos, de modo que la infraestructura insegura no pueda hacer merge. Las advertencias pueden informar, pero los críticos deben bloquear. Ejecutar el análisis en cada pull request también le da a los revisores feedback de seguridad inline, junto al cambio, que es donde resulta más barato actuar sobre él.
El orden también importa aquí. Ejecuta primero las verificaciones rápidas y baratas, para que un error de formato o de validación falle en segundos, y reserva el análisis de seguridad y la evaluación de policy para el plan, que es la representación más fiel de lo que realmente va a cambiar. Analizar el plan en lugar de solo la configuración en crudo captura problemas que surgen de cómo módulos y variables se resuelven en conjunto, y no solo de lo que dice un único archivo de forma aislada. Por último, mantén el conjunto de reglas en el control de versiones junto con la infraestructura, para que ajustar una policy sea, en sí mismo, un cambio revisado con un historial claro, y para que cada branch se mida con el mismo estándar.
# Etapa de CI ilustrativa
steps:
- run: terraform fmt -check
- run: terraform validate
- run: terraform plan -out=plan.tfplan
- run: iac-scan plan.tfplan --fail-on=critical
Cómo ayuda Rainforest
Rainforest ofrece un análisis genérico de seguridad de IaC que encaja de forma natural en este flujo de trabajo. Analiza tu Terraform en busca de valores predeterminados inseguros y configuraciones incorrectas, conecta los hallazgos con el recurso y la línea exactos y se ejecuta dentro del CI, de modo que los problemas se detectan en los pull requests antes de aprovisionar cualquier cosa. Como trata la infraestructura como código como parte del mismo panorama de seguridad de aplicaciones, obtienes una vista única y consistente entre tu código y tus definiciones de nube en lugar de un silo separado. Puedes leer más sobre nuestro enfoque de pruebas de seguridad de IaC y cómo encaja en la plataforma más amplia de pruebas de seguridad de aplicaciones.
Terraform te da un enorme apalancamiento sobre tu infraestructura, y la seguridad consiste en asegurarte de que ese apalancamiento apunte en la dirección correcta. Protege tu state, mantén los secretos en un vault, acota tus providers, fija tus módulos y deja que el análisis automatizado y las verificaciones de policy capturen el resto en el CI. Si quieres ver cómo se ve el análisis automatizado de Terraform contra tus propias configuraciones, agenda una demo. Para plataformas vecinas, nuestras guías sobre seguridad en CloudFormation y seguridad en Kubernetes aplican los mismos principios a sus respectivos ecosistemas.
Preguntas frecuentes
¿Terraform es seguro por defecto?
No. Terraform aprovisiona fielmente lo que describa tu configuración, y los proveedores de nube a menudo tienen como valor predeterminado la opción más permisiva. Si tu código especifica un bucket público, un volumen sin cifrar o un security group abierto a internet, Terraform construirá exactamente eso. La seguridad proviene de cómo escribes y revisas la configuración, proteges el state y analizas los cambios, no de Terraform en sí.
¿Cómo protejo el state de Terraform?
Usa un backend remoto con cifrado en reposo, locking de state y un control de acceso estricto, y nunca subas el state al control de versiones. El state puede contener secretos en texto plano, así que restringe quién y qué puede leerlo, activa el versionado en el store de respaldo y bloquea el acceso público al bucket o contenedor que lo alberga. Trata el almacén de state como un datastore sensible.
¿Cómo mantengo los secretos fuera de Terraform?
No hardcodees secretos en archivos .tf o .tfvars y no subas archivos que los contengan. Obtén los secretos en tiempo de ejecución desde un secrets manager o un provider de vault, y marca las variables y outputs sensibles con sensitive = true para que no se impriman en los logs de plan o apply. Recuerda que marcar los valores como sensibles no cifra el state, así que combínalo con un backend protegido.
¿Cómo analizo Terraform en busca de configuraciones incorrectas?
Ejecuta el análisis estático, también llamado IaC scanning, contra tu Terraform antes de aplicarlo. Un scanner lee tu configuración o plan y señala valores predeterminados inseguros como almacenamiento público, puertos abiertos y recursos sin cifrar, ligando cada hallazgo al recurso y a la línea. Integra el análisis en el CI para que se ejecute en cada pull request y falle el build ante hallazgos críticos.
¿Qué es policy as code para Terraform?
Policy as code significa escribir las reglas de seguridad y cumplimiento de tu organización como verificaciones ejecutables, usando un motor al estilo OPA o Sentinel, y aplicarlas automáticamente. Evaluados en el momento del plan, estos guardrails bloquean los cambios que violan reglas como exigir cifrado, prohibir el acceso de entrada sin restricciones o limitar las regiones permitidas, convirtiendo los estándares escritos en gates automatizados y consistentes.

Escrito por
Bruno Baldo
CMO
Um pouco de marketing e um pouco de curiosidade e temos a receita pra criar um apaixonado por cyber!

Seguridad de Infrastructure as Code (IaC): la guía completa
Seguridad de IaC explicada: el modelo de amenazas, el scanning a lo largo del SDLC, policy as code, secrets y state y un flujo práctico de remediación.

Seguridad en AWS CloudFormation: mejores prácticas
Una guía práctica de seguridad en CloudFormation: manejo de secretos, mínimo privilegio de IAM, defaults inseguros, drift, stack policies y scanning en CI.

Seguridad en Kubernetes: la guía completa
Guía completa de seguridad en Kubernetes: el modelo de las 4C, superficie de ataque, RBAC, pods, network policies, secrets, cadena de suministro y shift-left.
