Introducción

En clusters Kubernetes, el kubelet expone un endpoint HTTPS (puerto 10250) que brinda acceso a datos críticos: métricas de nodos, logs de contenedores, estados de pods e incluso la capacidad de ejecutar comandos dentro de contenedores vivos. Hasta la versión v1.35, la autorización de este API se basaba en un modelo grueso: casi cualquier solicitud requería el permiso nodes/proxy, que otorga control total sobre el nodo. Esto violaba el principio de privilegio mínimo y ampliaba el radio de explosión de un incidente de seguridad.

A partir de Kubernetes v1.36, la autorización fina del kubelet (KubeletFineGrainedAuthz) pasa a General Availability (GA), reemplazando el permiso nodes/proxy por subrecursos específicos para endpoints comunes como /pods, /metrics y /healthz. El feature gate se habilita por defecto y ya no puede desactivarse, lo que obliga a los administradores a migrar sus permisos existentes a políticas más estrictas.

Qué ocurrió

El problema detrás de esta mejora se remonta a una vulnerabilidad crítica descubierta a principios de 2026: investigadores demostraron que otorgar nodes/proxy GET —el permiso mínimo para monitoreo— permitía ejecución remota de código no registrado mediante WebSocket, incluso sin permisos CREATE explícitos. El vector de ataque explotaba el mapeo incorrecto entre el protocolo WebSocket (RFC 6455) y los verbos RBAC en el kubelet:

  1. WebSocket inicia con un GET al endpoint /exec.
  2. El kubelet autoriza el GET como get en RBAC, sin verificar que el cliente tenga create para la operación subsiguiente.
  3. Un atacante con solo nodes/proxy GET puede ejecutar comandos arbitrarios en cualquier pod del nodo.

Esta falla está documentada en kubernetes/kubernetes#83465 y motivó el KEP-2862, que ahora llega a GA en v1.36.

Impacto para DevOps / Infraestructura / Cloud / Seguridad

Riesgo para equipos de operaciones

  • Radio de explosión ampliado: Un agente de monitoreo comprometido con nodes/proxy puede ejecutar código en todos los contenedores del nodo, incluso si solo necesitaba leer métricas.
  • Exposición en Helm charts: Investigaciones de 2026 encontraron que docenas de charts populares (como kube-prometheus-stack y node-exporter) distribuían RBAC con nodes/proxy por defecto, exponiendo clústeres en producción.
  • Falta de auditoría: Las operaciones /exec mediante WebSocket no quedan registradas en logs estándar del kubelet, dificultando la detección de intrusiones.

Impacto en seguridad y cumplimiento

  • Cumplimiento de principio de mínimo privilegio: La autorización fina permite asignar permisos específicos (kubelet/metrics, kubelet/pods, kubelet/healthz) sin conceder control total del nodo.
  • Reducción de superficie de ataque: Eliminar nodes/proxy en favor de subrecursos específicos reduce el impacto de un compromiso en herramientas de observabilidad.

Datos concretos

  • Versión afectada: Clusters con kubelets en v1.32–v1.35 pueden tener nodes/proxy activo si usaron Webhook authorization.
  • CVSS base: No aplica aún, pero el riesgo de RCE no registrado se considera medio-alto por la falta de logs y el alcance de compromiso.
  • Componentes críticos:
– Kubelet en nodos (puerto 10250).

– RBAC en el API Server.

– Herramientas de monitoreo como Prometheus Node Exporter, cAdvisor y Datadog Agent.

Detalles técnicos

¿Cómo funciona la autorización fina?

El kubelet en v1.36 implementa un doble chequeo de autorización:

  1. Primera verificación: Para endpoints mapeados a subrecursos finos (ver tabla abajo), el kubelet envía un SubjectAccessReview específico. Si la verificación falla, continúa.
  2. Fallback: Si no hay permiso para el subrecurso, el kubelet intenta con nodes/proxy para mantener compatibilidad.
Endpoint kubeletSubrecurso RBACPermiso mínimo recomendado
BLOCK35BLOCK36BLOCK37 en BLOCK38
BLOCK39BLOCK40BLOCK41 en BLOCK42
BLOCK43BLOCK44BLOCK45 en BLOCK46
BLOCK47BLOCK48BLOCK49 en BLOCK50
### Migración de permisos existentes

El rol integrado system:kubelet-api-admin se actualiza automáticamente en v1.36 para incluir los nuevos subrecursos:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: system:kubelet-api-admin
rules:
- apiGroups: [""]
  resources: ["nodes/proxy"]
  verbs: ["*"]
