Introducción

Uno de los conceptos más importantes y a la vez más malentendidos de Terraform es el estado (state). Sin comprender cómo funciona el estado, es imposible trabajar de forma segura y eficiente con Terraform en entornos reales. En esta lección aprenderás qué es el estado, por qué existe, cómo se estructura y cómo interactuar con él de manera segura.


¿Qué es el Estado en Terraform?

El estado de Terraform es un archivo que actúa como la "memoria" de Terraform. Contiene un mapa detallado de todos los recursos que Terraform ha creado y gestionado, junto con sus atributos y metadatos actuales.

En términos simples:

  • Terraform crea recursos en la nube (por ejemplo, una instancia EC2 en AWS).
  • Terraform guarda la información de ese recurso en un archivo llamado terraform.tfstate.
  • La próxima vez que ejecutes terraform plan o terraform apply, Terraform compara tu configuración actual con lo que hay en ese archivo de estado para determinar qué cambios son necesarios.

Sin el estado, Terraform no sabría:

  • Qué recursos ya existen.
  • Qué atributos tienen esos recursos.
  • Cuál es la relación entre los recursos de tu código HCL y los recursos reales en la nube.

Por Qué Terraform Necesita el Estado

Terraform es una herramienta declarativa: tú describes el estado deseado de tu infraestructura, y Terraform se encarga de llegar a ese estado desde la situación actual. Para hacer esto, necesita saber cuál es el estado actual.

El problema que resuelve el estado

Imagina que tienes este código:

# main.tf
resource "aws_instance" "servidor_web" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"

  tags = {
    Name = "ServidorWeb"
  }
}

La primera vez que ejecutas terraform apply, Terraform crea la instancia y guarda su ID (por ejemplo, i-0a1b2c3d4e5f67890) en el estado.

La segunda vez que ejecutas terraform plan, Terraform:

  1. Lee el archivo de estado y sabe que ya existe una instancia con ID i-0a1b2c3d4e5f67890.
  2. Consulta la API de AWS para obtener los atributos actuales de esa instancia.
  3. Compara lo que hay en la nube con lo que dice tu código HCL.
  4. Si no hay diferencias, informa "No changes. Infrastructure is up-to-date."

Sin el estado, Terraform intentaría crear una nueva instancia cada vez que ejecutaras apply, provocando duplicados y costos innecesarios.

Beneficios clave del estado

Beneficio Descripción
Mapeo de recursos Asocia cada bloque resource en HCL con un recurso real en la nube
Rendimiento Evita consultar la API del proveedor para cada atributo en cada ejecución
Seguimiento de dependencias Registra las relaciones entre recursos para el orden de creación/destrucción
Metadatos Almacena información que no está disponible en la API del proveedor

Cómo Terraform Mapea Recursos Reales al Estado

Cada recurso en tu código HCL tiene una dirección (address) única. Por ejemplo:

resource "aws_instance" "servidor_web" {
  # ...
}

La dirección de este recurso es: aws_instance.servidor_web

Cuando Terraform crea este recurso, almacena en el estado:

  • La dirección lógica: aws_instance.servidor_web
  • El ID del recurso real: por ejemplo, i-0a1b2c3d4e5f67890
  • Todos los atributos del recurso (tipo de instancia, AMI, IP pública, etc.)

Este mapeo es fundamental. Si borras un recurso del estado sin borrarlo de la nube, Terraform lo "olvidará" y ya no lo gestionará.


El Archivo terraform.tfstate: Estructura JSON Explicada

El archivo terraform.tfstate es un archivo JSON. Veamos un ejemplo simplificado:

{
  "version": 4,
  "terraform_version": "1.5.0",
  "serial": 3,
  "lineage": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "outputs": {
    "ip_publica": {
      "value": "54.123.45.67",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "servidor_web",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "ami": "ami-0c55b159cbfafe1f0",
            "id": "i-0a1b2c3d4e5f67890",
            "instance_type": "t2.micro",
            "public_ip": "54.123.45.67",
            "tags": {
              "Name": "ServidorWeb"
            }
          }
        }
      ]
    }
  ]
}

Explicación campo por campo

