Docker pour les devs - 14 - Variables d'environnement et secrets

ENV, ARG, env_file, .env, Docker secrets : tout ce qu'il faut savoir pour configurer tes conteneurs sans exposer tes secrets.

  1. 01 Docker pour les devs - 00 - Pourquoi Docker change tout
  2. 02 Docker pour les devs - 01 - Containers vs VMs
  3. 03 Docker pour les devs - 02 - L'architecture de Docker
  4. 04 Docker pour les devs - 03 - Docker Desktop, Engine et alternatives
  5. 05 Docker pour les devs - 04 - Écrire un Dockerfile
  6. 06 Docker pour les devs - 05 - Layers et cache
  7. 07 Docker pour les devs - 06 - Le .dockerignore
  8. 08 Docker pour les devs - 07 - Multi-stage builds
  9. 09 Docker pour les devs - 08 - Choisir son image de base
  10. 10 Docker pour les devs - 09 - Docker Compose, les bases
  11. 11 Docker pour les devs - 10 - Docker Compose avance
  12. 12 Docker pour les devs - 11 - Networking Docker, les bases
  13. 13 Docker pour les devs - 12 - Networking Docker avance
  14. 14 Docker pour les devs - 13 - Volumes et persistance
  15. 15 Docker pour les devs - 14 - Variables d'environnement et secrets
  16. 16 Docker pour les devs - 15 - Permissions et utilisateurs
  17. 17 Docker pour les devs - 16 - Docker et monorepo
  18. 18 Docker pour les devs - 17 - Dev vs Prod
  19. 19 Docker pour les devs - 18 - ENTRYPOINT, CMD et scripts d'initialisation
  20. 20 Docker pour les devs - 19 - Debugger ses conteneurs
  21. 21 Docker pour les devs - 20 - Bases de donnees dans Docker
  22. 22 Docker pour les devs - 21 - Sauvegardes et restauration
  23. 23 Docker pour les devs - 22 - Conteneuriser un frontend
  24. 24 Docker pour les devs - 23 - Sécurité des conteneurs
  25. 25 Docker pour les devs - 24 - Optimisation des images
  26. 26 Docker pour les devs - 25 - Builds multi-platform
  27. 27 Docker pour les devs - 26 - Limiter les ressources de tes conteneurs
  28. 28 Docker pour les devs - 27 - Gerer les logs comme un adulte
  29. 29 Docker pour les devs - 28 - Healthchecks et restart policies
  30. 30 Docker pour les devs - 29 - Nettoyer Docker avant qu'il mange ton disque
  31. 31 Docker pour les devs - 30 - Registries et stratégie de tags
  32. 32 Docker pour les devs - 31 - Docker en CI/CD
  33. 33 Docker pour les devs - 32 - Au-dela de Compose
  34. 34 Docker pour les devs - 33 - Glossaire Docker de A a Z

14 - Variables d'environnement et secrets

Ce que tu vas apprendre

  • La différence entre ENV et ARG dans un Dockerfile
  • Les différentes facons de passer des variables dans Compose
  • Le fichier .env et son chargement automatique
  • Docker secrets pour les donnees sensibles
  • Comment vérifier qu'un secret n'a pas fuite dans une image

Prerequisites


J'ai vu un mot de passe de base de donnees en production dans un docker inspect une fois. Le dev avait mis le mot de passe directement dans le Dockerfile avec ENV. L'image etait poussee sur un registry prive, accessible a toute l'équipe. Tout le monde pouvait voir le mot de passe. Ce genre d'erreur, ca ne devrait jamais arriver.

ENV dans le Dockerfile

ENV definit une variable d'environnement qui persiste dans l'image et dans les conteneurs qui en derivent :

dockerfileFROM node:20-alpine
ENV NODE_ENV=production
ENV PORT=3000

Ces variables sont visibles dans l'image finale. N'importe qui avec acces a l'image peut les voir avec docker inspect ou docker history. Ne mets jamais de secret dans un ENV.

ENV est fait pour la configuration non sensible : NODE_ENV, PORT, TZ, ce genre de choses.

ARG : le build-time only

ARG est différent. Il n'existe que pendant le build :

dockerfileFROM node:20-alpine
ARG APP_VERSION=1.0.0
RUN echo "Building version $APP_VERSION"
# APP_VERSION n'existe plus dans le conteneur final

Pour passer un ARG au build :

bashdocker build --build-arg APP_VERSION=2.3.1 .

Ou dans Compose :

yamlservices:
  app:
    build:
      context: .
      args:
        APP_VERSION: 2.3.1

Attention : meme si ARG n'existe pas dans le conteneur final, il est visible dans l'historique de l'image (docker history). Ne mets pas de secrets dans ARG non plus. C'est pour des valeurs comme le numero de version ou le choix d'un registry npm.

