El estado local de Terraform puede perderse, sobrescribirse entre operadores o exponer información sensible si permanece en una laptop o se incorpora por error al repositorio.

Un backend remoto centraliza el state, permite aplicar controles de acceso y, cuando ofrece locking, evita que dos procesos modifiquen simultáneamente la misma infraestructura.

Esta guía utiliza Amazon S3 como ejemplo e incluye bloqueo mediante archivo .tflock, cifrado, versionado y migración segura desde un estado local.

Cuándo conviene usar un backend remoto

Resulta especialmente útil en:

  • Equipos que comparten infraestructura como código.
  • Infraestructura cloud administrada desde CI/CD.
  • Ambientes con cambios frecuentes.
  • Proyectos ejecutados desde distintos equipos.
  • Sistemas que requieren recuperación y auditoría del estado.

Terraform recomienda el estado remoto cuando varias personas trabajan sobre los mismos recursos. Los backends compatibles también pueden bloquear el estado durante operaciones que podrían modificarlo. Estado remoto en Terraform.

Qué contiene el state

Terraform utiliza el state para relacionar cada recurso declarado con su objeto real, además de almacenar dependencias, identificadores y atributos devueltos por los proveedores.

Ese archivo puede contener:

  • Direcciones e identificadores internos.
  • Contraseñas iniciales.
  • Tokens o claves generadas por recursos.
  • Cadenas de conexión.
  • Atributos marcados como sensibles.

Marcar una variable como sensitive oculta su valor en algunas salidas, pero no impide necesariamente que se guarde en el state o en un plan. Por eso ambos deben tratarse como información sensible. Gestión de datos sensibles.

Arquitectura recomendada

El flujo conecta:

  1. Código Terraform versionado.
  2. terraform init.
  3. Backend S3 con cifrado y versionado.
  4. Archivo .tflock para impedir concurrencia.
  5. Plan guardado y revisado.
  6. Apply controlado.
  7. Actualización del state remoto.

El locking evita escrituras simultáneas. El versionado cumple otra función: permite recuperar una versión anterior ante una eliminación o actualización accidental.

Requisitos previos

Necesitas:

  • Terraform instalado.
  • Una versión compatible con use_lockfile.
  • Un bucket S3 creado previamente.
  • Versionado habilitado en ese bucket.
  • Cifrado en reposo.
  • Bloqueo de acceso público.
  • Una identidad IAM con permisos mínimos.
  • Credenciales obtenidas mediante variables de entorno, perfiles o roles.
  • Acceso exclusivo al state local durante la migración.

Comprueba la versión:

terraform version

El backend no crea el bucket. Debe aprovisionarse antes, mediante un proceso de bootstrap independiente o una plataforma administrativa.

Paso 1: preparar el bucket

El bucket debe contar, como mínimo, con:

  • Versionado habilitado.
  • Cifrado SSE-S3 o SSE-KMS.
  • Acceso público bloqueado.
  • Política IAM limitada al prefijo del entorno.
  • Monitoreo y registro cuando el nivel de criticidad lo requiera.

Del código al backend remoto: el state se guarda con bloqueo y el plan se revisa antes de aplicarlo en firme
Flujo de Codigo con Terraform

HashiCorp recomienda expresamente habilitar S3 Bucket Versioning para recuperar el state ante eliminaciones accidentales o errores humanos. Backend S3 de Terraform.

No uses el mismo objeto key para proyectos o entornos diferentes.

Paso 2: declarar el backend

Crea backend.tf:

terraform {
  backend "s3" {
    bucket       = "mi-organizacion-tfstate-prod"
    key          = "web/terraform.tfstate"
    region       = "us-east-1"
    encrypt      = true
    use_lockfile = true
  }
}

Los parámetros principales son:

  • bucket: bucket existente donde se almacena el state.
  • key: ruta del objeto dentro del bucket.
  • region: región del bucket.
  • encrypt: solicita cifrado del state y del archivo de lock.
  • use_lockfile: habilita el locking mediante <key>.tflock.

El locking de S3 es opcional y debe habilitarse explícitamente. El mecanismo anterior basado en DynamoDB está deprecado y será eliminado en una versión futura. State locking del backend S3.

Si utilizas una clave KMS administrada por la organización:

terraform {
  backend "s3" {
    bucket       = "mi-organizacion-tfstate-prod"
    key          = "web/terraform.tfstate"
    region       = "us-east-1"
    encrypt      = true
    kms_key_id   = "arn:aws:kms:us-east-1:123456789012:key/TU_KEY_ID"
    use_lockfile = true
  }
}

La identidad necesitará también permisos como kms:Encrypt, kms:Decrypt y kms:GenerateDataKey.

Paso 3: configurar permisos mínimos

