E-NO
DevOps 12 min de lecture

Durcissement de la sécurité Docker : guide pratique d'implémentation avec exemples

calendar_today Publié : 2026-07-28
update Dernière mise à jour : 2026-07-28
analytics Efficacité SEO : 97%
Illustration du guide technique pour « Durcissement de la sécurité Docker : guide pratique d'implémentation avec exemples ».

Introduction

Voici un guide pratique, étape par étape, pour durcir Docker avec des exemples que vous pouvez exécuter dans un projet pilote contrôlé. Vous établirez une base de référence fiable, appliquerez des modifications de configuration sécurisées, vérifierez les résultats et pourrez revenir en arrière en cas de problème. L'accent est mis sur le moindre privilège, les secrets, les permissions et la limitation de l'exposition réseau, tout en gardant les changements mesurables et réversibles.

Note sur la portée : les exemples ci-dessous sont construits pour illustrer des patterns sûrs que vous pouvez adapter à votre environnement.

---

Inventaire des versions et de l'environnement

Avant toute modification, capturez l'état actuel afin de pouvoir comparer, vérifier et revenir en arrière si nécessaire. Limitez cette démarche à un petit conteneur ou service pilote que vous pouvez inspecter localement.

  1. Enregistrer les versions et réglages principaux

Exemples de commandes construits :

   # Enregistrer les infos Docker et noyau
   sudo docker version
   sudo docker info
   uname -a

   # Sauvegarder dans un instantané daté
   sudo docker version > baseline-$(date +%F).txt
   sudo docker info >> baseline-$(date +%F).txt
  1. Identifier le pilote et la topologie
  • Choisissez un service simple pour le pilote (par exemple, un petit serveur HTTP lié à localhost).
  • Déterminez les chemins hôtes minimaux qui doivent être montés.
  • Déterminez le plus petit ensemble de ports exposés et de réseaux requis.
  1. Confirmer les prérequis
  • Hôte Linux avec un Docker Engine supporté.
  • Capacité d'éditer /etc/docker/daemon.json et de redémarrer Docker.
  • Privilèges sudo pour les étapes administratives.

Pourquoi commencer petit ? Un pilote étroit et mesurable est facile à inspecter, permet de quantifier les effets de chaque contrôle et réduit la reprise lorsque des problèmes surviennent plus tard.

---

Question rapide 1 sur 2

Quelles sont les prochaines étapes après avoir exploré le matériel de démarrage dans la référence, selon le premier passage ?

Le premier passage de référence indique : « Explorez les fonctionnalités Hardened Docker Desktop pour comprendre comment elles peuvent renforcer la posture de sécurité de votre organisation. »

Chemin de configuration sécurisée

Appliquez le durcissement par couches et vérifiez après chaque couche. L'objectif est le moindre privilège et l'exposition minimale sans casser les fonctionnalités requises.

1. Contrôle d'accès autour du démon Docker

  • N'accordez pas largement l'appartenance au groupe docker ; cela fournit effectivement un accès root sur l'hôte.
  • Préférez l'exécution des commandes via sudo pour les administrateurs. Pour les développeurs, envisagez Docker rootless sur les machines de développement si c'est faisable.

Pilote optionnel : Docker rootless sur un poste de travail développeur (exemple construit)

# Prérequis : s'assurer que 'uidmap' est installé, puis :
sudo apt-get install -y uidmap
export XDG_RUNTIME_DIR=/run/user/$(id -u)
export PATH=/usr/bin:$PATH

# Configurer rootless (exemple construit)
dockerd-rootless-setuptool.sh install
systemctl --user enable --now docker
export DOCKER_HOST=unix:///run/user/$(id -u)/docker.sock

Vérifiez avec docker info qu'il rapporte un mode rootless si utilisé.

2. Valeurs par défaut du démon qui réduisent la surface d'attaque

Éditez /etc/docker/daemon.json et redémarrez Docker. Sauvegardez le fichier d'abord.

Exemple construit de daemon.json :

{
  "icc": false,
  "live-restore": true,
  "userns-remap": "default",
  "log-driver": "local",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}
  • icc: false bloque la communication inter-conteneurs sur le bridge par défaut à moins qu'ils ne soient explicitement mis en réseau ensemble.
  • live-restore: true aide les conteneurs à survivre à un redémarrage du démon.
  • userns-remap: default mappe le root du conteneur vers un UID/GID non privilégié sur l'hôte.
  • La journalisation locale avec limites de taille aide à éviter le remplissage du disque.

Appliquer et redémarrer :

sudo cp /etc/docker/daemon.json /etc/docker/daemon.json.bak.$(date +%F)
sudo systemctl restart docker

Note sur le remappage d'espace de noms utilisateur : après l'activation, la propriété des fichiers hôtes pour les montages bind peut devoir correspondre à la plage remappée. Voir Récupération pour les détails.

3. Pattern d'exécution de conteneur durci

Commencez avec un conteneur minimal et ajoutez progressivement seulement ce qui est requis. Les drapeaux ci-dessous démontrent une position par défaut solide.

Exemple construit : conteneur web durci

# Image et digest d'exemple construits ; remplacez par les vôtres
IMAGE="mycorp/web:1.2.3@sha256:deadbeef..."

sudo docker network create --driver bridge --subnet 172.30.0.0/24 --internal app_net || true

sudo docker run --rm -d \
  --name web \
  --network app_net \
  --read-only \
  --tmpfs /tmp:rw,noexec,nosuid,nodev,size=64m \
  --pids-limit=200 \
  --memory=256m --memory-swap=256m --cpus=1.0 \
  --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
  --security-opt no-new-privileges \
  --security-opt seccomp=default \
  --user 10001:10001 \
  -v /srv/web/static:/srv/web/static:ro \
  -p 127.0.0.1:8080:8080 \
  --health-cmd='curl -sSf http://127.0.0.1:8080/health || exit 1' \
  --health-interval=30s --health-retries=3 \
  "$IMAGE"

Pourquoi ces choix :

  • --read-only empêche les écritures inattendues sur le système de fichiers racine.
  • --tmpfs /tmp:... offre une zone d'écriture sûre pour les fichiers temporaires.
  • --cap-drop=ALL puis --cap-add=NET_BIND_SERVICE applique le moindre privilège.
  • --security-opt no-new-privileges bloque l'escalade de privilèges.
  • --security-opt seccomp=default maintient le filtre d'appels système par défaut en place.
  • --user 10001:10001 évite de s'exécuter en root à l'intérieur du conteneur.
  • -v ...:ro lie les données en lecture seule depuis l'hôte.
  • --network app_net --internal combiné avec la publication de port local sur 127.0.0.1 garde l'exposition réseau étroite.

Si une application a besoin de chemins d'écriture au-delà de /tmp, montez ces chemins explicitement avec des options appropriées au lieu de désactiver --read-only globalement.

4. Gestion des secrets

Objectifs : éviter les secrets dans les images et les variables d'environnement ; privilégier les fichiers avec permissions restreintes.

  • Secrets Docker Swarm (exemple construit) :
echo "constructed-db-password" | docker secret create db_password -

docker service create \
  --name app \
  --secret source=db_password,target=/run/secrets/db_password,mode=0400 \
  "$IMAGE"
  • Conteneurs autonomes utilisant un fichier hôte (exemple construit) :
# Créer un fichier lisible seulement par l'utilisateur du conteneur (UID 10001 ici)
sudo install -o 10001 -g 10001 -m 0400 /root/db_password /srv/app/db_password

sudo docker run --rm \
  --user 10001:10001 \
  -v /srv/app/db_password:/run/secrets/db_password:ro \
  "$IMAGE"

Privilégiez les montages de fichiers aux variables d'environnement pour les secrets. Assurez-vous du bon UID/GID et du mode (0400/0440) sur le fichier hôte.

5. Éviter les drapeaux et modes dangereux

  • N'utilisez pas --privileged sauf si absolument nécessaire.
  • Évitez --pid=host, --net=host et --ipc=host dans le pilote ; ils élargissent la surface d'attaque.
  • Publiez les ports explicitement et liez à loopback si le service est destiné à être local seulement, par exemple -p 127.0.0.1:8080:8080.

6. Exposition de l'API distante

  • N'exposez pas l'API Docker non authentifiée sur tcp://0.0.0.0:2375.
  • Si un accès distant est requis, activez TLS et des règles de pare-feu strictes.

Extrait daemon.json construit pour TLS :

{
  "hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
  "tls": true,
  "tlscert":
  "tlskey":
  "tlscacert":
  "tlsverify": true
}

7. Hygiène des images et verrouillage

  • Verrouillez les images par digest : repo:tag@sha256: pour assurer la reproductibilité.
  • Gardez les images de base minimales et supprimez les paquets inutiles dans vos propres images.
  • Optionnellement, définissez DOCKER_CONTENT_TRUST=1 lors du pull et de l'exécution d'images dans les environnements où la confiance de contenu est configurée.

8. Limites de ressources

  • Limites mémoire et CPU : --memory, --memory-swap, --cpus.
  • Limite de nombre de processus : --pids-limit. Ces mesures empêchent un seul conteneur d'épuiser les ressources de l'hôte.

---

Carte rapide des contrôles de durcissement

Le tableau montre où chaque contrôle est défini et le résultat attendu.