Variables d'environnement dans Compose

Directement dans le fichier

yamlservices:
  app:
    environment:
      NODE_ENV: production
      DATABASE_URL: postgres://postgres:secret@db:5432/myapp

Simple et lisible, mais les secrets sont en clair dans le fichier. Acceptable en dev local, jamais en production.

Avec env_file

yamlservices:
  app:
    env_file:
      - .env.app

Le fichier .env.app :

NODE_ENV=production
DATABASE_URL=postgres://postgres:secret@db:5432/myapp

Ca évité de polluer le compose.yaml avec 30 variables. Tu peux spécifier plusieurs fichiers, ils sont charges dans l'ordre.

Le fichier .env magique

Compose charge automatiquement le fichier .env a la racine du projet. Mais attention : il ne le passe pas aux conteneurs. Il sert a interpoler les variables dans le fichier compose.yaml :

# .env
POSTGRES_VERSION=16
APP_PORT=3000
yaml# compose.yaml
services:
  db:
    image: postgres:${POSTGRES_VERSION}-alpine
  app:
    ports:
      - "${APP_PORT}:3000"

C'est utile pour paramétrer le fichier Compose sans le modifier. Sur paltemps.fr, j'utilise le .env pour le numero de version des images et les ports, et un env_file pour les variables passees aux conteneurs.

Pour passer les variables du .env aux conteneurs, il faut les déclarer explicitement :

yamlservices:
  app:
    environment:
      - APP_PORT  # la valeur vient du shell ou du .env

Docker secrets

Pour les vrais secrets en production, Docker propose un mecanisme dédié. Les secrets sont stockes sous forme de fichiers dans /run/secrets/ a l'intérieur du conteneur :

yamlservices:
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

  app:
    build: .
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    environment: "API_KEY"

Le contenu du fichier ./secrets/db_password.txt est monte en lecture seule dans /run/secrets/db_password. L'image officielle PostgreSQL supporte nativement le suffixe _FILE sur ses variables d'environnement.

Pour les applications custom, tu dois lire le fichier toi-meme :

typescriptimport { readFileSync } from "fs";

function getSecret(name: string): string {
  const secretPath = `/run/secrets/${name}`;
  try {
    return readFileSync(secretPath, "utf-8").trim();
  } catch {
    // Fallback sur la variable d'environnement en dev
    const envValue = process.env[name.toUpperCase()];
    if (!envValue) throw new Error(`Secret ${name} not found`);
    return envValue;
  }
}

const dbPassword = getSecret("db_password");

Ne jamais cuire les secrets dans l'image

Meme si tu supprimes un fichier de secret dans une couche ulterieure du Dockerfile, il reste accessible dans les couches précédentes :

dockerfile# MAUVAIS : le secret est dans l'historique de l'image
COPY .env /app/.env
RUN source /app/.env && npm run build
RUN rm /app/.env  # trop tard, il est dans la couche precedente

Avec un build multi-stage, tu peux limiter les degats :

dockerfileFROM node:20-alpine AS builder
COPY .env /app/.env
RUN source /app/.env && npm run build

FROM node:20-alpine
COPY --from=builder /app/dist /app/dist
# le .env n'est pas dans l'image finale

Mais la bonne pratique, c'est de passer les secrets au build via --mount=type=secret :

dockerfileRUN --mount=type=secret,id=npmrc,target=/root/.npmrc npm ci
bashdocker build --secret id=npmrc,src=.npmrc .

Le secret est accessible pendant le build mais n'apparaît dans aucune couche de l'image.

Verifier les fuites de secrets

Quelques commandes pour vérifier qu'un secret n'a pas fuite :

bash# Voir toutes les variables d'environnement de l'image
docker inspect <image> --format '{{json .Config.Env}}'

# Voir l'historique des couches
docker history <image> --no-trunc

# Chercher un pattern dans l'image
docker run --rm <image> env | grep -i password

Des outils comme trivy ou dockle scannent automatiquement les images a la recherche de secrets exposes.

Résumé

  • ENV : configuration non sensible, visible dans l'image
  • ARG : valeurs de build uniquement, visibles dans l'historique
  • env_file : fichier de variables charge par Compose
  • .env : interpole les variables dans compose.yaml, pas passe aux conteneurs par défaut
  • Docker secrets : fichiers montes en lecture seule dans /run/secrets/
  • --mount=type=secret protégé les secrets pendant le build

Navigation : Precedent : 13 - Volumes | Suivant : 15 - Permissions


Sources

Réservez un audit gratuit de 30 minutes. Je vous montre concrètement ce qu'on peut automatiser.