Para un state sin workspaces, Terraform necesita normalmente:

  • s3:ListBucket limitado al prefijo correspondiente.
  • s3:GetObject y s3:PutObject sobre el objeto de state.
  • s3:GetObject, s3:PutObject y s3:DeleteObject sobre el archivo .tflock.

Terraform no necesita s3:DeleteObject sobre el state para su operación normal. Sí lo necesita sobre .tflock, porque debe eliminar el bloqueo al finalizar. Permisos requeridos por el backend S3.

No concedas acceso general a todos los states de producción cuando cada equipo solo necesita administrar un prefijo.

Paso 4: proporcionar credenciales

No incluyas claves de acceso dentro de backend.tf:

# No hacer esto
access_key = "..."
secret_key = "..."

Utiliza perfiles, variables de entorno de corta duración o roles asumidos:

export AWS_PROFILE=infra-produccion
export AWS_REGION=us-east-1

Las credenciales entregadas directamente mediante la configuración del backend o ciertos usos de -backend-config pueden quedar registradas dentro de .terraform/ y de archivos de plan. HashiCorp recomienda utilizar variables de entorno o archivos de credenciales estándar. Credenciales del backend S3.

Paso 5: inicializar un proyecto nuevo

Si el proyecto todavía no tiene state:

terraform init

init:

  • Configura el backend.
  • Descarga proveedores y módulos.
  • Crea .terraform/.
  • Genera o actualiza .terraform.lock.hcl.

terraform init es idempotente y puede ejecutarse nuevamente cuando cambian módulos, proveedores o la configuración del backend. Inicialización de Terraform.

Versiona .terraform.lock.hcl: permite que el equipo utilice las mismas versiones seleccionadas de los proveedores.

Paso 6: migrar un state local existente

Si ya existe terraform.tfstate, detén temporalmente las ejecuciones del equipo. No permitas planes ni applies mientras se realiza la migración.

Primero crea una copia protegida fuera del repositorio:

cp terraform.tfstate ../terraform.tfstate.pre-migration
chmod 600 ../terraform.tfstate.pre-migration

Después agrega el bloque del backend y ejecuta:

terraform init -migrate-state

Revisa la pregunta de confirmación antes de aceptar la copia al backend.

-migrate-state intenta trasladar el estado existente. En cambio, -reconfigure descarta la configuración anterior del backend y no migra automáticamente el state. Opciones de inicialización del backend.

No uses -force-copy durante la primera migración: elimina las confirmaciones interactivas y aumenta el riesgo de copiar el state equivocado.

Paso 7: verificar la migración

Comprueba que Terraform puede leer el state remoto:

terraform state list

Compara los recursos mostrados con los esperados. Después genera un plan:

terraform plan -lock-timeout=5m

Una migración correcta no debería proponer crear nuevamente todos los recursos existentes.

Confirma también en S3:

  • Que existe el objeto definido por key.
  • Que el objeto tiene cifrado.
  • Que el bucket conserva versiones.
  • Que las políticas públicas están bloqueadas.
  • Que el archivo .tflock aparece temporalmente durante operaciones con lock.

Conserva la copia local solo hasta completar estas verificaciones. Después elimínala mediante el procedimiento seguro definido por la organización.

Paso 8: validar formato y configuración

terraform fmt -check -recursive
terraform validate

fmt -check devuelve un código distinto de cero cuando encuentra archivos con formato no canónico. validate comprueba sintaxis, tipos y consistencia interna, pero no valida credenciales, APIs del proveedor ni recursos remotos. Formato y validación.

Para validar un módulo sin conectarse al backend:

terraform init -backend=false
terraform validate

Paso 9: generar un plan revisable

terraform plan \
  -lock-timeout=5m \
  -out=tfplan

Muestra el contenido legible:

terraform show -no-color tfplan

Revisa especialmente:

  • Recursos con destroy.
  • Reemplazos representados como destrucción y creación.
  • Cambios de red, IAM, almacenamiento o bases de datos.
  • Valores conocidos únicamente después del apply.
  • Diferencias causadas por cambios fuera de Terraform.
  • Cantidad total de altas, modificaciones y bajas.

Un plan guardado puede contener secretos en texto claro, incluso cuando las variables estén marcadas como sensibles. No lo subas al repositorio ni lo publiques como log abierto. Seguridad de los planes guardados.

Si CI conserva tfplan, debe hacerlo como un artefacto privado, cifrado, con acceso restringido y retención breve.

Paso 10: aplicar exactamente el plan revisado

Cuando la revisión haya sido aprobada:

terraform apply \
  -lock-timeout=5m \
  tfplan

Al recibir un archivo guardado, terraform apply ejecuta sus acciones sin solicitar una confirmación adicional. Pasar tfplan se interpreta como la aprobación del plan. Modo de plan guardado.

