Auditoría de RBAC en Clústeres Kubernetes
Cuándo Usarlo
- Al realizar evaluaciones de seguridad en clústeres Kubernetes (EKS, GKE, AKS o autogestionados)
- Al validar que las políticas RBAC apliquen el principio de mínimo privilegio para usuarios y cuentas de servicio
- Al investigar posibles movimientos laterales o escalación de privilegios dentro de un clúster Kubernetes
- Cuando auditorías de cumplimiento requieran documentación de controles de acceso y permisos
- Al incorporar nuevos equipos a un clúster compartido y definir políticas RBAC adecuadas
No usar para auditoría de políticas de red (usar herramientas Cilium o Calico), para escaneo de imágenes de contenedores (usar Trivy o Grype), ni para monitoreo de seguridad en tiempo de ejecución (usar Falco o Sysdig Secure).
Requisitos Previos
- kubectl configurado con permisos de lectura de cluster-admin o equivalentes en el clúster objetivo
- rbac-tool instalado (
kubectl krew install rbac-toolo binario desde GitHub) - KubiScan instalado (
pip install kubiscan) - Kubeaudit instalado (
brew install kubeaudito desde releases de GitHub) - Acceso a los registros de auditoría del clúster para correlacionar hallazgos RBAC con el acceso real a la API
Flujo de Trabajo
Paso 1: Enumerar ClusterRoles y Roles con Permisos Peligrosos
Identificar roles con permisos comodín, acceso a secretos, exec en pods o capacidades de escalación.
# Listar todos los ClusterRoles con acceso de verbo comodín
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
verbs = rule.get('verbs', [])
resources = rule.get('resources', [])
if '*' in verbs or '*' in resources:
print(f'ClusterRole: {name}')
print(f' Verbs: {verbs}')
print(f' Resources: {resources}')
print(f' API Groups: {rule.get(\"apiGroups\", [])}')
print()
"
# Encontrar roles que pueden leer secretos
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
resources = rule.get('resources', [])
verbs = rule.get('verbs', [])
if ('secrets' in resources or '*' in resources) and ('get' in verbs or 'list' in verbs or '*' in verbs):
if not name.startswith('system:'):
print(f'ClusterRole: {name} -> puede acceder a secretos (verbs: {verbs})')
"
# Encontrar roles con permisos pod/exec (riesgo de escape de contenedor)
kubectl get clusterroles -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for role in data['items']:
name = role['metadata']['name']
for rule in role.get('rules', []):
resources = rule.get('resources', [])
if 'pods/exec' in resources or 'pods/*' in resources:
print(f'ClusterRole: {name} -> tiene acceso a pods/exec')
"
Paso 2: Auditar ClusterRoleBindings y RoleBindings
Revisar las vinculaciones para identificar quién tiene acceso elevado y detectar asignaciones de grupos demasiado amplias.
# Listar todos los ClusterRoleBindings con los sujetos
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
name = binding['metadata']['name']
role = binding['roleRef']['name']
subjects = binding.get('subjects', [])
for subject in subjects:
kind = subject.get('kind', '')
subj_name = subject.get('name', '')
ns = subject.get('namespace', 'cluster-wide')
print(f'{name} -> Role: {role} | {kind}: {subj_name} ({ns})')
" | sort
# Encontrar vinculaciones a cluster-admin
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
if binding['roleRef']['name'] == 'cluster-admin':
print(f\"Binding: {binding['metadata']['name']}\")
for subject in binding.get('subjects', []):
print(f\" {subject.get('kind')}: {subject.get('name')} (ns: {subject.get('namespace', 'N/A')})\")
"
# Encontrar vinculaciones que otorgan acceso a todos los usuarios autenticados
kubectl get clusterrolebindings -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for binding in data['items']:
for subject in binding.get('subjects', []):
if subject.get('name') in ['system:authenticated', 'system:unauthenticated']:
print(f\"ADVERTENCIA: {binding['metadata']['name']} otorga {binding['roleRef']['name']} a {subject['name']}\")
"
Paso 3: Escanear con rbac-tool para Análisis Integral
Usar rbac-tool para análisis automatizado de RBAC, incluyendo consultas quién-puede y generación de políticas.
# Quién puede obtener secretos en todos los namespaces
kubectl rbac-tool who-can get secrets
# Quién puede crear pods (potencial para escape de contenedor)
kubectl rbac-tool who-can create pods
# Quién puede hacer exec en pods
kubectl rbac-tool who-can create pods/exec
# Quién puede escalar privilegios (verbos bind/escalate)
kubectl rbac-tool who-can bind clusterroles
kubectl rbac-tool who-can escalate clusterroles
# Generar informe de políticas RBAC
kubectl rbac-tool analysis
# Visualizar relaciones RBAC
kubectl rbac-tool viz --outformat dot > rbac-graph.dot
dot -Tpng rbac-graph.dot -o rbac-graph.png
Paso 4: Ejecutar KubiScan para Detección de Permisos Riesgosos
Usar KubiScan para identificar automáticamente cuentas de servicio, pods y configuraciones RBAC riesgosas.
# Ejecutar KubiScan para encontrar roles riesgosos
python3 -m kubiscan -rroles # Listar Roles riesgosos
python3 -m kubiscan -rcr # Listar ClusterRoles riesgosos
python3 -m kubiscan -rrb # Listar RoleBindings riesgosos
python3 -m kubiscan -rcrb # Listar ClusterRoleBindings riesgosos
# Encontrar cuentas de servicio riesgosas
python3 -m kubiscan -rs # Cuentas de servicio riesgosas
# Encontrar pods ejecutándose con cuentas de servicio riesgosas
python3 -m kubiscan -rp # Pods riesgosos
# Verificar rutas de escalación de privilegios
python3 -m kubiscan -pe # Vectores de escalación de privilegios
# Generar informe completo
python3 -m kubiscan -a # Todas las verificaciones
Paso 5: Auditar Montaje y Uso de Tokens de Cuentas de Servicio
Verificar montajes innecesarios de tokens de cuentas de servicio que podrían permitir movimiento lateral desde pods comprometidos.
# Encontrar pods con tokens de cuenta de servicio montados automáticamente
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pod in data['items']:
name = pod['metadata']['name']
ns = pod['metadata']['namespace']
sa = pod['spec'].get('serviceAccountName', 'default')
automount = pod['spec'].get('automountServiceAccountToken', True)
if automount and sa != 'default':
print(f'{ns}/{name} -> SA: {sa} (token montado automáticamente)')
"
# Encontrar cuentas de servicio con secretos de token no predeterminados
kubectl get serviceaccounts --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for sa in data['items']:
name = sa['metadata']['name']
ns = sa['metadata']['namespace']
secrets = sa.get('secrets', [])
if name != 'default' and len(secrets) > 0:
print(f'{ns}/{name}: {len(secrets)} secreto(s) vinculado(s)')
"
# Verificar pods ejecutándose como privilegiados o con acceso a host
kubectl get pods --all-namespaces -o json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for pod in data['items']:
name = pod['metadata']['name']
ns = pod['metadata']['namespace']
for container in pod['spec'].get('containers', []):
sc = container.get('securityContext', {})
if sc.get('privileged', False) or sc.get('runAsUser', 1) == 0:
print(f'RIESGO: {ns}/{name}/{container[\"name\"]} - privileged={sc.get(\"privileged\",False)} runAsRoot={sc.get(\"runAsUser\",\"no establecido\")==0}')
"
Paso 6: Ejecutar Kubeaudit para Validación de RBAC y Políticas de Seguridad
Ejecutar Kubeaudit para verificaciones de seguridad integrales, incluidos hallazgos relacionados con RBAC.
# Ejecutar todas las verificaciones de kubeaudit
kubeaudit all --kubeconfig ~/.kube/config
# Ejecutar verificaciones específicas relacionadas con RBAC
kubeaudit privesc # Verificar allowPrivilegeEscalation
kubeaudit rootfs # Verificar readOnlyRootFilesystem
kubeaudit nonroot # Verificar runAsNonRoot
kubeaudit capabilities # Verificar capacidades peligrosas
# Salida como JSON para procesamiento
kubeaudit all --kubeconfig ~/.kube/config -f json > kubeaudit-results.json
Conceptos Clave
| Término | Definición |
|---|---|
| RBAC | Control de Acceso Basado en Roles en Kubernetes, método para regular el acceso a recursos del clúster según los roles de usuarios individuales o cuentas de servicio |
| ClusterRole | Definición de rol a nivel de clúster que especifica permisos (verbos sobre recursos) aplicables en todos los namespaces |
| ClusterRoleBinding | Asocia un ClusterRole con sujetos (usuarios, grupos, cuentas de servicio) a nivel de clúster |
| Cuenta de Servicio | Identidad asociada a pods para autenticarse en el servidor API de Kubernetes; se monta automáticamente a menos que se deshabilite |
| automountServiceAccountToken | Campo de especificación de pod que controla si el token de la cuenta de servicio se monta automáticamente en el sistema de archivos del pod |
| Escalación de Privilegios | Verbos RBAC (bind, escalate, impersonate) que permiten a un usuario otorgarse a sí mismo o a otros permisos elevados |
Herramientas y Sistemas
- kubectl: CLI principal para consultar recursos RBAC de Kubernetes (roles, vinculaciones, cuentas de servicio)
- rbac-tool: Plugin de kubectl para análisis RBAC que incluye consultas quién-puede, visualización y generación de políticas
- KubiScan: Herramienta Python para escanear RBAC de Kubernetes en busca de permisos riesgosos y rutas de escalación de privilegios
- Kubeaudit: Herramienta de auditoría de seguridad que verifica pods y cargas de trabajo en busca de anti-patrones de seguridad, incluidos problemas RBAC
- rakkess: Plugin de kubectl que muestra la matriz de acceso del usuario actual en todos los tipos de recursos
Escenarios Comunes
Escenario: Auditoría de un Clúster EKS Compartido por Múltiples Equipos de Desarrollo
Contexto: Un clúster EKS compartido da servicio a cuatro equipos de desarrollo. El RBAC se configuró durante la configuración inicial pero no se ha revisado en 12 meses. Los equipos informan que pueden acceder a namespaces de otros equipos.
Enfoque:
- Listar todos los ClusterRoleBindings para identificar vinculaciones que otorgan acceso amplio a usuarios autenticados
- Ejecutar
kubectl rbac-tool who-can get secretspara encontrar sujetos que pueden leer secretos en todos los namespaces - Descubrir que un ClusterRoleBinding otorga
editasystem:authenticated, dando acceso de escritura a todos los usuarios en todo el clúster - Ejecutar KubiScan para identificar cuentas de servicio con permisos riesgosos y pods ejecutándose con cuentas de servicio elevadas
- Reemplazar el ClusterRoleBinding con RoleBindings limitados a namespaces para cada equipo
- Deshabilitar automountServiceAccountToken para cargas de trabajo que no necesitan acceso a la API
- Crear una NetworkPolicy para aislar el tráfico de namespaces entre equipos
Errores Comunes: Eliminar ClusterRoleBindings puede romper pipelines CI/CD y operadores que dependen de acceso a nivel de clúster. Siempre auditar qué cargas de trabajo usan las vinculaciones antes de eliminarlas. EKS mapea roles IAM a grupos de Kubernetes mediante el ConfigMap aws-auth, por lo que los cambios en RBAC deben coordinarse con los mapeos de roles IAM.
Formato de Salida
Informe de Auditoría RBAC de Kubernetes
=========================================
Clúster: production-eks (EKS 1.28)
Fecha de Auditoría: 2026-02-23
Namespaces: 12
INVENTARIO RBAC:
ClusterRoles: 48 (18 personalizados, 30 del sistema)
ClusterRoleBindings: 32 (12 personalizados, 20 del sistema)
Roles (por namespace): 24
RoleBindings (por namespace): 36
Cuentas de Servicio: 67
HALLAZGOS CRÍTICOS:
[RBAC-001] ClusterRoleBinding otorga edit a system:authenticated
Vinculación: authenticated-edit
Efecto: TODOS los usuarios autenticados tienen acceso de edición en TODOS los namespaces
Riesgo: Cualquier usuario puede modificar recursos en cualquier namespace
Remedio: Reemplazar con RoleBindings limitados a namespaces por equipo
[RBAC-002] ClusterRole personalizado con permisos comodín
ClusterRole: developer-admin
Reglas: verbs=["*"], resources=["*"], apiGroups=["*"]
Vinculaciones: 4 usuarios mediante developer-admin-binding
Riesgo: Equivalente a cluster-admin sin el nombre
Remedio: Limitar a recursos y verbos específicos según necesidad
RESUMEN:
Principales con cluster-admin: 6 (recomendado: <= 3)
Roles con permisos comodín: 4
Cuentas de servicio con acceso a secretos: 12
Pods con tokens montados automáticamente: 45 / 67
Contenedores privilegiados: 8