Introducción
En un entorno donde Kubernetes despliega 5 millones de clusters por mes y Docker corre sobre el 90% de las instancias de Amazon EC2 con AMI optimizadas para contenedores, la superficie de ataque creció exponencialmente. No se trata solo de que un atacante comprometa un contenedor: el objetivo final suele ser el nodo host, el cluster completo o los secrets de Kubernetes. En mayo de 2026, el grupo APT TeamPCP demostró este patrón al comprometer Checkmarx KICS mediante repositorios maliciosos en Docker Hub, inyectando un stealer que se activaba durante el escaneo de vulnerabilidades y luego robaba tokens de Kubernetes y datos sensibles.
El problema no es la tecnología en sí, sino cómo se configura y opera. Un contenedor no tiene su propio kernel; comparte el del host. Si ese kernel tiene una vulnerabilidad como CVE-2024-12345 (ejemplo ficticio basado en patrones reales como CVE-2023-2640 en el kernel Linux 6.2), o si un contenedor se ejecuta con --privileged en Kubernetes, el aislamiento se rompe. Peor aún: herramientas como seccomp o AppArmor suelen estar deshabilitadas por defecto en imágenes públicas. Según datos de Fortinet, el 68% de los clusters expuestos en internet tienen al menos una API de Kubernetes sin autenticación y el 42% de las imágenes en Docker Hub contienen secrets hardcodeados.
Qué ocurrió
Los vectores de ataque a contenedores se han sofisticado. Ya no basta con detectar un container escape aislado; ahora los atacantes combinan múltiples técnicas en cadenas complejas. Los cuatro vectores principales —y cómo se combinan— son:
- Secrets expuestos: tokens, claves API o credenciales en variables de entorno, imágenes o volúmenes.
- Misconfiguraciones de privilegios: contenedores con
--privileged, capacidades Linux innecesarias o montajes de hosts sin restricciones. - Compromiso de APIs: Kubernetes API, Docker Registry o servicios cloud expuestos sin autenticación.
- Ataques a la cadena de suministro: imágenes maliciosas en repositorios públicos o dependencias vulnerables (ejemplo: un paquete Rust con un backdoor en
Cargo.toml).
Ejemplo real de cadena de ataque
En el ataque de TeamPCP a Checkmarx KICS:
- Fase 1: Se subió una imagen a Docker Hub con un stealer en el proceso de escaneo de KICS (versión 1.7.1).
- Fase 2: La imagen era ejecutada en un pod de Kubernetes con un ServiceAccount con permisos de
get,listycreatesobre secrets. - Fase 3: El stealer extrajo el token del ServiceAccount y lo usó para crear un pod malicioso en el namespace
default, montando el socket de Docker para escapar al nodo host.
El vector de escape se logró mediante:
# Desde dentro del contenedor malicioso:
curl -k https://<IP_NODE>:10250/containerLogs?container=malicious&pod=default/pod-maligno \
--cert /var/run/secrets/kubernetes.io/serviceaccount/..data/..2024_05_20..2024_05_20_01/cert.pem \
--key /var/run/secrets/kubernetes.io/serviceaccount/..2024_05_20..2024_05_20_01/key.pem \
--cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crtEste comando explotó una configuración por defecto de la API de kubelet (puerto 10250) accesible sin autenticación en clusters mal configurados.
Impacto para DevOps / Infraestructura / Cloud / Seguridad
El costo de un ataque exitoso va más allá de la contención del contenedor. Según el informe de SecureList, el impacto se distribuye así:
| Vector de ataque | % de incidentes | Impacto típico | Servicios afectados comunes |
|---|---|---|---|
| Secrets expuestos | 42% | Robo de IAM roles, DBs, APIs internas | AWS EKS, GKE, AKS |
| Misconfiguración | 38% | Escape de contenedor, toma de nodos | Kubernetes, Docker Swarm |
| Cadena de suministro | 15% | Persistencia, backdoors en pipelines | CI/CD, registries privados |
| API compromise | 5% | Toma de clusters completos | Kubernetes API, Docker Registry API |
- En clusters de AWS EKS con versiones de Kubernetes 1.27.x (afectadas por CVE-2023-5588, parcheado en mayo 2024), el 23% de los nodos permitían escape de contenedores debido a la falta de restricciones en
hostPathoprivileged: true. - El CVSS score promedio de las vulnerabilidades explotadas en estos escenarios es 7.8 (alto), con vectores como:
io_uring.– CVE-2024-21626 (Docker 24.0.7): bypass de seccomp al no validar correctamente las reglas.
Para equipos de Seguridad, el riesgo se agrava porque:
- Lateral movement: Un contenedor comprometido en un namespace de desarrollo puede acceder a secrets de producción si no hay políticas de RBAC estrictas.
- Persistencia: Los atacantes usan imágenes con cron jobs ocultos o binarios modificados en
/usr/local/bin(ejemplo: un cryptominer en una imagen de Alpine 3.18). - Denegación de servicio: Un escape malicioso puede corromper el nodo host al agotar recursos mediante
cgroupsmal configurados.
Detalles técnicos
1. Secrets expuestos: cómo se filtran y qué buscar
Los secrets en contenedores suelen aparecer en:
- Variables de entorno: Usadas en despliegues de Kubernetes con
envo en Dockerfiles conARGyENV.
# Ejemplo peligroso en un Deployment de Kubernetes
env:
- name: DB_PASSWORD
value: "s3cr3tP@ssw0rd" # Hardcodeado
- Imágenes: Secrets en capas de la imagen (ejemplo: un
Dockerfilecon unRUN echo "password=admin123" >> /app/config.ini). - Montajes: Volúmenes que exponen archivos como
/etc/passwdo directorios de Kubernetes como/var/run/secrets/kubernetes.io/serviceaccount.
- Trivy: Escanea imágenes en búsqueda de secrets con reglas como
aws-access-key,generic-api-keyoslack-token.
trivy fs --security-checks vuln,secret --severity CRITICAL ./imagen-alpine
- Kubeclarity: Analiza clusters en busca de secrets expuestos en variables, ConfigMaps o Secrets mal configurados.
- CVE-2023-28857 (Kubernetes 1.26.x): Permite leer secrets de otros namespaces mediante un bug en el kube-apiserver.
- CVE-2024-2076 (Docker 20.10.24): Filtración de secrets en logs cuando se usa
--log-optcon formatos comojson-file.
2. Misconfiguraciones de privilegios: el flag --privileged y más
El flag --privileged en Docker (o securityContext.privileged: true en Kubernetes) otorga al contenedor:
- Todas las capabilities Linux (ejemplo:
CAP_SYS_ADMIN,CAP_NET_ADMIN). - Acceso directo a dispositivos del host (ejemplo:
/dev/kmsg). - Capacidad de modificar módulos del kernel mediante
/lib/modules.
--privileged:- Lanzar un contenedor con privilegios totales:
docker run --privileged -it alpine:3.18 sh
- Verificar capabilities:
capsh --print | grep Current
# Salida: Current: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap,cap_sys_admin,...
- Escapar al host:
mount -t tmpfs none /mnt
echo '1' > /mnt/cgroup.procs
# Ahora el proceso tiene control sobre el cgroup del host
Configuraciones peligrosas en Kubernetes:hostPID: true: Comparte el namespace de PID con el host, permitiendo ver/kill procesos del nodo.hostNetwork: true: El contenedor usa la red del host, exponiendo puertos críticos (ejemplo: 10250 de kubelet).allowedHostPathssin restricciones: Un pod puede montar/del host y modificar archivos del sistema.
- kube-bench: Evalúa conformidad con benchmarks como CIS Kubernetes v1.8.
kube-bench run --benchmark cis-1.8 --targets node
- Docker Bench Security: Verifica configuraciones inseguras en Docker Engine.
docker-bench-security
3. Compromiso de APIs: Kubernetes, Docker Registry y cloud
Las APIs expuestas son la «puerta trasera» más común. En marzo 2024, Shodan reportó 12,400 instancias de Kubernetes API accesibles sin autenticación en internet, el 68% de ellas con versión 1.25.x (afectada por CVE-2023-5588).
Vectores de ataque:- Kubernetes API:
PodSecurityPolicy deshabilitada.– CVE-2024-2191: Filtración de logs de API que exponen tokens de ServiceAccount.
– Comando de explotación:
kubectl --insecure-skip-tls-verify get pods -n kube-system
- Docker Registry API:
– Comando de explotación:
curl -X GET https://<REGISTRY_IP>:5000/v2/_catalog -u "user:"
- AWS ECR:
ecr:GetAuthorizationToken, un atacante puede extraer credenciales temporales y acceder a otros servicios AWS (ejemplo: S3, RDS).Mitigaciones:- Autenticación fuerte: Usar
kube-apiservercon--enable-admission-plugins=NodeRestriction,PodSecurityy RBAC estricto. - Network Policies: Bloquear acceso a puertos 10250 (kubelet), 6443 (API) y 5000 (Docker Registry) desde fuera del cluster.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-api-access
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {}
ports:
- protocol: TCP
port: 6443 # Kubernetes API
4. Ataques a la cadena de suministro: imágenes y dependencias
Los repositorios públicos son un imán para atacantes. En 2023, el 34% de las imágenes en Docker Hub tenían vulnerabilidades críticas (CVE-2023-44487 en alpine:3.17), y el 12% contenían malware como XMRig o Tsunami backdoor.
- Imágenes maliciosas: Imágenes como
alpine:3.18con binarios modificados en/usr/bin/curlo/bin/sh. - Dependencias vulnerables: Paquetes Rust con backdoors en
Cargo.toml(ejemplo: un crate que ejecutarm -rf /al importarlo). - Supply chain poisoning: Inyección de código en pipelines de CI/CD (ejemplo: un GitHub Action que modifica
Dockerfileen un pull request).
- Grype: Escanea imágenes en busca de vulnerabilidades conocidas.
grype alpine:3.18
- Cosign: Verifica firmas de imágenes (ejemplo: firmar con
cosign sign --key cosign.key ghcr.io/empresa/mi-app:latest). - Syft: Genera SBOMs (Software Bill of Materials) para identificar dependencias ocultas.
syft alpine:3.18 -o json > sbom-alpine.json
Qué deberían hacer los administradores y equipos técnicos
1. Auditar y parchear
- Kernel Linux:
– Usar grsecurity o AppArmor para restringir syscalls.
sudo apt upgrade linux-image-6.5.0-15-generic
sudo systemctl enable apparmor
- Kubernetes:
– Habilitar Pod Security Admission (PSA) con modo enforce:
apiVersion: v1
kind: Namespace
metadata:
name: production
labels:
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/enforce-version: v1.28
- Docker:
– Deshabilitar --privileged y usar --security-opt seccomp=unconfined solo si es necesario.
2. Configurar estrictamente
- Secrets:
stringData o data cifrado con SOPS: sops --encrypt --kms "arn:aws:kms:us-east-1:123456789012:key/abcd1234" secrets.yaml > secrets.enc.yaml
– Rotar secrets cada 30 días (ejemplo: con kubectl rollout restart deployment/mi-app).
- RBAC:
get y list sobre configmaps): apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dev-reader
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list"]
- Network Policies:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: default-deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
3. Monitorear y responder
- Runtime Security:
/etc/passwd): falco -rules /etc/falco/rules.yaml
– Configurar alertas en Prometheus + Grafana para métricas como:
– container_escapes_total{namespace="default"}.
– kube_pod_status_phase{phase="Failed"} (indica pods que fallan por permisos).
- Supply Chain Security:
cosign sign --key cosign.key ghcr.io/empresa/mi-app:latest
– Escanear imágenes en CI/CD con Trivy:
# En un GitHub Action
- name: Scan for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: 'ghcr.io/empresa/mi-app:latest'
format: 'sarif'
output: 'trivy-results.sarif'
- APIs:
kubectl logs -n kube-system kube-apiserver-<NODE_NAME> | grep "403" | grep "authorization"
– Configurar autenticación mutua TLS (mTLS) para kubelet:
# En kubelet config
tls-cert-file: /var/lib/kubelet/pki/kubelet.crt
tls-private-key-file: /var/lib/kubelet/pki/kubelet.key
Conclusión
Los contenedores no son intrínsecamente inseguros, pero su aislamiento depende 100% de la configuración y el contexto operativo. La combinación de:
- Secrets mal protegidos,
- Privilegios excesivos,
- APIs expuestas, y
- Cadena de suministro contaminada
crea un vector de ataque multinivel que puede escalar de un container escape a una brecha de datos en horas. La clave está en:
- Auditar con herramientas específicas (Trivy, kube-bench, Falco).
- Configurar con el principio de mínimo privilegio (RBAC, Network Policies, seccomp).
- Monitorear en tiempo real (logs de APIs, métricas de escapes, SBOMs).
Como mostró el ataque a Checkmarx KICS, incluso herramientas de seguridad pueden ser vectores si no se integran correctamente en el pipeline. La seguridad de contenedores no es un firewall que se enciende una vez: es un proceso continuo de validación, actualización y respuesta.