Por esta razón:

  • No apliques un plan que no hayas inspeccionado.
  • No reemplaces el archivo después de la aprobación.
  • Limita quién puede ejecutar el job de apply.
  • Conserva la relación entre commit, plan aprobado y ejecución.
  • No uses -lock=false para evitar una espera.

Paso 11: comprobar el resultado

Revisa las salidas:

terraform output

Genera un nuevo plan:

terraform plan \
  -lock-timeout=5m \
  -detailed-exitcode

Los códigos son útiles en automatización:

  • 0: no hay cambios.
  • 1: ocurrió un error.
  • 2: todavía existen cambios pendientes.

Comprueba además:

  • Resultado del pipeline.
  • Estado de los recursos críticos.
  • Versión nueva del state en S3.
  • Ausencia de un .tflock abandonado.
  • Logs de auditoría del proveedor.

Separación de entornos

Para producción y staging, prioriza directorios raíz, objetos de state, permisos y, cuando corresponda, cuentas cloud diferentes:

environments/
├── staging/
│   ├── backend.tf
│   └── main.tf
└── production/
    ├── backend.tf
    └── main.tf

Cada entorno debe usar un key diferente:

staging/web/terraform.tfstate
production/web/terraform.tfstate

Los workspaces de Terraform CLI equivalen principalmente a mantener estados separados dentro del mismo directorio. No son una frontera fuerte de seguridad ni una buena herramienta para separar sistemas que requieren distintas credenciales y controles de acceso. Limitaciones de los workspaces.

Archivos que deben excluirse del repositorio

Incluye reglas como estas en .gitignore:

.terraform/
*.tfstate
*.tfstate.*
.terraform.tfstate.lock.info

tfplan
*.tfplan
plan.txt

*.tfvars
!example.tfvars

Debes versionar:

*.tf
.terraform.lock.hcl
example.tfvars

HashiCorp recomienda excluir states, backups, planes guardados, .terraform/ y archivos de variables con secretos, pero conservar .terraform.lock.hcl. Guía de estilo de Terraform.

Problemas frecuentes

El backend no inicializa

Comprueba:

  • Nombre y región del bucket.
  • Credenciales o rol activo.
  • Acceso de red hacia S3.
  • Permisos sobre el prefijo.
  • Permisos sobre .tflock.
  • Compatibilidad de la versión de Terraform.

Usa registros detallados solo de forma temporal:

TF_LOG=INFO terraform init

Los logs pueden contener información sensible. No los publiques sin revisarlos.

Error al adquirir el lock

No uses inmediatamente terraform force-unlock. Primero confirma:

  • Que no exista otro plan o apply activo.
  • Que el pipeline anterior haya terminado.
  • Que el archivo .tflock no pertenezca a una operación válida.
  • Que la identidad tenga permiso para eliminar el lock.

force-unlock debe utilizarse únicamente con el identificador correcto y después de descartar una ejecución concurrente.

El plan recrea todos los recursos después de migrar

Detén el apply. Terraform probablemente está leyendo otro state, workspace o key.

Comprueba:

terraform workspace show
terraform state list

Revisa el backend efectivo almacenado en .terraform/ y repite la migración solo después de identificar el state correcto.

El plan muestra reemplazos inesperados

Busca qué atributo provoca el reemplazo y consulta la documentación del recurso. No asumas que el cambio es inocuo: un reemplazo puede implicar pérdida de datos, cambio de dirección o indisponibilidad.

El locking no funciona

Confirma que el backend contenga:

use_lockfile = true

y que IAM permita GetObject, PutObject y DeleteObject sobre:

web/terraform.tfstate.tflock

Buenas prácticas para producción

  • Habilita versionado y cifrado del bucket.
  • Activa use_lockfile.
  • Aplica privilegios mínimos sobre el state y .tflock.
  • Usa roles y credenciales temporales.
  • Separa states y permisos por entorno.
  • Versiona .terraform.lock.hcl.
  • Conserva planes únicamente como artefactos protegidos.
  • Exige revisión de pares para producción.
  • Revisa todos los reemplazos y destrucciones.
  • Evita -lock=false y force-unlock salvo diagnóstico confirmado.
  • Relaciona cada apply con un commit y un plan aprobado.
  • Prueba periódicamente el procedimiento de recuperación desde versiones de S3.

Un backend remoto reduce el riesgo operativo, pero no vuelve seguro al state por sí solo. La protección real depende de combinar locking, versionado, cifrado, permisos mínimos y un flujo donde se aplique exactamente el plan revisado.

Cloud Servers by Donweb

Ya cambias infraestructura con plan revisado. Esa infraestructura puede estar aquí.
Alojamiento ultra rápido, escalable y con alta disponibilidad.

  • Performance que te sorprenderá
  • Rápida escalabilidad y sin limitaciones
  • Arquitectura de alta disponibilidad
  • Soporte experto y ejecutivos de cuenta
  • Pagos en tu moneda y facturación local

Provisiona tus servidores en la nube