Skip to main content
  1. Concetti/

Docker Security

Alessio Barnini
Author
Alessio Barnini
Table of Contents

Cosa fa
#

Raccoglie i rischi di sicurezza specifici dell'ambiente Docker e le contromisure corrispondenti. Docker aggiunge una superficie di attacco nuova rispetto a Linux tradizionale — capirla e' fondamentale per il blue team.


La superficie di attacco Docker
#

graph TD
    A[Attaccante] -->|1 immagine vulnerabile| IMG[Immagine con CVE]
    A -->|2 container root| ROOT[Container gira come root]
    A -->|3 docker.sock esposto| SOCK[Accesso docker.sock]
    A -->|4 porta esposta| PORT[DB esposto su 0.0.0.0]
    A -->|5 secrets in env| ENV[Password in docker inspect]

    IMG -->|RCE nel container| ESC[Escape dal container]
    ROOT --> ESC
    SOCK -->|controlla Docker| HOST[Accesso all'host]
    PORT -->|accesso diretto DB| DATA[Dati rubati]
    ENV --> DATA
    ESC --> HOST

1. docker.sock — la chiave master
#

/var/run/docker.sock e' il file che il demone Docker usa per ricevere comandi. Chi lo controlla, controlla Docker. Chi controlla Docker, controlla l'host.

ls -la /var/run/docker.sock
# srw-rw---- 1 root docker /var/run/docker.sock
#                   ^^^^^^
#                   solo gruppo docker puo' accedere

# Un attaccante con accesso a docker.sock puo':
docker run -v /:/host --rm -it alpine chroot /host sh
# monta il filesystem dell'host dentro un container
# chroot /host = l'host e' la root
# risultato: shell root sull'host

Contromisure:

# Non montare mai docker.sock in un container senza necessita'
# Nel docker-compose, questa e' una flag rossa:
volumes:
  - /var/run/docker.sock:/var/run/docker.sock  # pericoloso

# Verifica chi e' nel gruppo docker:
getent group docker
# ogni utente in questo gruppo ha accesso root effettivo all'host

2. Container root — il problema piu' comune
#

Per default, i processi dentro un container girano come root (UID 0). Se c'e' una vulnerabilita' nel processo, l'attaccante ha root nel container — e con alcune configurazioni, puo' uscire sull'host.

# Verifica se un container gira come root:
docker exec container_rails whoami
# se risponde "root" → problema

# Nel Dockerfile — imposta un utente non-root:
RUN groupadd -r appuser && useradd -r -g appuser appuser
USER appuser    # da qui in poi, tutti i comandi girano come appuser

# Nel docker-compose — sovrascrive l'utente del container:
services:
  rails:
    user: "1000:1000"   # UID:GID dell'utente non-root

3. Porte esposte — 0.0.0.0 vs 127.0.0.1
#

# PERICOLOSO — database esposto su tutte le interfacce:
ports:
  - "5432:5432"         # equivale a 0.0.0.0:5432:5432
  # raggiungibile da internet se il firewall non blocca

# SICURO — solo da localhost:
ports:
  - "127.0.0.1:5432:5432"
  # solo SSH tunnel o processi locali possono accedere

# MEGLIO — non esporre la porta affatto:
# usa le reti Docker per la comunicazione tra container
# e SSH tunnel per accesso dal tuo Mac
graph LR
    Internet -->|bloccato| P1["0.0.0.0:5432\npericoloso"]
    Internet -->|bloccato| P2["127.0.0.1:5432\nsicuro"]
    Mac -->|SSH tunnel| P2
    Mac -->|connessione diretta| P1

4. Secrets — non metterli nelle variabili d'ambiente
#

Le variabili d'ambiente sono visibili a chiunque abbia accesso al container:

docker inspect chatwoot_rails | grep -A 50 '"Env"'
# mostra tutte le variabili d'ambiente — incluse le password

Livelli di sicurezza crescente:

# PEGGIO — hardcoded nel docker-compose.yml (finisce su git)
environment:
  POSTGRES_PASSWORD: miapassword123

# MEGLIO — file .env (non committare su git)
environment:
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
# .env contiene: POSTGRES_PASSWORD=miapassword123
# .gitignore contiene: .env

# MEGLIO ANCORA — Docker Secrets (solo Docker Swarm/Kubernetes)
secrets:
  db_password:
    file: ./secrets/db_password.txt

5. Immagini vulnerabili
#

Ogni immagine contiene software — software ha CVE. Un'immagine vecchia e' una superficie di attacco:

# Scansiona un'immagine per CVE (richiede trivy installato):
trivy image chatwoot/chatwoot:latest

# Usa immagini alpine quando possibile — meno software = meno CVE:
postgres:16         # immagine completa Debian
postgres:16-alpine  # immagine minima Alpine — molto meno superficie

# Aggiorna regolarmente:
docker compose pull   # scarica versioni aggiornate
docker compose up -d  # riavvia con le nuove immagini

Checklist blue team — audit rapido Docker
#

# 1. Quali container girano come root?
for c in $(docker ps -q); do
  echo -n "$c: "
  docker exec $c whoami 2>/dev/null
done

# 2. Qualcuno ha docker.sock montato?
docker inspect $(docker ps -q) | grep docker.sock

# 3. Porte esposte su 0.0.0.0?
docker ps --format "{{.Names}}: {{.Ports}}" | grep "0.0.0.0"

# 4. Container con capabilities privilegiate?
docker inspect $(docker ps -q) | grep -E '"Privileged": true'

# 5. Immagini non aggiornate?
docker images --format "{{.Repository}}:{{.Tag}}\t{{.CreatedSince}}"
Warning

Un container --privileged ha accesso completo all'host — e' equivalente a girare come root sull'host senza container. Non usarlo mai in produzione.

Tip

La regola piu' importante: ogni container deve avere solo i permessi strettamente necessari per fare il suo lavoro. Principio del minimo privilegio — stesso concetto di Linux UGO, applicato ai container.


Collegato a
#

Related