Skip to content

Esta herramienta no está afiliada a The Linux Foundation, la Cloud Native Computing Foundation (CNCF) ni el proyecto Kubernetes, ni está respaldada ni patrocinada por ellos. Kubernetes y K8s son marcas registradas de The Linux Foundation. EKS, GKE, AKS y otros nombres son marcas comerciales de sus respectivos propietarios.

Pods privilegiados y escape de contenedores: los indicios

Detecta la preparación de un escape de contenedor en los audit logs de Kubernetes: pods privilegiados, hostPID, hostPath de / y DaemonSets en kube-system.

Publicado el 6 min de lectura

TL;DR. El audit log no puede ver cómo ocurre un escape de contenedor, pero sí ve el spec del pod que lo vuelve trivial. Busca escrituras de workloads (pods, deployments, daemonsets, jobs, cronjobs…) cuyo cuerpo fije securityContext.privileged: true, añada SYS_ADMIN, comparta hostPID / hostNetwork / hostIPC o monte un hostPath de /, /etc, /var/lib/kubelet o un socket del runtime de contenedores. Un contenedor privilegiado con el sistema de archivos raíz o el espacio de PIDs del nodo equivale a tomar el nodo. Sigue con el exec que lo aprovechó (chroot /host, nsenter). Todo esto requiere los cuerpos de las solicitudes en el log.

ATT&CK lo divide en T1610, Deploy Container y T1611, Escape to Host. En Kubernetes ambos suelen ocurrir con menos de un minuto de diferencia, y el audit log registra el primero completo.

Por qué importan estos ajustes

Un contenedor es un conjunto de namespaces de Linux y restricciones sobre un kernel compartido. Cada uno de estos ajustes del pod quita una capa:

AjusteQué le da al contenedor
securityContext.privileged: trueTodas las capabilities, acceso a los dispositivos del host; puede montar el disco del host
capabilities.add: ["SYS_ADMIN"] (o ALL)Casi todo lo que da privileged, montajes incluidos
hostPID: trueVe y puede enviar señales a todos los procesos del nodo; nsenter -t 1 entra en el host
hostNetwork: trueUsa la pila de red del nodo: servicios locales, endpoint de metadatos cloud, captura de tráfico
hostIPC: trueComparte el namespace IPC del nodo
hostPath de /Todo el sistema de archivos del nodo: credenciales del kubelet, volúmenes de otros pods, chroot
hostPath de /var/run/docker.sock, containerd.sock, crio.sockHabla con el runtime de contenedores: arranca contenedores fuera de Kubernetes
hostPath de /etc, /root, /var/lib/kubeletConfiguración del host, claves SSH, credenciales del kubelet y secrets de los pods

Las buenas prácticas de RBAC de Kubernetes señalan que el permiso para crear workloads o PersistentVolumes puede incluir la creación de volúmenes hostPath y, por tanto, acceso al sistema de archivos del host. El perfil Baseline de los Pod Security Standards prohíbe todos los ajustes anteriores por ese motivo.

Qué muestra el audit log

Un DaemonSet ficticio, recortado a lo que importa:

{
  "verb": "create",
  "user": { "username": "system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard" },
  "objectRef": { "resource": "daemonsets", "namespace": "kube-system", "name": "kube-proxy-monitor", "apiGroup": "apps" },
  "requestObject": {
    "spec": { "template": { "spec": {
      "hostPID": true,
      "hostNetwork": true,
      "containers": [{
        "name": "monitor",
        "image": "docker.io/library/alpine:3.20",
        "securityContext": { "privileged": true },
        "volumeMounts": [{ "name": "host", "mountPath": "/host" }]
      }],
      "volumes": [{ "name": "host", "hostPath": { "path": "/", "type": "Directory" } }]
    } } }
  },
  "responseStatus": { "code": 201 }
}

Una imagen corriente, un nombre que imita a kube-proxy, el namespace kube-system y todos los ajustes de escape a la vez. Un DaemonSet pone una copia en cada nodo, así que no es un nodo tomado, son todos.

Quién lo creó: la persona, no el controlador

Los pods los crea el controlador de DaemonSet, ReplicaSet o Job, una identidad de sistema. Si solo miras las creaciones de pods, atribuirás el pod a system:serviceaccount:kube-system:daemon-set-controller. La identidad responsable es la que escribió el objeto workload. El analizador de la página principal lee la plantilla del pod dentro de Deployments, DaemonSets, StatefulSets, ReplicaSets, Jobs y CronJobs, así que los hallazgos apuntan a la persona o al token que escribió el spec.

Creado no siempre significa en ejecución

