Terraform describe infraestructura deseada y compara esa configuración con recursos y estado conocidos para proponer cambios. El resultado operativo depende de la configuración, las versiones utilizadas, las APIs del proveedor y el estado real. Guardar archivos de infraestructura como código permite revisar intención y cambios; no convierte una ejecución en una transacción global.

Esta nota describe un flujo de decisión y recuperación. No requiere crear recursos: antes de operar una cuenta, deben definirse el entorno, los permisos y el radio de impacto admitido.

Configuración, plan y apply

La configuración declara recursos, referencias y dependencias. Terraform construye un grafo y puede ejecutar operaciones independientes en paralelo. Una referencia ayuda a ordenar dependencias; un orden correcto no garantiza que varias APIs cambien atómicamente ni que un servicio esté listo para recibir tráfico apenas su creación termine.

Plan calcula acciones previstas con la información disponible. Normalmente refresca su visión de recursos y compara contra la configuración. Es una fotografía condicionada por ese momento, los permisos, valores desconocidos y comportamiento del proveedor. Un cambio externo entre plan y apply puede alterar el resultado; los controles de estado pueden rechazar un plan guardado que quedó obsoleto, pero no congelan las APIs remotas.

Apply ejecuta el plan. Un plan guardado permite revisar el conjunto que se pretende aplicar sin recalcular silenciosamente otro; debe protegerse como artefacto sensible y vincularse al commit, entorno y versiones revisados. Puede contener valores secretos, aunque la salida los marque como sensibles. El review debe identificar reemplazos, eliminaciones y cambios en red, identidades o datos que afecten seguridad y recuperación.

---
config:
  look: handDrawn
---
flowchart TD
    code["Configuración deseada revisada"] --> plan["Plan con versiones fijadas"]
    cloud["Recursos observados del proveedor"] --> plan
    state[("Estado remoto<br/>Protegido y versionado")] --> plan
    plan --> review["Revisar cambios y radio de impacto"]
    review --> apply["Aplicar artefacto aprobado"]
    identity["Identidad temporal de despliegue"] --> apply
    lock["Bloqueo del backend"] -->|"Coordinar escritores del estado"| apply
    apply -->|"Operaciones en APIs de recursos"| cloud
    apply -->|"Registrar resultados"| state
    cloud --> reconcile["Reconciliar fallo parcial o desviaciones"]
    reconcile --> plan

State como vínculo operativo

El state relaciona direcciones de Terraform con objetos remotos y conserva atributos necesarios para gestionar su ciclo de vida. No es un inventario completo de toda la cuenta. Borrarlo no elimina automáticamente los recursos; puede hacer que Terraform pierda la relación con objetos que todavía existen.

El state requiere control de acceso, cifrado y recuperación. Puede contener secretos y datos operativos aunque el repositorio solo tenga referencias. Un backend remoto permite compartirlo entre ejecuciones autorizadas. Separar states por entorno o dominio reduce el alcance de una ejecución, siempre que las dependencias entre ellos estén explícitas. Tener muchos archivos sin una frontera clara también puede dificultar cambios coordinados.

El versionado de objetos en S3 ayuda a recuperar versiones del archivo. Restaurar una versión antigua no deshace la infraestructura: puede describir recursos que ya cambiaron. La recuperación compara primero el state, los recursos reales y la intención antes de decidir cómo reconciliarlos. Tampoco debe confundirse versionado con una prueba de restauración.

Locking en S3

El backend S3 dispone de locking nativo mediante use_lockfile = true desde Terraform 1.10.0; es una opción que debe activarse y cuya compatibilidad depende de la versión que ejecute cada worker. El locking basado en DynamoDB está deprecado en la documentación actual. Una migración debe considerar todos los ejecutores y conservar coordinación durante el cambio, no limitarse a editar una línea.

El siguiente fragmento pertenece al módulo raíz de una sola frontera de entorno o dominio. Los valores REPLACE_* son placeholders. El bucket, su cifrado, versionado y permisos deben existir mediante un bootstrap previo al uso del backend; el bloque no los crea ni contiene credenciales. La versión mínima habilita locking nativo, pero la política del proyecto debe fijar las versiones admitidas.

terraform {
  required_version = ">= 1.10.0"
 
  backend "s3" {
    bucket       = "REPLACE_STATE_BUCKET"
    key          = "REPLACE_ENV_OR_DOMAIN/terraform.tfstate"
    region       = "REPLACE_AWS_REGION"
    encrypt      = true
    use_lockfile = true
  }
}

Los permisos deben distinguir el objeto del state del archivo .tflock. El state necesita lectura y escritura del objeto; el lockfile necesita lectura, escritura y eliminación para gestionar el bloqueo. Para el state default, no debe concederse eliminación del objeto solo porque el lockfile la requiere; borrar states de otros workspaces tiene requisitos distintos. Las operaciones de listado y su alcance también deben ajustarse al backend y ruta utilizados.

El lock coordina escritores que usan el mismo backend y clave y respetan ese mecanismo. No protege otros states, cambios manuales en la cuenta ni ejecuciones que evadan el bloqueo. Si una ejecución cae, liberar un lock requiere comprobar que su propietario ya no opera. Forzarlo mientras continúa puede permitir escritores concurrentes y dañar la coordinación.

Identidad y versiones

Un runner puede obtener credenciales temporales mediante OIDC, con una trust policy que valide emisor, audience y el subject real de los tokens autorizados. En GitHub.com se usan IDs inmutables en subjects de repositorios creados, renombrados o transferidos después del 15 de julio de 2026, o con opt-in; otros pueden conservar el formato anterior. El subject también puede personalizarse; no debe copiarse un patrón de nombres como formato universal. Si el job usa un environment, el subject y sus restricciones deben corresponder a ese contexto y a sus reglas de protección. Estos claims son de GitHub Actions; no deben extrapolarse a Forgejo.

La identidad debe poder cambiar únicamente el alcance previsto y acceder al backend necesario. Separar permisos de plan y apply puede reducir exposición, aunque el proveedor puede requerir lecturas amplias para calcular cambios. El pipeline vincula la identidad y el artefacto al entorno revisado.

Se deben fijar versiones compatibles de Terraform y proveedores, revisar el dependency lockfile y controlar la fuente y versión de los módulos. Un lockfile de proveedores no inmoviliza por sí mismo cada módulo ni el comportamiento externo de una API.

Fallos y verificación

Si apply crea un recurso y falla después, algunos cambios ya existen. Reejecutar sin observar puede agravar el incidente. Debe conservarse el diagnóstico, comprobar el state y consultar recursos reales antes de un nuevo plan. Importar o mover direcciones exige entender la relación que se repara; editar state a ciegas puede perderla.

La verificación útil usa un entorno aislado o fixtures apropiados para comprobar planes, permisos y recuperación sin tocar producción. Debe cubrir dos ejecuciones que compiten por el mismo state, un runner interrumpido, drift y un fallo después de una operación exitosa. Las señales son cambios previstos y efectivos, duración, locks, errores del proveedor y recursos pendientes de reconciliación.

El resultado esperado es un cambio revisable con alcance explícito y una ruta de recuperación cuando solo parte del grafo termina. La infraestructura declarada sigue necesitando observación y operación después de apply.

Referencias