|

Protege tus Secretos en Terraform | Guía 2026

Los secretos en Terraform fuguen por tres vías principales: hardcoding en código, variables con valores por defecto, y state files en plaintext. AWS Secrets Manager, variables de entorno y remote backends encriptados son las soluciones recomendadas para proteger credenciales, API keys y datos sensibles en infraestructura.

En 30 segundos

  • Terraform almacena secretos en plaintext en el state file por defecto — cualquiera con acceso al archivo ve todas tus credenciales
  • Hardcoding secretos directamente en archivos .tf es irrecuperable: quedan en el historial de Git incluso si los borras
  • AWS Secrets Manager, Terraform Cloud y remote backends encriptados son las tres formas principales de proteger datos sensibles
  • Usá sensitive=true en outputs y nunca committées .tfstate ni archivos .tfvars con datos reales a Git
  • Herramientas como Checkov y tfsec detectan automáticamente secretos hardcodeados antes de que lleguen a producción

La gestión de secretos en Terraform es el arte y la técnica de proteger datos sensibles (contraseñas, API keys, tokens, certificados) para que no terminen expuestos en código fuente, logs, archivos de estado o historial de Git. Cuando vos definís un recurso de base de datos en Terraform, la contraseña y el usuario tienen que llegar de algún lado — el riesgo es que, si no sabés cómo hacerlo correctamente, esos datos quedan visibles en un montón de lugares.

Los tres caminos por donde fugan los secretos

Existen tres vías principales por las cuales los secretos se filtraban históricamente en Terraform, y la mayoría de las vulnerabilidades que ves hoy en día siguen estos patrones. Entender cómo ocurren estas filtraciones es la mitad del camino para prevenirlas.

Fuga Ruta 1: Hardcoding directo en archivos .tf

Esto es lo más obvio pero también lo más peligroso. Escribís una contraseña directamente en tu código Terraform:

resource “aws_db_instance” “production” { allocated_storage = 100 engine = “mysql” instance_class = “db.t3.medium” username = “admin” password = “super-secret-password” }

Acordate: esa contraseña ahora vive en tu repositorio Git. Cuando lo committeás, entra al historial de la rama. Más tarde, alguien hace `git log` o revisa un commit anterior, y ahí está la contraseña. Incluso si borras el archivo después, los commits viejos siguen conteniendo el secreto. La única forma de sacarlo completamente es hacer un rebase destructivo o usar herramientas especializadas (como git-filter-branch). Para entonces, cualquiera que haya clonado el repo tiene una copia de la contraseña en su máquina local.

Fuga Ruta 2: Secretos en variables con defaults

Parece más limpio, así que gente lo intenta:

variable “db_password” { type = string default = “super-secret-password” sensitive = true }

El problema es el mismo que la Ruta 1, solo que disfrazado. El valor está ahí, en el código, en el historial de Git. El atributo sensitive=true solo hace que Terraform no muestre el valor en los logs de terraform plan o terraform apply — pero no protege nada si el archivo ya está comprometido. Relacionado: ejecución local de agentes sin credenciales.

Fuga Ruta 3: Secretos en el state file

Acá es donde la cosa se pone seria. El archivo terraform.tfstate es un JSON que contiene el estado completo de toda tu infraestructura — y sí, toda eso incluye cada atributo de cada recurso que creaste, en plaintext. Si tu database tiene una contraseña, el password está en el state file. Si creaste un certificado SSL, ahí está. AWS credentials, API keys, todo.

Si subís ese archivo a Git (y muchos lo hacen accidentalmente, ponele que ignorás el .gitignore), cualquiera que pueda leer el repo accede a todos tus secretos de producción. Si guardás el state file en un S3 bucket y lo dejás público por error, lo mismo. Si compartes tu laptop con alguien (o te la roban) y el estado está en el disco local, exposición total.

Solución 1: AWS Secrets Manager y data sources

La forma correcta es no hardcodear nada. En cambio, guardás el secreto en un servicio de gestión de secretos (AWS Secrets Manager, Google Secret Manager, HashiCorp Vault) y le pedís a Terraform que lo traiga en runtime.

Con AWS Secrets Manager, creás el secreto una sola vez desde la consola AWS o con CLI. Luego en Terraform, usás un data source para traerlo:

data “aws_secretsmanager_secret” “db_credentials” { name = “prod/db/credentials” } data “aws_secretsmanager_secret_version” “db_credentials” { secret_id = data.aws_secretsmanager_secret.db_credentials.id } resource “aws_db_instance” “production” { allocated_storage = 100 engine = “mysql” instance_class = “db.t3.medium” username = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)[“username”] password = jsondecode(data.aws_secretsmanager_secret_version.db_credentials.secret_string)[“password”] }

Lo que cambia: el secreto nunca entra en tu código. Terraform lo solicita a AWS en el momento de aplicar la configuración, lo usa, y continúa. El state file sigue conteniendo el valor (eso es un tradeoff que aceptas), pero al menos no está en Git ni hardcodeado en ningún lado.