Campo Descripción
version Versión del formato del archivo de estado (actualmente 4)
terraform_version Versión de Terraform con la que se generó el estado
serial Número que incrementa con cada modificación del estado; ayuda a detectar conflictos
lineage UUID único generado al crear el estado por primera vez; identifica la "línea" del estado
outputs Valores de salida declarados con output en tu código
resources Lista de todos los recursos gestionados por Terraform
mode managed para recursos gestionados; data para fuentes de datos
type Tipo de recurso (por ejemplo, aws_instance)
name Nombre lógico del recurso en tu código HCL
provider Proveedor responsable de gestionar este recurso
instances Lista de instancias del recurso (normalmente una, salvo con count o for_each)
attributes Todos los atributos del recurso tal como los conoce Terraform

Estado Local vs Estado Remoto

Por defecto, Terraform guarda el estado en un archivo local llamado terraform.tfstate en el directorio de trabajo.

Estado Local

mi-proyecto/
├── main.tf
├── variables.tf
├── terraform.tfstate        ← Estado local
└── terraform.tfstate.backup ← Copia de seguridad del estado anterior

Ventajas del estado local:

  • Simple, sin configuración adicional.
  • Ideal para aprendizaje y proyectos personales.

Desventajas del estado local:

  • No es apto para equipos (conflictos cuando varios desarrolladores trabajan al mismo tiempo).
  • Sin locking nativo (riesgo de corrupción del estado).
  • Si se pierde el archivo, se pierde el control sobre la infraestructura.

Estado Remoto

Para equipos y entornos de producción, el estado se guarda en un backend remoto (S3, Azure Blob Storage, Terraform Cloud, etc.).

# backend.tf
terraform {
  backend "s3" {
    bucket = "mi-terraform-state"
    key    = "produccion/terraform.tfstate"
    region = "us-east-1"
  }
}

Ventajas del estado remoto:

  • Compartido entre todo el equipo.
  • Soporte para locking (bloqueo) para evitar escrituras concurrentes.
  • Historial y versionado del estado.
  • Separación del estado del código fuente.

Veremos los backends remotos en detalle en la lección 03-03-remote-state.md.


Operaciones que Modifican el Estado

No todas las operaciones de Terraform modifican el estado. Es importante saber cuáles sí lo hacen:

Operación ¿Modifica el estado? Descripción
terraform plan No Solo calcula los cambios necesarios
terraform apply Aplica cambios y actualiza el estado
terraform destroy Destruye recursos y los elimina del estado
terraform refresh Actualiza el estado con la realidad actual
terraform state mv Mueve recursos dentro del estado
terraform state rm Elimina recursos del estado (sin destruirlos)
terraform import Añade recursos existentes al estado
terraform init No Configura el backend y descarga proveedores

Comandos para Inspeccionar el Estado

terraform show

Muestra el estado actual de forma legible:

terraform show

Salida de ejemplo:

# aws_instance.servidor_web:
resource "aws_instance" "servidor_web" {
    ami                          = "ami-0c55b159cbfafe1f0"
    id                           = "i-0a1b2c3d4e5f67890"
    instance_type                = "t2.micro"
    public_ip                    = "54.123.45.67"

    tags = {
        "Name" = "ServidorWeb"
    }
}

También puedes usar -json para obtener la salida en formato JSON:

terraform show -json

terraform state list

Lista todos los recursos gestionados por Terraform:

terraform state list

Salida de ejemplo:

aws_instance.servidor_web
aws_security_group.sg_web
aws_vpc.mi_vpc

Muy útil cuando tienes muchos recursos y necesitas encontrar rápidamente la dirección de uno.

terraform state show

Muestra los detalles de un recurso específico en el estado:

terraform state show aws_instance.servidor_web

Salida de ejemplo:

# aws_instance.servidor_web:
resource "aws_instance" "servidor_web" {
    ami                          = "ami-0c55b159cbfafe1f0"
    availability_zone            = "us-east-1a"
    id                           = "i-0a1b2c3d4e5f67890"
    instance_type                = "t2.micro"
    private_ip                   = "10.0.1.25"
    public_ip                    = "54.123.45.67"
    vpc_security_group_ids       = [
        "sg-0a1b2c3d",
    ]

    tags = {
        "Name" = "ServidorWeb"
    }
}

El Concepto de Drift (Desincronización)

El drift (o desincronización) ocurre cuando el estado real de la infraestructura difiere del estado que Terraform conoce. Esto puede ocurrir por varias razones:

  • Alguien modificó un recurso manualmente a través de la consola de AWS/Azure/GCP.
  • Un proceso automatizado externo cambió un atributo.
  • Un recurso fue eliminado fuera de Terraform.
  • Un recurso cambió su estado debido a un evento externo (por ejemplo, una instancia que se apagó).

