Etiquetado Cloud para Asignación de Costos: Guía Práctica con Terraform

Aprende a implementar una estrategia de etiquetado cloud multi-nube con Terraform. Incluye código listo para producción en AWS, Azure y GCP, políticas de enforcement con OPA y Azure Policy, y métricas FinOps de cumplimiento.

Por Qué el Etiquetado Es la Base de Toda Estrategia FinOps

Vamos directo al grano: en 2026, con el gasto global en nube pública superando el billón de dólares, el 82% de las empresas con cargas de trabajo en la nube está tirando dinero por la ventana. Y la razón es casi siempre la misma — un etiquetado de recursos inconsistente o, peor aún, inexistente.

Las etiquetas (tags en AWS y Azure, labels en GCP) son simples pares clave-valor que asignas a tus recursos cloud para clasificarlos. Suena básico, ¿verdad? Pero sin ellas, tu factura mensual no es más que un número enorme imposible de desglosar.

Con una buena estrategia de etiquetado, puedes responder preguntas como: ¿Cuánto gasta el equipo de marketing en producción? o ¿Qué proyecto se está comiendo los recursos en desarrollo?

En esta guía te muestro cómo diseñar, implementar y automatizar una estrategia de etiquetado multi-cloud con Terraform, cubriendo AWS, Azure y GCP con código listo para producción. Así que, manos a la obra.

Esquema Mínimo Viable de Etiquetas

El error más común que veo en equipos nuevos en FinOps es intentar etiquetar todo con 20 claves obligatorias desde el día uno. Lo que pasa es predecible: los equipos se resisten, la calidad de los datos se desploma y el esfuerzo muere en la primera semana.

No cometas ese error. Empieza con 5 a 8 etiquetas obligatorias que cubran lo esencial:

ClaveDescripciónEjemplo de valor
EnvironmentEntorno de despliegueproduction, staging, development
TeamEquipo propietario del recursoplatform, data-engineering, marketing
ProjectProyecto o aplicación asociadacheckout-service, analytics-pipeline
CostCenterCentro de costos contableCC-1234, engineering-ops
OwnerPersona o grupo responsable[email protected]
ManagedByHerramienta de aprovisionamientoterraform, manual, cloudformation

Reglas clave de nomenclatura:

  • Usa siempre minúsculas para los valores (o al menos define una convención y respétala religiosamente)
  • Nada de espacios ni caracteres especiales en las claves
  • Documenta cada clave con su descripción, valores permitidos y ejemplos
  • Las claves deben ser idénticas en los tres proveedores cloud — esto es clave para los reportes multi-cloud

Implementación con Terraform: AWS Default Tags

Aquí es donde la cosa se pone interesante. AWS permite definir default_tags directamente en el provider de Terraform, lo que significa que todos los recursos creados heredan automáticamente las etiquetas base. Nada de copiar y pegar en cada bloque de recurso.

# variables.tf
variable "environment" {
  type    = string
  default = "production"
}

variable "team" {
  type    = string
  default = "platform"
}

variable "project" {
  type    = string
  default = "cost-allocation"
}

variable "cost_center" {
  type    = string
  default = "CC-1234"
}

# providers.tf
provider "aws" {
  region = "us-east-1"

  default_tags {
    tags = {
      Environment = var.environment
      Team        = var.team
      Project     = var.project
      CostCenter  = var.cost_center
      ManagedBy   = "terraform"
    }
  }
}

# Los recursos heredan las default_tags automáticamente
resource "aws_instance" "web" {
  ami           = "ami-0c02fb55956c7d316"
  instance_type = "t3.medium"

  # Solo añadimos etiquetas específicas del recurso
  tags = {
    Name = "web-server-01"
    Role = "web"
  }
}

Con esta configuración, la instancia EC2 terminará con 7 etiquetas: las 5 del default_tags más las 2 específicas (Name y Role). Y si un recurso necesita sobrescribir una etiqueta base, simplemente la redefines en su bloque tags. Así de limpio.

Activar etiquetas de asignación de costos en AWS

Ojo, que esto es importante: crear las etiquetas no basta. Tienes que activarlas como Cost Allocation Tags en la consola de Billing para que aparezcan en Cost Explorer y en los informes CUR. La buena noticia es que puedes automatizarlo con la CLI:

# Activar etiquetas de asignación de costos
aws ce update-cost-allocation-tags-status \
  --cost-allocation-tags-status \
    TagKey=Environment,Status=Active \
    TagKey=Team,Status=Active \
    TagKey=Project,Status=Active \
    TagKey=CostCenter,Status=Active

