Plantilla de Política de Versionado de Módulos Terraform
Política lista para adaptar sobre versionado y publicación de módulos Terraform: reglas de semver, gestión de breaking changes y deprecación, formato de changelog, publicación en registro y pipelines CI/CD de release.
Visión General
Una política que tu equipo puede copiar y adaptar para versionar módulos Terraform: reglas de versionado semántico, flujos de breaking changes y deprecación, requisitos de changelog, publicación en registro y pipelines CI/CD de release. Úsala tal cual o recorta las secciones que no necesites — sirve para el Terraform Registry público, registros privados en Terraform Cloud/Enterprise y fuentes git simples.
1. Reglas de Versionado Semántico
1.1 Formato de Versión
Formato: MAJOR.MINOR.PATCH (ej.: 2.3.1)
MAJOR (X.0.0) — Cambios que rompen compatibilidad
- Variable renombrada o eliminada
- Tipo de recurso cambiado o eliminado
- Output renombrado o eliminado
- Versión mínima de Terraform incrementada
- Constraint de versión de provider cambiada a incompatible
MINOR (0.X.0) — Nuevas funcionalidades, compatible hacia atrás
- Nueva variable añadida (con default)
- Nuevo recurso añadido
- Nuevo output añadido
- Nuevo feature flag añadido
PATCH (0.0.X) — Correcciones, compatible hacia atrás
- Bug fix en configuración de recursos
- Actualización de documentación
- Bump de versión de dependencia (compatible)
- Actualización de ejemplos
1.2 Versiones Pre-release
1.0.0-alpha.1 — Preview temprano, espera breaking changes
1.0.0-beta.1 — Funcionalidad completa, en pruebas
1.0.0-rc.1 — Release candidate, pruebas finales
1.0.0 — Release estable
1.3 Cómo Elegir el Incremento
Cuando no tengas claro qué número mover, recorre la API pública del módulo: inputs, outputs y constraints de versión.
2. Estructura del Módulo
2.1 Archivos Requeridos
modules/
└── my-module/
├── main.tf # Definiciones de recursos
├── variables.tf # Variables de entrada
├── outputs.tf # Valores de salida
├── versions.tf # Constraints de Terraform y providers
├── README.md # Documentación del módulo
├── CHANGELOG.md # Historial de versiones
├── examples/ # Ejemplos de uso
│ └── basic/
│ ├── main.tf
│ └── README.md
└── tests/
└── basic_test.go # Terratest o kitchen-terraform
2.2 versions.tf — Restricciones de Versión
terraform {
required_version = ">= 1.5.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0, < 6.0"
}
}
}
2.3 Plantilla de README.md
# my-module
Descripción corta de lo que hace este módulo.
## Uso
module "my_module" {
source = "myorg/my-module/aws"
version = "2.3.1"
name = "my-app"
environment = "production"
}
## Inputs
| Nombre | Descripción | Tipo | Default | Requerido |
|--------|-------------|------|---------|-----------|
| name | Nombre del recurso | string | n/a | sí |
| environment | Nombre del entorno | string | "production" | no |
## Outputs
| Nombre | Descripción |
|--------|-------------|
| id | ID del recurso |
| arn | ARN del recurso |
3. Gestión de Breaking Changes
Los cambios que rompen compatibilidad son inevitables en módulos compartidos — lo importante es que los consumidores los vean venir. Esta sección define qué tiene que salir junto a cada release incompatible.
3.1 Checklist de Breaking Changes
- [ ] Sube la versión MAJOR
- [ ] Documenta el breaking change en CHANGELOG.md
- [ ] Incluye una guía de migración en CHANGELOG.md
- [ ] Añade un aviso de deprecación en la versión MINOR anterior
- [ ] Actualiza todos los ejemplos para usar la nueva API
- [ ] Ejecuta los tests contra la nueva versión
- [ ] Notifica a los equipos consumidores por Slack/email
- [ ] Fija una fecha de deprecación para la versión antigua (mínimo 90 días)
- [ ] Crea un issue tracker para el progreso de migración
- [ ] Actualiza la documentación del módulo
3.2 Patrón de Deprecación
variable "instance_type" {
description = "(Deprecated) Usa `instance_types` en su lugar. Se eliminará en v3.0.0."
type = string
default = null
deprecated = true
}
variable "instance_types" {
description = "Lista de tipos de instancia para el auto-scaling group"
type = list(string)
default = ["t3.micro"]
}
3.3 Plantilla de Guía de Migración
## Guía de Migración: v1.x a v2.x
### Breaking Changes
1. Variable `instance_type` eliminada → usa `instance_types` (list)
2. El output `tags` cambió de `map(string)` a `map(any)`
3. La versión mínima de Terraform subió de 1.0 a 1.5
### Pasos de Migración
1. Actualiza la versión del módulo en tu configuración:
module "my_module" {
source = "myorg/my-module/aws"
version = "2.0.0"
}
2. Reemplaza `instance_type` por `instance_types`:
# Antes (v1.x)
module "my_module" {
instance_type = "t3.micro"
}
# Después (v2.x)
module "my_module" {
instance_types = ["t3.micro"]
}
3. Ejecuta `terraform init -upgrade` para descargar la nueva versión
4. Ejecuta `terraform plan` y revisa los cambios
5. Ejecuta `terraform apply` cuando estés listo
4. Requisitos del CHANGELOG
4.1 Formato del CHANGELOG
# Changelog
## [2.3.1] - 2026-07-04
### Fixed
- Corregida la política IAM cuando `enable_logging` es false
- Corregido panic cuando `tags` es un mapa vacío
## [2.3.0] - 2026-06-15
### Added
- Nueva variable `enable_monitoring` (default: false)
- Nuevo output `monitoring_dashboard_url`
### Changed
- Constraint del provider AWS actualizada a >= 5.0, < 6.0
## [2.2.0] - 2026-05-01
### Added
- Soporte de `kms_key_id` en el módulo de bucket S3
### Deprecated
- Variable `instance_type` deprecada, usa `instance_types`
## [2.0.0] - 2026-03-01
### Breaking
- `instance_type` eliminada, reemplazada por `instance_types` (list)
- El output `tags` cambió de `map(string)` a `map(any)`
- Versión mínima de Terraform elevada a 1.5
5. Publicación en el Registro de Módulos
El versionado solo se vuelve real cuando los consumidores pueden descargar lo que taggeaste. Esta sección cubre los tres canales de publicación — elige uno por módulo y sé consistente.
5.1 Terraform Registry (Público)
# Taggea el release en git
git tag v2.3.1
git push origin v2.3.1
# Terraform Registry detecta los tags desde GitHub automáticamente
# URL del módulo: terraform-aws-modules/s3-bucket/aws
# Versión: 2.3.1
5.2 Registro Privado (Terraform Cloud/Enterprise)
# Configura Terraform CLI para el registro privado
terraform login app.terraform.io
# Usa un módulo desde el registro privado
module "my_module" {
source = "app.terraform.io/myorg/my-module/aws"
version = "2.3.1"
}
5.3 Módulos por Fuente Git
# Versionado por tag
module "my_module" {
source = "git::https://github.com/myorg/terraform-modules.git//my-module?ref=v2.3.1"
}
# Por rama (no recomendado para producción)
module "my_module" {
source = "git::https://github.com/myorg/terraform-modules.git//my-module?ref=main"
}
6. Pipeline CI/CD
6.1 GitHub Actions — Pipeline de Release del Módulo
name: Terraform Module Release
on:
push:
tags: ['v*']
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: 1.7.0
- name: Terraform format check
run: terraform fmt -check -recursive
- name: Terraform validate
run: |
terraform init -backend=false
terraform validate
- name: Run Terratest
run: |
cd tests/
go test -v -timeout 30m
- name: Generate docs
uses: terraform-docs/terraform-docs@v1.0.0
with:
output-file: README.md
output-method: inject
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
generate_release_notes: true
body_path: CHANGELOG.md
- name: Notify teams
run: |
curl -X POST ${{ secrets.SLACK_WEBHOOK }} -d "{
\"text\": \"Terraform module ${{ github.ref_name }} released\"
}"
6.2 Validación Pre-Release
name: Terraform Module Validation
on: [pull_request]
jobs:
validate:
runs-on: ubuntu-latest
strategy:
matrix:
terraform_version: ['1.5.0', '1.6.0', '1.7.0']
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ matrix.terraform_version }}
- name: Format check
run: terraform fmt -check -recursive
- name: Init
run: terraform init -backend=false
- name: Validate
run: terraform validate
- name: Security scan (tfsec)
uses: aquasecurity/tfsec-action@v1.0.0
- name: Cost estimation (infracost)
uses: infracost/infracost-action@v3
with:
path: examples/basic
7. Pin de Versión en Proyectos Consumidores
Las reglas de publicación cubren la mitad del contrato — la otra mitad es cómo los consumidores fijan tu módulo. Estos son los defaults recomendados para que las actualizaciones sean aburridas.
7.1 Estrategias de Pin
Estrategia | Ejemplo | Riesgo
──────────────────────┼──────────────────────┼──────────────────────────
Pin exacto | version = "2.3.1" | Sin auto-updates, manual
Constraint pesimista | version = "~> 2.3" | Auto patch + minor updates
Major pesimista | version = "~> 2.0" | Solo auto minor updates
Rango | version = ">= 2.0" | Arriesgado, puede romper
Latest | (sin version) | Muy arriesgado, evitar
7.2 Pin Recomendado
# Producción — pin exacto
module "production_db" {
source = "terraform-aws-modules/rds/aws"
version = "6.10.0"
}
# Staging — constraint pesimista (auto patch updates)
module "staging_db" {
source = "terraform-aws-modules/rds/aws"
version = "~> 6.10"
}
# Desarrollo — major pesimista (auto minor + patch)
module "dev_db" {
source = "terraform-aws-modules/rds/aws"
version = "~> 6.0"
}
Ver También
- Módulos de Terraform
- Buenas Prácticas de Terraform: Módulos, State y Workspaces
- Infrastructure as Code — Terraform y Pulumi
- Plantilla de Seguridad de Pipeline CI/CD
- Terraform en Producción
Referencias externas:
- Terraform Docs — Publicación de Módulos
- Terraform Docs — Constraints de Versión
- Semantic Versioning 2.0.0
Versiones ejecutables de esta política en el repositorio companion.
Preguntas frecuentes
¿Cómo sé cuándo subir la versión major?
Sube major siempre que los consumidores tengan que tocar su propia configuración para adoptar tu cambio. Los disparadores típicos:
- Una variable u output se elimina o renombra
- Una variable cambia de tipo (de string a list, por ejemplo)
- Un default cambia de forma que produce recursos distintos
- Sube la versión mínima de Terraform o del provider
Ante la duda, sube major — sobre-comunicar una ruptura sale mucho más barato que romper en silencio el terraform apply de alguien. Y suaviza el aterrizaje: marca la interfaz antigua como deprecated en la versión minor actual antes de eliminarla en la siguiente major.
¿Debería usar el Terraform Registry o fuentes git para módulos internos?
Usa el registro privado si tienes Terraform Cloud/Enterprise — te da gestión de versiones, UI navegable e integración con workspaces gratis.
Si no, las fuentes git con refs a tag son el fallback: git::https://github.com/myorg/modules.git//my-module?ref=v2.3.1. Dos reglas para ese camino:
- Fija siempre un tag (
?ref=v2.3.1) — los refs a rama como?ref=mainpueden cambiar bajo tus pies y no son reproducibles. - Cuando pasas de ~5 módulos compartidos o ~10 equipos consumidores, el registro se paga solo; la distribución por git no escala a nivel organización.
¿Cómo depreco una funcionalidad de un módulo sin romper a los consumidores actuales?
Abre una ventana de deprecación en lugar de un corte seco:
- Marca la variable u output como
deprecatedy señala el reemplazo en la descripción. - Anúncialo en el README, el CHANGELOG y un mensaje a los equipos consumidores.
- Mantén el comportamiento antiguo funcionando junto al nuevo al menos una versión minor.
- Fija una fecha de deprecación — 90 días como mínimo — y trackea las migraciones en tu issue tracker.
- Publica la eliminación en el siguiente release major, con una guía de migración que muestre el antes y el después.
¿Qué hago si un release de módulo tiene un bug?
Depende de la severidad. Si el bug rompe infraestructura o pierde datos, trátalo como un incidente:
- No puedes borrar una versión publicada del registro, pero puedes señalarla en el README y notificar a los equipos consumidores de inmediato.
- Saca un release patch (ej.: 2.3.2) con el fix y actualiza el CHANGELOG.
- ¿Bug no crítico? Con el patch release y la entrada en el changelog basta.
Una regla vale en ambos casos: nunca hagas force-push de un tag. Los consumidores que ya lo descargaron se quedan con el contenido antiguo mientras las descargas nuevas reciben el nuevo — el mismo número de versión pasa a significar dos cosas distintas, y eso es peor que el bug.
¿Cómo testeo un módulo antes de publicarlo?
Automatízalo en CI — el pipeline de la sección 6 es el setup de referencia:
- Escribe tests con Terratest o kitchen-terraform que desplieguen el módulo en una cuenta cloud desechable, verifiquen los recursos y lo destruyan todo.
- Corre los tests en cada PR contra una matriz de versiones de Terraform (y de providers si soportas un rango).
- Añade
terraform fmt -check,terraform validate, tfsec/checkov para seguridad e infracost para visibilidad de coste. - Publica solo cuando el PR esté en verde, revisado y mergeado.
Recursos Relacionados
Checklist de Hardening de Docker Images
Checklist para hardening de Docker container images para production: base image selection, user permissions, filesystem restrictions, network isolation, resource limits, secret management, vulnerability scanning y CI/CD integration con Dockerfile examples.
DocPlantilla de Kubernetes Resource Quotas
Plantilla para definir Kubernetes resource quotas por namespace: CPU y memory limits, object count quotas, storage quotas, LimitRanges para default requests, priority class integration y monitoring con ejemplos para multi-tenant clusters.
DocRunbook de Rollback de Despliegues
Runbook para revertir despliegues fallidos: triggers, comandos de kubectl/Helm/ArgoCD, rollback de migraciones de base de datos y checklists de verificación.
DocPlantilla de Seguridad de Pipeline CI/CD
Una plantilla para asegurar pipelines de compilación y despliegue contra filtraciones de credenciales, manipulación, ataques a la cadena de suministro y despliegues no autorizados.
GuideBuenas Prácticas de Terraform: Módulos, State y Workspaces
Guía práctica de Terraform: módulos, estado remoto, workspaces y seguridad para IaC de producción.
GuideMódulos de Terraform
Construye módulos de Terraform reutilizables con estructura adecuada, inputs, outputs y versionado. Cubre composición, testing y publicación en el Registry.