Problema

En entornos híbridos y multi‑cloud, los equipos de seguridad suelen aplicar políticas genéricas (por ejemplo, Azure Security Baselines o CIS Benchmarks) a cientos de máquinas virtuales. La configuración por defecto incluye cientos de reglas que, si bien cubren la mayor parte de los requisitos de hardening, rara vez encajan al 100 % con la realidad de una organización. Los síntomas típicos son:

  • Alertas de incumplimiento por controles que la empresa ha decidido excluir (por ejemplo, auditorías de auditoría de logs en sistemas que usan otro agente).
  • Sobrecarga de agentes de configuración cuando se intentan aplicar reglas incompatibles con la distribución Linux elegida.
  • Dificultad para mantener un estado de cumplimiento coherente entre Azure, AWS, GCP y servidores on‑premise.

El reto es conseguir que una política de baseline sea asignable, editable y sobrescribible sin perder la trazabilidad que ofrece Azure Policy.

Causa

  1. Política monolítica – Los baselines vienen como una única definición que incluye todas las reglas recomendadas. Cuando se asigna tal definición, cualquier regla no deseada se vuelve obligatoria.
  2. Falta de capas de exclusión – Azure Policy no permite, de forma nativa, excluir reglas dentro de una asignación; solo se pueden excluir recursos completos mediante scopes.
  3. Inconsistencias entre distribuciones Linux – Los CIS Benchmarks cubren más de 15 distros, pero algunas reglas dependen de paquetes o servicios que no existen en todas ellas.
  4. Desalineación de versiones – Cuando se actualiza el baseline (por ejemplo, una nueva versión de CIS), las personalizaciones previas pueden quedar huérfanas o generar conflictos.

Solución

La estrategia se basa en descomponer el baseline en componentes reutilizables y reconstruir una asignación a medida usando Azure Policy y Machine Configuration.

1. Exportar la definición original

Azure CLI permite descargar la definición JSON del baseline:

az policy definition show --name "AzureSecurityBaseline_Windows" > baseline-windows.json
az policy definition show --name "CIS_Benchmark_Ubuntu20.04" > cis-ubuntu.json

2. Crear una política “wrapper” para cada regla

En el JSON exportado, cada regla está bajo policyRule.if. Copia cada regla a un archivo independiente y conviértela en una policy definition con un nombre descriptivo, por ejemplo audit-ssh-root-login.json. Luego, registra cada una:

az policy definition create --name "audit-ssh-root-login" --rules audit-ssh-root-login.json --mode All

Este paso genera un catálogo de reglas atómicas que pueden ser combinadas libremente.

3. Construir una policy set definition (initiative) a medida

Crea un archivo custom-baseline-initiative.json que incluya solo las reglas que tu organización necesita. Usa la propiedad policyDefinitions para referenciar los IDs de las reglas creadas en el paso anterior. Puedes marcar reglas opcionales con effect: "auditIfNotExists" o effect: "deny" según el nivel de control deseado.

az policy set-definition create --name "custom-security-baseline" --definitions @custom-baseline-initiative.json

4. Asignar la iniciativa al scope correcto

El scope puede ser una suscripción, un grupo de recursos o una etiqueta que identifique máquinas en Azure, AWS, GCP o on‑premise (cuando se usa Azure Arc). La asignación incluye parámetros para sobrescribir valores por defecto (por ejemplo, puertos permitidos).

az policy assignment create \
  --name "custom-baseline-prod" \
  --scope "/subscriptions/xxxx-xxxx-xxxx/resourceGroups/prod-rg" \
  --policy-set-definition "custom-security-baseline" \
  --params @baseline-params.json

5. Integrar con Azure Arc para máquinas fuera de Azure

Para VMs en AWS, GCP o on‑premise, primero registra el agente Azure Arc y habilita la extensión Microsoft.GuestConfiguration. Después, la misma iniciativa asignada al mismo scope se aplica automáticamente a los nodos Arc.

az connectedmachine extension create \
  --name "Microsoft.GuestConfiguration" \
  --resource-group "arc-rg" \
  --machine-name "vm-onprem-01"

6. Automatizar la remediación

Una vez asignada la iniciativa, Azure Policy genera remediation tasks para los recursos que no cumplen. Puedes lanzar la tarea manualmente o programarla con Azure Automation:

az policy remediation create \
  --name "remediate-custom-baseline" \
  --policy-assignment "/subscriptions/xxxx-xxxx-xxxx/resourceGroups/prod-rg/providers/Microsoft.Authorization/policyAssignments/custom-baseline-prod"

Cuándo aplicar esta solución

Aplica cuando:

  • Necesitas aplicar un baseline de seguridad a gran escala pero con exclusiones específicas.
  • Gestionas máquinas en varios proveedores de nube o on‑premise mediante Azure Arc.
  • Quieres mantener la trazabilidad de cada regla (audit, deny, modify) y poder versionar la iniciativa.

No aplica si:

  • Solo gestionas unos pocos VMs y prefieres editar manualmente los archivos de configuración del SO.
  • Tu organización no usa Azure Policy o Azure Arc; en ese caso, la solución requiere una re‑evaluación de la herramienta de gestión de configuración.

Código

# 1. Exportar baseline original
az policy definition show --name "AzureSecurityBaseline_Linux" > baseline-linux.json

# 2. Crear policy definitions individuales (ejemplo para una regla)
az policy definition create \
  --name "audit-ssh-root-login" \
  --rules audit-ssh-root-login.json \
  --mode All

# 3. Crear initiative personalizada
az policy set-definition create \
  --name "custom-security-baseline" \
  --definitions @custom-baseline-initiative.json

# 4. Asignar initiative al scope deseado
az policy assignment create \
  --name "custom-baseline-prod" \
  --scope "/subscriptions/xxxx-xxxx-xxxx/resourceGroups/prod-rg" \
  --policy-set-definition "custom-security-baseline" \
  --params @baseline-params.json

# 5. Registrar Azure Arc en una VM on‑premise
az connectedmachine extension create \
  --name "Microsoft.GuestConfiguration" \
  --resource-group "arc-rg" \
  --machine-name "vm-onprem-01"

# 6. Ejecutar remediación
az policy remediation create \
  --name "remediate-custom-baseline" \
  --policy-assignment "/subscriptions/xxxx-xxxx-xxxx/resourceGroups/prod-rg/providers/Microsoft.Authorization/policyAssignments/custom-baseline-prod"

Verificación

  1. Estado de cumplimiento – Ejecuta az policy state list --resource "/subscriptions/xxxx-xxxx-xxxx/resourceGroups/prod-rg" y revisa que complianceState sea Compliant para la mayoría de recursos.
  2. Portal – En Azure Portal, abre Policy → Compliance y filtra por la iniciativa custom-security-baseline. Los recursos con problemas aparecerán en la tabla de Non‑compliant resources.
  3. Logs de Azure Arc – En la máquina Arc, revisa el log de Guest Configuration (/var/log/azure/Microsoft.GuestConfiguration/) para confirmar que las reglas se aplicaron sin errores.
  4. Remediación completada – Verifica que la tarea de remediación tenga provisioningState: Succeeded mediante az policy remediation show --name remediate-custom-baseline.

Notas adicionales

  • Orden de precedencia – Si existen políticas de nivel superior (por ejemplo, una política de Deny a nivel de suscripción), pueden bloquear la iniciativa personalizada. Revisa la jerarquía de asignaciones antes de desplegar.
  • Versionado de iniciativas – Guarda cada versión de custom-baseline-initiative.json en un repositorio Git. Así puedes comparar cambios entre versiones de CIS y revertir rápidamente si una regla nueva rompe alguna aplicación.
  • Pruebas en entornos de staging – Asigna la iniciativa a un grupo de recursos de pruebas antes de lanzarla a producción. Observa los tiempos de remediación; en entornos con miles de VMs, la primera ejecución puede tardar varios minutos.
  • Parámetros dinámicos – Usa parámetros de tipo Array para permitir que el mismo initiative acepte listas de puertos o usuarios permitidos, evitando la necesidad de crear una iniciativa distinta por cada variación.
  • Compatibilidad de distros – Cuando una regla depende de un paquete que no está presente en cierta distro, marca la regla con effect: "auditIfNotExists" y añade una condición field: "type" que verifique la distro antes de aplicar la regla. Esto reduce falsos positivos en auditorías.