Solución 2: Variables de entorno, .tfvars y remote backends

La segunda aproximación es pasar secretos a través de variables de entorno o archivos .tfvars que nunca committeás. Ya lo cubrimos antes en aspectos de privacidad en control de versiones.

Definís una variable en Terraform:

variable “db_password” { type = string sensitive = true }

Y la pasas vía variable de entorno TF_VAR_db_password=tu-contraseña, o mediante un archivo terraform.tfvars que incluís en .gitignore:

db_password = “tu-contraseña”

Eso sí, el secreto sigue apareciendo en el state file. Para evitar que el state file sea accesible, usás un remote backend — es decir, guardás el estado en un servidor central (S3 con encriptación, Google Cloud Storage, Terraform Cloud) en lugar de en tu máquina local.

Terraform Cloud es lo más simple: es un servicio gestionado por HashiCorp, creás una cuenta, conectás tu repo, y todo el estado vive encriptado en sus servidores (encriptación at-rest + TLS in-transit). Otros con acceso al workspace pueden ver el estado, pero no pueden accederlo si no tienen credenciales. Si usás S3, podés encriptar con KMS y controlar el acceso vía IAM policies.

Solución 3: HashiCorp Vault y Mozilla SOPS

Si tu infraestructura ya es más compleja, te recomendaría Vault o SOPS.

HashiCorp Vault es un servidor centralizado de gestión de secretos (podés correrlo vos en tu infraestructura). Almacena secretos, controla quién tiene acceso, y hasta puede hacer rotación automática. Terraform tiene integración nativa con Vault, así que podés consultar secretos directamente sin pasar por AWS Secrets Manager.

Mozilla SOPS (Secrets Operations) es diferente: encripta valores dentro de archivos YAML/JSON y te permite committeear esos archivos encriptados al repo. Vos decís “encriptá este archivo con esta clave KMS”, hoy SOPS lo encripta, lo subes a Git, y en producción tu CI/CD tiene la clave para desencriptarlo. El archivo versionado en Git está seguro, pero sigue siendo legible desde el repo.

Cuándo usar cada una: Vault si querés centralización y rotación automática de secretos. SOPS si querés que los secretos viajen con el código pero encriptados. Ambas requieren más infraestructura que AWS Secrets Manager, pero escalable mejor si tenés cientos de aplicaciones. Cubrimos ese tema en detalle en herramientas de validación de infraestructura.

Errores comunes que veo todo el tiempo

1. Creer que sensitive=true protege el código

No lo hace. Solo oculta el valor en los logs. El archivo .tf sigue conteniendo el secreto en plaintext.

2. Guardar .tfstate en un S3 bucket sin encriptación

Es la trampa clásica. Creás un bucket, subís el state, olvidás activar encriptación por defecto, y cualquiera que adivine el nombre del bucket puede leer tus secretos de producción. Siempre: sse_algorithm = "AES256" mínimo, o mejor aún, KMS encryption.

3. No controlar acceso al remote backend

Si el state vive en S3, asegurate de que solo tu rol IAM pueda leerlo. Si está en Terraform Cloud, revisa quién tiene acceso al workspace. El state file es tan sensible como tus secretos — porque contiene tus secretos.

4. Compartir state files o .tfvars sin sanitizar

Si le mandás el state a un colega por mail, o lo pegás en un ticket, o lo compartís en Slack, estás fugando todas las credenciales. Nunca compartas state files sin revisar primero.

Tabla comparativa: opciones de protección de secretos

OpciónDificultadSecretos en GitSecretos en StateControl de accesoRotación automáticaCosto
HardcodingMuy bajaSí, comprometidoNingunoNoGratis (malo)
Variables .tfvars + .gitignoreBajaNo, si gitignore funcionaFile systemNoGratis
AWS Secrets ManagerMediaNoIAM policiesSí (manual setup)USD 0,40/secreto/mes
Terraform CloudMediaNoNo (encriptado)Team-basedNo, pero auditableGratis (hasta 5 usuarios) o USD 20-200/mes
Remote S3 + KMSMedia-AltaNoEncriptadoIAM + KMSNoUSD 1-5/mes (S3 + KMS)
HashiCorp VaultAltaNoNo, centralizadoToken-based + RBACSí, nativaGratis (self-hosted) o USD 250+/mes (cloud)
Mozilla SOPSMediaEncriptado, seguro en GitKMS/PGPManualGratis (solo KMS si usás AWS)
gestión de secretos en terraform diagrama explicativo

Ejemplos prácticos de implementación

Ejemplo 1: AWS Secrets Manager en producción

Tu empresa usa RDS para PostgreSQL en AWS. En lugar de escribir la contraseña en Terraform, guardás el secret en AWS Secrets Manager bajo el nombre prod/rds/master-password. El equipo DevOps tiene permiso en IAM para leer ese secreto. Cuando corres Terraform, pide el secreto a AWS, configura la BD, y el valor nunca toca tu código ni Git. Además, en AWS puedes rotar la contraseña cada 30 días automáticamente — Terraform se refresca y usa la nueva cuando aplicas cambios.

