Parte: 10 — Seguridad en la nube y contenedores · Fuente: Liz Rice, "Container Security" (O'Reilly) y CIS Docker Benchmark ⏱️ Duración estimada: 130 min · Nivel: Intermedio
Entender cómo se aísla realmente un contenedor (namespaces, cgroups, capabilities) y aplicar seguridad en las tres fases del ciclo de vida: construcción de imágenes, almacenamiento/registro y ejecución. Al terminar, el alumno podrá escanear imágenes con Trivy, endurecer un Dockerfile y configurar el runtime según el CIS Docker Benchmark.
Al finalizar, el alumno podrá:
| # | Tema | Por qué importa |
|---|---|---|
| 1 | Namespaces y cgroups | Base del aislamiento; no es una VM |
| 2 | Capabilities y user namespaces | Reducir privilegios del proceso |
| 3 | Imágenes y capas | Superficie de vulnerabilidades y secretos |
| 4 | Dockerfile seguro y multi-stage | Imágenes pequeñas y limpias |
| 5 | Escaneo de imágenes (Trivy) | Detectar CVEs antes de desplegar |
| 6 | Runtime seguro (seccomp, AppArmor) | Contener el proceso en ejecución |
| 7 | Registro y firma de imágenes | Cadena de suministro confiable |
CAP_NET_ADMIN). Clave: recórtalas con --cap-drop=ALL y añade solo las necesarias.--privileged desactiva casi todo el aislamiento. Clave: casi equivale a root en el host; evítalo.docker run aquasec/trivy.# Escanear una imagen en busca de CVEs y secretos
trivy image --severity HIGH,CRITICAL nginx:latest
# Ver capabilities y perfil seccomp de un contenedor en ejecución
docker inspect --format '{{ .HostConfig.CapAdd }} {{ .HostConfig.SecurityOpt }}' mi_contenedor
🧪 Laboratorio ejecutable del programa:
devsecops-pipeline— son las capas 4 y 5 del lab de DevSecOps: un Dockerfile con diez antipatrones y las CVE del sistema base.
docker run -it --rm alpine sh y explora los namespaces con lsns desde el host para ver el aislamiento.--privileged y muestra que puede montar el disco del host; borra el contenedor y nunca uses privileged en producción.ENV) y pásalo por Hadolint; corrige los hallazgos.distroless o scratch, usuario no root (USER 1000) y sin secretos.trivy image y compara el número de CVEs y el tamaño.docker run --read-only --cap-drop=ALL --security-opt=no-new-privileges --user 1000 mi_imagen.userns-remap, logging).ubuntu a una distroless y mide la reducción de CVEs..dockerignore que evite filtrar .env y .git.Toma una imagen de aplicación real y prodúcela endurecida: multi-stage, base mínima, usuario no root, sin secretos, y ejecución con capabilities recortadas y read-only.
Criterio de aceptación: trivy image no reporta CVEs CRÍTICAS ni secretos en la imagen final, la
imagen corre como UID no root, y docker inspect confirma CapDrop: [ALL] y ReadonlyRootfs: true.
| Síntoma / mensaje | Causa y cómo arreglar |
|---|---|
permission denied al escribir en read-only |
El proceso necesita escribir; monta un volumen/tmpfs acotado para esa ruta. |
Secreto visible en docker history |
Se pasó por ENV/ARG o COPY; usa build secrets o inyección en runtime. |
| Contenedor corre como root sin querer | Falta USER en el Dockerfile; añádelo y ajusta permisos de archivos. |
| Trivy reporta cientos de CVEs | Imagen base gorda/antigua; cambia a base mínima y actualiza. |
--privileged "necesario" para que funcione |
Casi nunca lo es; identifica la capability concreta y añádela sola. |
❓ ¿Un contenedor es tan seguro como una máquina virtual? No. Comparten el kernel del host; una fuga o un contenedor privilegiado pueden comprometer el host. Para aislamiento fuerte se usan sandboxes como gVisor o Kata Containers.
❓ ¿Por qué correr como no root si el contenedor ya está aislado? Porque si el atacante escapa del contenedor o explota una capability, ser root dentro facilita el escape hacia el host. El usuario no root reduce el impacto de un compromiso.
❓ ¿Dónde guardo los secretos si no en el Dockerfile? Fuera de la imagen: en un gestor de secretos (clase 233), variables inyectadas en runtime o montajes de secretos del orquestador. Nunca en capas de la imagen.
Clase 226 — Ataques y pentest en entornos cloud