Ejemplo de Drift

Imagina este escenario:

  1. Terraform creó una instancia EC2 de tipo t2.micro.
  2. Un administrador cambió manualmente el tipo a t2.small en la consola de AWS.
  3. El estado de Terraform sigue diciendo t2.micro.

Ahora hay un drift: la realidad (t2.small) difiere del estado conocido por Terraform (t2.micro).

¿Por qué es problemático el drift?

  • terraform plan puede mostrar cambios inesperados.
  • Si aplicas sin revisar, Terraform podría revertir cambios manuales.
  • En entornos críticos, puede causar interrupciones del servicio.

terraform refresh y Cómo Detectar Drift

El comando terraform refresh (o terraform apply -refresh-only en versiones modernas) actualiza el archivo de estado para reflejar el estado real de los recursos sin aplicar ningún cambio de configuración.

# Forma moderna (recomendada en Terraform >= 0.15.4)
terraform apply -refresh-only

# Forma tradicional (deprecada en versiones recientes)
terraform refresh

Flujo para detectar drift

# 1. Actualiza el estado con la realidad actual
terraform apply -refresh-only

# 2. Ahora ejecuta plan para ver qué Terraform querría cambiar
terraform plan

Si plan muestra cambios, significa que hay drift: la configuración en tu código HCL difiere de lo que existe realmente.

Ejemplo de salida con drift detectado

Terraform will perform the following actions:

  # aws_instance.servidor_web will be updated in-place
  ~ resource "aws_instance" "servidor_web" {
        id            = "i-0a1b2c3d4e5f67890"
      ~ instance_type = "t2.small" -> "t2.micro"
        # (otros atributos sin cambios)
    }

Plan: 0 to add, 1 to change, 0 to destroy.

El símbolo ~ indica una actualización. Terraform detectó que la instancia es actualmente t2.small (que fue cambiado manualmente) y quiere revertirla a t2.micro (que es lo que dice tu código).

Decisión después de detectar drift

Al detectar drift, tienes dos opciones:

  1. Aplicar el plan: Terraform revertirá los cambios manuales y volverá al estado declarado en el código.
  2. Actualizar el código: Si el cambio manual era intencionado, actualiza tu código HCL para reflejar el nuevo estado y ejecuta terraform apply.

La segunda opción es generalmente la correcta en entornos maduros: el código HCL debe ser la fuente de verdad.


Ejercicio Práctico: Explorar el Estado Después de Aplicar una Configuración

Objetivo

Crear una configuración simple con el proveedor local (que no requiere credenciales de nube) y explorar el estado resultante.

Configuración de partida

Crea un directorio de trabajo y los siguientes archivos:

mkdir terraform-estado-ejercicio
cd terraform-estado-ejercicio
# main.tf
terraform {
  required_providers {
    local = {
      source  = "hashicorp/local"
      version = "~> 2.0"
    }
  }
}

# Recurso 1: Un archivo de texto
resource "local_file" "archivo_bienvenida" {
  content  = "Hola, mundo! Este archivo fue creado por Terraform."
  filename = "${path.module}/bienvenida.txt"
}

# Recurso 2: Otro archivo de texto con contenido diferente
resource "local_file" "archivo_configuracion" {
  content  = "ambiente=desarrollo\nversion=1.0"
  filename = "${path.module}/config.txt"
}

# Output para mostrar las rutas de los archivos
output "ruta_bienvenida" {
  value = local_file.archivo_bienvenida.filename
}

output "ruta_configuracion" {
  value = local_file.archivo_configuracion.filename
}

Pasos del ejercicio

Paso 1: Inicializar Terraform

terraform init

Salida esperada:

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/local versions matching "~> 2.0"...
- Installing hashicorp/local v2.4.0...
Terraform has been successfully initialized!

Paso 2: Aplicar la configuración

terraform apply -auto-approve

Paso 3: Listar los recursos en el estado

terraform state list

Respuesta esperada:

local_file.archivo_bienvenida
local_file.archivo_configuracion

Paso 4: Ver los detalles de un recurso específico

terraform state show local_file.archivo_bienvenida

Paso 5: Ver el estado completo

terraform show

Paso 6: Abrir el archivo terraform.tfstate directamente

cat terraform.tfstate

Observa la estructura JSON. Identifica los campos serial, lineage, resources y attributes.

