Docker sur un serveur, c’est un peu le super pouvoir qu’on veut tous. Déployer vite, isoler proprement, reproduire les environnements, scaler sans (trop) se prendre la tête.
Sauf que. Sur un VPS ou un serveur dédié, Docker peut aussi devenir un joli accélérateur d’incident si on part sur des « recettes » trouvées vite fait, ou si on traite la prod comme un laptop.
Dans cet article, je te liste les erreurs de sécurité les plus fréquentes que je vois sur des serveurs Docker, avec des exemples concrets, et surtout quoi faire à la place. On va rester pragmatique. Pas un guide théorique de conformité. Juste ce qui casse en vrai.
Pourquoi Docker sur serveur change la donne côté sécurité
En local, tu fais n’importe quoi, ça te retombe dessus. Sur un serveur exposé, tu fais n’importe quoi, ça retombe sur tes clients, ton SEO, ton business, ton image. Et parfois, sur ton compte cloud aussi.
Le point clé à garder en tête : un conteneur n’est pas une VM. L’isolation est réelle, mais pas absolue. Une mauvaise config Docker peut transformer un petit bug applicatif en accès à l’hôte.
Bon. Passons aux erreurs.
1. Lancer les conteneurs en root (et « c’est bon, c’est isolé »)
C’est LA classique.
Beaucoup d’images tournent en root par défaut. Et beaucoup de gens laissent comme ça, parce que… ça marche.
Problème : si une appli se fait exploiter, l’attaquant obtient souvent un shell dans le conteneur. Et si le conteneur tourne en root, on augmente fortement la surface pour sortir du conteneur, abuser de capabilities, écrire là où il ne faut pas, etc.
Ce qu’il faut faire à la place :
- Utiliser des images qui tournent en non root, ou les adapter.
- Définir un
USERdans le Dockerfile. - Dans Compose, forcer
user: "1000:1000"quand c’est possible.
Exemple Dockerfile :
dockerfile FROM node:20-alpine WORKDIR /app COPY . . RUN addgroup -S app && adduser -S app -G app USER app CMD ["node","server.js"]
Oui, parfois ça casse des permissions. Oui, tu vas ajuster. Mais c’est le prix normal.
Pour éviter ces erreurs courantes et garantir une sécurité optimale lors de l'utilisation de Docker sur vos serveurs dédiés ou VPS, il est essentiel de suivre certaines pratiques recommandées. Par exemple, lancer les conteneurs en root est une erreur classique qui peut avoir des conséquences désastreuses. En effet, cela augmente considérablement la surface d'attaque pour les hackers en cas d'exploitation d'une application dans le conteneur.
Par ailleurs, il est crucial de comprendre que l'[autopsie d
2. Monter le socket Docker dans un conteneur
Le fameux :
yaml volumes:
- /var/run/docker.sock:/var/run/docker.sock
Tu vois ça dans des stacks « pratiques » : Portainer, des watchers, des outils CI maison, des reverse proxies « auto discovery ».
Sauf que monter docker.sock, c’est pratiquement donner root sur l’hôte. Parce que l’API Docker permet de créer des conteneurs, monter /, lire des secrets, etc. Si le conteneur est compromis, l’hôte l’est souvent aussi.
Alternatives :
- Éviter. Vraiment.
- Utiliser un proxy d’API Docker avec règles strictes (moins courant, mais possible).
- Utiliser des mécanismes d’intégration moins puissants (labels statiques, config explicite).
- Si tu dois absolument, isoler ce composant sur une machine dédiée ou un contexte dédié.
3. Exposer le daemon Docker sur le réseau (2375) sans TLS
Tu sais, ce truc :
-H tcp://0.0.0.0:2375
C’est une porte d’entrée directe. Il y a des bots qui scannent internet pour ça. Et quand ils trouvent, c’est terminé. Mining, exfiltration, pivot réseau, tout le pack.
Ce qu’il faut faire :
- Ne jamais exposer 2375.
- Si accès distant nécessaire : TLS mutualisé sur 2376, ou mieux, un tunnel SSH, ou un VPN.
- Sur serveur, privilégier l’admin via SSH.
Petit rappel : Docker n’est pas un service à exposer « comme ça ».
4. Publier tous les ports « pour tester », puis oublier
Le -p 0.0.0.0:xxxx:xxxx permanent. Le Compose où tout est publié. Le Redis accessible depuis internet. Le PostgreSQL pareil. Et on se dit « j’ai mis un mot de passe ».
Oui mais non.
Erreurs typiques :
- Base de données exposée publiquement.
- Interfaces admin (Grafana, Kibana, pgAdmin, phpMyAdmin) sans restriction IP.
- ElasticSearch ouvert, sans auth.
- RabbitMQ ouvert.
Bon réflexe :
- N’exposer publiquement que le reverse proxy (80, 443).
- Les services internes restent sur un réseau Docker interne, sans
ports:mais avecexpose:si besoin. - Pour accéder à un service interne : SSH tunnel, VPN, ou réseau d’admin.
Exemple Compose (principe) :
yaml services: reverse-proxy: image: caddy:2 ports: - "80:80" - "443:443"
db: image: postgres:16 environment: POSTGRES_PASSWORD: "${POSTGRES_PASSWORD}" expose: - "5432"
5. Utiliser des images « latest » en production
nginx:latest, node:latest, myapp:latest.
Ça a l’air propre. En réalité, c’est instable et dangereux :
- Tu ne contrôles pas la version.
- Tu peux prendre une mise à jour majeure qui casse.
- Tu ne sais pas exactement ce qui tourne aujourd’hui vs demain.
- Et côté sécu, tu compliques la traçabilité.
À faire :
- Pinner une version précise :
nginx:1.27-alpine,postgres:16.3, etc. - Idéalement pinner aussi par digest (
@sha256:...) pour du « vraiment immuable ». - Mettre en place un process de mise à jour : test, puis déploiement.
6. Oublier les mises à jour de l’hôte (pas que les conteneurs)
On patch l’app. On rebuild l’image. Mais l’hôte Ubuntu/Debian tourne avec un kernel pas mis à jour depuis 8 mois. Ou containerd, runc, iptables vieillissent.
Or, une évasion de conteneur, quand elle arrive, exploite souvent des composants bas niveau.
À faire :
- MAJ régulières de l’OS.
- Redémarrages planifiés (oui, ça compte).
- Suivi des CVE Docker Engine, runc, kernel.
- Si tu es en mode « uptime religieux », tu vas finir par payer autrement.
7. Tout mettre dans le même réseau Docker (flat network)
Par défaut, beaucoup de stacks finissent dans un réseau unique, ou pire, dans bridge sans segmentation.
Résultat : si un service web est compromis, il peut scanner et attaquer les services internes (DB, cache, broker).
À faire :
- Créer des réseaux séparés :
frontend,backend,monitoring. - N’attacher un conteneur qu’aux réseaux nécessaires.
- Bloquer la communication inter conteneurs inutile.
Exemple :
yaml networks: frontend: backend:
services: app: networks: ["frontend","backend"] db: networks: ["backend"]
8. Secrets en clair dans docker-compose.yml
Le classique :
yaml environment: DB_PASSWORD: "motdepasse123"
Ou pire, un token API en dur, committé sur GitHub. Et ensuite on se demande pourquoi un service tiers se fait spammer.
À faire :
- Utiliser un
.envhors repo (au minimum). - Utiliser des Docker secrets (Swarm) ou un gestionnaire de secrets (Vault, SOPS, AWS Secrets Manager, etc.).
- Limiter la diffusion : un secret ne doit pas être dans l’image, ni dans un log.
Et pitié, évite de logger les variables d’environnement au démarrage.
9. Volumes montés trop larges, surtout avec accès écriture
Exemples dangereux :
- Monter
/dans un conteneur. - Monter
/var/logou/etcsans raison. - Monter des répertoires d’app sensibles en écriture alors qu’ils peuvent être en lecture seule.
Les montages de volumes, c’est pratique, mais ça peut devenir un pont direct vers l’hôte.
À faire :
- Monter uniquement ce qui est nécessaire.
- Utiliser
:ro(read-only) dès que possible.
Exemple :
yaml volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
10. Conteneurs « privileged » ou capabilities inutiles
Tu vois privileged: true et tu sais que quelqu’un a eu un souci de permission et a décidé de… contourner la planète.
En privileged, le conteneur a des accès très étendus au noyau. C’est quasiment l’équivalent de dire « fais comme chez toi ».
À faire :
- Ne jamais utiliser
privilegedsauf cas très spécifiques (et isolés). - Ajouter uniquement les capabilities nécessaires, pas plus.
- Supprimer le reste.
Exemple :
yaml cap_drop:
- ALL cap_add:
- NET_BIND_SERVICE
11. Systèmes de fichiers en écriture et absence de durcissement minimal
Une mesure simple : rendre le conteneur en lecture seule, et gérer les dossiers temporaires via tmpfs. Beaucoup d’applications peuvent tourner comme ça, surtout côté reverse proxy, front statique, etc.
Exemple :
yaml read_only: true tmpfs:
- /tmp
- /run
Ce n’est pas universel, mais quand c’est possible, c’est un gros gain.
12. Pas de limites de ressources (DoS facile)
Sans limites, un conteneur peut :
- bouffer la RAM,
- saturer le CPU,
- remplir le disque via logs,
- faire tomber tout le serveur.
À faire :
- Mettre des limites CPU/RAM.
- Mettre une stratégie de logs.
- Monitorer.
Exemple (Compose) :
yaml deploy: resources: limits: cpus: "1.0" memory: 512M
Note : selon ton mode (Swarm vs Compose classique), le support diffère. Mais l’idée reste.
13. Logs qui grossissent sans rotation
Le driver json-file par défaut peut devenir un gouffre. Tu te réveilles avec un disque plein. Et là, tout s’arrête. Base de données incluse. C’est bête, mais fréquent.
À faire :
- Configurer la rotation.
Exemple dans /etc/docker/daemon.json :
json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } }
Puis redémarrer Docker.
14. Oublier la sécurité TLS côté reverse proxy (ou faire du HTTPS « à moitié »)
Si ton serveur Docker héberge des apps web, le reverse proxy est ton garde du corps. Mais parfois il est mal configuré :
- HTTP encore accessible.
- TLS faible.
- Pas de HSTS.
- Pas de headers de base.
- Pas de rate limiting.
Ce qu’il faut faire :
- Forcer HTTPS.
- Mettre des headers raisonnables.
- Activer des limites et protections.
- Et surtout, ne pas exposer des dashboards sans auth.
Si tu utilises Caddy, Traefik ou Nginx, prends le temps de faire une config propre. Une seule fois. Ensuite tu clones.
15. Chaîne CI/CD qui pousse en prod sans garde-fous
Côté « business en ligne », on adore automatiser. Je comprends, j’en parle souvent aussi sur Le Blog Tech Pro de Samyn-Antoy ABASSE.
Mais une CI/CD qui :
- build une image non scannée,
- la tag en latest,
- déploie direct,
- sans review,
- sans environnement de staging,
… c’est une fabrique à incidents.
À faire :
- Scanner les images (Trivy, Grype).
- Signer ou au moins vérifier la provenance.
- Déployer via tags versionnés.
- Garder un staging, même minimal.
Mini checklist de durcissement (à copier)
Si tu veux une liste rapide, la voilà :
- Conteneurs non root.
- Pas de montage de
docker.sock(ou alors très isolé). - Pas d’API Docker exposée en clair.
- Exposition publique limitée à 80 et 443.
- Réseaux Docker segmentés.
- Images versionnées (pas latest).
- Secrets hors YAML et hors Git.
- Volumes minimaux,
:roquand possible. - Pas de
privileged, capabilities réduites. read_onlyettmpfsquand possible.- Limites CPU/RAM + rotation des logs.
- OS hôte patché régulièrement.
- Reverse proxy durci.
Conclusion : Docker est simple, mais pas « automatiquement sûr »
Docker te simplifie la vie. Oui. Mais sur serveur, il faut penser comme un admin système, même si tu viens du dev, même si tu es freelance, même si tu gères juste ton tunnel de vente et deux landing pages.
Les erreurs que je viens de lister, je les ai vues sur des projets très différents. SaaS, e-commerce, sites vitrine, stacks de monitoring, serveurs perso. C’est souvent les mêmes raccourcis, et les mêmes conséquences.
Si tu veux approfondir le sujet des erreurs fatales liées à la sécurité dans le domaine de l'IA, je t'invite à lire cet article sur les erreurs fatales de la sécurité IA.
De plus, il est crucial de comprendre qu'il existe une unique erreur de sécurité qui peut avoir des conséquences désastreuses. Pour en savoir plus sur cette problématique majeure, je te recommande cet article sur l'unique erreur de sécurité qui fait.
Si tu veux aussi que je publie une suite plus « pratique » sur mon site avec par exemple une configuration Docker Compose type pour une petite prod (reverse proxy, app, DB) avec segmentation réseau, secrets, rotation de logs et quelques garde-fous supplémentaires. Tu peux garder un oeil sur Le Blog Tech Pro de Samyn-Antoy ABASSE ici : https://monblog-sa-abasse.blogspot.com
 dans un conteneur ?
