CommunityProgramación y desarrollogithub.com

daily-dreamer/terraform-standardize

Estandariza código Terraform crudo, brownfield o importado (AWS, GCP, Azure) siguiendo las mejores prácticas de HashiCorp: separa provider.tf, versions.tf y backend.tf, parametriza valores fijos en variables.tf y locals.tf, reemplaza IDs estáticos por referencias dinámicas, aplica guardarraíles ForceNew y moved blocks, y ejecuta formateo, validación y resumen de plan.

¿Qué es terraform-standardize?

Esta habilidad guía a un agente de IA (como Claude Code, Cursor o Codex) en la refactorización de configuraciones Terraform crudas, brownfield o importadas (por ejemplo, desde Terraformer o `terraform import`) hacia una arquitectura modular y lista para producción según los estándares de HashiCorp. Es especialmente útil cuando se necesita limpiar código monolítico con cadenas hardcodeadas, IDs estáticos de la nube (ami-*, vpc-*, subnet-*, sg-*), o importaciones de recursos existentes. El flujo de trabajo consta de cinco fases: auditoría y detección de malas prácticas, establecimiento de la estructura de archivos estándar, parametrización de literales en variables y locales, reemplazo de valores estáticos por referencias dinámicas con guardarraíles de zero-drift (usando `moved` blocks y evitando cambios `ForceNew` no intencionados), y finalmente formateo, validación y verificación del plan. Soporta múltiples proveedores de nube (AWS, GCP, Azure) y proporciona pautas detalladas para manejar importaciones de Terraformer, conservar etiquetas heredadas y separar la seguridad del código de la refactorización sin desvíos.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/daily-dreamer/terraform-standardize/tree/HEAD/skills/terraform-standardize

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

Habilidad de Estandarización Terraform

Esta habilidad guía al agente en la refactorización de código Terraform crudo, brownfield, importado (por ejemplo, desde Terraformer o terraform import), o heredado en una arquitectura modular y lista para producción según los estándares de HashiCorp.

Cuándo Usar Esta Habilidad

Activa esta habilidad cuando:

  • El usuario solicite "estandarizar", "refactorizar", "limpiar" o "modularizar" configuraciones Terraform.
  • El código Terraform contenga cadenas hardcodeadas, números mágicos o IDs estáticos de la nube (ami-*, vpc-*, subnet-*, sg-*, arn:*).
  • Configuraciones monolíticas de un solo archivo (main.tf con todo) necesiten separarse en diseños estándar de múltiples archivos (provider.tf, variables.tf, locals.tf, outputs.tf, backend.tf).
  • Los recursos de la nube necesiten taxonomías de etiquetado estandarizadas (por ejemplo, Environment, Project, ManagedBy = "terraform").
  • El código base carezca de definiciones de variables, restricciones de tipo o bloques de descripción.

Flujo de Trabajo de Estandarización

Sigue este procedimiento de 5 fases al estandarizar cualquier código base Terraform:

┌────────────────────────────────────────────────────────┐
│ Fase 1: Auditoría y Detección de Malas Prácticas       │
│ • Detectar literales hardcodeados, IDs, regiones y CIDRs│
│ • Inspeccionar la estructura de archivos existente      │
└──────────────────────────┬─────────────────────────────┘
                           │
                           ▼
┌────────────────────────────────────────────────────────┐
│ Fase 2: Establecer Arquitectura de Archivos Estándar   │
│ • Extraer provider.tf, versions.tf y backend.tf         │
│ • Crear variables.tf, locals.tf y outputs.tf            │
└──────────────────────────┬─────────────────────────────┘
                           │
                           ▼
┌────────────────────────────────────────────────────────┐
│ Fase 3: Parametrizar Literales en Variables y Locales  │
│ • Extraer variables de entorno/región con tipos         │
│ • Construir local.common_tags para etiquetado unificado │
│ • Crear terraform.tfvars.example                        │
└──────────────────────────┬─────────────────────────────┘
                           │
                           ▼
