2.5Sécurité de base : non-root, secrets et scan
L'essentiel en 30 secondes
- Non-root systématique : le conteneur tourne en root par défaut — deux lignes (USER dédié) changent tout.
- Zéro secret dans l'image : COPY ou ENV figé reste lisible dans l'historique et part au push — injecter au run, jamais au build.
- Bases officielles + scan rythmé : slim à jour, CVE scannées, rebuild régulier — la sécurité est un rythme, pas un état.
Mini-cas filé — Idir et l'image qui tournait en root
Dernier acte : l'image configurable d'Idir (2.4) est prête, mais elle tourne en root, un fichier de variables traînait dans le contexte, et personne n'a jamais scanné les couches. Idir durcit : base slim officielle, utilisateur dédié (celui fourni par l'image officielle), propriété ajustée au build, vérification via exec + whoami — ce n'est plus root. Il exclut les fichiers sensibles du contexte (.dockerignore), injecte la config au run, puis scanne et met la base à jour. Le niveau 2 est livré : emballé, optimisé, versionné, configurable, durci.
Épilogue du fil rouge 2.1-2.4 : l'app d'Idir tourne non-root, sans secret, scannée — prête pour Compose (niveau 3).
1. Ne plus tourner en root
Par défaut, le processus du conteneur est root : en cas de faille, l'impact est maximal. On crée un utilisateur dédié (l'utilisateur fourni par l'image officielle comme node, propriété ajustée au build) et on déclare USER avant le CMD : deux lignes, un monde de différence. On vérifie avec exec … whoami : on doit voir l'utilisateur dédié, pas root. Idir ajoute USER et contrôle : fini le root « pour simplifier ».
2. Zéro secret dans l'image
Un secret COPY ou ENV dans le Dockerfile reste lisible dans l'historique des couches et part au push avec l'image. On l'injecte au run (variable -e, fichier monté, secret managé) et on l'exclut du contexte (.dockerignore). Ce qui n'est jamais commité ni embarqué ne fuitera jamais du registre. Idir retire tout secret du Dockerfile et du contexte : la config sensible voyage hors image.
3. Scanner avant de déployer
docker scout (ou Trivy/Grype) liste les CVE des couches avec leur gravité. Réflexe : partir de bases slim officielles, mettre à jour les tags, reconstruire régulièrement — une image de 6 mois accumule les failles. En production, une variable au run reste visible via inspect : on préfère les secrets managés (fichiers, orchestrateur, coffre). Idir scanne, met à jour, rebuild, rescanne : la sécurité est un rythme.
🔎 Exemple concret — 🔎 Exemple concret — Durcir l'app Node
L'app d'Idir, version durcie et vérifiée :
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN chown -R node:node /app
USER node
EXPOSE 3000
CMD ["node", "server.js"]
docker scout quickview mon-app:1.0
docker exec -it app whoami # → node, pas root
Lecture : l'appli tourne en « node », les couches sont scannées, le port reste déclaré et publié au run.
Leçon : le .dockerignore a exclu les fichiers sensibles avant même le build — aucun secret embarqué.
Vocabulaire de la section
- USER
- L'utilisateur d'exécution déclaré dans le Dockerfile (avant CMD) : le conteneur ne tourne plus en root.
Exemple simple : Idir déclare USER node avant de démarrer son app.
Ce que ce n'est pas : le propriétaire du dépôt de code.
Réflexe : USER dédié avant CMD, toujours.
- Secret
- Mot de passe, clé, token : information sensible qui ne doit JAMAIS entrer dans l'image ni le dépôt.
Exemple simple : Idir injecte la config sensible au run, jamais au build.
Ce que ce n'est pas : un simple réglage comme le port.
Réflexe : sensible = hors image, hors git.
- CVE
- Une référence publique de vulnérabilité connue, avec sa gravité : ce que les scanners listent couche par couche.
Exemple simple : Idir note les CVE critiques de son scan et met la base à jour.
Ce que ce n'est pas : une erreur de configuration du Dockerfile.
Réflexe : scanner = lister les CVE.
- Surface d'attaque
- Tout ce qui est embarqué et attaquable dans l'image : on la réduit (slim, multi-stage, rebuild).
Exemple simple : Idir livre en slim sans SDK : moins d'embarqué, moins d'exposition.
Ce que ce n'est pas : le nombre de conteneurs lancés.
Réflexe : moins d'embarqué = moins d'exposition.
En pratique — En pratique — Durcir votre image
- Ajoutez un USER non-root à votre Dockerfile (avant CMD) et rebuildez.
- Vérifiez avec exec + whoami (utilisateur dédié, pas root).
- Scannez l'image et notez les CVE critiques.
- Mettez la base à jour, rebuildez, rescannez : comparez.
Script prêt à dire — annoncer une image durcie (30 s)
« L'image tourne en utilisateur dédié, vérifié par whoami — plus de root. Aucun secret dedans : la config sensible est injectée au run et exclue du contexte. Base officielle à jour, scan sans critique, rebuild régulier prévu. On peut la pousser et la déployer sereinement. »
À dire en montrant le whoami non-root d'Idir puis le rapport de scan.
Modèle copier-coller — Dockerfile durci non-root
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
RUN chown -R node:node /app
USER node
EXPOSE 3000
CMD ["node", "server.js"]
Permission cassée
USER casse l'écriture sur un volume : Idir ajuste la propriété au build au lieu de revenir à root.
Fichier sensible embarqué
Variables poussées avec l'image : Idir les retire, .dockerignore + injection au run.
Scan oublié
Image de 6 mois jamais rescannée : Idir met la base à jour, rebuild, rescanne — rythme repris.
Secret au run visible
Variable sensible lisible via inspect : Idir passe aux secrets managés (fichiers, orchestrateur) en prod.
✓ Bonnes pratiques
- USER dédié systématique, vérifié par whoami.
- Bases slim officielles à jour.
- Rebuild régulier (CVE = rythme).
✗ Pièges fréquents
- Rester root « pour simplifier ».
- Committer un fichier de variables avec secrets.
- Scanner une fois puis oublier.
Points clés à retenir
- Non-root : USER dédié avant CMD, deux lignes, énorme effet.
- Zéro secret commité ou embarqué (injecté au run, exclu du contexte).
- On scanne (CVE), on met à jour, on reconstruit régulièrement.
- Moindre base officielle = moindre surface d'attaque.
Défi 48h — appliquez demain
Durcissez votre image 1.0 : USER non-root + whoami vérifié, .dockerignore sans fichiers sensibles, scan + mise à jour + rebuild comparé.
- Je peux faire tourner une image en non-root (USER + whoami vérifié).
- Je sais exclure tout secret de l'image et du contexte (injecté au run).
- Je scanne, mets à jour et reconstruis à rythme régulier.
Questions fréquentes
USER casse mes permissions, que faire ?
Souvent un volume monté en root : ajustez la propriété (chown) au build ou alignez l'UID au run. Ne revenez pas à root par facilité : réparez la permission proprement et revérifiez avec whoami.
ENV avec mot de passe au run, est-ce sûr ?
Mieux que dans l'image, mais visible via inspect : en production on préfère les secrets managés (fichiers montés, orchestrateur, coffre). Le run n'est qu'une étape, pas une protection.
Quelle image fuitera un secret au push ?