Paso 7: Simular un drift editando el archivo manualmente

# Modifica el contenido del archivo creado por Terraform (simulando un cambio manual)
echo "Contenido modificado manualmente" > bienvenida.txt

Paso 8: Detectar el drift

terraform plan

Terraform detectará que el contenido del archivo difiere de lo que espera y propondrá restaurarlo.

Solución: Salida esperada del paso 8

Terraform used the selected providers to generate the following execution plan.

  # local_file.archivo_bienvenida must be replaced
-/+ resource "local_file" "archivo_bienvenida" {
      ~ content              = "Contenido modificado manualmente" -> "Hola, mundo! Este archivo fue creado por Terraform."
      ~ id                   = "abc123..." -> (known after apply)
        # (otros atributos sin cambios)
    }

Plan: 1 to add, 0 to change, 1 to destroy.

El símbolo -/+ indica que el recurso será destruido y recreado (porque el proveedor local reemplaza los archivos en lugar de actualizarlos en lugar).


Errores Comunes Relacionados con el Estado

Error 1: "Error acquiring the state lock"

Error: Error acquiring the state lock

Error message: ConditionalCheckFailedException: The conditional request failed
Lock Info:
  ID:        12345678-abcd-efgh-ijkl-123456789012
  Path:      terraform.tfstate
  Operation: OperationTypePlan
  Who:       usuario@maquina
  Version:   1.5.0
  Created:   2024-01-15 10:30:00 +0000 UTC
  Info:

Causa: Otro proceso de Terraform está ejecutándose (o un proceso anterior no liberó el lock). Solución: Espera a que el otro proceso termine o usa terraform force-unlock <ID> con precaución.

Error 2: Estado corrupto o inconsistente

Error: Invalid resource type

A managed resource type "aws_instance.servidor_web" was declared,
but no resource type with that name is registered in the "aws" provider.

Causa: El estado hace referencia a un tipo de recurso que ya no existe o cambió de nombre. Solución: Revisa la versión del proveedor y usa terraform state mv para actualizar las referencias si es necesario.

Error 3: Recurso en el estado pero eliminado en la nube

Error: error reading EC2 Instance (i-0a1b2c3d4e5f67890): InvalidInstanceID.NotFound:
The instance ID 'i-0a1b2c3d4e5f67890' does not exist

Causa: El recurso fue eliminado manualmente en la nube pero Terraform todavía lo tiene en el estado. Solución:

# Elimina el recurso del estado sin intentar destruirlo en la nube
terraform state rm aws_instance.servidor_web

Error 4: Archivo de estado no encontrado

Error: Failed to load state: open terraform.tfstate: no such file or directory

Causa: No existe archivo de estado (primera ejecución o se eliminó accidentalmente). Solución: Si es la primera ejecución, ejecuta terraform init. Si se eliminó accidentalmente y no hay backup, el estado está perdido y tendrás que usar terraform import para recuperar los recursos.

Consejo adicional: Nunca edites el estado manualmente

Editar el archivo terraform.tfstate directamente con un editor de texto es extremadamente peligroso. Puede corromper el estado y hacer que Terraform falle de formas impredecibles. Siempre usa los comandos oficiales de Terraform para manipular el estado.


Resumen

En esta lección has aprendido los conceptos fundamentales del estado de Terraform:

  • El estado es la memoria de Terraform: mapea tus recursos HCL con los recursos reales en la nube.
  • Sin estado, Terraform no puede determinar qué ya existe y qué necesita crear, modificar o destruir.
  • El estado se almacena por defecto en terraform.tfstate, un archivo JSON con campos como version, serial, lineage, resources y attributes.
  • Los comandos de inspección clave son:
    • terraform show: muestra el estado completo de forma legible.
    • terraform state list: lista todos los recursos gestionados.
    • terraform state show <recurso>: muestra los detalles de un recurso específico.
  • El drift es la desincronización entre el estado de Terraform y la realidad. Se detecta con terraform apply -refresh-only seguido de terraform plan.
  • El estado local es simple pero no apto para equipos; el estado remoto es la solución para entornos colaborativos.

En la siguiente lección (03-02-state-files.md) profundizaremos en la estructura del archivo de estado, aprenderemos a manipularlo con comandos como terraform state mv y terraform state rm, y veremos cómo importar infraestructura existente con terraform import.

© Copyright 2026. Todos los derechos reservados