DomaineContrôleOù définirExempleRésultat attendu
AccèsRestreindre groupe dockerHôteGérer l'appartenance avec sudoMoins d'utilisateurs avec accès équivalent root
Démonuserns-remap/etc/docker/daemon.json"userns-remap": "default"Root conteneur mappé vers UID hôte non privilégié
ExécutionUtilisateur non-rootDockerfile/drapeaux run--user 10001:10001Application s'exécute sans root dans le conteneur
ExécutionCapacitésDrapeaux run--cap-drop=ALL --cap-add=NET_BIND_SERVICECapacités au moindre privilège
ExécutionPas de nouveaux privilègesDrapeaux run--security-opt no-new-privilegesBlocage de l'escalade de privilèges
ExécutionProfil seccompDrapeaux run--security-opt seccomp=defaultFiltrage d'appels système actif
Système de fichiersRacine en lecture seuleDrapeaux run--read-only; --tmpfs /tmpEmpêche les écritures inattendues sur rootfs
SecretsMontages fichiers ou SwarmDrapeaux run/service-v secret:...:ro; --secret ...Secrets pas dans env ni couches d'image
RéseauMinimiser expositionDrapeaux run/réseaux-p 127.0.0.1:8080:8080; --internalSurface d'attaque externe réduite
LimitesMémoire/CPU/PIDsDrapeaux run--memory 256m --cpus 1 --pids-limit 200Utilisation des ressources contenue

---

Vérification et diagnostics

Vérifiez chaque contrôle avec des contrôles ciblés et enregistrez les résultats.

  1. Réglages du démon
sudo docker info | grep -E "userns|Live Restore|Security Options"
cat /etc/docker/daemon.json

Attendu : userns activé, Live Restore vrai, options de sécurité incluent apparmor/selinux le cas échéant.

  1. Options d'exécution du conteneur (nom du conteneur construit : web)
sudo docker inspect web \
  --format 'User={{.Config.User}} ReadonlyRootfs={{.HostConfig.ReadonlyRootfs}} CapAdd={{.HostConfig.CapAdd}} CapDrop={{.HostConfig.CapDrop}} NoNewPrivs={{.HostConfig.SecurityOpt}} PidsLimit={{.HostConfig.PidsLimit}} Memory={{.HostConfig.Memory}} CPUs={{.HostConfig.NanoCpus}}'

Attendu : ID utilisateur non-root, read-only true, CapDrop inclut ALL, NoNewPrivs présent, limites non nulles.

  1. Vérifications dans le conteneur
sudo docker exec web id -u
sudo docker exec web sh -c 'test -w / || echo "rootfs est en lecture seule"'
sudo docker exec web sh -c 'grep NoNewPrivs /proc/1/status || true'
sudo docker exec web sh -c 'grep CapEff /proc/1/status'

Attendu : ID utilisateur pas 0, rootfs non inscriptible, ligne NoNewPrivs : 1 présente (selon noyau), masque de capacités effectives petit.

  1. Secrets
sudo docker exec web sh -c 'stat -c "%U %G %a %n" /run/secrets/* 2>/dev/null || true'

Attendu : fichiers secrets existent seulement si vous les avez montés ; modes devraient être 400/440 et appartenir à l'utilisateur de l'application.

  1. Exposition réseau
sudo ss -ltnp | grep 8080
sudo docker network inspect app_net | grep -E '"Internal":|"Subnet"'

Attendu : service en écoute sur 127.0.0.1:8080, réseau montre "Internal": true.

  1. Santé et journaux
sudo docker ps --format 'table {{.Names}}	{{.Status}}	{{.Ports}}'
sudo docker logs --tail 50 web

Attendu : conteneur sain, pas d'erreurs de permission dues au read-only ou aux capacités manquantes.

---

Question rapide 2 sur 2

Selon le passage, quel est le rôle utilisateur-Docker concernant les Docker Hardened Images ?

Le passage dit : « Votre rôle est de faire un usage éclairé de ces images, d'appliquer rapidement les mises à jour et de valider que vos configurations et applications répondent à vos exigences internes. »

Modes de défaillance et récupération

Lors du durcissement, les problèmes les plus courants concernent les permissions, les capacités et les chemins d'écriture. Gardez un plan de retour en arrière simple.

Problèmes courants

