DCNA
Docker Certified Network Associate
DCNANetwork Security

Docker Network Security

La sécurité réseau Docker repose sur un principe simple : chaque container n'accède qu'à ce dont il a besoin. Un container de base de données n'a aucune raison d'être accessible depuis le frontend, et aucune raison d'avoir accès à internet.

Segmentation réseau : le principe de moindre privilège

Le pattern classique est la séparation en tiers réseau :

# Mauvais : tout sur un réseau = tout peut parler à tout
docker network create everything
docker run --network everything frontend
docker run --network everything api
docker run --network everything database   # DB accessible depuis le frontend !

# Bon : un réseau par tier
docker network create frontend-net   # proxy + frontend
docker network create backend-net    # frontend + api (pont entre tiers)
docker network create db-net         # api + database (jamais accessible depuis frontend)

docker run --network frontend-net proxy
docker run --network frontend-net --network backend-net api-gateway
docker run --network backend-net --network db-net api
docker run --network db-net database  # isolée du reste

Le container database ne peut être joint que depuis api. Le frontend ne peut jamais l'atteindre, même accidentellement.

Réseaux internes : couper l'accès internet

# Un réseau "internal" = pas de route vers l'extérieur
docker network create \
  --internal \
  --driver bridge \
  isolated-db-net

docker run --network isolated-db-net postgres
# Ce container ne peut pas initier de connexions vers internet
# Utile pour les bases de données qui n'en ont aucun besoin

Comment ça marche : Docker supprime la règle de routage par défaut du namespace. Le container a une interface mais pas de route vers l'hôte ou internet.

# Vérifier depuis le container
docker exec my-db-container ip route
# 172.28.0.0/16 dev eth0    ← seulement la route locale, pas de "default via ..."

Chiffrement des communications

Overlay chiffré (Swarm)

docker network create \
  --driver overlay \
  --opt encrypted=true \
  secure-overlay

Sans chiffrement, le trafic VXLAN circule en clair sur le réseau physique — lisible par n'importe qui sur ce réseau. Le chiffrement AES-GCM 256-bit protège le data plane.

Note : le management plane (Raft entre managers) est toujours TLS, même sans --opt encrypted.

TLS entre containers (mTLS)

Pour une sécurité maximale entre services, utiliser mTLS via Docker Secrets :

# Stocker les certificats comme Secrets
docker secret create ca.crt ca.crt
docker secret create server.crt server.crt
docker secret create server.key server.key

# Monter dans le service (accessible à /run/secrets/)
docker service create \
  --name api \
  --secret ca.crt \
  --secret server.crt \
  --secret server.key \
  my-api-image
# Les secrets sont montés à /run/secrets/ca.crt, etc.

iptables et Docker

Docker gère iptables automatiquement mais te laisse un endroit pour tes règles : la chaîne DOCKER-USER.

# Voir toutes les chaînes Docker
sudo iptables -L -n | grep -E "DOCKER|Chain"
# Chain DOCKER-USER           ← tes règles ici
# Chain DOCKER                ← règles de port publishing (ne pas modifier)
# Chain DOCKER-ISOLATION-STAGE-1  ← isolation inter-réseaux
# Chain DOCKER-ISOLATION-STAGE-2  ← suite de l'isolation

# Bloquer tout le trafic entre deux réseaux Docker
sudo iptables -I DOCKER-USER -j DROP

# Autoriser seulement un subnet spécifique
sudo iptables -I DOCKER-USER -s 10.10.0.0/24 -d 10.10.1.0/24 -j ACCEPT
sudo iptables -I DOCKER-USER -j DROP  # drop le reste

# Vérifier les règles NAT de Docker
sudo iptables -t nat -L DOCKER -n -v
sudo iptables -L DOCKER-ISOLATION-STAGE-1 -n -v

Utilise toujours DOCKER-USER pour tes règles custom — c'est la seule chaîne que Docker ne touche jamais au redémarrage.

Sécuriser le socket Docker

Le socket /var/run/docker.sock donne un accès root sur la machine. Un container qui le monte peut faire docker run --privileged et sortir de l'isolation.

# NE PAS faire ça en production
docker run -v /var/run/docker.sock:/var/run/docker.sock some-image

# Pour l'API distante, utiliser TLS
dockerd \
  --tlsverify \
  --tlscacert=ca.pem \
  --tlscert=server-cert.pem \
  --tlskey=server-key.pem \
  --host tcp://0.0.0.0:2376

# Client avec TLS
docker --tlsverify \
  --tlscacert=ca.pem \
  --tlscert=client-cert.pem \
  --tlskey=client-key.pem \
  -H tcp://remote-host:2376 ps

Capabilities réseau

Par défaut, les containers n'ont pas NET_ADMIN ni NET_RAW. Les ajouter élargit la surface d'attaque.

# NET_ADMIN permet de modifier les interfaces, routes, iptables
docker run --cap-add NET_ADMIN my-image   # risqué

# NET_RAW permet les raw sockets (ping, packet capture)
docker run --cap-add NET_RAW my-image     # éviter sauf si nécessaire

# Retirer toutes les capabilities et n'ajouter que le nécessaire
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE my-app

Secrets vs Variables d'environnement

Variables d'environnementDocker Secrets
Visible dans docker inspectOuiNon
Visible via /proc/1/environOuiNon
Stocké dans l'imageSi hardcodé dans DockerfileNon
DisponibilitéTous containersSwarm uniquement
Rotation sans rebuildRedémarrage requisService update
# Mauvais : password dans une variable d'env
docker run -e DB_PASSWORD=secret123 myapp
docker inspect myapp  # → password visible !

# Bon : Docker Secret
echo "secret123" | docker secret create db_password -
docker service create \
  --name myapp \
  --secret db_password \
  myapp
# App lit /run/secrets/db_password

Profils Seccomp et AppArmor

# Profil Seccomp : limite les syscalls autorisés
docker run --security-opt seccomp=custom-profile.json nginx

# AppArmor : contrôle MAC (Mandatory Access Control)
docker run --security-opt apparmor=docker-default nginx

# Désactiver Seccomp (dangereux, jamais en production)
docker run --security-opt seccomp=unconfined nginx

Le profil Seccomp par défaut de Docker bloque ~44 syscalls dangereux.

Résumé

  • Segmenter par tiers réseau : frontend, backend, db — pas de communication directe entre non-voisins
  • --internal coupe l'accès internet pour les containers qui n'en ont pas besoin
  • --opt encrypted chiffre le data plane overlay (AES-GCM 256-bit)
  • Toujours utiliser la chaîne DOCKER-USER pour les règles iptables custom
  • Ne jamais monter le socket Docker en production ; utiliser TLS pour l'API distante
  • Préférer Docker Secrets aux variables d'environnement pour les credentials
  • Limiter les capabilities avec --cap-drop ALL + --cap-add ciblé