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.

Ataque a Kubernetes paso a paso: un incidente ficticio

Un incidente ficticio de Kubernetes, paso a paso en el audit log: token de dashboard expuesto, recon con can-i, robo de secrets, DaemonSet privilegiado, XMRig.

Publicado el 8 min de lectura

TL;DR. Este es un incidente ficticio, generado para el botón «Probar un ejemplo» del analizador de audit logs de Kubernetes. El clúster, las personas, las direcciones IP, las imágenes y el registry son inventados. En quince minutos de eventos de auditoría, un atacante usa desde Internet un token expuesto de la cuenta de servicio del Kubernetes Dashboard, mapea sus permisos con kubectl auth can-i, lista todos los secrets, despliega un DaemonSet privilegiado que monta el sistema de archivos de cada nodo, abre una shell de root con chroot /host, crea una cuenta de servicio enlazada a cluster-admin, programa un CronJob de XMRig y borra los Events. El veredicto es «Probable compromiso»; este artículo lee la evidencia línea a línea.

Escenario ficticio. Todo lo que sigue es sintético. Las direcciones de Internet proceden de los rangos reservados para documentación (RFC 5737), los dominios terminan en .example y no se describe ninguna organización, persona ni incidente reales.

El ejemplo cubre seis horas (de 08:00 a 14:00 UTC del 14 de septiembre de 2026) de un pequeño clúster de producción llamado shop-prod: tres nodos worker renovando leases, controladores reconciliando, Prometheus haciendo scraping, una CI basada en Helm que despliega dos veces por hora, una administradora de plataforma, Alice, que usa kubectl, y el Kubernetes Dashboard consultando pods desde su dirección interna del clúster. Unos 2080 eventos en total, de los que unos cuarenta y cinco pertenecen al ataque. Esa proporción es realista: lo difícil es encontrar esas pocas decenas de líneas.

El veredicto

Al cargar el ejemplo (el audit log más dos alertas de Falco) se obtiene Probable compromiso, motivado por tres hallazgos críticos (escape de contenedor hacia el nodo, binding a cluster-admin, imagen de crypto-mining) y varios altos. La checklist de remediación empieza por preservar la evidencia y delimitar el alcance, y sigue con borrar workloads maliciosos, reconstruir nodos, aplicar Pod Security, eliminar bindings y revocar tokens.

Ahora, la línea de tiempo tal como la muestra la línea de tiempo del incidente del analizador (horas en UTC).

13:01:58 – Una identidad conocida desde un lugar desconocido

El primer evento del ataque es un get /version de system:serviceaccount:kubernetes-dashboard:kubernetes-dashboard. Esa cuenta de servicio lleva activa toda la mañana, pero desde 10.0.3.15 con el user agent dashboard/v2.7.0. Esta solicitud llega desde 203.0.113.45, una dirección pública, con kubectl/v1.30.2 (linux/amd64).

Saltan dos hallazgos: Token de cuenta de servicio usado desde una IP pública (alta) y Token de cuenta de servicio usado con kubectl / curl (media). La historia que cuentan es sencilla: el token del dashboard salió del clúster y alguien lo está usando a mano. En este escenario, el dashboard corre con un rol con demasiados privilegios, y eso es lo que hace posible todo lo demás.

Las llamadas de descubrimiento a /api y /apis llegan en menos de dos segundos, como hace siempre kubectl en el primer contacto.

13:02:31 – «¿Qué puedo hacer?»

Siete solicitudes en quince segundos: seis selfsubjectaccessreviews y una selfsubjectrulesreviews. Con registro RequestResponse, los cuerpos muestran exactamente qué se preguntó: ¿puedo hacer list secrets, create pods en kube-system, create daemonsets en kube-system, create clusterrolebindings, create pods/exec en kube-system y * *? Todo está permitido salvo el comodín.

Eso es Enumeración de permisos (kubectl auth can-i), media. Dos respuestas 403 a las 13:03 sobre list nodes y list clusterroles confirman que el rol es amplio pero no ilimitado. El atacante ya sabe que su plan funcionará. Consulta secrets y robo de tokens para este patrón de reconocimiento.

13:04:02 – Todos los secrets del clúster

Un único list sobre secrets sin namespace: Secrets listados en todos los namespaces (alta). Esa sola respuesta contiene todos los secrets del clúster. Después, el atacante lee doce secrets uno a uno entre las 13:04:40 y las 13:05:13: credenciales de base de datos, una clave de API de pagos, las credenciales del registry, una clave de firma JWT, un token de Vault, un secret de webhook, credenciales de Grafana y Alertmanager, el token del desplegador de CI, la clave privada de una GitHub App, credenciales cloud y la clave de un bucket de copias de etcd. La Ráfaga de lecturas de secrets (media) salta con el décimo nombre distinto.

Para quien responde, esta lista es el plan de rotación. Dado el list global, todos los demás secrets deben considerarse expuestos también.

13:06:12 – Un DaemonSet privilegiado en kube-system

El token del dashboard crea un DaemonSet llamado kube-proxy-monitor en kube-system: imagen alpine:3.20, hostPID y hostNetwork, un contenedor privilegiado, el / del nodo montado en /host y una toleration para cualquier taint, de modo que acaba en todos los nodos. Cinco hallazgos saltan con este único evento:

  • Escape de contenedor hacia el nodo (crítica): privilegiado más hostPath / más hostPID;
  • Contenedor privilegiado desplegado, Ruta sensible del host montada, DaemonSet creado en kube-system (alta);
  • El workload comparte el namespace de PID / red / IPC del nodo (media).

Un segundo después, el controlador de DaemonSet crea tres pods, uno por nodo. Esas creaciones las hace una identidad de sistema; la identidad responsable es la que escribió el DaemonSet. El artículo sobre pods privilegiados explica por qué el analizador lee la plantilla del pod dentro del workload.

13:07:40 – Una shell de root en el nodo

Un exec en kube-proxy-monitor-x7k2p con command=chroot&command=%2Fhost&command=sh: chroot /host sh, una shell en el propio sistema de archivos de worker-1. Una cuenta de servicio ejecutó un comando en un contenedor (alta). El evento aparece en tres stages que comparten un auditID (RequestReceived, ResponseStarted con código 101, ResponseComplete a las 13:08:55); el analizador los agrupa en una sesión de unos 75 segundos.

El audit log se detiene aquí: lo que se tecleó en esa shell es invisible. El archivo de Falco del ejemplo contiene una alerta «Terminal shell in container» a las 13:07:41 en el mismo pod, con chroot como proceso padre. Es una alerta de nivel Notice, por debajo del umbral de alertas del analizador, pero está en la misma línea de tiempo y confirma la shell. El artículo sobre limitaciones explica por qué importa esta combinación.

13:09 – Una identidad nueva con cluster-admin

Tres escrituras en 26 segundos:

  1. create serviceaccounts kube-system/node-health: un nombre verosímil.
  2. create clusterrolebindings node-health-admin, roleRef cluster-admin, con la nueva cuenta de servicio como sujeto: Binding a cluster-admin creado (crítica) y Role binding a nivel de clúster creado (baja).
  3. create serviceaccounts/token para node-health, con expirationSeconds: 31536000: Token de cuenta de servicio generado (media). Un token de un año para una identidad que a nadie se le ocurrirá revocar.

Es el paso de persistencia descrito en el artículo sobre escalada RBAC. Desde las 13:11:02 las solicitudes vienen de node-health, todavía desde 203.0.113.45 y con la misma compilación de kubectl: la IP y el user agent vinculan ambas identidades a un mismo operador.

13:12:30 – El minero

node-health crea un CronJob kube-state-sync en kube-system, cada cinco minutos, imagen registry.k8s-mirror.example:5000/xmrig/xmrig:6.21.0, argumentos --url=pool.minexmr.example:4444 --donate-level=0. Hallazgos: Imagen o comando de crypto-mining (crítica), CronJob creado (media), Imagen proveniente de un registry inusual (baja). A las 13:15 y las 13:20, el controlador de Jobs crea los jobs y los pods; la regla de mineros también salta con ellos, porque un minero es un minero lo lance quien lo lance.

La segunda alerta de Falco, Critical, a las 13:15:07 en worker-2, muestra a xmrig conectándose al puerto 4444: Alerta de runtime de Falco (alta). El artículo sobre criptominería cubre este patrón.

13:16:40 – Borrar huellas

deletecollection sobre events en kube-system: Eventos de Kubernetes eliminados (baja). Los Events habrían mostrado la programación de los pods del DaemonSet y la descarga de la imagen del minero. El audit log, guardado fuera del clúster, sigue teniéndolo todo. (En EKS, cuya política gestionada no registra Events en absoluto, este paso no sería visible).

El falso positivo del informe

Un hallazgo no tiene nada que ver con el ataque: Comando interactivo en un contenedor (exec / attach) (media) de alice@example.com a las 10:12:03, un sh en un pod de API de shop. Es una sesión de depuración legítima desde su IP habitual con su kubectl habitual. Así hay que tratar los hallazgos de exec: confirmar con la persona responsable, anotarlo y seguir. Consulta cómo detectar kubectl exec.

Qué hace después quien responde

Siguiendo la checklist del analizador y la guía de respuesta a incidentes:

  1. Preservar: exportar los audit logs, guardar los specs del DaemonSet, el CronJob, la ServiceAccount y el ClusterRoleBinding, y hacer snapshots de worker-1 (la shell) y de los demás nodos (los pods privilegiados corrieron en los tres).
  2. Contener: borrar node-health-admin, borrar y volver a crear ambas cuentas de servicio (el token de un año muere con node-health), restringir el acceso al API server y desconectar el dashboard.
  3. Erradicar: borrar el CronJob, sus Jobs y pods, y el DaemonSet; buscar la imagen y el pool en todos los namespaces.
  4. Recuperar: sustituir los tres nodos; rotar todos los secrets, empezando por las credenciales cloud, la clave de la GitHub App y el token de CI, que dan acceso fuera del clúster.
  5. Ampliar el alcance fuera del clúster: las credenciales cloud y el token de CI robados deben rastrearse en los logs de auditoría del cloud y de la CI.
  6. Endurecer: ningún dashboard expuesto, rol del dashboard de mínimo privilegio, Pod Security Admission en kube-system y solo registries de confianza.

Pruébalo tú

Abre el analizador, haz clic en Probar un ejemplo y sigue el recorrido: la línea de tiempo, el pivote por entidades sobre 203.0.113.45 y la ficha de detalle de cada evento muestran todo lo descrito aquí. La guía paso a paso explica cada panel.

Artículos relacionados

Artículos relacionados

Análisis de audit logs de Kubernetes paso a paso con una herramienta gratuita en el navegador: exportaciones de EKS, GKE, AKS o en bruto y veredicto.
Los puntos ciegos de los audit logs de Kubernetes: actividad en contenedores, acceso a kubelet y etcd, huecos de política, campos falsificables y qué los cubre.
Guía de respuesta a incidentes en Kubernetes: qué evidencias reunir en los audit logs, qué preguntas responder, qué patrones de ataque buscar y cómo contener.

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.