Un detalle que muchos pasan por alto: las etiquetas de asignación de costos no son retroactivas. Solo aparecen en los reportes de facturación a partir del momento en que las activas. Así que configúralas desde el inicio del proyecto o vas a tener un agujero en tus datos históricos.

Implementación con Terraform: Azure Tags y Azure Policy

Azure no tiene un equivalente exacto a default_tags de AWS en el provider de Terraform (una pena, sinceramente). Pero puedes lograr algo muy parecido usando un bloque locals con etiquetas comunes y pasándolo a cada recurso.

# locals.tf
locals {
  common_tags = {
    Environment = var.environment
    Team        = var.team
    Project     = var.project
    CostCenter  = var.cost_center
    ManagedBy   = "terraform"
  }
}

# resource_group.tf
resource "azurerm_resource_group" "main" {
  name     = "rg-${var.project}-${var.environment}"
  location = "eastus"
  tags     = local.common_tags
}

# vm.tf
resource "azurerm_linux_virtual_machine" "web" {
  name                = "vm-web-01"
  resource_group_name = azurerm_resource_group.main.name
  location            = azurerm_resource_group.main.location
  size                = "Standard_B2s"

  # Merge: etiquetas comunes + específicas
  tags = merge(local.common_tags, {
    Role = "web"
  })

  # ... configuración adicional omitida por brevedad
}

Enforcement con Azure Policy

Ahora, donde Azure realmente brilla es en Azure Policy. Puedes literalmente bloquear la creación de recursos que no tengan las etiquetas obligatorias. Y lo mejor: se define todo con Terraform.

# azure_policy.tf
resource "azurerm_policy_definition" "require_tags" {
  name         = "require-cost-allocation-tags"
  policy_type  = "Custom"
  mode         = "Indexed"
  display_name = "Requerir etiquetas de asignación de costos"
  description  = "Deniega la creación de recursos sin las etiquetas obligatorias"

  metadata = jsonencode({
    category = "Cost Management"
  })

  policy_rule = jsonencode({
    if = {
      anyOf = [
        { field = "tags['Environment']", exists = false },
        { field = "tags['Team']", exists = false },
        { field = "tags['Project']", exists = false },
        { field = "tags['CostCenter']", exists = false }
      ]
    }
    then = {
      effect = "deny"
    }
  })
}

resource "azurerm_policy_assignment" "require_tags" {
  name                 = "require-cost-tags-assignment"
  scope                = azurerm_resource_group.main.id
  policy_definition_id = azurerm_policy_definition.require_tags.id
  display_name         = "Requerir etiquetas de costos"
  description          = "Asignación de política que exige etiquetas de costos"
}

Con esta política activa, cualquier intento de crear un recurso sin Environment, Team, Project o CostCenter va a ser rechazado en seco por Azure. Es enforcement de verdad.

Implementación con Terraform: GCP Labels

Google Cloud tiene su propia terminología (porque, claro, cada proveedor necesita ser diferente). Aquí se usan labels en lugar de tags — los "tags" en GCP son un concepto de red completamente distinto, así que cuidado con la confusión.

Los labels se aplican de forma similar, pero con restricciones propias: solo minúsculas, números, guiones y guiones bajos, con un máximo de 64 caracteres por clave y valor.

# variables.tf (GCP)
variable "gcp_project_id" {
  type    = string
  default = "mi-proyecto-prod"
}

# locals.tf
locals {
  gcp_labels = {
    environment = var.environment
    team        = var.team
    project     = var.project
    cost_center = var.cost_center
    managed_by  = "terraform"
  }
}

# provider.tf
provider "google" {
  project = var.gcp_project_id
  region  = "us-central1"

  default_labels = local.gcp_labels
}

# compute_instance.tf
resource "google_compute_instance" "web" {
  name         = "web-server-01"
  machine_type = "e2-medium"
  zone         = "us-central1-a"

  labels = merge(local.gcp_labels, {
    role = "web"
  })

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
    }
  }

  network_interface {
    network = "default"
  }
}

A partir del provider de Google para Terraform v5.x, puedes usar default_labels en el bloque provider, que funciona de forma análoga a default_tags en AWS. Los labels se aplican automáticamente a todos los recursos compatibles, lo cual es un alivio.

Módulo Terraform Reutilizable para Etiquetado Multi-Cloud

Si gestionas infraestructura en varias nubes (y honestamente, la mayoría de empresas medianas y grandes lo hacen), un módulo centralizado de etiquetado te va a ahorrar muchos dolores de cabeza. Este módulo genera las etiquetas o labels adecuadas para cada proveedor a partir de un conjunto único de variables:

