Terraform Import y Gestión de Estado

Terraform gestiona la infraestructura a través de su archivo de estado, que registra todos los recursos desplegados y su configuración actual. Dominar la gestión del estado es esencial para trabajar con infraestructura existente, migrar backends y mantener la consistencia entre el código y la realidad. Esta guía cubre las operaciones de estado más importantes que necesitarás en entornos de producción.

Requisitos Previos

  • Terraform >= 1.0 instalado
  • Acceso a una cuenta de proveedor cloud (AWS, GCP, Azure)
  • Permisos suficientes para gestionar recursos
  • Conocimientos básicos de HCL (HashiCorp Configuration Language)

Entender el Archivo de Estado

El estado de Terraform se almacena en terraform.tfstate (local) o en un backend remoto. Es un archivo JSON que mapea los recursos del código a los recursos reales en el proveedor.

# Ver el estado actual en formato legible
terraform show

# Listar todos los recursos en el estado
terraform state list

# Ver detalles de un recurso específico
terraform state show aws_instance.web

# Ver el archivo de estado en crudo (útil para depuración)
cat terraform.tfstate | python3 -m json.tool

El estado contiene información sensible como IPs, IDs de recursos y en algunos casos credenciales. Nunca lo commits a un repositorio público.

Importar Recursos Existentes

Cuando tienes infraestructura creada manualmente que quieres gestionar con Terraform, usa terraform import.

Importación básica

# Sintaxis: terraform import <tipo_recurso>.<nombre_local> <id_real_en_proveedor>

# Importar una instancia EC2 de AWS
terraform import aws_instance.web i-0abcd1234efgh5678

# Importar un grupo de seguridad
terraform import aws_security_group.main sg-0123456789abcdef0

# Importar un bucket S3
terraform import aws_s3_bucket.data my-existing-bucket-name

# Importar un registro de Route53
terraform import aws_route53_record.www Z1234567890ABC_example.com_A

Preparar el código antes de importar

Antes de importar, debes escribir el bloque de recurso correspondiente en tu código HCL:

# Definir el recurso antes de importar
resource "aws_instance" "web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.micro"
  
  tags = {
    Name = "servidor-web-produccion"
  }
}
# Después de importar, ejecutar plan para ver diferencias
terraform plan

# Si hay diferencias menores, ajustar el código para que coincida
# Luego aplicar para sincronizar el estado
terraform apply

Import block (Terraform >= 1.5)

La versión 1.5 introdujo bloques de importación declarativos:

# importaciones.tf - Define las importaciones como código
import {
  to = aws_instance.web
  id = "i-0abcd1234efgh5678"
}

import {
  to = aws_s3_bucket.data
  id = "my-existing-bucket-name"
}
# Generar código automáticamente para los recursos importados
terraform plan -generate-config-out=generated.tf

# Revisar el código generado y ajustar según necesidad
cat generated.tf

Manipulación del Estado

Mover recursos en el estado

Cuando renombras un recurso en el código sin querer destruirlo:

# Mover un recurso a un nuevo nombre
terraform state mv aws_instance.web aws_instance.servidor_web

# Mover un recurso a un módulo
terraform state mv aws_instance.web module.compute.aws_instance.web

# Mover múltiples recursos (hacerlo uno a uno para mayor control)
terraform state mv aws_security_group.old module.network.aws_security_group.main

El bloque moved (Terraform >= 1.1) es la forma declarativa y preferida:

# En tu código .tf, declarar el movimiento
moved {
  from = aws_instance.web
  to   = aws_instance.servidor_web
}

Eliminar recursos del estado

Útil cuando quieres que Terraform deje de gestionar un recurso sin destruirlo:

# Eliminar un recurso del estado (el recurso real NO se destruye)
terraform state rm aws_instance.temporal

# Eliminar todos los recursos de un módulo del estado
terraform state rm module.legacy

# Eliminar múltiples recursos con patrón
terraform state rm 'aws_instance.web[0]'

Extraer e importar estado

# Hacer backup del estado antes de cualquier operación destructiva
cp terraform.tfstate terraform.tfstate.backup.$(date +%Y%m%d)

# Extraer un recurso del estado a un archivo separado
terraform state pull > estado_completo.json