Monter le socket Docker dans un conteneur revient à donner un accès root complet à l'hôte via l'API Docker. Un conteneur compromis avec ce montage permettrait de créer d'autres conteneurs, accéder au système de fichiers de l'hôte, lire des secrets, etc. Il faut éviter ce montage ou bien utiliser des proxys API avec des règles strictes et isoler ces composants si nécessaire.
Pourquoi ne faut-il pas exposer le daemon Docker sur le réseau sans TLS ?
Exposer le daemon Docker sur le port 2375 sans TLS ouvre une porte directe aux attaques, car ce port est souvent scanné par des bots malveillants. Cela peut entraîner du mining illégal, de l'exfiltration de données ou des pivotements réseau. La bonne pratique est de ne jamais exposer ce port sans sécurité, préférer TLS mutuel sur 2376 ou utiliser un tunnel SSH/VPN pour l'administration distante.
Quels sont les dangers de publier tous les ports d'un conteneur « pour tester » puis oublier ?
Publier tous les ports expose inutilement les services du conteneur à internet ou au réseau local, augmentant la surface d'attaque et facilitant la compromission. Il faut limiter la publication aux ports strictement nécessaires et nettoyer les configurations temporaires après test pour éviter des failles de sécurité.
En quoi la sécurité Docker sur serveur diffère-t-elle de celle en local ?
Sur un environnement local, une mauvaise configuration affecte surtout l'utilisateur lui-même. Sur un serveur exposé, une erreur peut impacter les clients, la réputation SEO, le business et même entraîner des coûts cloud supplémentaires. De plus, contrairement à une VM, l'isolation des conteneurs n'est pas absolue ; une mauvaise configuration peut permettre à un attaquant de s'échapper vers l'hôte.
Quelles bonnes pratiques adopter pour sécuriser Docker sur un VPS ou serveur dédié ?
Il faut utiliser des images non root ou adapter ses images pour tourner sous un utilisateur non privilégié, éviter de monter docker.sock dans les conteneurs sauf nécessité absolue et isolation renforcée, ne pas exposer le daemon Docker sans chiffrement TLS ni tunnel sécurisé, limiter la publication des ports aux besoins réels et privilégier l'administration via SSH sécurisé plutôt que par accès direct au daemon.
0 Commentaires