# modules/tagging/variables.tf
variable "environment" { type = string }
variable "team" { type = string }
variable "project" { type = string }
variable "cost_center" { type = string }
variable "extra_tags" {
  type    = map(string)
  default = {}
}

# modules/tagging/outputs.tf
output "aws_tags" {
  value = merge({
    Environment = var.environment
    Team        = var.team
    Project     = var.project
    CostCenter  = var.cost_center
    ManagedBy   = "terraform"
  }, var.extra_tags)
}

output "azure_tags" {
  value = merge({
    Environment = var.environment
    Team        = var.team
    Project     = var.project
    CostCenter  = var.cost_center
    ManagedBy   = "terraform"
  }, var.extra_tags)
}

output "gcp_labels" {
  # GCP requiere minúsculas y guiones bajos
  value = merge({
    environment = lower(var.environment)
    team        = lower(replace(var.team, "-", "_"))
    project     = lower(replace(var.project, "-", "_"))
    cost_center = lower(replace(var.cost_center, "-", "_"))
    managed_by  = "terraform"
  }, {
    for k, v in var.extra_tags :
    lower(replace(k, "-", "_")) => lower(replace(v, "-", "_"))
  })
}

# Uso del módulo
module "tags" {
  source       = "./modules/tagging"
  environment  = "production"
  team         = "platform"
  project      = "checkout-service"
  cost_center  = "CC-1234"
}

Después, cada recurso simplemente referencia las salidas del módulo: module.tags.aws_tags, module.tags.azure_tags o module.tags.gcp_labels según el proveedor. Elegante y consistente.

Enforcement Automatizado: Políticas Pre-Despliegue

La automatización del etiquetado no sirve de mucho si no tienes mecanismos que bloqueen los despliegues no conformes antes de que lleguen a producción. Porque seamos honestos: si dejamos una puerta abierta, alguien va a pasar por ahí.

Open Policy Agent (OPA) con Conftest

OPA te permite validar los planes de Terraform contra políticas definidas en Rego antes de aplicarlos. Es como un guardia de seguridad para tu infraestructura:

# policy/enforce-tags.rego
package terraform.tags

required_tags := ["Environment", "Team", "Project", "CostCenter"]

deny[msg] {
  resource := input.resource_changes[_]
  resource.change.actions[_] == "create"
  tags := resource.change.after.tags
  tag := required_tags[_]
  not tags[tag]
  msg := sprintf(
    "Recurso %s no tiene la etiqueta obligatoria: %s",
    [resource.address, tag]
  )
}

La integración en tu pipeline CI/CD es directa:

# En tu pipeline CI/CD
terraform plan -out=tfplan
terraform show -json tfplan > tfplan.json
conftest test tfplan.json --policy policy/

AWS Service Control Policies (SCPs)

Las SCPs se aplican a nivel de AWS Organizations y pueden denegar acciones de creación de recursos sin etiquetas requeridas. Desde noviembre de 2025, AWS Organizations incluye "Reporting for Required Tags", que valida plantillas de CloudFormation, Terraform y Pulumi contra las políticas de etiquetado antes del despliegue. Las organizaciones que usan esta funcionalidad reportan una reducción del 95% en violaciones de cumplimiento de etiquetas.

GCP Organization Policies

GCP permite restringir la creación de recursos sin labels a través de Organization Policies a nivel de carpeta o proyecto. No es tan granular como Azure Policy, pero cumple su función.

Auditoría y Monitoreo Continuo del Cumplimiento

Aquí va una verdad incómoda: con el tiempo, las etiquetas se degradan. Alguien crea un recurso manualmente sin etiquetas, un script antiguo no las incluye, o un valor cambia sin actualizar la etiqueta. Este fenómeno se conoce como tag drift, y si no lo vigilas, tus reportes de costos se vuelven poco fiables.

Herramientas nativas por proveedor

  • AWS Config: crea reglas que evalúan continuamente los recursos contra tus estándares de etiquetado e identifica los que no cumplen
  • Azure Resource Graph: ejecuta consultas KQL para encontrar recursos sin etiquetas (o con etiquetas incorrectas) en todas tus suscripciones
  • GCP Cloud Asset Inventory: escanea labels en todos los recursos del proyecto u organización

Query de ejemplo para Azure Resource Graph

// Encontrar recursos sin la etiqueta CostCenter
resources
| where tags !has "CostCenter" or tags["CostCenter"] == ""
| project name, type, resourceGroup, subscriptionId
| order by type asc

KPIs de cumplimiento recomendados

Según el marco FinOps Foundation, una práctica de etiquetado madura debería alcanzar estos umbrales:

  • Nivel "Walk": al menos el 80% del gasto cloud asignado a un propietario vía etiquetas
  • Nivel "Run": al menos el 90% del gasto cloud asignado y con auditoría automatizada
  • Meta ideal: 95%+ de cobertura con remediación automática de no conformidades

En mi experiencia, la mayoría de equipos se estancan entre el 70% y el 80%. Pasar del 90% requiere un compromiso real de liderazgo y automatización agresiva.

De las Etiquetas a la Acción: Showback y Chargeback

Una vez que tus etiquetas están en su lugar y la cobertura supera el 80%, llega el momento de hacer algo útil con toda esa información:

  • Showback: los equipos ven cuánto cuestan sus recursos, pero no se les cobra directamente. Es ideal para crear conciencia de costos sin generar fricciones organizativas.
  • Chargeback: los costos se asignan formalmente al presupuesto de cada equipo. Requiere alta precisión en el etiquetado (90%+) y acuerdos claros sobre cómo distribuir costos compartidos.

Mi recomendación: empieza siempre con showback. Deja que los equipos se acostumbren a ver los números antes de que esos números impacten su presupuesto. Cuando la madurez del etiquetado lo permita, evolucionas a chargeback.

Errores Comunes que Debes Evitar

  1. Sensibilidad a mayúsculas: Project y project son etiquetas diferentes en AWS. Este error es más frecuente de lo que imaginas. Usa variables de Terraform para garantizar consistencia.
  2. Tag sprawl: crear decenas de claves sin propósito claro. Menos es más — mantén tu esquema enfocado y reutiliza claves existentes.
  3. No etiquetar recursos efímeros: contenedores, funciones Lambda y recursos de auto-scaling también necesitan etiquetas. Si no los etiquetas, vas a tener un porcentaje importante de gasto sin asignar.
  4. Olvidar los recursos no etiquetables: algunos servicios (como ciertos cargos de soporte o transferencia de datos) no soportan etiquetas. Define una estrategia para asignar estos costos compartidos proporcionalmente.
  5. Depender del etiquetado manual: si dependes de que las personas recuerden etiquetar cada recurso, te va a ir mal. La automatización vía IaC no es opcional, es obligatoria.

Preguntas Frecuentes

¿Cuántas etiquetas obligatorias debería tener mi estrategia de etiquetado cloud?

La recomendación de expertos en FinOps es empezar con 5 a 8 etiquetas obligatorias que cubran identificación de entorno, equipo propietario, proyecto, centro de costos y herramienta de gestión. Más de 8 obligatorias genera resistencia en los equipos y reduce la calidad de los datos. Siempre puedes agregar etiquetas opcionales según las necesidades de cada equipo.

¿Las etiquetas de asignación de costos en AWS son retroactivas?

No, y esto es algo que pilla desprevenidos a muchos. Las Cost Allocation Tags en AWS solo aparecen en los reportes de facturación desde el momento en que las activas en la consola de Billing. No hay forma de aplicarlas retroactivamente a periodos anteriores. Por eso es tan importante activarlas desde el primer día y automatizar su aplicación con Terraform.

¿Cuál es la diferencia entre tags y labels en los distintos proveedores cloud?

AWS y Azure usan "tags" para los pares clave-valor de metadatos en recursos. GCP usa "labels" para el mismo concepto — ojo, los "tags" en GCP se refieren a etiquetas de red para reglas de firewall, que es algo completamente diferente. En la práctica, tags y labels cumplen la misma función de clasificación y asignación de costos, pero cada proveedor tiene sus propias restricciones en longitud de claves, caracteres permitidos y número máximo por recurso.

¿Cómo puedo auditar el cumplimiento de etiquetas automáticamente?

Cada proveedor ofrece herramientas nativas: AWS Config para evaluación continua, Azure Resource Graph para consultas KQL sobre recursos no conformes, y GCP Cloud Asset Inventory para escaneo de labels. Además, puedes (y deberías) integrar validación pre-despliegue en tu pipeline CI/CD con OPA y Conftest para verificar los planes de Terraform antes de aplicarlos.

¿Qué porcentaje de cobertura de etiquetado se considera maduro en FinOps?

Según el marco de la FinOps Foundation, una organización en nivel "Walk" necesita al menos el 80% de su gasto cloud asignado vía etiquetas. El nivel "Run" requiere 90% o más con auditoría automatizada. Las organizaciones líderes apuntan al 95%+ de cobertura con remediación automática. Solo el 14.2% de las organizaciones ha alcanzado ese nivel de madurez avanzada, así que no te frustres si el camino es gradual.

Sobre el Autor Editorial Team

Our team of expert writers and editors.