Un défaut dans le serveur d’une petite boutique
Une image sûre à livrer tourne sous un utilisateur ordinaire, reste petite, fixe sa version et ne contient aucun secret. Chaque point réduit les dégâts d’une attaque.
Quelqu’un trouve un défaut dans le programme qui sert les pages d’une boutique. Il peut maintenant lui faire faire des choses.
Ce qu’il peut atteindre ensuite dépend de l’utilisateur sous lequel tourne le programme. Cela dépend aussi de ce qu’il y a d’autre dans l’image, et de ce qui y est écrit.
À la fin de cette leçon
Remarque
Je peux dire ce qui rend une image sûre à livrer et corriger un Dockerfile peu sûr.
Mots-clés
| Mot | Ce que ça veut dire | Exemple |
|---|---|---|
| Root | l’utilisateur qui peut tout changer sur le système | uid=0 |
| Utilisateur ordinaire | un utilisateur aux droits limités | |
| Étiquette fixée | une étiquette d’image qui nomme une seule version exacte | nginx:1.27-alpine |
| Secret | un mot de passe ou une clé que seul le programme doit connaître | |
| Surface d’attaque | tout ce qu’il y a dans une image qu’un attaquant pourrait utiliser |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Tourner sous un utilisateur qui peut peu
Sauf consigne contraire, le programme d’un conteneur tourne en root. Root peut changer tout fichier où le conteneur peut écrire, y compris un volume monté.
Un utilisateur ordinaire ne le peut pas. Si le programme est attaqué, les dégâts restent plus petits. Comparez les deux services principaux de votre labo.
Sous quel utilisateur web tourne-t-il ?
docker exec web idAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Sous quel utilisateur cache tourne-t-il ?
docker exec cache idAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Laisser cache essayer d’écrire dans /etc
docker exec cache touch /etc/probeAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Laisser web essayer la même chose
docker exec web touch /etc/probeAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Créer un utilisateur dans un Dockerfile
FROM python:3.12-alpine
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
RUN adduser -D -u 10001 shop
USER shop
CMD ["python", "app.py"]
Une erreur fréquente
Attention
On croit souvent que root dans un conteneur n’a pas d’importance, puisque le conteneur est cloisonné. Les cloisons ont des failles, et un volume monté contient de vraies données. Ajoutez un utilisateur et passez à lui avec USER, comme le fait le cache du labo.
Moins dans l’image, moins à attaquer
Chaque programme d’une image est une faille possible de plus. Chaque outil est un outil de plus pour un attaquant.
Une base légère comme une image Alpine en contient bien moins. L’étiquette décide quelle version vous recevez. Une étiquette comme latest bouge : une reconstruction le mois prochain peut donner une autre image.
Exemple travaillé : deux étiquettes d’une même image
| Étiquette | Taille sur notre machine de test | Ce que cela veut dire |
|---|---|---|
| nginx:1.27 | 284 Mo | un système complet dessous |
| nginx:1.27-alpine | 76,8 Mo | un petit système dessous |
| nginx:latest | non mesurée | ce qui est le plus récent à la construction |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Quelle étiquette cache fixe-t-il ?
docker inspect --format '{{.Config.Image}}' cacheAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Un secret écrit dans une image y reste
Une image se partage. On la pousse vers un registre, on la copie sur des serveurs, on la donne à des collègues. Tout ce qui est dans une couche part avec elle.
Un mot de passe dans un Dockerfile reste dans les couches pour toujours, même si une étape suivante supprime le fichier. Gardez les secrets hors de l’image et donnez-les au conteneur au démarrage.
Un Dockerfile avec un secret, à éviter
FROM alpine:3.20
ENV API_KEY=abc123-not-real
RUN echo hello
Exemple travaillé : où un secret est apparu
| Comment il a été réglé | Où nous l’avons relu | Ce qui s’est affiché |
|---|---|---|
| ENV dans le Dockerfile | docker history --no-trunc | la ligne ENV API_KEY=abc123-not-real |
| -e au démarrage du conteneur | docker inspect, Config.Env | DB_PASSWORD=hunter2 dans la liste |
| Ni l’un ni l’autre | rien dans l’image ni les réglages | un secret donné au moment du lancement |
Les cellules que les étudiants remplissent restent vides dans cet aperçu.
Lire tout ce qu’on a dit à cache
docker inspect --format '{{json .Config.Env}}' cacheAffichée ici, non exécutée. Créez un compte gratuit pour appuyer sur Exécuter et la saisir dans le terminal de votre propre labo.
Pour aller plus loin
Prenez le Dockerfile qui contient un secret. Réécrivez-le pour qu’il fixe son étiquette, tourne sous un utilisateur et ne contienne aucun secret.
Lancez ensuite les trois fonctions du devoir sur l’ancienne version et sur la vôtre. La nouvelle doit sortir propre.