Terraform para laboratorios reproducibles

Artículo 5 de 7

71%

completado

Cloud e infraestructuraEngineering guide6 min de lectura

Testing IaC: del HCL válido al plan que una política puede aprobar

Capas de prueba para Terraform/OpenTofu: formato, validación, tests, planes guardados, políticas y evidencia sin crear infraestructura por accidente.

terraform validate responde si la configuración es sintáctica e internamente consistente. No responde si una base de datos quedará pública, si un cambio reemplaza un recurso crítico o si el módulo conserva la propiedad que prometía. La prueba útil aparece cuando cada capa responde una pregunta distinta.

Terraform carga archivos de prueba y ejecuta secuencias de plan o apply con assertions; la propia documentación advierte que un test puede crear infraestructura real y generar costo.

La pirámide que evita probar todo con apply

Evidencia incremental

Cinco filtros antes del cambio real

Cada etapa debe ser más costosa, más contextual y menos frecuente que la anterior.
  1. fmtforma canónica y diff legible
  2. validatetipos, referencias y esquema
  3. test / planassertions sobre comportamiento
  4. policylímites organizacionales
  5. apply + smokeobjeto real y evidencia final

La regla práctica es sencilla: no subas de capa para probar algo que la capa anterior puede rechazar. Una variable sin validación no necesita una VPC real. Un nombre inválido no necesita credenciales. Una política de “sin ingress global” puede inspeccionar el plan antes de que exista una regla de firewall.

plan es una propuesta, no una promesa eterna

OpenTofu crea un plan comparando configuración, state previo y objetos remotos; el comando no ejecuta los cambios y permite revisar la propuesta antes de aplicar.

Tres objetos suelen confundirse:

  • plan especulativo: sirve para revisar intención; puede quedar obsoleto;
  • plan guardado: congela acciones concretas para aplicar exactamente ese artefacto;
  • salida textual: ayuda a humanos, pero no es una interfaz estable para políticas.

Para automatización, conserva el archivo de plan solo dentro de un entorno protegido: puede incluir valores sensibles derivados de configuración y state. Extrae JSON para inspección mecánica, pero trata ambos artefactos como datos confidenciales.

Bash
tofu plan -out=tfplan -detailed-exitcode
tofu show -json tfplan > tfplan.json

Con -detailed-exitcode, diferencia “sin cambios”, “hay cambios” y “error”. Mezclarlos produce pipelines que celebran un fallo o marcan drift como error genérico sin evidencia.

Qué probar en un módulo

Una prueba eficaz no copia toda la salida. Formula una propiedad:

hcl
run "plan_rejects_public_ingress" {
  command = plan
 
  variables {
    allowed_cidrs = ["0.0.0.0/0"]
  }
 
  expect_failures = [var.allowed_cidrs]
}

Luego cubre al menos:

  1. camino feliz mínimo;
  2. input fuera del dominio;
  3. output que otro módulo consume;
  4. recurso que nunca debe reemplazarse por un cambio compatible;
  5. teardown o mock cuando el test hace apply.

No asserts el ID aleatorio de un recurso; asserts la relación que debe sobrevivir a una implementación distinta.

Policy as code: contrato externo al módulo

Una policy revisa decisiones que el módulo no debería autoadjudicarse: regiones permitidas, cifrado, tags, gasto máximo, tipos de instancia o reemplazo de datos persistentes. Debe consumir una representación estructurada del plan y producir:

  • regla evaluada;
  • recurso afectado;
  • evidencia observada;
  • severidad;
  • excepción, responsable y caducidad cuando exista.
Matriz de Decisión

Ubicar la regla en la capa correcta

Reglas de Decisión Rápida
¿El valor es inválido en cualquier contexto?CIDR mal formado o string fuera del enum.
Validación de variable
¿La propiedad define el contrato del módulo?Siempre debe crear logs o cifrado.
Test del módulo
¿La regla depende del entorno o la organización?Regiones, costos, tags o reemplazos prohibidos.
Policy sobre el plan
¿Solo puede conocerse tras crear el objeto?Endpoint responde, alarma recibe datos.
Smoke check post-apply

