Azure Key Vault: RBAC vs Access Policies
Resumen
Azure Key Vault soporta dos modelos de autorización: Azure RBAC (recomendado) y Access Policies (legacy). RBAC proporciona control granular, separación de responsabilidades y soporte para Privileged Identity Management (PIM), mientras que Access Policies permite que roles con permisos de escritura (Contributor) se otorguen a sí mismos acceso al plano de datos, representando un riesgo de seguridad. Este post explica las diferencias, cómo migrar de Access Policies a RBAC, y las buenas prácticas de seguridad.
¿Por qué migrar a RBAC?
Problema con Access Policies
Riesgo de elevación de privilegios:
- Usuarios con rol
ContributoroKey Vault Contributorpueden modificar Access Policies - Pueden otorgarse acceso completo a secrets/keys/certificates sin aprobación
- No hay separación entre gestión del vault y acceso a datos sensibles
- No soporta PIM para acceso just-in-time
Ejemplo del problema:
# Usuario con rol Contributor puede hacer esto:
az keyvault set-policy \
--name my-vault \
--upn malicious-user@company.com \
--secret-permissions get list \
--key-permissions get list \
--certificate-permissions get list
# Ahora tiene acceso a todos los secrets sin auditoría
Ventajas de Azure RBAC
Seguridad mejorada:
- Solo roles
OwneryUser Access Administratorpueden asignar permisos de datos - Separación clara entre management plane y data plane
- Soporte completo para PIM (acceso temporal con aprobación)
- Auditoría centralizada en Activity Log
Control granular:
- Scope a nivel de vault, secret individual, key o certificate
- Roles predefinidos específicos (Key Vault Secrets User, Key Vault Crypto User)
- Integración con Conditional Access policies
- Managed identities nativo
Arquitectura de permisos
flowchart TB
subgraph "Access Policies (Legacy)"
A[Contributor Role] -->|puede modificar| B[Access Policy]
B -->|otorga acceso| C[Secrets/Keys/Certs]
end
subgraph "Azure RBAC (Recomendado)"
D[Owner/UAA Role] -->|único que asigna| E[Data Plane Role]
E -->|acceso controlado| F[Secrets/Keys/Certs]
G[Contributor] -.->|NO puede modificar| E
end
style A fill:#e74c3c
style D fill:#2ecc71
style G fill:#95a5a6
Roles RBAC predefinidos
Management Plane (Control Plane)
| Rol | Descripción | Uso |
|---|---|---|
| Owner | Control completo del vault + asignación de roles | Administradores principales |
| Contributor | Gestión del vault SIN asignación de roles data plane | DevOps, operadores |
| Reader | Solo lectura de propiedades del vault | Auditoría, monitorización |
Data Plane (Acceso a datos)
| Rol | Permisos | Uso típico |
|---|---|---|
| Key Vault Administrator | Acceso completo a secrets/keys/certs | Break-glass, emergencias |
| Key Vault Secrets User | Get secrets | Aplicaciones, managed identities |
| Key Vault Secrets Officer | CRUD secrets | Administradores de secrets |
| Key Vault Crypto User | Operaciones criptográficas (sign, verify, encrypt) | Apps con cifrado |
| Key Vault Crypto Officer | Crear/eliminar keys | Gestión de claves |
| Key Vault Certificates Officer | CRUD certificados | Gestión de TLS/SSL |
| Key Vault Reader | Listar secrets/keys/certs (no leer valores) | Inventario, discovery |
Migración de Access Policies a RBAC
Paso 1: Auditar permisos actuales
# Listar access policies existentes
az keyvault show \
--name my-vault \
--resource-group my-rg \
--query "properties.accessPolicies" \
-o table
Ejemplo output:
ObjectId Permissions
------------------------------------ -----------------
12345678-1234-1234-1234-123456789012 Secrets: get, list
87654321-4321-4321-4321-210987654321 Keys: all, Secrets: all
Paso 2: Mapear Access Policies a roles RBAC
Mapeo típico:
| Access Policy | Rol RBAC equivalente |
|---|---|
| Secrets: get, list | Key Vault Secrets User |
| Secrets: all | Key Vault Secrets Officer |
| Keys: encrypt, decrypt, sign, verify | Key Vault Crypto User |
| Keys: all | Key Vault Crypto Officer |
| Certificates: get, list | Key Vault Certificates User (custom) |
| All permissions | Key Vault Administrator |
Paso 3: Habilitar RBAC en el vault
# Cambiar permission model a RBAC
az keyvault update \
--name my-vault \
--resource-group my-rg \
--enable-rbac-authorization true
⚠️ Importante: Tras habilitar RBAC, las Access Policies dejan de funcionar inmediatamente.
Paso 4: Asignar roles RBAC
# Obtener object ID del principal (usuario, grupo, managed identity)
PRINCIPAL_ID=$(az ad user show --id user@company.com --query id -o tsv)
# Asignar rol a nivel de vault
az role assignment create \
--role "Key Vault Secrets User" \
--assignee $PRINCIPAL_ID \
--scope $(az keyvault show --name my-vault --resource-group my-rg --query id -o tsv)
# Asignar rol a un secret específico
SECRET_ID=$(az keyvault secret show \
--vault-name my-vault \
--name db-password \
--query id -o tsv)
az role assignment create \
--role "Key Vault Secrets User" \
--assignee $PRINCIPAL_ID \
--scope $SECRET_ID
Paso 5: Configurar PIM (opcional pero recomendado)
# Crear eligible assignment (requiere activación)
az role assignment create \
--role "Key Vault Administrator" \
--assignee $ADMIN_PRINCIPAL_ID \
--scope $(az keyvault show --name my-vault -g my-rg --query id -o tsv) \
--assignee-object-type User \
--assignee-principal-type User \
# Nota: Configuración de PIM requiere Azure Portal o API de PIM
Configurar en Portal:
- Key Vault → Access control (IAM) → Privileged roles
- Add assignment → Select role → Key Vault Administrator
- Assignment type: Eligible
- Settings:
- Max activation duration: 8 hours
- Require justification: Yes
- Require approval: Yes (añadir approvers)
- Require MFA: Yes
Configuración con Managed Identity
System-assigned MI
# Crear VM con system-assigned identity
az vm create \
--name app-vm \
--resource-group my-rg \
--image Ubuntu2204 \
--assign-identity \
--role "Key Vault Secrets User" \
--scope $(az keyvault show --name my-vault -g my-rg --query id -o tsv)
# Obtener identity para verificar
az vm identity show --name app-vm --resource-group my-rg
User-assigned MI
# Crear user-assigned identity
az identity create \
--name app-identity \
--resource-group my-rg
IDENTITY_ID=$(az identity show -n app-identity -g my-rg --query id -o tsv)
PRINCIPAL_ID=$(az identity show -n app-identity -g my-rg --query principalId -o tsv)
# Asignar role
az role assignment create \
--role "Key Vault Secrets User" \
--assignee $PRINCIPAL_ID \
--scope $(az keyvault show --name my-vault -g my-rg --query id -o tsv)
# Asignar identity a App Service
az webapp identity assign \
--name my-app \
--resource-group my-rg \
--identities $IDENTITY_ID
Código de aplicación con RBAC
.NET (C#)
using Azure.Identity;
using Azure.Security.KeyVault.Secrets;
// Usar DefaultAzureCredential (soporta Managed Identity automáticamente)
var client = new SecretClient(
new Uri("https://my-vault.vault.azure.net/"),
new DefaultAzureCredential()
);
// Obtener secret
KeyVaultSecret secret = await client.GetSecretAsync("db-password");
string connectionString = secret.Value;
Python
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
credential = DefaultAzureCredential()
client = SecretClient(
vault_url="https://my-vault.vault.azure.net/",
credential=credential
)
# Obtener secret
secret = client.get_secret("db-password")
connection_string = secret.value
Azure CLI en scripts
# Autenticación con managed identity en Azure VM/App Service
export AZURE_CLIENT_ID=<user-assigned-mi-client-id> # Solo si es user-assigned
# Obtener secret
az keyvault secret show \
--vault-name my-vault \
--name db-password \
--query value \
-o tsv
Casos de uso avanzados
1. Acceso granular por entorno
# Production: solo lectura para apps
az role assignment create \
--role "Key Vault Secrets User" \
--assignee $PROD_APP_IDENTITY \
--scope $(az keyvault show --name prod-vault -g prod-rg --query id -o tsv)
# Development: lectura y escritura para devs
az role assignment create \
--role "Key Vault Secrets Officer" \
--assignee $DEV_GROUP_ID \
--scope $(az keyvault show --name dev-vault -g dev-rg --query id -o tsv)
2. Rotation de secrets con Function App
# Function App con system MI y permiso de escritura
FUNCTION_IDENTITY=$(az functionapp identity show \
--name secret-rotator \
--resource-group my-rg \
--query principalId -o tsv)
az role assignment create \
--role "Key Vault Secrets Officer" \
--assignee $FUNCTION_IDENTITY \
--scope $(az keyvault secret show \
--vault-name my-vault \
--name api-key \
--query id -o tsv)
3. Break-glass access con PIM
# Rol permanente: Key Vault Reader (solo lista)
az role assignment create \
--role "Key Vault Reader" \
--assignee $ADMIN_ID \
--scope $(az keyvault show --name my-vault -g my-rg --query id -o tsv)
# Rol eligible (activable): Key Vault Administrator
# Configurar via Portal → IAM → Privileged access
# Activación requiere:
# - Justificación de negocio
# - Aprobación de 2 owners
# - MFA
# - Duración máxima: 4 horas
Seguridad adicional
Firewall y Private Endpoint
# Deshabilitar acceso público
az keyvault update \
--name my-vault \
--resource-group my-rg \
--public-network-access Disabled
# Crear private endpoint
az network private-endpoint create \
--name my-vault-pe \
--resource-group my-rg \
--vnet-name my-vnet \
--subnet private-endpoints \
--private-connection-resource-id $(az keyvault show --name my-vault -g my-rg --query id -o tsv) \
--group-id vault \
--connection-name my-vault-connection
Conditional Access
Configurar en Azure AD:
- Azure AD → Security → Conditional Access
- New policy:
- Users: Grupo de admins Key Vault
- Cloud apps: Azure Key Vault (API: cfa8b339-82a2-471a-a3c9-0fc0be7a4093)
- Conditions: Location = Fuera de oficina
- Grant: Require MFA + Compliant device
Auditoría y alertas
# Habilitar diagnostic settings
az monitor diagnostic-settings create \
--name key-vault-audit \
--resource $(az keyvault show --name my-vault -g my-rg --query id -o tsv) \
--logs '[{"category": "AuditEvent", "enabled": true}]' \
--workspace $(az monitor log-analytics workspace show -n my-la-ws -g my-rg --query id -o tsv)
# Crear alerta de acceso no autorizado
az monitor metrics alert create \
--name unauthorized-access \
--resource-group my-rg \
--scopes $(az keyvault show --name my-vault -g my-rg --query id -o tsv) \
--condition "count ActivityType_s == 'SecretGet' and ResultType == 'Unauthorized' > 5" \
--window-size 5m \
--evaluation-frequency 1m \
--action action-group-id
Troubleshooting
Error: "Forbidden" tras habilitar RBAC
# Verificar roles asignados
az role assignment list \
--scope $(az keyvault show --name my-vault -g my-rg --query id -o tsv) \
--output table
# Si no tienes acceso, pedir a Owner/UAA que asigne rol
Error: "Network restricted"
# Añadir tu IP al firewall temporalmente
MY_IP=$(curl -s ifconfig.me)
az keyvault network-rule add \
--name my-vault \
--resource-group my-rg \
--ip-address $MY_IP
Buenas prácticas
- Usar RBAC siempre: Migrar todos los vaults a RBAC authorization
- Principle of least privilege: Asignar solo permisos mínimos necesarios
- Scope granular: Preferir scope a secrets individuales sobre vault completo
- PIM para admins: Acceso eligible con aprobación y MFA para roles privilegiados
- Managed Identities: Nunca usar service principals con secrets en código
- Private Endpoints: Deshabilitar acceso público en production
- Auditoría: Habilitar diagnostic logs y revisar periódicamente
- Rotación: Implementar rotación automática de secrets con Azure Functions/Logic Apps
- Conditional Access: Requerir MFA y compliant device para admins
- Separación de vaults: Vaults separados por entorno (prod/dev/test)