Leer un plan de Terraform no es lo mismo que verlo
Un plan son mil líneas de diff en un terminal. Las preguntas que de verdad quieres responder —cuánto cuesta esto, qué expone, qué se rompe si falla— no están en ese formato. Así hicimos que Skyline las responda solo con el código.
Todos los equipos que usan Terraform tienen el mismo ritual. Alguien abre una pull request, CI publica el plan y un revisor baja por mil líneas de +, ~ y - buscando algo alarmante. Después lo aprueba, porque lo alarmante, si está, no parece alarmante en ese formato.
El plan es un artefacto excelente para una máquina y malo para una persona. Te dice exactamente qué atributos cambian en qué direcciones. No te dice cuánto costará el resultado, cuál de esos recursos acaba siendo alcanzable desde internet, ni qué más depende de lo que se va a reemplazar. Esas son las tres preguntas que salen de verdad en una revisión, y responderlas exige leer el plan y sostener toda la arquitectura en la cabeza a la vez.
Skyline lee ficheros .tf, carpetas de proyecto completas y el JSON de terraform plan, y responde esas tres preguntas directamente, sin ningún acceso a la nube.
Lo que el parser tiene que hacer bien
Parsear HCL para dibujar un mapa es fácil hasta que se encuentra con un repositorio real. Algunas cosas que tuvimos que resolver antes de que sirviera fuera de una demo:
La estructura de directorios importa. Los equipos no suben un fichero, suben un árbol: modules/network/main.tf, envs/prod/main.tf, envs/staging/main.tf. El parser conserva las rutas, porque el mismo nombre de recurso en dos carpetas de entorno son dos recursos distintos, y aplanarlos produce un mapa equivocado de una forma confusa.
Los módulos locales hay que expandirlos. Un bloque source = "./modules/database" es donde vive la mayor parte de la infraestructura real. Si no lo sigues, dibujas el mapa del envoltorio y te pierdes el entorno. Skyline expande las fuentes de módulos locales de forma recursiva, con un límite de profundidad para que una referencia circular no cuelgue el parseo.
Las referencias son el grafo de dependencias. ${aws_vpc.main.id} dentro de una subred no es solo una cadena, es una arista. Sacar las referencias a recursos de los valores de atributo y de depends_on te da el grafo gratis, y ese grafo es lo que hace legible un reemplazo: esta instancia RDS se va a reemplazar, y estas cuatro cosas apuntan a ella.
Las variables hay que resolverlas donde se pueda. instance_type = var.db_size no sirve para estimar coste. Resolverlo contra los valores por defecto del mismo proyecto lo convierte en db.r6g.xlarge, que sí es un número. Donde una variable no tiene valor por defecto, el recurso se reporta con menos confianza en lugar de adivinarlo en silencio.
Las tres respuestas
Cuando el código ya es un modelo de recursos, las tres vistas salen del mismo dato, que es lo que las hace útiles juntas.
Cuánto va a costar
Cada recurso pasa por un catálogo de precios por proveedor —AWS, Google Cloud, Azure y Oracle Cloud tienen el suyo— que convierte un tipo y sus atributos en un coste mensual estimado, ajustado por un factor de región. La salida es una cifra mensual por región, por servicio y por recurso.
Dos matices sobre ese número. Sale de listas de precios públicas, así que es una estimación para priorizar, no una factura; los compromisos, las tarifas negociadas y las líneas por uso la moverán. Y los recursos que se facturan puramente por uso —llamadas a API, procesamiento de datos— se marcan como tales en lugar de darles un número falso, porque una cifra equivocada con seguridad es peor que un hueco honesto.
En lo que es realmente bueno es en la comparación que nadie hace a mano: esta pull request añade 1.400 € al mes, y 1.100 de ellos son un NAT gateway por zona de disponibilidad en un módulo que alguien copió.
Qué expone
El mismo motor de reglas que corre sobre una cuenta en vivo corre sobre el código parseado, porque ambos producen la misma lista plana de recursos. Así que un grupo de seguridad con 0.0.0.0/0 en el 3306, un bucket con ACL pública, una política con Action: "*", una base de datos sin cifrar, una Lambda en un runtime obsoleto: son hallazgos antes del apply, no después.
Los que más aparecen en revisión de plan, por nuestra experiencia, son políticas IAM con comodín y puertos sensibles abiertos al mundo, y casi siempre son accidentales: una regla permisiva escrita para depurar que acabó commiteada.
Hay además una comprobación que solo tiene sentido sobre código: secretos en atributos. password, client_secret, private_key, access_token y familia, escritos a pelo en HCL o en un bloque de entorno de Lambda. Ese hallazgo no existe en un escaneo en vivo porque el valor ya está en la API del proveedor; existe en el parser porque el valor está también en tu historial de git.
Qué se rompe
El grafo de dependencias, dibujado a partir de las referencias, convierte "este recurso se va a reemplazar" en "este recurso se va a reemplazar y estas seis cosas apuntan a él". Para un plan con un -/+ sobre algo con estado, eso es la revisión entera.
Dónde encaja esto en el flujo
No creemos que sustituya la revisión de plan en CI. Va al lado, y es más útil en dos momentos:
- Antes de la pull request, sobre la rama, cuando cambiar el diseño todavía cuesta cero. Sube la carpeta, mira el número y los hallazgos, ajusta el módulo.
- En la revisión, sobre el JSON del plan, cuando el diff es demasiado grande para que nadie lo sostenga en la cabeza: una primera landing zone, un entorno nuevo, una migración.
Para un plan, Skyline muestra qué se creará, cambiará, reemplazará o destruirá, de modo que la estimación es un delta y no solo un total.
Pruébalo con algo real
La prueba honesta es un proyecto que ya conozcas bien. Sube la carpeta, mira el desglose de coste por servicio y comprueba si las tres primeras líneas son las que habrías dicho. Por nuestra experiencia no lo son alrededor de la mitad de las veces, y esa diferencia es donde empieza la conversación interesante.
Skyline es gratuito y la vía de Terraform no necesita ningún acceso a la nube. Si el resultado plantea preguntas más grandes que una pull request, para eso está nuestro trabajo de cloud.