Con Pod Security Admission, el modo enforce se aplica a los pods, no a los objetos workload: la documentación de PSA indica que los recursos de workload solo reciben audit y warn. Por eso un DaemonSet privilegiado puede aceptarse (201) mientras se rechaza cada pod que intenta crear. Revisa los eventos create de pods del controlador y sus códigos de respuesta antes de concluir que el escape ocurrió. En modo audit, PSA añade al evento de auditoría una anotación que describe la infracción, lo cual es una señal útil por sí misma.

Detecciones

ReglaSeveridadLógica
Escape de contenedor hacia el nodoCríticaContenedor privilegiado y (hostPath / o hostPID)
Contenedor privilegiado desplegadoAltaprivileged: true o SYS_ADMIN / ALL añadidos
Ruta sensible del host montadaAltahostPath de /, /etc, /etc/kubernetes, /root, /home, /proc, /sys, /dev, /boot, /var/lib/kubelet o un socket de Docker, containerd o CRI-O
El workload comparte el namespace de PID / red / IPC del nodoMediahostPID, hostNetwork o hostIPC
DaemonSet creado en kube-systemAltaCualquier DaemonSet creado ahí por una identidad que no es de sistema

Todas se aplican a create, update y patch: parchear un Deployment existente para añadir un hostPath es tan eficaz como crear uno nuevo, y menos visible.

Espera coincidencias legítimas. Plugins CNI, drivers CSI, agentes de logs, node exporters y agentes de seguridad corren como DaemonSets privilegiados con montajes del host. Normalmente los instala una identidad de pipeline conocida, en un momento conocido y desde un registry conocido. Uno nuevo creado con kubectl desde un portátil, o por una cuenta de servicio que nunca despliega nada, no lo es.

Luego busca el exec

A la preparación le sigue el uso. Filtra los eventos pods/exec de los pods creados a partir del workload sospechoso (los nombres empiezan por el del workload) y lee los comandos:

  • chroot /host sh o chroot /host bash: una shell en el sistema de archivos del nodo;
  • nsenter --target 1 --mount --uts --ipc --net --pid: una shell en los namespaces del nodo a través del PID 1;
  • cat /host/var/lib/kubelet/…, ls /host/etc/kubernetes: búsqueda de credenciales;
  • crictl, ctr o docker contra un socket montado: contenedores arrancados fuera de Kubernetes.

Consulta cómo detectar kubectl exec para ver cómo aparecen los comandos en requestURI. Si no hay ningún exec, puede que el propio comando del contenedor haga el trabajo: lee command y args en el spec.

Lo que no verás

Una vez en el nodo, el atacante queda fuera de la vista del API server. Procesos, claves SSH nuevas, reutilización de credenciales del kubelet y contenedores arrancados directamente a través del socket del runtime no generan eventos de auditoría de Kubernetes. Necesitas evidencia a nivel de nodo: detección de runtime como Falco, EDR, los logs del propio nodo y un snapshot del disco. El artículo sobre limitaciones explica cómo combinar ambas cosas. El analizador puede cargar alertas de Falco en JSON junto a los audit logs y ponerlas en la misma línea de tiempo.

Remediación

  1. Guarda los specs de los workloads como evidencia, luego borra los workloads y busca copias en otros namespaces.
  2. Trata como comprometido cada nodo que ejecutó el pod: cordon, drain, snapshot, sustitución. Rota los certificados del kubelet y el rol de instancia cloud o la identidad administrada que usaba el nodo.
  3. Rota los secrets de cada pod que corrió en esos nodos: se podían leer desde el host.
  4. Aplica Pod Security Admission baseline o restricted en todos los namespaces, incluido kube-system con exenciones estrechas y nominales.
  5. Restringe quién puede crear workloads en kube-system.

Artículos relacionados

Artículos relacionados

Detecta criptominería en clústeres de Kubernetes con los audit logs: imágenes y argumentos de mineros, registries inusuales, persistencia con CronJob.
Encuentra escaladas de privilegios RBAC de Kubernetes en los audit logs: bindings a cluster-admin, verbos escalate, bind e impersonate, acceso anónimo.
Detecta robo de secrets y tokens de cuentas de servicio de Kubernetes en los audit logs: list globales, ráfagas, TokenRequest, uso desde IP pública, can-i.

Esta herramienta no está afiliada a The Linux Foundation, la Cloud Native Computing Foundation (CNCF) ni el proyecto Kubernetes, ni está respaldada ni patrocinada por ellos. Kubernetes y K8s son marcas registradas de The Linux Foundation. EKS, GKE, AKS y otros nombres son marcas comerciales de sus respectivos propietarios.