guest@6admin.io:~$

Durcir Docker Swarm

Tout ce qui relève du durcissement Docker mono-hôte s’applique encore à chaque container d’un Swarm, donc cette note ne porte que sur ce que le cluster ajoute: un plan de contrôle, une frontière de confiance entre manager et worker, un réseau qui enjambe les hôtes et un magasin de secrets. La bonne nouvelle et elle mérite d’être dite parce qu’on dédaigne Swarm, c’est que ses défauts de sécurité sont meilleurs qu’on ne le suppose. Les nœuds s’authentifient entre eux par TLS mutuel avec des certificats qui tournent, d’emblée et le magasin Raft qui tient l’état du cluster est chiffré au repos. Les lacunes sont plus étroites et précises: un réglage réseau coupé par défaut, une habitude d’exploitation qui effondre la frontière de confiance et la tentation habituelle de mettre les secrets au mauvais endroit.

Le manager est le cluster

Le fait le plus important d’un Swarm est que les managers détiennent tout. Le log Raft d’un manager contient l’état du cluster, les définitions de services, les jetons d’adhésion et les secrets; un manager compromis est un cluster compromis, point. Deux conséquences suivent, toutes deux opérationnelles plutôt que malignes.

D’abord, ne faites tourner aucune charge sur les managers. Un manager qui planifie aussi des containers applicatifs a fusionné le nœud le plus sensible du cluster avec le plus exposé, de sorte qu’une seule app vulnérable devient un chemin vers le magasin Raft. Videz-les:

docker node update --availability drain manager1

Ensuite, gardez le nombre de managers petit et impair, parce que Raft veut un quorum et que chaque manager est une copie de plus des joyaux. Trois managers tolèrent une panne, cinq en tolèrent deux et sept est le plafond sensé; au-delà, c’est plus de surface d’attaque et un consensus plus lent pour une résilience que vous n’utiliserez pas. Les workers peuvent être aussi nombreux que vous voulez, parce qu’un worker ne détient que ce qui est planifié dessus, pas le magasin.

Le mTLS est un défaut qu’il faut garder

Quand un nœud rejoint, Swarm lui émet un certificat depuis l’autorité du cluster et les nœuds authentifient chaque connexion du plan de contrôle par TLS mutuel, en faisant tourner les certificats automatiquement. C’est un défaut vraiment solide et le durcissement consiste surtout à ne pas le saper: raccourcissez l’intervalle de rotation si votre modèle de menace le veut et protégez les jetons d’adhésion, qui sont le sésame laissant entrer un nouveau nœud.

docker swarm ca --rotate                      # faire tourner l'autorité du cluster
docker swarm update --cert-expiry 48h         # durée de vie des certificats de nœud plus courte
docker swarm join-token --rotate worker       # invalider un jeton worker fuité

Les jetons d’adhésion équivalent à un mot de passe de cluster et ils fuient comme des mots de passe, dans l’historique shell, les logs de CI, un wiki. Le jeton manager en particulier est catastrophique à perdre, parce qu’il ajoute un manager complet. Faites-les tourner au moindre soupçon et traitez le jeton manager avec le soin que son rayon d’impact mérite.

Chiffrez l’overlay, parce qu’il ne l’est pas par défaut

Les services sur un réseau overlay parlent d’un hôte à l’autre et par défaut ce trafic n’est pas chiffré, seul le plan de contrôle l’est. Sur un réseau de nœuds de confiance et isolé, cela peut être acceptable; sur tout ce qui est partagé ou routé, c’est de la donnée en clair sur le fil. Le chiffrement est un drapeau à la création du réseau et c’est le drapeau qu’on oublie:

docker network create --driver overlay --opt encrypted app-net

Il ajoute de l’IPSec entre les nœuds à un certain coût CPU et c’est la différence entre un sniffer sur le réseau de nœuds qui voit votre trafic inter-services et qui voit du bruit. Segmentez tant que vous y êtes: un service ne s’attache qu’aux réseaux overlay dont il a besoin, pas à un réseau plat unique qui laisse tout container compromis atteindre tous les autres.

Les secrets : utilisez le mécanisme, pas l’environnement

Swarm a un vrai mécanisme de secrets et l’échec courant est de ne pas l’utiliser. Un secret Swarm est stocké chiffré dans Raft, livré aux seuls services qui en ont reçu l’octroi et monté dans chaque tâche en fichier sous /run/secrets sur un tmpfs qui ne touche jamais le disque:

printf 'db-pass' | docker secret create db_password -
docker service create --name app --secret db_password myimage:tag

Les anti-patterns sont les alternatives vers lesquelles on se tourne à la place: un secret dans une variable d’environnement fuit par docker inspect, par l’environnement de processus que tout RCE interne peut lire et souvent dans les logs; un secret cuit dans l’image est dans chaque copie du registre pour toujours. La livraison par fichier-sous-tmpfs existe précisément pour éviter cela, donc le durcissement consiste à router chaque identifiant par docker secret et à ne l’octroyer qu’aux services qui l’utilisent. La rotation est un remplacement de secret plus une mise à jour de service et les anciens secrets doivent être retirés, pas laissés octroyés à des tâches qui n’en ont plus besoin.

Le reste est par container et par nœud

Au-delà des mécaniques de cluster, la sécurité d’un Swarm est la somme de ses containers et de ses hôtes, donc la discipline mono-hôte se reporte sur la définition de service: retirer les capabilities, poser no-new-privileges, utilisateur non-root, racine en lecture seule, limites de ressources et jamais un service privilégié ni un montage de socket Docker, ce qui dans un Swarm déploie l’évasion sur chaque nœud où le service atterrit plutôt que sur un seul. Un service privilégié en --mode global est la version à l’échelle du cluster de l’erreur mono-hôte et pire exactement en proportion du nombre de nœuds.

Où atterrir

Gardez les charges hors des managers et le nombre de managers petit et impair, parce que les managers sont le cluster et que chacun est une copie de plus du magasin Raft. Appuyez-vous sur les défauts mTLS et Raft chiffré, faites tourner les jetons d’adhésion et l’autorité et gardez le jeton manager comme le mot de passe de cluster qu’il est. Créez les réseaux overlay avec --opt encrypted parce que le défaut est en clair et n’attachez chaque service qu’aux réseaux dont il a besoin. Livrez chaque identifiant par les secrets Swarm pour qu’il vive chiffré dans Raft et arrive en fichier tmpfs, jamais en variable d’environnement. Puis appliquez le durcissement de container ordinaire à chaque service, en vous rappelant que dans un cluster un faux pas privilégié est multiplié par le nombre de nœuds où il tourne.

[edit: 2026] L’implémentation Ansible de tout ceci: le rôle docker .