## 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.

- 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 

- 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.

- 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.

---

## 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.

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Domaine</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Contrôle</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Où définir</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Exemple</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Résultat attendu</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Accès</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Restreindre groupe docker</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Hôte</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Gérer l&#39;appartenance avec sudo</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Moins d&#39;utilisateurs avec accès équivalent root</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Démon</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">userns-remap</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">/etc/docker/daemon.json</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">&quot;userns-remap&quot;: &quot;default&quot;</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Root conteneur mappé vers UID hôte non privilégié</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Exécution</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Utilisateur non-root</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Dockerfile/drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--user 10001:10001</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Application s&#39;exécute sans root dans le conteneur</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Exécution</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Capacités</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--cap-drop=ALL --cap-add=NET_BIND_SERVICE</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Capacités au moindre privilège</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Exécution</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Pas de nouveaux privilèges</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--security-opt no-new-privileges</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Blocage de l&#39;escalade de privilèges</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Exécution</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Profil seccomp</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--security-opt seccomp=default</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Filtrage d&#39;appels système actif</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Système de fichiers</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Racine en lecture seule</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--read-only; --tmpfs /tmp</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Empêche les écritures inattendues sur rootfs</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Secrets</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Montages fichiers ou Swarm</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run/service</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">-v secret:...:ro; --secret ...</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Secrets pas dans env ni couches d&#39;image</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Réseau</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Minimiser exposition</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run/réseaux</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">-p 127.0.0.1:8080:8080; --internal</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Surface d&#39;attaque externe réduite</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Limites</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Mémoire/CPU/PIDs</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Drapeaux run</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--memory 256m --cpus 1 --pids-limit 200</code></td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Utilisation des ressources contenue</td></tr></tbody>
</table>
</div>
---

## Vérification et diagnostics

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

- 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.

- 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.

- 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.

- 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.

- 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 .

- 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.

---

## 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

<div class="my-stack-md overflow-x-auto">
<table class="w-full min-w-[42rem] border-collapse text-left">
<thead><tr><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Symptôme</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Cause probable</th><th scope="col" class="border border-outline-variant bg-surface-container-low px-4 py-3 text-left font-label-md font-semibold text-on-surface">Correction rapide</th></tr></thead>
<tbody><tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">L&#39;application ne peut pas écrire au chemin attendu</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--read-only</code> bloque les écritures</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Monter un chemin inscriptible : <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">-v /srv/app/data:/app/data:rw</code> ou ajouter <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--tmpfs /var/cache/app</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Permission refusée sur montage bind</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">userns-remap</code> a changé le mapping UID/GID hôte</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">chown -R &lt;uid_remappe&gt;:&lt;gid_remappe&gt; /srv/app/data</code> (exemple construit : 165536:165536)</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Impossible de lier le port 80 en non-root</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Capacité <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">NET_BIND_SERVICE</code> manquante</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Ajouter <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--cap-add=NET_BIND_SERVICE</code> ou utiliser port &gt;= 1024</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Appels réseau échouent depuis réseau interne</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant"><code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--internal</code> bloque la sortie</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Utiliser un réseau non-interne pour les services nécessitant la sortie</td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Fichier secret illisible</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Mauvais UID/GID ou mode sur l&#39;hôte</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Définir <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">-o &lt;uid&gt; -g &lt;gid&gt; -m 0400</code> sur le fichier secret et monter <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">:ro</code></td></tr>
<tr><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Processus tué par OOM (Out of Memory) ou limite pids</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Limites trop serrées</td><td class="border border-outline-variant px-4 py-3 align-top text-body-md text-on-surface-variant">Augmenter <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--memory</code> ou <code class="font-mono text-[0.9em] bg-surface-container px-1 py-0.5 rounded">--pids-limit</code> avec marge mesurée</td></tr></tbody>
</table>
</div>

### 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.