SymptômeCause probableCorrection rapide
L'application ne peut pas écrire au chemin attendu--read-only bloque les écrituresMonter un chemin inscriptible : -v /srv/app/data:/app/data:rw ou ajouter --tmpfs /var/cache/app
Permission refusée sur montage binduserns-remap a changé le mapping UID/GID hôtechown -R <uid_remappe>:<gid_remappe> /srv/app/data (exemple construit : 165536:165536)
Impossible de lier le port 80 en non-rootCapacité NET_BIND_SERVICE manquanteAjouter --cap-add=NET_BIND_SERVICE ou utiliser port >= 1024
Appels réseau échouent depuis réseau interne--internal bloque la sortieUtiliser un réseau non-interne pour les services nécessitant la sortie
Fichier secret illisibleMauvais UID/GID ou mode sur l'hôteDéfinir -o <uid> -g <gid> -m 0400 sur le fichier secret et monter :ro
Processus tué par OOM (Out of Memory) ou limite pidsLimites trop serréesAugmenter --memory ou --pids-limit avec marge mesurée

Spécificités du remappage d'espace de noms utilisateur

Après userns-remap, le root du conteneur mappe vers une plage non privilégiée sur l'hôte, typiquement à partir d'un UID élevé comme 165536 (exemple construit). Les fichiers montés depuis l'hôte doivent appartenir à cet UID/GID pour être inscriptibles à l'intérieur du conteneur.

Exemple de correction construit pour un montage inscriptible :

# Déterminer l'UID/GID remappé (exemple construit suppose 165536)
grep dockremap /etc/subuid /etc/subgid || true

# Ajuster la propriété pour un répertoire de données
sudo chown -R 165536:165536 /srv/app/data

Retour en arrière des changements du démon

  • Restaurer le daemon.json précédent
sudo cp /etc/docker/daemon.json.bak.$(date +%F -d 'yesterday' 2>/dev/null || echo backup) /etc/docker/daemon.json
  • Redémarrer le démon
sudo systemctl restart docker

Note : redémarrer Docker peut arrêter les conteneurs sauf si live-restore est activé. Prévoyez une fenêtre de maintenance pour les changements en production.

Retour en arrière d'une exécution de conteneur

  • Arrêter le conteneur durci et le redémarrer avec les drapeaux qui fonctionnaient auparavant.
sudo docker stop web
# Relancer sans read-only et avec capacités plus larges comme retour temporaire (exemple construit)
sudo docker run -d --name web --cap-drop=NET_RAW -p 127.0.0.1:8080:8080 "$IMAGE"

Documentez les différences et réappliquez le durcissement étape par étape pour isoler le drapeau qui casse.

---

Liste de contrôle opérationnelle

Utilisez cette liste de contrôle concise pour chaque service que vous durcissez. Marquez N/A là où non applicable.

Accès et démon

  • [ ] Réviser l'appartenance au groupe docker ; retirer les utilisateurs inutiles
  • [ ] Confirmer userns-remap activé et fonctionnel
  • [ ] Définir live-restore et options de journalisation bornées

Image et exécution

  • [ ] Verrouiller l'image par digest
  • [ ] Exécuter en utilisateur non-root
  • [ ] Supprimer toutes les capacités ; rajouter seulement ce qui est nécessaire
  • [ ] Activer no-new-privileges
  • [ ] Utiliser le profil seccomp par défaut ou un plus strict personnalisé

Système de fichiers et secrets

  • [ ] Activer --read-only
  • [ ] Fournir les chemins inscriptibles requis via --tmpfs ou montages dédiés
  • [ ] Monter les secrets comme fichiers en lecture seule avec bon UID/GID et mode

Réseau et exposition

  • [ ] Utiliser des réseaux définis par l'utilisateur ; internes quand possible
  • [ ] Lier les ports publiés à loopback sauf si accès externe requis
  • [ ] Garder l'API Docker distante désactivée ; si activée, exiger TLS et pare-feu

Limites et santé

  • [ ] Définir limites mémoire, CPU et PIDs
  • [ ] Configurer un healthcheck le cas échéant

Vérification

  • [ ] Capturer les champs clés de docker inspect pour le service
  • [ ] Valider dans le conteneur : non-root, rootfs lecture seule, capacités limitées
  • [ ] Confirmer propriété et permissions des secrets
  • [ ] Confirmer que seuls les ports requis sont en écoute

Récupération

  • [ ] Sauvegarder daemon.json avant les changements
  • [ ] Documenter les drapeaux d'exécution précédents pour permettre un retour rapide

---

Conclusion

Vous disposez maintenant d'un chemin mesuré et reproductible pour durcir Docker dans des conditions proches de la production sans deviner : établir la base de référence de l'environnement, appliquer des contrôles en couches pour l'accès, l'exécution, le système de fichiers, les secrets, le réseau et les limites, puis vérifier chaque résultat avec des contrôles ciblés. Commencez avec un pilote étroit que vous pouvez inspecter localement, enregistrez ce qui fonctionne, et étendez la même approche aux services supplémentaires. Gardez les instructions de retour en arrière à portée de main pour avancer vite sans rester bloqué quand quelque chose casse.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 97%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO