"Les conteneurs sont des espaces isolés, donc ça ne devrait pas poser de problème d'utiliser root à l'intérieur, non ?"
"Créer un utilisateur n'ajoute que des couches, c'est fastidieux..."
"C'est chiant de devoir gérer les permissions pour que l'utilisateur du conteneur puisse accéder aux répertoires montés depuis l'hôte..."
Beaucoup de développeurs pensent ainsi et utilisent l'utilisateur root, qui est la valeur par défaut dans le Dockerfile.
Cependant, c'est une pratique extrêmement risquée en termes de sécurité. L'isolement des conteneurs n'est pas un pare-feu parfait, et exécuter un conteneur avec les privilèges root peut exposer l'ensemble du serveur à des risques.
Dans cet article, nous expliquerons clairement pourquoi il n'est pas recommandé d'exécuter des conteneurs en tant que root et comment éviter cela.
1. Scénario catastrophique : "Évasion de conteneur" (Container Escape)
C'est la raison la plus déterminante pour éviter l'utilisation de root.
-
Mapping par défaut : l'utilisateur
rootà l'intérieur du conteneur Docker (UID 0) est par défaut le même que l'utilisateur root du serveur hôte (UID 0). -
Quand la barrièrre est brisée : Supposons qu'un attaquant réussisse à "échapper" à l'environnement isolé du conteneur en exploitant une vulnérabilité de l'application, de Docker ou même du noyau Linux lui-même.
-
Conséquences : Si le conteneur s'exécutait avec des privilèges
root, l'attaquant obtiendrait immédiatement les droits root du serveur hôte. Le serveur entier serait alors complètement compromis.
Analogie : Exécuter des conteneurs en tant que
rootrevient à faire dormir un client avec une "clé maîtresse d'hôtel" dans sa chambre. Dès que ce client ouvre la porte de sa chambre (conteneur), il peut se déplacer à sa guise dans tout l'hôtel (hôte).
En revanche, si le conteneur était exécuté avec un utilisateur normal sans privilèges, comme appuser (UID 1001), que se passerait-il ? Même si l'attaquant réussit à s'échapper, il n'obtiendrait que les droits d'un utilisateur sans privilèges, minimisant ainsi les dégâts.
2. Principe du moindre privilège (Principle of Least Privilege)
Le principe de base en matière de sécurité est que "tous les programmes et utilisateurs ne devraient avoir que les droits minimum nécessaires pour accomplir leurs tâches".
Il n'est absolument pas nécessaire d'avoir des privilèges root pour exécuter des applications web.
-
Quand on est
root: Si un attaquant s'introduit dans le conteneur (même sans évasion), il estrootà l'intérieur du conteneur.-
Il peut installer à volonté des logiciels malveillants, des mineurs de cryptomonnaie, etc., via
apt-get install. -
Il peut modifier et supprimer tous les fichiers, y compris les fichiers de configuration contenant des informations de connexion à la base de données (
settings.py, etc.).
-
-
Quand on est
appuser: Même en cas d'intrusion, l'attaquant est juste unappuser.-
apt-get install? Permission refusée. -
Modification des fichiers de configuration système ? Permission refusée.
-
Les dégâts sont limités au répertoire du code source de l'application possédé par
appuser.
-
3. Corriger des idées reçues
🤔 "La commande USER n'augmente-t-elle pas seulement la taille de l'image ?"
Non. C'est la plus grande idée reçue.
La commande USER dans le Dockerfile ne crée pas de couches dans le système de fichiers. Elle ajoute juste une directive dans les métadonnées de l'image disant "l'utilisateur par défaut de ce conteneur au démarrage doit être 'appuser'".
La taille de l'image n'augmente pas d'un octet et cela n'affecte pas la vitesse de construction.
Bien sûr, la commande RUN useradd... crée un utilisateur et ajoute une très légère couche, mais c'est un coût que l'on doit payer pour la sécurité.
🤔 "Pour ouvrir le port 80, il faut de toute façon être root, non ?"
En effet. Dans Linux, seuls les utilisateurs root peuvent ouvrir les ports inférieurs à 1024 (ex : 80, 443). Ceci ne justifie toutefois pas de continuer à exécuter le conteneur en tant que root.
La démarche moderne est la suivante :
-
L'application à l'intérieur du conteneur s'exécute sous les droits de
appusersur un port élevé comme le 8000. -
Docker mappe le port depuis l'extérieur (
docker run -p 80:8000), ou un proxy inverse comme Nginx redirige les requêtes externes sur le port 80 vers le port 8000 interne.
Il n'est pas nécessaire d'avoir des droits root à l'intérieur du conteneur.
4. COMMENT : Bonnes pratiques du Dockerfile
Comment appliquer cela ? Ajouter les quelques lignes suivantes à la fin du Dockerfile n'est pas un gaspillage, mais une règle de sécurité basique et essentielle.
Dockerfile
FROM python:3.12-slim
WORKDIR /app
# ... (apt-get install, pip install, etc.)
# 1. Créer un groupe et un utilisateur non privilégié
# -r : créer comme utilisateur/groupe système, --no-create-home : ne pas créer de répertoire personnel
RUN groupadd -r appgroup && useradd -r -g appgroup --no-create-home appuser
# 2. Lors de la copie des fichiers de l'application, définir la propriété à appuser
# (les fichiers du WORKDIR respecteront aussi cette propriété)
COPY --chown=appuser:appgroup . .
# 3. Passer à l'utilisateur appuser pour les commandes suivantes
USER appuser
# 4. Exécuter l'application sur un port élevé, comme 8000
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
Résumé
Exécuter un conteneur en tant que root revient à abandonner la notion de "défense en profondeur". C'est se priver intentionnellement d'une seconde ligne de défense (USER) au cas où le premier mur de protection de l'isolement serait franchi.
Vérifiez dès maintenant votre Dockerfile.
Aucun commentaire.