- apiGroups: [""]
  resources: ["kubelet/metrics", "kubelet/pods", "kubelet/healthz", "kubelet/configz"]
  verbs: ["get", "list"]

Configuración en nodos

Para verificar que el feature gate esté activo en un nodo específico:

# 1. Crear un ServiceAccount y ClusterRole para consultar métricas del kubelet
kubectl apply -f - <<EOF
apiVersion: v1
kind: ServiceAccount
metadata:
  name: kubelet-checker
  namespace: default
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: kubelet-metrics-reader
rules:
- apiGroups: [""]
  resources: ["kubelet/metrics"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: kubelet-metrics-reader-binding
subjects:
- kind: ServiceAccount
  name: kubelet-checker
  namespace: default
roleRef:
  kind: ClusterRole
  name: kubelet-metrics-reader
  apiGroup: rbac.authorization.k8s.io
EOF

# 2. Ejecutar un pod con el ServiceAccount y consultar el feature
kubectl run kubelet-checker --image=alpine/curl:latest -n default --rm -it --overrides='{
  "spec": {
    "serviceAccountName": "kubelet-checker",
    "containers": [{
      "name": "curl",
      "image": "alpine/curl:latest",
      "command": ["sh", "-c"],
      "args": ["curl -k -H \"Authorization: Bearer $(cat /var/run/secrets/kubernetes.io/serviceaccount/token)\" https://$NODE_IP:10250/metrics"]
    }]
  }
}'

Si el feature está activo, la respuesta incluirá métricas del kubelet y la línea:

kubelet_feature_enabled{name="KubeletFineGrainedAuthz"} 1

Qué deberían hacer los administradores y equipos técnicos

1. Auditar permisos existentes en clusters

Ejecutar este comando para identificar roles y bindings que usen nodes/proxy:

kubectl get clusterroles,roles -o yaml | grep -A5 "nodes/proxy" || echo "No se encontraron permisos nodes/proxy"

2. Migrar permisos a subrecursos finos

Para herramientas de monitoreo como Prometheus:

# clusterrole-monitor-prometheus.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus-kubelet-reader
rules:
- apiGroups: [""]
  resources: ["kubelet/metrics", "kubelet/configz"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-kubelet-reader-binding
subjects:
- kind: ServiceAccount
  name: prometheus-node-exporter
  namespace: monitoring
roleRef:
  kind: ClusterRole
  name: prometheus-kubelet-reader
  apiGroup: rbac.authorization.k8s.io

Aplicar con:

kubectl apply -f clusterrole-monitor-prometheus.yaml

3. Actualizar Helm charts y manifiestos

Verificar que los charts de monitoreo usen permisos específicos:

# Ejemplo para kube-prometheus-stack (v60.0.0+)
helm upgrade --install kube-prometheus-stack prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --set kubelet.serviceMonitor.https=true \
  --set kubelet.serviceMonitor.insecureSkipVerify=true

4. Deshabilitar nodes/proxy en entornos nuevos

Para clusters nuevos, evitar asignar nodes/proxy y usar solo los subrecursos finos recomendados.

5. Validar logs del kubelet

Verificar que las operaciones /exec mediante WebSocket ya no sean posibles con los nuevos permisos:

journalctl -u kubelet -n 1000 | grep -i websocket || echo "No se detectaron conexiones WebSocket"

6. Actualizar políticas de red (si aplica)

Si usás NetworkPolicies, asegurate de permitir tráfico al puerto 10250 solo desde pods autorizados:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-kubelet-metrics
  namespace: monitoring
spec:
  podSelector:
    matchLabels:
      app: prometheus-node-exporter
  policyTypes:
  - Egress
  egress:
  - to:
    - ipBlock:
        cidr: 10.0.0.0/8  # Ajustar a tu rango de nodos
    ports:
    - protocol: TCP
      port: 10250

Conclusión

La migración a autorización fina del kubelet en Kubernetes v1.36 no es opcional: es una corrección crítica para reducir el radio de explosión de incidentes de seguridad en clústeres de producción. Los equipos de SRE y seguridad deben priorizar:

  1. Auditar permisos existentes de nodes/proxy en herramientas de monitoreo.
  2. Implementar RBAC con subrecursos específicos (kubelet/metrics, kubelet/pods, etc.).
  3. Validar que los endpoints del kubelet no permitan operaciones no autorizadas mediante WebSocket.

La comunidad Kubernetes recomienda migrar antes de finales de 2026, cuando herramientas como Helm aún distribuyan configuraciones inseguras por defecto. Con esta mejora, los equipos de DevOps ganan control granular y reducen drásticamente la posibilidad de ejecución remota de código no registrado en sus nodos.

Por Gustavo

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *