Automatización de FinOps: Implementación de Presupuestos y Alertas con Terraform en Azure para 2026
La Evolución del FinOps en Azure: Más Allá del Control Manual
El control de costes en la nube ha evolucionado de ser una tarea reactiva a convertirse en una disciplina proactiva y automatizada. En este artículo, exploraremos cómo implementar una estrategia FinOps completa en Azure utilizando Terraform.
Requisitos Previos
- Terraform instalado (versión ≥ 1.0.0)
- Azure CLI configurado
- Permisos de Contributor en la suscripción de Azure
- Conocimientos básicos de FinOps
Arquitectura de la Solución
# Estructura del proyecto
finops-automation/
├── main.tf
├── variables.tf
├── outputs.tf
├── modules/
│ ├── budget/
│ ├── alerts/
│ └── dashboard/
└── environments/
├── dev/
└── prod/
1. Configuración de Presupuestos con Terraform
# modules/budget/main.tf
resource "azurerm_consumption_budget_subscription" "monthly" {
name = "monthly-budget-${var.environment}"
subscription_id = data.azurerm_subscription.current.id
amount = var.monthly_budget_amount
time_grain = "Monthly"
time_period {
start_date = formatdate("YYYY-MM-01", timestamp())
end_date = timeadd(formatdate("YYYY-MM-01", timestamp()), "8760h") # 1 año
}
notification {
enabled = true
threshold = 80.0
operator = "GreaterThan"
threshold_type = "Actual"
contact_emails = var.alert_contacts
}
notification {
enabled = true
threshold = 100.0
operator = "GreaterThan"
threshold_type = "Forecasted"
contact_emails = var.alert_contacts
contact_roles = ["Owner"]
}
}
2. Implementación de Alertas Inteligentes
# modules/alerts/main.tf
resource "azurerm_monitor_action_group" "cost_alerts" {
name = "cost-alerts-${var.environment}"
resource_group_name = azurerm_resource_group.monitoring.name
short_name = "costalerts"
email_receiver {
name = "finance-team"
email_address = var.finance_email
use_common_alert_schema = true
}
logic_app_receiver {
name = "teams-notification"
resource_id = azurerm_logic_app_workflow.teams_notification.id
callback_url = azurerm_logic_app_trigger_http_request.cost_alert.callback_url
use_common_alert_schema = true
}
}
resource "azurerm_monitor_metric_alert" "cost_spike" {
name = "cost-spike-alert"
resource_group_name = azurerm_resource_group.monitoring.name
scopes = [data.azurerm_subscription.current.id]
description = "Alerta cuando se detecta un incremento anormal en el coste"
criteria {
metric_namespace = "Microsoft.CostManagement/budgets"
metric_name = "ActualCost"
aggregation = "Total"
operator = "GreaterThan"
threshold = var.cost_spike_threshold
dimension {
name = "ResourceGroup"
operator = "Include"
values = ["*"]
}
}
action {
action_group_id = azurerm_monitor_action_group.cost_alerts.id
}
}
3. Dashboard de Costes Automatizado
# modules/dashboard/main.tf
resource "azurerm_dashboard" "cost_management" {
name = "cost-dashboard-${var.environment}"
resource_group_name = azurerm_resource_group.monitoring.name
location = var.location
dashboard_properties = templatefile("${path.module}/dashboard.tpl", {
subscription_id = data.azurerm_subscription.current.id
timeframe = var.dashboard_timeframe
})
tags = {
environment = var.environment
managed_by = "terraform"
}
}
4. Integración con Azure Policy
resource "azurerm_policy_definition" "cost_center_tag" {
name = "require-cost-center-tag"
policy_type = "Custom"
mode = "All"
display_name = "Require cost center tag for resources"
policy_rule = <<POLICY_RULE
{
"if": {
"allOf": [
{
"field": "type",
"equals": "Microsoft.Resources/subscriptions/resourceGroups"
},
{
"field": "tags['CostCenter']",
"exists": "false"
}
]
},
"then": {
"effect": "deny"
}
}
POLICY_RULE
}
5. Pipeline de CI/CD para FinOps
# .github/workflows/finops.yml
name: FinOps Pipeline
on:
schedule:
- cron: '0 0 1 * *' # Ejecutar el primer día de cada mes
workflow_dispatch:
jobs:
cost-analysis:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Azure Login
uses: azure/login@v1
with:
creds: $
- name: Run Cost Analysis
run: |
az cost-management export create \
--name "monthly-export" \
--type "ActualCost" \
--scope "subscriptions/$" \
--storage-account-id "$" \
--storage-container "cost-exports" \
--timeframe "MonthToDate" \
--schedule-status "Active"
Mejores Prácticas y Recomendaciones
- Estratificación de Presupuestos
- Presupuestos por suscripción
- Presupuestos por grupo de recursos
- Presupuestos por etiquetas
- Automatización de Respuesta
resource "azurerm_automation_runbook" "cost_optimization" { name = "cost-optimization" location = var.location resource_group_name = azurerm_resource_group.automation.name automation_account_name = azurerm_automation_account.main.name log_verbose = true log_progress = true description = "Runbook para optimización automática de costes" runbook_type = "PowerShell" publish_content_link { uri = "https://raw.githubusercontent.com/your-org/scripts/main/cost-optimization.ps1" } } - Gestión de Excepciones
- Proceso de aprobación para excesos de presupuesto
- Documentación de justificaciones
- Auditoría automática
Monitorización y Reporting
# Ejemplo de query para Log Analytics
let timeRange = 30d;
CostManagement
| where TimeGenerated > ago(timeRange)
| summarize TotalCost = sum(Cost) by bin(TimeGenerated, 1d), ResourceGroup
| render timechart
Conclusiones y Próximos Pasos
La automatización de FinOps con Terraform proporciona:
- Control proactivo de costes
- Respuesta automática a desviaciones
- Visibilidad mejorada
- Cumplimiento continuo
Pasos Siguientes Recomendados
- Implementar la estructura base de Terraform
- Configurar las alertas iniciales
- Establecer los primeros presupuestos
- Integrar con el sistema de tickets
- Configurar dashboards personalizados
El código completo está disponible en nuestro repositorio de GitHub.