Seguridad Docker: Mejores Prácticas - Guía Completa para Producción
La seguridad de contenedores Docker es crítica para proteger aplicaciones, datos e infraestructura. Esta guía completa cubre el endurecimiento de seguridad de Docker, gestión de vulnerabilidades, protección en tiempo de ejecución y mejores prácticas de cumplimiento para entornos de producción.
Tabla de Contenidos
- Introducción
- Principios de Seguridad
- Seguridad de Imágenes
- Seguridad en Tiempo de Ejecución de Contenedores
- Seguridad de Red
- Gestión de Secretos
- Límites de Recursos
- Escaneo de Seguridad
- Control de Acceso
- Seguridad del Daemon
- Cumplimiento y Auditoría
- Lista de Verificación para Producción
- Conclusión
Introducción
La seguridad de contenedores requiere un enfoque de múltiples capas que cubra imágenes, configuración en tiempo de ejecución, redes, secretos y el daemon de Docker mismo. Las prácticas de seguridad adecuadas previenen accesos no autorizados, violaciones de datos y abuso de recursos.
Superficie de Ataque de Seguridad
- Imágenes: Dependencias vulnerables y malware
- Tiempo de Ejecución: Escalación de privilegios y escape de contenedores
- Red: Acceso no autorizado e interceptación de datos
- Secretos: Credenciales expuestas y claves API
- Daemon: Exposición del socket Docker y configuraciones incorrectas
Principios de Seguridad
Mínimo Privilegio
Ejecutar contenedores con los permisos mínimos necesarios:
# No ejecutar como root
FROM node:18-alpine
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
Defensa en Profundidad
Múltiples capas de seguridad:
- Imágenes base seguras
- Escaneo de vulnerabilidades
- Restricciones en tiempo de ejecución
- Aislamiento de red
- Encriptación de secretos
Infraestructura Inmutable
# Sistema de archivos raíz de solo lectura
docker run --read-only --tmpfs /tmp my-app
Seguridad de Imágenes
Usar Imágenes Oficiales
# Solo fuentes confiables
FROM node:18-alpine # Imagen oficial de Node
FROM nginx:alpine # Imagen oficial de Nginx
# Evitar fuentes desconocidas
# FROM randomuser/suspicious-image # No usar
Fijar Versiones Específicas
# Malo - impredecible
FROM node:latest
# Bueno - reproducible
FROM node:18.17.0-alpine3.18
# Incluir digest SHA256
FROM node:18.17.0-alpine3.18@sha256:abc123...
Minimizar Tamaño de Imagen
# Imágenes más pequeñas = menor superficie de ataque
FROM alpine:3.18
# O distroless
FROM gcr.io/distroless/static-debian11
Construcciones Multi-Etapa
# Etapa de construcción con herramientas
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o app
# Runtime mínimo
FROM gcr.io/distroless/static-debian11
COPY --from=builder /app/app /
ENTRYPOINT ["/app"]
No Incluir Secretos en Imágenes
# Malo - secretos en imagen
ENV API_KEY=secret123
COPY .env /app/.env
# Bueno - inyectar en tiempo de ejecución
# docker run -e API_KEY=${API_KEY} my-app
Firmar y Verificar Imágenes
# Habilitar Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# Construir imagen firmada
docker build -t my-image:latest .
# Push de imagen firmada
docker push my-image:latest
Seguridad en Tiempo de Ejecución de Contenedores
Ejecutar como Usuario No Root
# Crear y usar usuario no root
FROM alpine:3.18
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
WORKDIR /app
COPY --chown=appuser:appgroup . .
CMD ["./app"]
# O especificar en tiempo de ejecución
docker run --user 1000:1000 my-app
Sistema de Archivos Raíz de Solo Lectura
# Prevenir modificaciones al sistema de archivos del contenedor
docker run -d \
--read-only \
--tmpfs /tmp \
--tmpfs /run \
nginx
# Docker Compose
services:
app:
image: my-app
read_only: true
tmpfs:
- /tmp
- /run
Eliminar Capacidades
# Eliminar todas las capacidades, agregar solo las necesarias
docker run -d \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
nginx
Capacidades disponibles:
NET_BIND_SERVICE: Vincular a puertos < 1024CHOWN: Cambiar propiedad de archivosDAC_OVERRIDE: Omitir verificaciones de permisos de archivosSETUID/SETGID: Cambiar ID de usuario/grupo
Desactivar Nuevos Privilegios
# Prevenir escalación de privilegios
docker run -d \
--security-opt=no-new-privileges:true \
my-app
Usar Perfiles de Seguridad
AppArmor
# Usar perfil AppArmor
docker run -d \
--security-opt apparmor=docker-default \
nginx
SELinux
# Etiquetas SELinux
docker run -d \
--security-opt label=level:s0:c100,c200 \
nginx
Seccomp
# Usar perfil seccomp
docker run -d \
--security-opt seccomp=/path/to/seccomp-profile.json \
my-app
Ejemplo de perfil Seccomp:
{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": ["SCMP_ARCH_X86_64"],
"syscalls": [
{
"names": ["read", "write", "open", "close"],
"action": "SCMP_ACT_ALLOW"
}
]
}
Limitar Recursos del Sistema
# Prevenir ataques DoS
docker run -d \
--memory="512m" \
--memory-swap="512m" \
--cpus="1.5" \
--pids-limit=100 \
my-app
Aislar Contenedores
# Usar espacios de nombres de usuario
docker run -d --userns-remap=default my-app
Configurar en /etc/docker/daemon.json:
{
"userns-remap": "default"
}
Seguridad de Red
Aislamiento de Red
# Crear redes aisladas
docker network create --driver bridge frontend
docker network create --driver bridge backend
docker network create --driver bridge database
# Conectar contenedores a redes apropiadas
docker run -d --name web --network frontend nginx
docker run -d --name api --network backend my-api
docker run -d --name db --network database postgres
Desactivar Comunicación Entre Contenedores
# Crear red con ICC desactivado
docker network create \
--driver bridge \
--opt com.docker.network.bridge.enable_icc=false \
isolated-network
Redes Overlay Encriptadas
# Crear red overlay encriptada (Swarm)
docker network create \
--driver overlay \
--opt encrypted=true \
secure-overlay
Restringir Acceso de Red del Contenedor
# Sin acceso a red
docker run -d --network none my-batch-processor
# Usar políticas de red en Kubernetes
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-all
spec:
podSelector: {}
policyTypes:
- Ingress
- Egress
TLS para Comunicación
# Configurar daemon Docker para TLS
dockerd \
--tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
Gestión de Secretos
Nunca Codificar Secretos en Duro
# Malo
ENV DB_PASSWORD=mysecretpassword
# Bueno - pasar en tiempo de ejecución
# docker run -e DB_PASSWORD=${DB_PASSWORD} my-app
Usar Docker Secrets (Swarm)
# Crear secreto
echo "mypassword" | docker secret create db_password -
# Usar en servicio
docker service create \
--name app \
--secret db_password \
my-app
Acceder en contenedor:
# Secreto disponible en /run/secrets/db_password
cat /run/secrets/db_password
Variables de Entorno
# Pasar secretos vía entorno
docker run -d \
-e DB_PASSWORD=${DB_PASSWORD} \
-e API_KEY=${API_KEY} \
my-app
Gestión Externa de Secretos
HashiCorp Vault
# Integrar con Vault
docker run -d \
-e VAULT_ADDR=https://vault.example.com \
-e VAULT_TOKEN=${VAULT_TOKEN} \
my-app
AWS Secrets Manager
# Usar secretos de AWS
docker run -d \
-e AWS_REGION=us-east-1 \
-e SECRET_ARN=arn:aws:secretsmanager:... \
my-app
Encriptar Variables de Entorno
# Usar archivos encriptados
docker run -d \
--env-file encrypted.env \
my-app
Límites de Recursos
Límites de Memoria
# Establecer límite de memoria
docker run -d \
--memory="1g" \
--memory-reservation="512m" \
--memory-swap="2g" \
--oom-kill-disable=false \
my-app
Límites de CPU
# Limitar uso de CPU
docker run -d \
--cpus="2.0" \
--cpu-shares=1024 \
--cpuset-cpus="0,1" \
my-app
Límites de I/O de Disco
# Limitar operaciones de disco
docker run -d \
--device-read-bps /dev/sda:1mb \
--device-write-bps /dev/sda:1mb \
my-app
Límites de Procesos
# Limitar número de procesos
docker run -d \
--pids-limit=200 \
my-app
Escaneo de Seguridad
Escáner Trivy
# Instalar Trivy
sudo apt-get install trivy
# Escanear imagen
trivy image my-app:latest
# Solo high y critical
trivy image --severity HIGH,CRITICAL my-app:latest
# Integración CI/CD
trivy image --exit-code 1 --severity CRITICAL my-app:latest
Escáner Clair
# Ejecutar Clair
docker run -d --name clair -p 6060:6060 quay.io/coreos/clair:latest
# Escanear con clair-scanner
clair-scanner --ip $(hostname -I | awk '{print $1}') my-app:latest
Docker Scan
# Usar escáner integrado de Docker
docker scan my-app:latest
# Escanear y mostrar recomendaciones de imagen base
docker scan --file Dockerfile my-app:latest
Anchore
# Escanear con Anchore
anchore-cli image add my-app:latest
anchore-cli image wait my-app:latest
anchore-cli image vuln my-app:latest all
Escaneo Continuo
# Ejemplo de GitHub Actions
name: Security Scan
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Build image
run: docker build -t my-app .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'my-app'
format: 'sarif'
output: 'trivy-results.sarif'
Control de Acceso
Protección del Socket Docker
# Nunca exponer socket Docker
# Malo:
# docker run -v /var/run/docker.sock:/var/run/docker.sock ...
# Usar Docker-in-Docker o enfoques alternativos
docker run --privileged docker:dind
Espacios de Nombres de Usuario
{
"userns-remap": "default"
}
# Reiniciar Docker
sudo systemctl restart docker
Control de Acceso Basado en Roles
# Usar Docker Enterprise para RBAC
# O implementar plugin de autorización personalizado
# Ejemplo: limitar usuarios a operaciones específicas
{
"authorization-plugins": ["docker-authz-plugin"]
}
Auditar Comandos Docker
# Habilitar registro de auditoría
sudo auditctl -w /usr/bin/docker -k docker
sudo auditctl -w /var/lib/docker -k docker
sudo auditctl -w /etc/docker -k docker
# Ver logs de auditoría
sudo ausearch -k docker
Seguridad del Daemon
Configuración Segura del Daemon Docker
{
"icc": false,
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"live-restore": true,
"userland-proxy": false,
"no-new-privileges": true,
"seccomp-profile": "/etc/docker/seccomp-profile.json"
}
Habilitar TLS
{
"tls": true,
"tlsverify": true,
"tlscacert": "/etc/docker/ca.pem",
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem"
}
Restringir Acceso al Daemon
# Limitar quién puede ejecutar comandos Docker
sudo usermod -aG docker limited-user
# Mejor: usar sudo para comandos Docker
# No agregar usuarios al grupo docker en producción
Desactivar Características Legacy
{
"disable-legacy-registry": true
}
Cumplimiento y Auditoría
CIS Docker Benchmark
# Ejecutar Docker Bench Security
git clone https://github.com/docker/docker-bench-security.git
cd docker-bench-security
sudo sh docker-bench-security.sh
Escaneo de Seguridad Docker
# Habilitar Docker Content Trust
export DOCKER_CONTENT_TRUST=1
# Verificar firmas de imágenes
docker pull my-registry.com/image:tag
Registrar Todo
{
"log-driver": "syslog",
"log-opts": {
"syslog-address": "tcp://siem.example.com:514",
"tag": "docker/{{.Name}}"
}
}
Auditorías Regulares
# Verificar contenedores en ejecución
docker ps --format "table {{.Names}}\t{{.Image}}\t{{.Ports}}"
# Revisar imágenes
docker images
# Verificar volúmenes
docker volume ls
# Revisar redes
docker network ls
Lista de Verificación para Producción
Seguridad de Imágenes
- Usar imágenes base oficiales
- Fijar versiones específicas con SHA256
- Escanear vulnerabilidades
- Sin secretos en imágenes
- Firmar imágenes con Docker Content Trust
- Imágenes base mínimas (Alpine/distroless)
- Construcciones multi-etapa
- Actualizaciones regulares de imágenes
Seguridad en Tiempo de Ejecución
- Ejecutar como usuario no root
- Sistema de archivos raíz de solo lectura
- Eliminar todas las capacidades, agregar solo las necesarias
- Habilitar no-new-privileges
- Usar perfiles de seguridad (AppArmor/SELinux/Seccomp)
- Límites de recursos (CPU, memoria, PIDs)
- Health checks configurados
- Políticas de reinicio adecuadas
Seguridad de Red
- Aislamiento de red por aplicación
- Sin exposición innecesaria de puertos
- Redes overlay encriptadas
- TLS para comunicación externa
- Políticas de red implementadas
Gestión de Secretos
- Sin secretos codificados en duro
- Usar Docker secrets o vault externo
- Encriptar secretos en reposo y en tránsito
- Rotar secretos regularmente
- Auditar acceso a secretos
Control de Acceso
- Socket Docker nunca expuesto
- Espacios de nombres de usuario habilitados
- RBAC implementado
- Registro de auditoría habilitado
- Principio de mínimo privilegio
Monitoreo y Cumplimiento
- Escaneo de seguridad en CI/CD
- Monitoreo de seguridad en tiempo de ejecución
- Agregación de logs configurada
- Cumplimiento con benchmark CIS
- Auditorías de seguridad regulares
- Plan de respuesta a incidentes
Conclusión
La seguridad de Docker requiere atención continua a lo largo de todo el ciclo de vida del contenedor. Implementar estas mejores prácticas reduce significativamente los riesgos de seguridad en entornos de producción.
Puntos Clave
- Defensa en Profundidad: Múltiples capas de seguridad
- Mínimo Privilegio: Permisos mínimos necesarios
- Inmutabilidad: Sistemas de archivos raíz de solo lectura
- Escaneo: Evaluación continua de vulnerabilidades
- Secretos: Nunca en imágenes, siempre encriptados
- Monitoreo: Auditar y registrar todo
Jerarquía de Seguridad
- Imágenes Base Seguras: Comenzar con imágenes confiables y mínimas
- Seguridad de Construcción: Escanear y firmar imágenes
- Restricciones en Tiempo de Ejecución: Capacidades, solo lectura, no root
- Aislamiento de Red: Redes separadas, comunicación encriptada
- Control de Acceso: Proteger socket Docker, espacios de nombres de usuario
- Monitoreo: Escaneo y auditoría de seguridad continua
Comandos Rápidos de Seguridad
# Ejecución segura de contenedor
docker run -d \
--read-only \
--tmpfs /tmp \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
--security-opt=no-new-privileges:true \
--memory="512m" \
--cpus="1" \
--pids-limit=100 \
--user 1000:1000 \
my-app
# Escanear imagen
trivy image --severity HIGH,CRITICAL my-app:latest
# Auditoría de seguridad
docker run -it --rm --pid host --userns host --cap-add audit_control \
-v /var/lib:/var/lib:ro \
-v /var/run/docker.sock:/var/run/docker.sock:ro \
-v /etc:/etc:ro \
--label docker_bench_security \
docker/docker-bench-security
Próximos Pasos
- Auditar: Ejecutar CIS Docker Benchmark
- Escanear: Implementar escaneo de seguridad continuo
- Endurecer: Aplicar restricciones de seguridad en tiempo de ejecución
- Monitorear: Configurar monitoreo y alertas de seguridad
- Capacitar: Educar al equipo en mejores prácticas de seguridad
- Probar: Realizar pruebas de penetración
- Actualizar: Mantener Docker e imágenes actualizadas
La seguridad es un proceso continuo. Revisa y actualiza regularmente tus prácticas de seguridad para proteger contra amenazas en evolución.