┌────────────────────────────────────────────────────────┐
│ Fase 4: Enlace de Referencias Dinámicas y Renombrado   │
│ • Reemplazar IDs de recursos estáticos por referencias │
│ • Reemplazar AMIs/subnets hardcodeados con data sources│
│ • Estandarizar etiquetas de recursos (snake_case, sin  │
│   tipos)                                               │
└──────────────────────────┬─────────────────────────────┘
                           │
                           ▼
┌────────────────────────────────────────────────────────┐
│ Fase 5: Formatear, Validar y Verificar                 │
│ • Ejecutar `terraform fmt -recursive`                  │
│ • Ejecutar `terraform validate`                        │
│ • Verificar con `terraform plan` (sin desvíos)         │
└────────────────────────────────────────────────────────┘

Instrucciones Paso a Paso

1. Fase 1: Auditoría y Descubrimiento

Antes de hacer ediciones, escanea el directorio destino para identificar:

  1. Disponibilidad de CLI: Ejecuta terraform version (o tofu version para OpenTofu) para determinar si las comprobaciones de formateo, validación y planificación de CLI pueden ejecutarse en la Fase 5.
  2. Archivos estándar faltantes: Verifica si existen versions.tf, provider.tf, variables.tf, locals.tf y outputs.tf.
  3. IDs y literales hardcodeados:
    • Identificadores de nube: ami-[a-f0-9]+, vpc-[a-f0-9]+, subnet-[a-f0-9]+, sg-[a-f0-9]+, igw-[a-f0-9]+, enlaces completos de GCP (https://www.googleapis.com/compute/...), IDs de project estáticos
    • Bloques CIDR: "10.0.0.0/16", "0.0.0.0/0"
    • Tipos de instancia: "t3.micro", "m5.large", "e2-standard-4"
    • Regiones y números de cuenta estáticos: "us-east-1", "us-central1", "123456789012"
    • Credenciales sin procesar o secretos no cifrados
  4. Línea base de formateo: Si Terraform está instalado, verifica si los archivos cumplen con terraform fmt -check -recursive.

2. Fase 2: Crear Archivos Centrales Estándar

Asegúrate de que la configuración destino esté dividida en archivos distintos y de responsabilidad única:

provider.tf / versions.tf

Centraliza la configuración de Terraform, la versión mínima de CLI y los proveedores requeridos (adapta para AWS, GCP o Azure):

# versions.tf
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    # Ejemplo GCP:
    # google = {
    #   source  = "hashicorp/google"
    #   version = "~> 5.5"
    # }
  }
}

# provider.tf (AWS)
provider "aws" {
  region = var.aws_region

  default_tags {
    tags = local.common_tags
  }
}

# provider.tf (alternativa GCP)
# provider "google" {
#   project        = var.project_id
#   region         = var.region
#   default_labels = local.common_labels
# }

Estrategia de Etiquetado Único: Usa o default_tags / default_labels a nivel de proveedor (poniendo solo claves específicas del recurso en recursos individuales) o merge(local.common_tags, ...) / merge(local.common_labels, ...) en cada recurso — nunca dupliques ambos.

backend.tf (si se usa estado remoto)

Configuración de almacenamiento de estado separada (s3 para AWS, gcs para GCP, azurerm para Azure):

terraform {
  backend "s3" {
    bucket         = "myorg-terraform-state"
    key            = "services/app/terraform.tfstate"
    region         = "us-east-1"
    dynamodb_table = "terraform-locks"
    encrypt        = true
  }
}

# Ejemplo GCP:
# terraform {
#   backend "gcs" {
#     bucket = "myorg-terraform-state"
#     prefix = "services/app"
#   }
# }

3. Fase 3: Convertir Cadenas Simples en Variables y Locales

Extrae todos los parámetros hardcodeados en variables.tf y locals.tf:

Reglas de variables.tf:

  • Declara siempre type: (string, number, bool, list(string), map(string)).
  • Incluye siempre description: Explica el propósito y el formato esperado.
  • Proporciona default solo cuando tenga sentido: Opciones de configuración como environment o aws_region pueden tener valores por defecto, pero los valores sensibles no deben tener valores por defecto hardcodeados.
  • Marca secretos como sensitive = true: Variables de contraseñas, tokens y secretos deben marcarse como sensibles.

Ejemplo de variables.tf:

variable "aws_region" {
  type        = string
  description = "La región de AWS donde se aprovisionarán los recursos."
  default     = "us-east-1"
}

variable "environment" {
  type        = string
  description = "Nombre del entorno de despliegue (ej., dev, staging, prod)."
  default     = "production"

  validation {
    condition     = contains(["dev", "staging", "production"], var.environment)
    error_message = "El entorno debe ser uno de: dev, staging, production."
  }
}

variable "instance_type" {
  type        = string
  description = "Tamaño de la instancia EC2 para el clúster de la aplicación."
  default     = "t3.medium"
}

variable "vpc_cidr" {
  type        = string
  description = "Bloque CIDR base para la Nube Privada Virtual."
  default     = "10.0.0.0/16"
}

Reglas de locals.tf:

Usa locals para valores derivados internamente, prefijos de entorno y etiquetas comunes:

locals {
  name_prefix = "${var.project_name}-${var.environment}"

  common_tags = {
    Project     = var.project_name
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

terraform.tfvars.example

Crea siempre un archivo de ejemplo de valores de variables para que los compañeros sepan cómo proporcionar valores:

aws_region   = "us-east-1"
environment  = "production"
project_name = "checkout-service"

4. Fase 4: Reemplazar Valores Estáticos con Referencias Dinámicas (Guardarraíles de Desvío Cero)

Convierte IDs de nube estáticos y referencias a recursos inconexas en expresiones HCL nativas mientras proteges la infraestructura en vivo de reemplazos accidentales:

Guardarraíl de Inmutabilidad y ForceNew (Crítico para Brownfield / Terraformer)

  • Distingue las direcciones Terraform de los atributos de name en la nube: Renombrar una etiqueta de recurso Terraform (tfer--prod-main-vpc → main) con un bloque moved {} es seguro y sin tiempo de inactividad. Cambiar un atributo de name en la nube (por ejemplo, google_compute_network.name, google_compute_subnetwork.name, google_compute_firewall.name, google_compute_instance.name, o aws_s3_bucket.bucket) es ForceNew y destruye y recrea la infraestructura en vivo. Parametriza los nombres de nube existentes en variables.tf / terraform.tfvars en lugar de reescribirlos como "${local.name_prefix}-...".
  • Fija imágenes/AMIs importadas en importaciones brownfield: Cambiar un ami-* hardcodeado o debian-12-bookworm-v20240515 a una búsqueda most_recent = true / de familia data reemplazará las VMs existentes si existe una imagen más nueva. Fija el nombre o ID exacto de la imagen/AMI importada a través de una variable/filtro data cuando se requiera desvío cero, y solo habilita most_recent = true cuando el usuario opte por actualizaciones de imagen.
  • Mantén el endurecimiento de seguridad separado de la refactorización sin desvíos: No cambies silenciosamente atributos de comportamiento/seguridad (por ejemplo, http_tokens "optional" → "required", public_access_prevention "inherited" → "enforced", o ámbitos OAuth de VM) durante una migración sin desvíos. Trata el endurecimiento como una opción explícita o enumera claramente cada diferencia intencional.
  • Preserva claves de etiquetas heredadas al migrar: Si los recursos existentes usan env = "prod", preserva las claves existentes (o agrega claves estandarizadas junto a ellas) a menos que se apruebe el reemplazo de claves.

Lista de Verificación de Limpieza Específica de Terraformer

  • Elimina atributos de estado de solo lectura calculados (tags_all en AWS; effective_labels y terraform_labels en GCP) y atributos vacíos/por defecto ("", [], {}, false, 0).
  • Elimina sub-bloques conflictivos volcados del estado (por ejemplo, network_interface primario de EC2 cuando se establece subnet_id).
  • Reemplaza interpolaciones heredadas ${data.terraform_remote_state.*.outputs.*} y URLs completas de auto-enlace con referencias directas a recursos (por ejemplo, google_compute_network.main.id) o búsquedas data.
  • Colapsa recursos duplicados numerados (vm-01, vm-02) en un solo recurso for_each emparejado con bloques moved (to = google_compute_instance.api["01"]).
  • Extrae cadenas de user_data / startup-script escapadas con \n en línea en archivos scripts/ cargados mediante file() o templatefile().
  • Al mutar scopes o machine_type de VM en GCP, asegúrate de que allow_stopping_for_update = true esté configurado si se pretenden actualizaciones en el lugar.

Anti-patrón (Crudo / Hardcodeado):

# MAL: IDs hardcodeados y cadenas literales
resource "aws_instance" "tfer--i-0123456789abcdef0" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t3.medium"
  subnet_id     = "subnet-01234567"
  vpc_security_group_ids = [
    "sg-0abcdef1234567890"
  ]
}

Patrón Estándar (Refactorizado):

# 1. Preservación del estado: Indica a Terraform que este recurso fue renombrado (evita destruir y recrear)
moved {
  from = aws_instance.tfer--i-0123456789abcdef0
  to   = aws_instance.web
}

# 2. Búsqueda dinámica de imagen base (fija el nombre exacto para brownfield sin desvíos, o most_recent para greenfield)
data "aws_ami" "ubuntu" {
  most_recent = true
  owners      = ["099720109477"] # Canonical

  filter {
    name   = "name"
    values = [var.ami_name_pattern]
  }
}

# 3. Definición estandarizada del recurso con referencias dinámicas
resource "aws_instance" "web" {
  ami                    = data.aws_ami.ubuntu.id
  instance_type          = var.instance_type
  subnet_id              = aws_subnet.private[0].id
  vpc_security_group_ids = [aws_security_group.web.id]

  # Omite common_tags aquí si provider.tf ya establece default_tags
  tags = {
    Name = var.instance_name
  }
}

5. Fase 5: Formateo, Auditoría de Desvíos y Validación

  1. Lista de Verificación de Auditoría de Desvíos Pre-Plan (realizar siempre, especialmente si la CLI terraform no está instalada localmente):

    • Compara el name de cada recurso en la nube, image/ami, location/zone, tags/labels, y configuraciones de seguridad/red contra la fuente importada.
    • Verifica que no se hayan cambiado campos ForceNew accidentalmente y que cada recurso tfer--* tenga un bloque moved {} coincidente.
    • Separa e informa cualquier diferencia intencional (por ejemplo, endurecimiento de seguridad) de la refactorización sin desvíos.
  2. Ejecuta comprobaciones de CLI de Terraform (cuando esté instalado):

# 1. Formatear código a la sangría HCL canónica estándar
terraform fmt -recursive

# 2. Inicializar plugins de proveedores (usa -backend=false al validar sin conexión/sin estado) y validar sintaxis
terraform init -backend=false
terraform validate

# 3. Si se trabaja en un entorno activo con estado, asegúrate de que el plan no produzca diferencias no intencionadas
terraform plan
  1. Resume los cambios de terraform plan (cuando se detecte alguna diferencia): Si terraform plan informa algo distinto a No changes, detente antes de recomendar apply y presenta un resumen estructurado:
    • Totales del plan: Indica los recuentos exactos de recursos (X para agregar, Y para cambiar, Z para destruir) y cualquier transición de estado moved.
    • Cambios de alto riesgo primero (-/+ reemplazar, - destruir): Destaca cada recurso marcado para reemplazo o eliminación, nombra el atributo ForceNew que lo causa (por ejemplo, name, image, boot_disk) y explica cómo solucionarlo (como agregar un bloque moved {} faltante o restaurar el valor original en tfvars).
    • Actualizaciones en el lugar (~) y creaciones (+): Enumera cada recurso afectado y los atributos exactos que cambian (por ejemplo, labels, tags, scopes, public_access_prevention).
    • Desvío intencional vs. no intencionado: Marca claramente qué diferencias son intencionales (endurecimiento de seguridad opt-in o estandarización de etiquetas) versus desvío brownfield no intencionado para que el usuario pueda aprobarlas o revertirlas.

Guías Detalladas y Referencias

Skills relacionados