
Un secret est toute donnée sensible que vous ne voulez pas exposer : mot de passe de base de données, clé API, certificat TLS, token d’authentification. Lorsque vous travaillez avec Docker, il est tentant de passer ces secrets via des variables d’environnement ou de les copier directement dans l’image. Erreur fatale ! Une fois dans l’image, ces secrets sont accessibles à quiconque la télécharge. Ce guide vous montre comment gérer vos secrets proprement, au build comme au runtime.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Pourquoi c’est critique : où vos secrets peuvent fuiter (images, logs, historique)
- BuildKit secrets : injection sécurisée au moment du build avec
--mount=type=secret - Docker Compose secrets : gestion déclarative des secrets au runtime
- Injection au runtime : bind mounts, tmpfs et variables d’environnement
- CI/CD : intégration avec GitLab CI, GitHub Actions
- Bonnes pratiques : chiffrement avec SOPS, audit des images
Prérequis
Section intitulée « Prérequis »- Connaissance de base des Dockerfile et de la CLI Docker
- Accès à un environnement Docker fonctionnel
Pourquoi protéger ses secrets est critique
Section intitulée « Pourquoi protéger ses secrets est critique »L’analogie du coffre-fort
Section intitulée « L’analogie du coffre-fort »Imaginez que vous construisiez une maison (votre image Docker). Vous avez besoin d’un code d’alarme temporaire pendant les travaux (le secret au build). Si vous gravez ce code dans le béton (l’image), tous les futurs propriétaires et visiteurs pourront le lire. La bonne approche : utiliser un code temporaire que vous effacez après les travaux, et installer un vrai système de sécurité pour les habitants (secrets au runtime).
Ce que vous risquez concrètement
Section intitulée « Ce que vous risquez concrètement »Selon une étude GitGuardian, des milliers d’images sur Docker Hub contiennent encore des clés AWS valides, tokens d’API et identifiants de production.
| Risque | Conséquence | Exemple réel |
|---|---|---|
| Piratage cloud | Machines supprimées ou utilisées pour miner des cryptos | Clé AWS exposée → facture de 50 000€ |
| Fuite de données | Accès non autorisé à vos bases de données | Token PostgreSQL → dump de la BDD clients |
| Compromission CI/CD | Accès à tous vos pipelines et artefacts | Secret GitLab → push de code malveillant |
| Attaque supply chain | Infection de toutes les images dérivées | Token NPM → package malveillant publié |
Où vos secrets peuvent fuiter
Section intitulée « Où vos secrets peuvent fuiter »Les 5 vecteurs de fuite les plus courants
Section intitulée « Les 5 vecteurs de fuite les plus courants »Comprendre où les secrets peuvent fuiter est la première étape pour les protéger.
| Vecteur | Exemple | Pourquoi c’est dangereux |
|---|---|---|
| Dockerfile | ENV API_KEY=abc123 | Visible dans l’historique et l’image |
| Image finale | COPY .env /app/ | Accessible à quiconque pull l’image |
| Logs CI/CD | echo $SECRET dans un script | Logs souvent accessibles à toute l’équipe |
| Conteneur runtime | docker exec env | Variables d’environnement visibles |
| Git history | Commit d’un .env puis suppression | git log révèle tout |
Dans le Dockerfile : les pièges classiques
Section intitulée « Dans le Dockerfile : les pièges classiques »# ❌ INTERDIT : Le secret reste dans l'historique de l'imageENV DATABASE_PASSWORD=supersecret
# ❌ INTERDIT : Le fichier est copié dans une couche permanenteCOPY config.env /app/config.env
# ❌ INTERDIT : ARG est visible dans docker historyARG NPM_TOKENRUN npm install --registry=https://:${NPM_TOKEN}@npm.pkg.github.comVérification : Vous pouvez voir ces secrets avec docker history :
docker history mon_image --no-trunc# Affiche toutes les instructions, y compris les ARG et ENVDans les logs de build et de pipeline
Section intitulée « Dans les logs de build et de pipeline »Même sans être dans l’image finale, un secret peut fuiter dans les logs :
# ❌ DANGEREUX : Le secret apparaît dans les logsecho "Connexion avec le token: $API_TOKEN"
# ✅ SÉCURISÉ : Ne jamais afficher de secretecho "Connexion au service..."BuildKit : secrets au moment du build
Section intitulée « BuildKit : secrets au moment du build »BuildKit est le moteur de build moderne de Docker, activé par défaut depuis Docker 23.0. Sa fonctionnalité phare pour la sécurité : le montage temporaire de secrets avec --mount=type=secret.
Principe de fonctionnement
Section intitulée « Principe de fonctionnement »Le secret est monté uniquement pendant l’exécution d’une instruction RUN, puis disparaît. Il n’est jamais stocké dans une couche de l’image.
Syntaxe de base
Section intitulée « Syntaxe de base »# syntax=docker/dockerfile:1FROM python:3.12-slim
WORKDIR /app
# Le secret est monté dans /run/secrets/pip_conf pendant le RUNRUN --mount=type=secret,id=pip_conf,target=/etc/pip.conf \ pip install -r requirements.txt
COPY . .CMD ["python", "app.py"]# Passer le secret depuis un fichierdocker build --secret id=pip_conf,src=./pip.conf -t mon_image .
# Passer le secret depuis une variable d'environnementexport NPM_TOKEN="mon_token_secret"docker build --secret id=NPM_TOKEN -t mon_image .Exemple complet : accès à un registre NPM privé
Section intitulée « Exemple complet : accès à un registre NPM privé »-
Créer le fichier
.npmrclocal (ne pas le commiter !)Fenêtre de terminal echo "//npm.pkg.github.com/:_authToken=${NPM_TOKEN}" > .npmrcecho ".npmrc" >> .gitignore -
Écrire le Dockerfile avec mount secret
# syntax=docker/dockerfile:1FROM node:20-alpineWORKDIR /appCOPY package*.json ./# Le .npmrc est monté temporairement pour npm installRUN --mount=type=secret,id=npmrc,target=/root/.npmrc \npm ci --only=productionCOPY . .CMD ["node", "server.js"] -
Builder l’image avec le secret
Fenêtre de terminal docker build --secret id=npmrc,src=.npmrc -t mon-app . -
Vérifier que le secret n’est pas dans l’image
Fenêtre de terminal # Le fichier ne doit pas existerdocker run --rm mon-app cat /root/.npmrc# cat: /root/.npmrc: No such file or directory# L'historique ne doit pas contenir le tokendocker history mon-app --no-trunc | grep -i token# (aucun résultat)
Options avancées du mount secret
Section intitulée « Options avancées du mount secret »| Option | Description | Exemple |
|---|---|---|
id | Identifiant du secret (obligatoire) | id=my_secret |
target | Chemin de montage dans le conteneur | target=/etc/config.json |
required | Échoue si le secret n’est pas fourni | required=true |
mode | Permissions du fichier (octal) | mode=0400 |
uid, gid | Propriétaire du fichier | uid=1000,gid=1000 |
# Exemple avec toutes les optionsRUN --mount=type=secret,id=db_password,target=/run/secrets/db,required=true,mode=0400,uid=1000 \ /app/init-db.shMonter un secret comme variable d’environnement
Section intitulée « Monter un secret comme variable d’environnement »Depuis BuildKit, vous pouvez aussi injecter un secret directement comme variable d’environnement (sans fichier) :
RUN --mount=type=secret,id=api_key,env=API_KEY \ curl -H "Authorization: Bearer $API_KEY" https://api.example.com/dataDocker Compose : secrets au runtime
Section intitulée « Docker Compose : secrets au runtime »Docker Compose propose un mécanisme déclaratif pour injecter des secrets dans les conteneurs au moment de l’exécution. Les secrets sont montés en tant que fichiers dans /run/secrets/.
Principe
Section intitulée « Principe »services: app: image: mon-app secrets: - db_password # Monté dans /run/secrets/db_password
secrets: db_password: file: ./secrets/db_password.txt # Source du secretExemple complet : WordPress avec MySQL
Section intitulée « Exemple complet : WordPress avec MySQL »services: db: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db_root_password MYSQL_DATABASE: wordpress MYSQL_USER: wordpress MYSQL_PASSWORD_FILE: /run/secrets/db_password secrets: - db_root_password - db_password volumes: - db_data:/var/lib/mysql
wordpress: image: wordpress:latest depends_on: - db ports: - "8080:80" environment: WORDPRESS_DB_HOST: db:3306 WORDPRESS_DB_USER: wordpress WORDPRESS_DB_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password
secrets: db_password: file: ./secrets/db_password.txt db_root_password: file: ./secrets/db_root_password.txt
volumes: db_data:Sources de secrets dans Compose
Section intitulée « Sources de secrets dans Compose »| Source | Syntaxe | Cas d’usage |
|---|---|---|
| Fichier local | file: ./secret.txt | Développement, fichiers chiffrés avec SOPS |
| Variable d’environnement | environment: MY_VAR | CI/CD, secrets injectés par la plateforme |
| Secret externe | external: true | Docker Swarm, secrets pré-créés |
secrets: # Depuis un fichier from_file: file: ./secrets/api_key.txt
# Depuis une variable d'environnement from_env: environment: API_KEY
# Secret externe (Docker Swarm) from_swarm: external: trueBuild secrets avec Compose
Section intitulée « Build secrets avec Compose »Docker Compose permet aussi de passer des secrets au moment du build :
services: app: build: context: . secrets: - npm_token
secrets: npm_token: environment: NPM_TOKENInjection au runtime : autres méthodes
Section intitulée « Injection au runtime : autres méthodes »En dehors de Docker Compose, plusieurs méthodes permettent d’injecter des secrets au lancement d’un conteneur.
Tableau comparatif des méthodes
Section intitulée « Tableau comparatif des méthodes »| Méthode | Sécurité | Persistance | Cas d’usage |
|---|---|---|---|
| Variables d’environnement | ⚠️ Faible | Pendant la vie du conteneur | Debug, développement local |
| Bind mount (readonly) | ✅ Moyenne | Fichier sur l’hôte | Production simple |
| tmpfs | ✅✅ Élevée | RAM uniquement | Secrets éphémères, haute sécurité |
| Docker Swarm secrets | ✅✅ Élevée | Chiffré at-rest | Clusters Swarm |
| Vault/External | ✅✅✅ Très élevée | Externe | Enterprise, compliance |
Variables d’environnement (à éviter en production)
Section intitulée « Variables d’environnement (à éviter en production) »# ⚠️ Le secret est visible avec docker inspectdocker run -e DATABASE_PASSWORD=secret mon-app
# ⚠️ Aussi visible avec docker execdocker exec mon-container env | grep PASSWORDQuand c’est acceptable : développement local, tests, conteneurs éphémères jetables.
Bind mount en lecture seule
Section intitulée « Bind mount en lecture seule »docker run \ --mount type=bind,source="$(pwd)/secrets/config.json",target=/run/secrets/config.json,readonly \ mon-appAvantages : Simple, le fichier reste sur l’hôte (pas dans l’image). Inconvénients : Le fichier existe en clair sur le disque de l’hôte.
tmpfs : secrets en mémoire uniquement
Section intitulée « tmpfs : secrets en mémoire uniquement »Le montage tmpfs stocke les données uniquement en RAM. Aucune trace sur le disque.
# Créer un tmpfs pour les secretsdocker run \ --mount type=tmpfs,destination=/run/secrets,tmpfs-size=1m,tmpfs-mode=0700 \ -e SECRET_DATA="$(cat secret.json)" \ --entrypoint /bin/sh mon-app \ -c 'echo "$SECRET_DATA" > /run/secrets/config.json && exec /app/start.sh'Intégration CI/CD
Section intitulée « Intégration CI/CD »GitLab CI
Section intitulée « GitLab CI »GitLab permet de définir des variables masquées et de type fichier.
-
Configurer la variable dans GitLab
- Aller dans Settings > CI/CD > Variables
- Ajouter une variable
NPM_TOKEN - Cocher Mask variable et Protect variable
-
Utiliser dans
.gitlab-ci.ymlbuild:stage: buildimage: docker:latestservices:- docker:dindvariables:DOCKER_BUILDKIT: "1"script:# Créer le fichier temporaire- echo "$NPM_TOKEN" > .npmrc# Builder avec le secret- docker build --secret id=npmrc,src=.npmrc -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .# Nettoyer- rm -f .npmrc# Pousser l'image- docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
GitHub Actions
Section intitulée « GitHub Actions »name: Build and Push
on: push: branches: [main]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v3
- name: Build with secrets uses: docker/build-push-action@v5 with: context: . push: true tags: ghcr.io/${{ github.repository }}:latest secrets: | "npm_token=${{ secrets.NPM_TOKEN }}"Chiffrer ses secrets avec SOPS
Section intitulée « Chiffrer ses secrets avec SOPS »Même avec --secret, les fichiers de secrets doivent être protégés avant le build. SOPS (Secrets OPerationS) permet de chiffrer des fichiers YAML, JSON ou ENV tout en gardant les clés lisibles.
Workflow avec SOPS
Section intitulée « Workflow avec SOPS »-
Chiffrer le fichier de secrets
Fenêtre de terminal # Avec une clé GPGsops -e -i secrets.json# Avec AWS KMSsops --kms arn:aws:kms:eu-west-1:123:key/abc -e -i secrets.json -
Commiter le fichier chiffré (les valeurs sont illisibles)
{"api_key": "ENC[AES256_GCM,data:abc123...,type:str]","db_password": "ENC[AES256_GCM,data:def456...,type:str]"} -
Déchiffrer dans le pipeline CI
Fenêtre de terminal # Le runner a accès à la clé de déchiffrementsops -d secrets.json > decrypted.jsondocker build --secret id=config,src=decrypted.json -t mon-app .rm -f decrypted.json
Bonnes pratiques et checklist
Section intitulée « Bonnes pratiques et checklist »Les règles d’or
Section intitulée « Les règles d’or »| ❌ Ne jamais faire | ✅ Toujours faire |
|---|---|
ENV SECRET=xxx dans Dockerfile | --mount=type=secret avec BuildKit |
COPY .env /app/ | Monter le secret au runtime |
ARG pour les secrets | Secrets Compose ou tmpfs |
| Commiter des secrets en clair | Chiffrer avec SOPS |
echo $SECRET dans les logs | Masquer et ne jamais afficher |
Commandes de vérification
Section intitulée « Commandes de vérification »# Vérifier qu'aucun secret n'est dans l'historiquedocker history mon-image --no-trunc | grep -iE 'password|secret|token|key'
# Vérifier le contenu de l'imagedocker run --rm mon-image find / -name "*.env" -o -name "*secret*" 2>/dev/null
# Scanner avec Trivytrivy image mon-image --scanners secret
# Scanner avec trufflehogtrufflehog docker --image mon-imageOutils de détection de secrets
Section intitulée « Outils de détection de secrets »| Outil | Usage | Lien |
|---|---|---|
| Trivy | Scan d’images Docker | Guide Trivy |
| trufflehog | Détection dans Git et images | Guide trufflehog |
| Gitleaks | Pre-commit hook | gitleaks.io |
| Dockle | Audit de bonnes pratiques Docker | goodwithtech/dockle |
Dépannage
Section intitulée « Dépannage »Problèmes courants
Section intitulée « Problèmes courants »| Symptôme | Cause probable | Solution |
|---|---|---|
secret not found | Secret non passé au build | Vérifier --secret id=xxx,src=fichier |
Secret visible dans docker history | Utilisation de ARG/ENV | Migrer vers --mount=type=secret |
Permission denied sur /run/secrets | Mode trop restrictif | Ajuster mode=0400 ou uid/gid |
| Secret vide dans le conteneur | Fichier source inexistant | Vérifier le chemin du src |
_FILE ne fonctionne pas | Image ne supporte pas la convention | Lire le fichier dans un entrypoint custom |
Vérifier que BuildKit est actif
Section intitulée « Vérifier que BuildKit est actif »# Doit afficher "buildkit" ou "1"docker info | grep -i buildkit
# Forcer BuildKit si nécessaireDOCKER_BUILDKIT=1 docker build ...À retenir
Section intitulée « À retenir »-
Ne jamais utiliser ARG, ENV ou COPY pour les secrets dans un Dockerfile — ils persistent dans l’image.
-
BuildKit
--mount=type=secretest la méthode recommandée pour les secrets au build — le secret est temporaire et n’est jamais stocké. -
Docker Compose secrets offre une gestion déclarative au runtime — les secrets sont montés dans
/run/secrets/. -
Préférer les fichiers aux variables d’environnement — les env vars fuient facilement via logs, proc, inspect.
-
tmpfs pour les secrets ultra-sensibles — aucune trace sur le disque, uniquement en RAM.
-
Chiffrer les fichiers de secrets avec SOPS avant de les commiter — permet de versionner sans exposer.
-
Scanner régulièrement vos images avec Trivy ou trufflehog — la détection automatique complète la prévention.
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications