Seguridad de contenedores Docker | Nicolás Garzón
Texto
Copiar vulnerabilidad en aplicación
→ ejecución dentro del container
→ controles de usuario/capabilities/seccomp/mounts/network
→ impacto limitado o escalado al hostLa seguridad debe diseñarse por capas: source, dependencias, image, registry, daemon, runtime, red, datos y host.
Antes de añadir flags, responde:
¿Qué código se ejecuta y quién lo controla?
¿Qué datos puede leer?
¿Qué redes puede alcanzar?
¿Qué privileges conserva?
¿Qué mounts y devices recibe?
¿Qué ocurre si obtiene ejecución remota?
¿Qué impacto tiene un escape?
¿Cómo se detecta y revoca?
Un servicio interno también puede ser comprometido. “No está publicado” no elimina el riesgo.
Utiliza bases con soporte, actualizaciones y provenance conocida.
Excluye toolchains, package managers y herramientas innecesarias del runtime mediante multi-stage.
No copies .env, tokens, keys o credenciales. Revisa layers y metadata.
Despliega el digest aprobado, genera SBOM/provenance y conserva relación con commit.
docker
Copiar RUN groupadd --gid 10001 app \
&& useradd --uid 10001 --gid app --no-create-home app
USER 10001:10001Root dentro del container puede estar restringido, pero conserva más capacidad de abuso, especialmente con mounts, capabilities o fallos del kernel.
Bash
Copiar docker run \
--user 10001 :10001 \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size= 64m \
--cap-drop ALL \
--security-opt no-new-privileges \
--memory 512m \
--pids-limit 200 \
my-apiCada control limita una dimensión:
--user: identidad;
--read-only: modificaciones del root filesystem;
tmpfs: escrituras temporales controladas;
cap-drop: privilegios del kernel;
no-new-privileges: evita ganar privilegios mediante exec;
límites: reducen agotamiento de host.
Bash
Copiar docker run --privileged imageAmplía devices, capabilities y controles de seguridad. Puede acercar el proceso al control del host.
No debe ser la solución a:
permission denied;
acceso a un único device;
bind de puerto;
debugging;
Docker-in-Docker improvisado.
Identifica la capability, device o mount exacto. Si privileged es imprescindible, aísla el host, reduce datos accesibles y documenta el riesgo.
Linux divide privilegios de root.
Bash
Copiar docker run \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
my-apiMuchas APIs en puertos altos no necesitan ninguna adicional.
Una capability puede ser poderosa:
administrar red;
cambiar ownership;
cargar aspectos del sistema;
saltar controles de filesystem.
Añade una por una y prueba funcionalidad. Usuario no root + capability excesiva sigue siendo riesgoso.
Bash
Copiar docker run --security-opt no-new-privileges my-apiImpide que un proceso obtenga nuevos privilegios mediante binarios setuid/setgid u otros mecanismos al ejecutar.
No elimina capabilities ya concedidas ni corrige mounts peligrosos.
Seccomp limita syscalls disponibles. Docker aplica un perfil predeterminado en configuraciones normales.
Bash
Copiar docker run --security-opt seccomp = unconfined imageamplía superficie. No lo hagas para resolver un error sin identificar la syscall y el motivo.
Un perfil personalizado puede ser útil para workloads sensibles, pero requiere:
observar syscalls legítimas;
pruebas completas;
compatibilidad con runtime y kernel;
mantenimiento durante upgrades.
Estos controles MAC limitan acceso más allá de permisos Unix.
paths;
capabilities;
signals;
devices;
network según política.
Errores permission denied pueden venir de estas políticas aunque UID/GID parezcan correctos. No desactives enforcement globalmente. Ajusta perfil o labels con alcance mínimo.
Bash
Copiar docker run --read-only my-api
impide persistir herramientas en rootfs;
descubre dependencias ocultas de escritura;
reduce cambios accidentales;
refuerza inmutabilidad.
Bash
Copiar docker run \
--read-only \
--tmpfs /tmp:rw,noexec,nosuid,size= 64m \
--mount type = volume,src= uploads,dst= /app/uploads \
my-apiUn atacante todavía puede escribir en mounts, memoria, red y servicios externos.
Bash
Copiar docker run -v /var/run/docker.sock:/var/run/docker.sock toolCon acceso al daemon, el proceso puede crear containers privilegiados y montar el host. Trátalo como root-equivalent.
Bash
Copiar docker run -v /:/host imageExpone archivos, credenciales y configuración. Read-only reduce escritura, no lectura/exfiltración.
Pueden revelar o modificar estado del host. Expón únicamente el recurso requerido.
Montar directorios de credenciales entrega identidad del operador. Prefiere identidad de workload de corto plazo.
Bash
Copiar docker run --device /dev/video0 imageConcede acceso específico. Evalúa:
datos producidos por el device;
ioctls disponibles;
multi-tenant;
ownership;
acceso físico.
No uses privileged para un único device.
conecta solo networks necesarias;
publica solo puntos de entrada;
usa TLS y autenticación internas cuando el riesgo lo exige;
limita egress si necesitas reducir exfiltración;
separa administración de tráfico de usuario;
no confíes en IP como identidad fuerte.
Una API comprometida puede atacar database aunque esta no tenga host port. Usa roles mínimos y segmentación.
Un secret montado como archivo puede ser leído por la aplicación y por un atacante con ejecución en ese proceso.
scope por service;
credenciales de corto plazo;
permisos mínimos;
rotación;
no logs;
no environment completo en dumps;
revocación y auditoría.
Container isolation no protege un secreto de la propia aplicación comprometida.
Bash
Copiar docker run \
--memory 512m \
--cpus 1 \
--pids-limit 200 \
my-api
memory exhaustion;
fork bombs;
monopolio de CPU.
No corrige un DoS lógico ni garantiza capacidad para otros workloads si todos tienen límites mal dimensionados.
Quien controla Docker daemon puede controlar el host en una configuración privilegiada normal.
Unix socket;
grupo docker;
API TCP con TLS/authorization;
contexts y credenciales;
plugins;
CI runners;
logs de auditoría.
No expongas el daemon sin autenticación. El grupo docker es acceso administrativo.
La seguridad del container depende del host:
kernel actualizado;
Engine/containerd/runc actualizados;
filesystem y disco protegidos;
usuarios administrados;
SSH endurecido;
firewall;
time sync;
monitoring;
separación de workloads sensibles.
Un host comprometido puede leer memoria, storage y procesos de containers.
Un runtime endurecido no ayuda si la image contiene malware.
source protegido;
reviews;
dependencias fijadas;
builders aislados;
secrets de build;
SBOM;
escaneo;
signatures/attestations;
digests;
políticas de admisión;
rebuilds periódicos.
YAML
Copiar services :
api :
image : registry.example.com/api@sha256: ...
user : "10001:10001"
read_only : true
cap_drop : [ ALL]
security_opt :
- no- new- privileges: true
tmpfs :
- /tmp: size=64m, noexec, nosuid
volumes :
- type : volume
source : uploads
target : /app/uploads
networks : [ backend, data]
mem_limit : 512m
pids_limit : 200
health y graceful shutdown;
secret file;
logs centralizados;
reverse proxy;
database role limitado;
backup y response plan.
Bash
Copiar docker run --rm my-api id Bash
Copiar docker inspect api
privileged false;
capabilities;
user;
mounts;
readonly rootfs;
devices;
security options;
resources;
networks.
Bash
Copiar docker exec api sh -c 'touch /should-fail' Si no hay shell, prueba desde la aplicación o target de test.
Escanea image y secrets; revisa findings con contexto y fixes.
En entorno aislado, verifica que un process comprometido no pueda:
escribir rootfs;
leer secrets ajenos;
alcanzar networks innecesarias;
controlar daemon;
crear demasiados procesos.
aislar/retirar tráfico;
conservar evidencia;
identificar digest y configuración;
rotar secretos accesibles;
revisar host y daemon;
eliminar/recrear desde image limpia;
escanear movimiento lateral;
corregir causa;
actualizar controles y runbooks.
No “limpies” manualmente el container comprometido y lo vuelvas a usar.
Sigue pudiendo controlar daemon.
El atacante persiste en el volume.
Identifica capability exacta; no vuelvas a privileged.
Reduce tooling, pero no corrige vulnerabilidad de aplicación.
Containers ordinarios pueden no ser frontera suficiente. Considera VMs, microVMs o sandboxes adicionales.
La app comprometida tiene reachability y credenciales.
Mounts/capabilities/socket pueden dominar el riesgo.
Resuelve el síntoma eliminando defensa.
Las fronteras dependen del kernel/runtime.
Hardening limita el impacto de una aplicación comprometida.
No existe un flag único de seguridad.
Non-root, capabilities mínimas, read-only y seccomp se complementan.
Mounts y Docker socket pueden anular otros controles.
Network isolation no reemplaza autenticación.
El host y supply chain forman parte del modelo.
Comprueba lo aprendido
Construye un modelo de amenaza para una API que procesa uploads.
¿Por qué non-root no neutraliza el Docker socket?
Diseña un runtime con rootfs read-only y paths mínimos.
¿Qué harías ante un error que solo desaparece con privileged?
Describe la respuesta a un container comprometido.
Rootless, user namespaces y capabilities , donde se profundiza en cómo Linux representa privilegios dentro y fuera del container.