Ejemplo 2: Terraform Cloud en startup

Sos una startup con 5 devs, usás Terraform para AWS. Todos comparten el mismo estado, pero no querés que alguien cometa accidentalmente un rm -rf en un bucket de producción. Usás Terraform Cloud, vinculas tu GitHub, habilitas “require approval before apply”, y cada cambio necesita aprobación de un senior antes de ejecutarse. El state vive en servidores de HashiCorp (encriptado), auditable, y nadie puede aplicar sin pasar por el tablero. Sobre eso hablamos en comparativa de plataformas de versionado.

Checklist de seguridad para equipos

  • Nunca committeés .tfstate o .tfvars con datos reales a Git — ignorá esos archivos en .gitignore
  • Usá un remote backend encriptado — Terraform Cloud, S3 + KMS, o Google Cloud Storage con encryption
  • Configurá least privilege en IAM — solo quién necesita aplicar Terraform tiene permisos en AWS/GCP
  • Activá logging y auditing — CloudTrail en AWS, Cloud Audit Logs en GCP, para ver quién accede al state
  • Code review obligatorio — antes de mergear cambios que toquen infraestructura sensible
  • Automatización de scanning — corré Checkov o tfsec en tu CI/CD para detectar hardcoding antes de mergear
  • Secretos rotados regularmente — cada 30-90 días, dependiendo del riesgo percibido
  • No compartas state files por mail, Slack, o tickets — si necesitás compartir, usa herramientas de versionado privadas
  • Usa sensitive=true en outputs sensibles — solo para prevenir accidental logging, no para protección real
  • Documenta la política de secretos — que todos en el equipo sepan cómo se manejan las credenciales en cada proyecto

La realidad es que muchos equipos en América Latina corren Terraform sin protección de secretos. Eso sí, fijate que la mayoría de las vulnerabilidades de infraestructura que ves en las noticias (desde donweb.com hasta cualquier proveedor de hosting) empiezan acá: alguien committeó un secret, el repo fue comprometido, y de ahí para adelante todo es robo de datos.

Preguntas Frecuentes

¿Cómo evito que mis secretos se filtren en Terraform?

Nunca escribas secretos directamente en código. Usá AWS Secrets Manager, variables de entorno, o un remote backend encriptado. Scannea el código con Checkov antes de committearlo, ignorá .tfstate y .tfvars en Git, y activá logging para auditar accesos al state.

¿Cuál es la forma correcta de guardar contraseñas en Terraform?

En AWS Secrets Manager, Google Secret Manager, o HashiCorp Vault. No en código, no en variables con defaults, no en el state file sin encriptación. El secreto vive en un servicio centralizado, Terraform lo consulta en runtime, y nunca queda hardcodeado en tu repo.

¿Cómo protejo el archivo de estado (state file) de Terraform?

Guardalo en un remote backend (S3 con KMS, Google Cloud Storage, Terraform Cloud). Nunca en tu máquina local, nunca en Git. Encriptá el backend (mínimo AES256, mejor KMS), controla acceso vía IAM, y activá logging para ver quién accede.

¿Puedo usar variables normales para guardar datos sensibles?

No es recomendable si les das valores por defecto. sensitive=true solo oculta el valor en logs — no protege nada si el archivo ya está en Git. Mejor: pasá la variable vía TF_VAR_ (variable de entorno), .tfvars (ignorado en Git), o consulta desde AWS Secrets Manager.

¿Qué diferencia hay entre sensitive=true y usar Secrets Manager?

sensitive=true solo evita que el valor aparezca en terraform plan — es una medida cosmética. Secrets Manager mantiene el secreto fuera de tu código completamente, en un servicio centralizado con control de acceso, rotación automática, y auditing. Una protege logs, la otra protege toda tu infraestructura.

Conclusión

La gestión de secretos en Terraform es una de esas cosas que parece simple hasta que no lo es. Vos querés escribir tu configuración, aplicar cambios, e ir a tomar un café — pero si no pensás en dónde viven las credenciales, los secretos terminan regados en 15 lugares diferentes: Git, state files, logs, backups.

Lo bueno es que las soluciones existen y son relativamente simples de implementar. Si recién empezás, usá AWS Secrets Manager o Terraform Cloud (dependiendo de dónde esté tu infraestructura). Si ya tenés algo corriendo y querés mejorar, configurá un remote backend encriptado y hacé scanning automático de secrets en tu CI/CD. Si tu infraestructura es compleja con docenas de proyectos, invertí en Vault o SOPS.

La clave es entender que un state file comprometido equivale a todas tus credenciales de producción comprometidas. Si lo proteges (remoto, encriptado, acceso limitado), proteges el 80% de la cadena. El resto es escaner de código + capacitación del equipo + culture de code review.

Fuentes

Te puede interesar...