# Forzar push de un estado modificado (usar con extremo cuidado)
terraform state push estado_modificado.json

Migración de Backends

Configurar un backend remoto en S3

# backend.tf
terraform {
  backend "s3" {
    bucket         = "mi-empresa-terraform-state"
    key            = "produccion/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-state-lock"
    encrypt        = true
  }
}
# Migrar el estado local al backend remoto
terraform init -migrate-state

# Confirmar la migración cuando se solicite
# Terraform copiará el estado automáticamente

Migrar entre backends

# Paso 1: Hacer pull del estado actual
terraform state pull > backup_estado.json

# Paso 2: Actualizar la configuración del backend en main.tf

# Paso 3: Inicializar con migración
terraform init -migrate-state

# Paso 4: Verificar que el estado se migró correctamente
terraform state list

Bloqueo de Estado y Workspaces

Bloqueo de estado

El bloqueo previene modificaciones simultáneas que podrían corromper el estado:

# Forzar desbloqueo si un proceso quedó colgado (usar con cuidado)
terraform force-unlock LOCK_ID

# Ver el ID del lock en el mensaje de error de Terraform
# Error: Error acquiring the state lock
# Lock Info:
#   ID: 12345678-abcd-1234-efgh-123456789012

Gestión de Workspaces

Los workspaces permiten múltiples estados para el mismo código:

# Listar workspaces disponibles
terraform workspace list

# Crear un nuevo workspace para staging
terraform workspace new staging

# Cambiar al workspace de producción
terraform workspace select produccion

# Ver el workspace actual
terraform workspace show

# Usar el workspace en el código
# En HCL: ${terraform.workspace}
# Usar el workspace para diferenciar entornos
resource "aws_instance" "web" {
  instance_type = terraform.workspace == "produccion" ? "t3.medium" : "t3.micro"
  
  tags = {
    Entorno = terraform.workspace
  }
}

Detección de Drift

El drift ocurre cuando la infraestructura real difiere del estado de Terraform (por cambios manuales):

# Refrescar el estado comparando con la infraestructura real
terraform refresh

# Plan que muestra el drift sin aplicar cambios
terraform plan -refresh-only

# Aplicar solo los cambios de refresh (actualizar estado sin modificar infraestructura)
terraform apply -refresh-only

# Deshabilitar refresh para operaciones más rápidas (en CI/CD con estado confiable)
terraform plan -refresh=false
# Detectar recursos que existen en el proveedor pero no en el estado
# Usando AWS como ejemplo
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId,Tags[?Key==`Name`].Value]' --output table

# Comparar con lo que Terraform conoce
terraform state list | grep aws_instance

Solución de Problemas

Error: Estado bloqueado

# Ver información del lock
terraform plan
# Copiar el Lock ID del mensaje de error

# Desbloquear (solo si estás seguro de que no hay otra operación en curso)
terraform force-unlock <LOCK_ID>

Error: Recurso ya existe en el estado

# Si intentas importar un recurso que ya está en el estado
terraform state show aws_instance.web
# Decidir si moverlo o eliminarlo primero
terraform state rm aws_instance.web
terraform import aws_instance.web <nuevo_id>

Estado corrupto o inconsistente

# Restaurar desde backup
cp terraform.tfstate.backup terraform.tfstate

# O hacer pull desde el backend remoto
terraform state pull > terraform.tfstate.recovery

# Verificar integridad del estado
terraform validate
terraform plan

Recurso no encontrado en el proveedor

# El recurso existe en el estado pero fue eliminado manualmente
# Eliminarlo del estado para que Terraform no intente gestionarlo
terraform state rm aws_instance.eliminado_manualmente

# O usar terraform apply para recrearlo según el código
terraform apply -target=aws_instance.eliminado_manualmente

Conclusión

La gestión del estado es el aspecto más crítico de trabajar con Terraform en producción. Dominar terraform import, state mv, state rm y la migración de backends te permite mantener la infraestructura sincronizada con el código, refactorizar módulos sin interrupciones y recuperarte de situaciones de drift o estado corrupto. Siempre mantén backups del estado antes de realizar operaciones destructivas y usa backends remotos con bloqueo habilitado en entornos de equipo.