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:

  1. Secrets expuestos: tokens, claves API o credenciales en variables de entorno, imágenes o volúmenes.
  2. Misconfiguraciones de privilegios: contenedores con --privileged, capacidades Linux innecesarias o montajes de hosts sin restricciones.
  3. Compromiso de APIs: Kubernetes API, Docker Registry o servicios cloud expuestos sin autenticación.
  4. 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, list y create sobre 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.crt

Este 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 incidentesImpacto típicoServicios afectados comunes
Secrets expuestos42%Robo de IAM roles, DBs, APIs internasAWS EKS, GKE, AKS
Misconfiguración38%Escape de contenedor, toma de nodosKubernetes, Docker Swarm
Cadena de suministro15%Persistencia, backdoors en pipelinesCI/CD, registries privados
API compromise5%Toma de clusters completosKubernetes API, Docker Registry API
Ejemplo cuantitativo:
  • 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 hostPath o privileged: true.
  • El CVSS score promedio de las vulnerabilidades explotadas en estos escenarios es 7.8 (alto), con vectores como:
CVE-2023-3278 (kernel Linux 5.15.0-76): permite escape mediante un race condition en 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:

  1. 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.
  2. 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).
  3. Denegación de servicio: Un escape malicioso puede corromper el nodo host al agotar recursos mediante cgroups mal 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 env o en Dockerfiles con ARG y ENV.
  # 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 Dockerfile con un RUN echo "password=admin123" >> /app/config.ini).
  • Montajes: Volúmenes que exponen archivos como /etc/passwd o directorios de Kubernetes como /var/run/secrets/kubernetes.io/serviceaccount.
Herramientas para detectarlo:
  • Trivy: Escanea imágenes en búsqueda de secrets con reglas como aws-access-key, generic-api-key o slack-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.
Vulnerabilidades asociadas:
  • 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-opt con formatos como json-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.
Ejemplo de escape con --privileged:
  1. Lanzar un contenedor con privilegios totales:
   docker run --privileged -it alpine:3.18 sh
   
  1. 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,...
   
  1. 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).
  • allowedHostPaths sin restricciones: Un pod puede montar / del host y modificar archivos del sistema.
Herramientas para auditar:
  • 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:
CVE-2023-5588: Permite acceso no autenticado a pods en namespaces con 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:
CVE-2023-28840: Permite pull de imágenes privadas sin credenciales si el registry usa autenticación básica mal configurada.

Comando de explotación:

    curl -X GET https://<REGISTRY_IP>:5000/v2/_catalog -u "user:"
    
  • AWS ECR:
– Si el rol IAM asociado al cluster tiene permisos ecr:GetAuthorizationToken, un atacante puede extraer credenciales temporales y acceder a otros servicios AWS (ejemplo: S3, RDS).Mitigaciones:
  • Autenticación fuerte: Usar kube-apiserver con --enable-admission-plugins=NodeRestriction,PodSecurity y 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.

Técnicas de ataque:
  • Imágenes maliciosas: Imágenes como alpine:3.18 con binarios modificados en /usr/bin/curl o /bin/sh.
  • Dependencias vulnerables: Paquetes Rust con backdoors en Cargo.toml (ejemplo: un crate que ejecuta rm -rf / al importarlo).
  • Supply chain poisoning: Inyección de código en pipelines de CI/CD (ejemplo: un GitHub Action que modifica Dockerfile en un pull request).
Herramientas para detectar:
  • 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:
– Actualizar a kernel 6.5.x (parchea CVE-2024-12345 y otras).

– Usar grsecurity o AppArmor para restringir syscalls.

  sudo apt upgrade linux-image-6.5.0-15-generic
  sudo systemctl enable apparmor
  
  • Kubernetes:
– Actualizar a 1.28.x (parchea CVE-2023-5588 y CVE-2024-2191).

– 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:
– Actualizar a Docker 25.0.3 (parchea CVE-2024-2076).

– Deshabilitar --privileged y usar --security-opt seccomp=unconfined solo si es necesario.

2. Configurar estrictamente

  • Secrets:
– Usar Kubernetes Secrets con 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:
– Crear roles mínimos (ejemplo: un ServiceAccount solo con 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:
– Bloquear todo el tráfico entre namespaces por defecto:
    apiVersion: networking.k8s.io/v1
    kind: NetworkPolicy
    metadata:
      name: default-deny-all
    spec:
      podSelector: {}
      policyTypes:
      - Ingress
      - Egress
    

3. Monitorear y responder

  • Runtime Security:
– Implementar Falco para detectar comportamientos sospechosos (ejemplo: un contenedor intentando escribir en /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:
– Firmar imágenes con Cosign:
    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:
– Auditar acceso a APIs con kube-apiserver logs:
    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:

  1. Auditar con herramientas específicas (Trivy, kube-bench, Falco).
  2. Configurar con el principio de mínimo privilegio (RBAC, Network Policies, seccomp).
  3. 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.

Deja una respuesta

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