La decisión no consiste en acumular checks: consiste en colocar cada restricción en la capa más temprana que pueda demostrarla sin crear infraestructura innecesaria. Se descarta un apply de prueba cuando una validación, assertion o policy sobre el plan ya puede rechazar el riesgo con mejor diagnóstico.

Fallo realista: aprobar el texto equivocado

Un pipeline publica un plan en el pull request. Después se mergea otra rama, cambia el state remoto y el job aplica un plan nuevo sin mostrarlo. Técnicamente hubo review; operacionalmente se revisó otro objeto. La corrección es diferenciar plan especulativo de PR y plan concreto de apply, y exigir que la aprobación final se asocie al hash del artefacto que realmente se ejecuta.

Una estrategia por capas, no una batería indiscriminada

Las pruebas más baratas deben responder primero. Formato y validación encuentran errores del lenguaje; tests de módulo comprueban invariantes de la interfaz; una policy evalúa el plan dentro de reglas organizacionales; la integración crea recursos y verifica comportamiento. Ejecutar siempre la capa más cara vuelve lento el feedback y no garantiza que el diagnóstico sea mejor.

Diseña también pruebas negativas. Un CIDR abierto, un tag ausente o un reemplazo prohibido debe fallar por la razón esperada. Si la policy acepta el caso inseguro o rechaza todo el plan por una expresión incidental, todavía no codifica el contrato. Conserva una muestra pequeña del JSON de plan como fixture, pero revísala cuando cambia el provider: los campos desconocidos y sensibles requieren tratamiento explícito.

En integración, cada fixture necesita nombre único, presupuesto, timeout y teardown idempotente. Registra los recursos creados antes del primer assertion para poder limpiarlos incluso si el test se interrumpe. Un pipeline verde que deja infraestructura huérfana no es reproducible; solo trasladó el fallo a la factura y al siguiente laboratorio.

Asocia cada prueba con un riesgo concreto. Si una assertion no protege contrato, seguridad, costo o comportamiento observable, quizá solo duplica la implementación. Esa relación permite retirar tests obsoletos y explica por qué un fallo bloquea el cambio.

Los resultados deben identificar fixture, versión de provider, modo plan/apply y recursos creados. Con ese contexto, una falla intermitente puede investigarse sin repetir a ciegas todo el pipeline.

Publica el reporte como artefacto con retención suficiente para comparar regresiones entre cambios consecutivos.

Contrato de lab

El lab debe correr sin credenciales reales mediante mocks o providers locales y producir:

  • fmt y validate limpios;
  • un test positivo y uno negativo;
  • tfplan.json inspeccionado por una policy simple;
  • rechazo de 0.0.0.0/0 y de un recurso fuera de allowlist;
  • evidencia de que ningún test dejó recursos;
  • hash del plan y reporte JUnit o JSON.

Conexiones dentro de la serie

Referencias

Bibliografía académica

Formato IEEENumerado para ingeniería, sistemas y protocolos.
  1. [1]

    HashiCorp, "terraform test command reference."

    official docsID: TF-TEST🔗 Abrir fuente

    Tests, assertions, plan/apply y cleanup.

  2. [2]

    OpenTofu, "Command: plan."

    official docsID: TOFU-PLAN🔗 Abrir fuente

    Plan como propuesta revisable antes de aplicar.

Fuentes primarias, papers seminales y especificaciones técnicas citadas en esta investigación.

Rutas vecinas

Si este tema te abrió hambre, sigue por aquí.

Series y labs que comparten área o dependen de esta ruta. Pocas opciones, para no convertir la curiosidad en menú infinito.

Sigue leyendo

Ideas conectadas con este artículo

Una ruta corta para continuar sin abrir veinte pestañas y perder el hilo.