Detección de drift en Terraform sin romper producción
En pocas palabras: Un agente de detección de drift corre terraform plan -refresh-only de forma programada, clasifica con un LLM como Claude los cambios hechos fuera del código, descarta el ruido y abre un pull request con la corrección, sin ejecutar nunca terraform apply.
La detección de drift en Terraform es correr terraform plan -refresh-only de forma programada para descubrir cambios hechos fuera del código: alguien que abre un security group en la consola a las 3am, un script que taggea recursos por atrás. Un agente clasifica esos cambios, descarta el ruido y abre un pull request con la corrección, sin ejecutar nunca terraform apply.
La parte fácil es detectar. La difícil es qué hacés después, porque en una infraestructura real el reporte se dispara todo el tiempo y la única línea que importa queda enterrada entre cincuenta que no.
El drift en Terraform es la diferencia entre lo que dice tu código (y tu archivo de estado) y lo que hay de verdad en la nube. Aparece cuando alguien modifica un recurso por fuera de Terraform: la consola de AWS, un script de deploy, un autoscaler que redimensiona algo. Detectarlo es mecánico; decidir si revertir o adoptar el cambio es lo que cuesta.
En 30 segundos
- El comando clave:
terraform plan -refresh-only, disponible desde Terraform 0.15.4, compara el estado contra las APIs del proveedor sin proponer cambios de configuración. - El flag que automatiza:
-detailed-exitcodedevuelve 0 (sin drift), 2 (drift detectado) o 1 (error), así un cron sabe cuándo actuar. - La línea roja: el agente tiene credenciales de solo lectura y nunca corre
terraform apply. Re-aplicar el código puede revertir en silencio un cambio de emergencia que estaba bien. - La arquitectura: reglas deterministas para los casos obvios, un LLM solo para rankear y explicar el medio ambiguo, y un pull request como salida.
- Alternativas: driftctl, Terraform Cloud, env0 y Spacelift resuelven partes del problema sin que escribas el agente vos mismo.
¿Por qué un cambio manual en la consola te rompe la infraestructura?
Porque a partir de ese momento tu código miente. Terraform cree que es el dueño de un recurso que ya no controla, y la próxima vez que alguien corra un apply legítimo, Terraform va a intentar “arreglar” ese recurso volviéndolo a como estaba en el estado. Ahí es donde el cambio de emergencia que salvó producción a las 3am se revierte solo.
El escenario es siempre parecido. Ponele que hay un incidente, alguien de guardia entra a la consola, amplía un security group para dejar pasar tráfico y apaga el fuego. Funcionó. Pero nadie llevó ese cambio al código. Complementá con cuando cambios manuales exponen tus secretos.
Dos semanas después otro equipo hace un deploy normal de una feature que no tiene nada que ver, Terraform detecta que el security group “no coincide” con el código, lo cierra para dejarlo prolijo, y de repente el mismo problema que se resolvió a las 3am vuelve a producción sin que nadie entienda por qué. Ese es el costo real de no detectar el drift a tiempo.
Es el problema número uno en equipos que dicen usar infrastructure as code pero conviven con cambios manuales. El código y la realidad se separan de a poco, sin ruido, hasta que un día se rompe algo.
La estrategia de 3 capas: cómo clasificar el drift sin ahogarte en ruido
La clave es no tratar todos los cambios igual. En una infraestructura viva, un refresh-only devuelve decenas de diferencias por corrida y la mayoría no significan nada. Si notificás todo, el equipo aprende a ignorar las alertas y perdés justo la que importaba.
La idea es partir el reporte en tres cubos. Los dos extremos los resolvés con reglas fijas. El del medio, el ambiguo, es el único que amerita gastar tokens de un LLM para que lo explique y lo rankee.
| Categoría | Qué cae acá | Quién decide | Acción |
|---|---|---|---|
| Crítico | Reglas de seguridad ampliadas, recursos eliminados, cambios en IAM | Regla determinista | Alerta inmediata + PR de reversión sugerida |
| Ruido | Atributos auto-calculados, tags propagados por el proveedor, timestamps | Regla determinista | Ignorar y filtrar |
| Ambiguo | Cambios manuales que podrían ser legítimos (tamaño de instancia, config de red) | LLM rankea y explica | PR con contexto para que un humano decida |
Fijate que la seguridad nunca la decide el LLM. Un modelo que clasifique un cambio de IAM como “inofensivo” es un riesgo que no vale la pena correr. Relacionado: igual que la deriva en configuración DNS.
Paso 1: detectar el drift con terraform plan -refresh-only
Desde Terraform 0.15.4, un plan de tipo refresh-only compara el estado contra las APIs reales del proveedor sin proponer ningún cambio de configuración. Solo te dice qué se movió afuera de Terraform. No toca nada, no aplica nada.
Para que un cron pueda ramificar sobre el resultado, se combina con -detailed-exitcode:
- Exit 0: no hay drift, todo coincide.
- Exit 2: se detectó drift, hay que actuar.
- Exit 1: error de ejecución (credenciales, red, provider).
El comando queda algo así como terraform plan -refresh-only -detailed-exitcode -out=drift.tfplan, y después exportás el resultado a JSON con terraform show -json drift.tfplan para tener algo que un script pueda parsear. El JSON es lo que después alimenta a las reglas.
Ojo con una confusión clásica: refresh-only no es un plan normal. Un plan normal te muestra qué cambiaría tu código; el refresh-only te muestra qué cambió la realidad. Son la misma pregunta al revés.
Paso 2: clasificar los cambios (reglas primero, LLM después)
La arquitectura sana es determinista por defecto y probabilística solo donde no queda otra. Las reglas resuelven lo obvio, rápido, barato y auditable. El LLM entra únicamente para el cubo ambiguo, y su trabajo no es decidir sino ordenar y explicar. Ya lo cubrimos antes en intégralo en tu pipeline de CI/CD.
Cinco reglas iniciales alcanzan para arrancar:
- Filtrar atributos calculados: si el campo es de solo lectura o lo genera el proveedor, descartalo. Es la fuente número uno de falsos positivos.
- Marcar seguridad como crítico: cualquier cambio en security groups, IAM o buckets abiertos salta directo a alerta.
- Marcar borrados como crítico: un recurso que estaba en el estado y ya no existe casi siempre importa.
- Ignorar tags propagados: los tags que el proveedor hereda solo no son drift real.
- Todo lo demás va a “ambiguo”: y de ahí lo levanta el LLM.
Para el medio ambiguo, a Claude le pasás el diff con herramientas forzadas: Revert (llevar la realidad de vuelta al código) o Adopt (aceptar el cambio y actualizar el código). El modelo elige una y escribe una explicación de dos líneas para el humano que va a revisar el PR. Nada más. La decisión final siempre la firma una persona.
Paso 3: generar PRs de remediación sin correr terraform apply
Acá está la línea que no se cruza. El agente nunca ejecuta terraform apply. Su única salida es un pull request en GitHub que un humano revisa y mergea (o rechaza). Tiene credenciales de solo lectura sobre la nube, punto.
¿Por qué tanto énfasis? Porque el “arreglo” ingenuo del drift es re-aplicar el código, y eso puede revertir en silencio el cambio de emergencia que alguien hizo bien, tirando producción abajo una segunda vez. Un agente que auto-aplica es un agente que te rompe cosas de noche.
El armado mínimo tiene tres piezas: un workflow de GitHub Actions que corre en un schedule tipo cron, un rol de solo lectura en AWS o Azure para el refresh, y un secret con el token de la API del modelo. Cuando el -detailed-exitcode devuelve 2, el job clasifica, arma la rama y abre el PR con el diff, la categoría y la recomendación adentro. Si toda tu infraestructura, incluida la de donweb.com o cualquier proveedor de hosting y cloud que uses, pasa por este chequeo, dejás de enterarte de los cambios manuales cuando ya rompieron algo.
Comparativa: herramientas para detectar drift en Terraform
No siempre hace falta escribir el agente vos. Si no querés mantener código propio, hay opciones que resuelven la detección (y a veces la clasificación) de fábrica. La elección depende de si ya pagás una plataforma de gestión de Terraform o preferís algo abierto y liviano.
| Opción | Detección | Clasificación de riesgo | Remediación | Cuándo usarla |
|---|---|---|---|---|
| Agente custom | Sí (refresh-only + cron) | Reglas + LLM | PR, nunca apply | Querés control total y lógica a medida |
| driftctl (open source) | Sí | Básica, por filtros | Manual | Equipos que quieren algo gratis y scripteable |
| Terraform Cloud | Sí, programada | Integrada | Guiada desde la UI | Ya usás el ecosistema HashiCorp |
| env0 | Sí, continua | Con políticas | Automatizada configurable | Necesitás gobernanza sobre muchos entornos |
| Spacelift | Sí, programada | Con policy-as-code | Automatizada con aprobación | Querés reconciliación con controles finos |
El agente custom gana cuando tu lógica de “qué es crítico” es rara o muy específica de tu negocio. Las plataformas ganan cuando no querés mantener nada y ya estás adentro de su mundo. driftctl es el punto medio para quien quiere gratis y a mano. Lo explicamos a fondo en según tu plataforma de automatización elegida.
Errores comunes al implementar detección de drift
- Auto-aplicar la corrección: es el más grave. Terraform revierte el cambio de emergencia y rompe producción de nuevo. Solución: el agente solo abre PRs, un humano mergea.
- Ignorar los atributos calculados: si no los filtrás, el reporte se llena de falsos positivos y nadie lo lee más. Solución: una regla que descarte campos de solo lectura desde el día uno.
- Confundir refresh-only con un plan normal: terminás midiendo qué cambiaría tu código en vez de qué cambió la realidad. Solución: usá siempre el flag
-refresh-onlypara detección. - No filtrar recursos no importados: si un recurso existe en la nube pero nunca lo trajiste al estado, Terraform ni lo ve. Solución: complementá con una herramienta de descubrimiento tipo driftctl para la ceguera de estado.
- Notificar a todo el equipo por cada cambio: el ruido mata la señal. Solución: alertar solo lo crítico y dejar lo ambiguo en un PR silencioso que se revisa sin urgencia.
Preguntas Frecuentes
¿Qué es el drift en Terraform?
El drift en Terraform es la diferencia entre lo que declara tu código (y el archivo de estado) y lo que existe de verdad en el proveedor de nube. Aparece cuando alguien modifica un recurso por fuera de Terraform, como cambiar un security group desde la consola de AWS. A partir de ahí, el estado deja de reflejar la realidad.
¿Cómo detecto automáticamente cambios hechos fuera de Terraform?
Corriendo terraform plan -refresh-only -detailed-exitcode de forma programada, disponible desde Terraform 0.15.4. El flag -detailed-exitcode devuelve 0 sin drift, 2 con drift y 1 con error, así un cron o un workflow de GitHub Actions decide cuándo disparar el proceso de clasificación.
¿Cómo diferencio un cambio crítico del ruido de drift?
Con reglas deterministas para los extremos y un LLM solo para el medio. Los atributos auto-calculados y los tags propagados son ruido y se filtran; los cambios en seguridad, IAM o recursos borrados son críticos y saltan alerta. Lo ambiguo (un tamaño de instancia distinto, por ejemplo) lo rankea y explica el modelo.
¿Puedo generar pull requests automáticas cuando detecto drift?
Sí, y es la salida recomendada. El agente arma una rama con el diff, la categoría y la corrección sugerida, y abre un PR en GitHub para que un humano lo revise. La regla de oro es que nunca ejecute terraform apply por su cuenta: solo propone, una persona aprueba.
¿Cuál es la diferencia entre driftctl y Terraform Cloud para detectar cambios?
driftctl es open source, gratuito y scripteable, y además detecta recursos que existen en la nube pero nunca importaste al estado. Terraform Cloud trae detección programada integrada a su UI y funciona mejor si ya vivís en el ecosistema HashiCorp. driftctl te da control manual; Terraform Cloud te da comodidad dentro de su plataforma.
Conclusión
Detectar drift es lo barato: un terraform plan -refresh-only en un cron y listo. Lo que separa un sistema útil de una fuente de alertas ignoradas es la clasificación, esa capa de tres cubos donde las reglas resuelven lo obvio y el LLM se gasta solo en el medio ambiguo.
Si te llevás una sola cosa, que sea la línea roja: el agente nunca corre apply. Solo abre PRs con credenciales de solo lectura, porque re-aplicar a ciegas puede revertir un cambio de emergencia que estaba bien y tirar producción abajo por segunda vez.
Empezá chico. Un workflow de GitHub Actions, un rol read-only, cinco reglas deterministas y un PR de prueba de concepto. Si preferís no mantener código, driftctl para lo abierto o una plataforma como Terraform Cloud, env0 o Spacelift si ya pagás una. Lo que no podés seguir haciendo es enterarte de los cambios manuales cuando ya rompieron algo.
Fuentes
- Build a Terraform Drift Detection Agent – guía original en dev.to sobre el agente y refresh-only plans
- HashiCorp – detección de drift en Terraform Cloud (fuente oficial)
- Spacelift – guía de detección de drift en Terraform
- env0 – guía completa para detectar, prevenir y remediar drift
- terraform-drift-detection – repositorio de referencia en GitHub





