Problema

En muchos proyectos de IA y micro‑servicios en Azure se construye un entorno que funciona perfectamente en la suscripción del autor, pero falla al intentar replicarlo en una cuenta limpia. El patrón típico es que la infraestructura depende de configuraciones implícitas: extensiones de PostgreSQL ya instaladas, nombres de secretos que coinciden con recursos creados manualmente, o rutas de archivos locales que sólo existen en la máquina del desarrollador. Cuando otro equipo o un pipeline de CI/CD intenta desplegar el mismo código, aparecen errores de “resource not found”, “invalid secret name” o “extension not allowed”. El resultado es una solución que no es verdaderamente portable y que requiere intervención manual para cada nueva suscripción.

Causa

  1. Suposiciones implícitas en el código

    • Scripts de seed que crean secretos vacíos. Azure Key Vault rechaza valores nulos.
    • Referencias a extensiones de PostgreSQL (por ejemplo pgvector) que no están en la lista allow‑list de la suscripción.
    • Variables de entorno que apuntan a rutas locales (./config/…) que no existen en el contenedor.
  2. Dependencias creadas fuera de Terraform

    • Recursos provisionados manualmente (bases de datos, identidades gestionadas) que Terraform no conoce y, por tanto, no controla su estado.
    • Identidades con permisos excesivos o insuficientes porque la política de IAM se definió después del despliegue inicial.
  3. Naming y seeding inconsistentes

    • Nombres de secretos que el script de seed genera de forma dinámica, pero que el código de la aplicación espera con un patrón distinto.
    • Uso de prefijos o sufijos diferentes entre entornos (dev‑, prod‑) sin una convención clara.
  4. Configuración de red y VNet ocultas

    • Servicios que dependen de un Private Endpoint configurado manualmente. En una suscripción nueva, el endpoint no existe y la aplicación no puede resolver el DNS interno.

Solución

Adoptar un enfoque infraestructura‑como‑código (IaC) completo y validación automática. Los pasos clave son:

1. Declarar todo con Terraform

  • Resource groups, VNet y Subnets: define la red privada desde el primer módulo.
  • Azure Container Apps: usa el recurso azurerm_container_app con ingress configurado y asigna una Managed Identity.
  • Azure Database for PostgreSQL: incluye la extensión pgvector en la propiedad extension del recurso azurerm_postgresql_flexible_server. Si la extensión no está en la allow‑list, añade una regla de azurerm_postgresql_server_configuration para habilitarla.
  • Key Vault: crea el vault y los secretos en el mismo plan. Usa azurerm_key_vault_secret con value = var.secret_value; nunca dejes valores vacíos.

2. Centralizar nombres y convenciones

Define variables en variables.tf para todos los prefijos y sufijos. Por ejemplo:

variable "env_prefix" {
  type    = string
  default = "dev"
}

Luego, construye los nombres con interpolación: "${var.env_prefix}-kv" para el Key Vault, "${var.env_prefix}-pg" para la base de datos, etc. Así el mismo código funciona en cualquier suscripción cambiando solo el valor de env_prefix.

3. Seed de secretos sin valores vacíos

Implementa un pequeño script de bootstrap que genere valores aleatorios cuando el secreto no exista. En Bash:

#!/usr/bin/env bash
set -euo pipefail

VAULT_NAME=$1
SECRET_NAME=$2
VALUE=${3:-$(openssl rand -hex 16)}

az keyvault secret set --vault-name "$VAULT_NAME" --name "$SECRET_NAME" --value "$VALUE"

Ejecuta este script desde un null_resource de Terraform para que la generación sea parte del plan.

4. Validaciones de pre‑despliegue

Añade un módulo de checks que utilice az cli o terraform validate para:

  • Verificar que la extensión requerida está allow‑listed (az postgres server configuration list).
  • Confirmar que la Managed Identity tiene los permisos get, list y set sobre el Key Vault.
  • Comprobar que los Private Endpoints están activos (az network private-endpoint show).

Si alguna validación falla, el pipeline aborta antes de crear los contenedores.

5. Documentación reproducible

Incluye un walkthrough con capturas de pantalla que muestre:

  1. Clonar el repo.
  2. Ejecutar terraform init && terraform apply -var="env_prefix=prod".
  3. Acceder a la consola web desplegada mediante la URL del Container App.

Mantén los pasos en un archivo README.md y enlázalo desde el Hugo frontmatter.

Cuándo aplicar esta solución

  • Síntomas: despliegues que funcionan solo en la suscripción del autor; errores de extensión no permitida; secretos que no se crean automáticamente.
  • Entornos: cualquier arquitectura basada en Azure Container Apps, PostgreSQL con extensiones, y Key Vault para gestión de secretos.
  • No aplicable: proyectos que usan exclusivamente PaaS sin necesidad de extensiones personalizadas o que dependen de recursos externos a Azure (por ejemplo, bases de datos gestionadas fuera de Azure).

Código

# Inicializar Terraform y aplicar con prefijo de entorno
terraform init
terraform apply -var="env_prefix=dev" -auto-approve

# Bootstrap de secretos (ejemplo para API_KEY)
./scripts/seed_secret.sh my-vault api-key

Verificación

  1. Infraestructura

    • Ejecuta az containerapp show --name <app-name> --resource-group <rg> y verifica que properties.provisioningState sea Succeeded.
    • Usa az postgres flexible-server show --name <db-name> y confirma que properties.extensions incluya pgvector.
  2. Aplicación

    • Accede a la URL pública del Container App y comprueba que la consola web carga sin errores de conexión a la base de datos.
    • Revisa los logs de la app (az monitor log-analytics query) para asegurarte de que no haya excepciones de secret not found.
  3. Seguridad

    • Ejecuta az keyvault secret list --vault-name <vault> y verifica que los secretos esperados existan y tengan valores no vacíos.
    • Comprueba que la Managed Identity tiene la política get, list, set en el vault (az keyvault set-policy).

Notas adicionales

  • Extensiones de PostgreSQL: la lista allow‑list varía por región. Si pgvector no está disponible, habilita la característica de “preview extensions” en la suscripción o usa un servidor de PostgreSQL auto‑gestionado en una VM.
  • Costos: Azure Container Apps en modo Consumption puede reducir gastos, pero los recursos de PostgreSQL y VNet generan costos fijos. Monitorea con Azure Cost Management para mantener el gasto mensual bajo $100.
  • Rotación de secretos: programa una Azure Function que lea la fecha de expiración de cada secreto (az keyvault secret show) y regenere los valores antes de que caduquen.
  • CI/CD: integra el plan de Terraform en GitHub Actions o Azure Pipelines. Usa el job terraform plan como gate antes de terraform apply.
  • Versionado: guarda los módulos de Terraform en un repositorio separado y versiona con tags semánticos; así los equipos pueden pinchar versiones estables sin romper dependencias.