
Les secrets Docker Compose donnent à un service accès à un fichier contenant un mot de passe, un jeton ou une autre valeur sensible. Il faut déclarer la source, autoriser le service et faire lire le fichier monté par l’application. Ce sont trois étapes distinctes.
Ce guide utilise une valeur fictive et deux services sous forme de conteneurs Linux. La configuration Compose et le lecteur Python ont été vérifiés localement. Nous n’avons téléchargé aucune image ni démarré de conteneur : les contrôles des fichiers montés ci-dessous sont à effectuer dans votre environnement de test.
La section secrets de premier niveau définit la source. L’entrée secrets du service lui accorde l’accès. Avec le montage de fichier habituel, l’application lit un chemin sous /run/secrets/.
| Élément | Exemple | Rôle |
|---|---|---|
| Fichier source sur l’hôte | ./secrets/demo_token.txt | Contient la valeur fournie à Compose |
| Nom du secret Compose | demo_token | Relie l’autorisation du service à la source |
| Nom du fichier cible | service_token | Place le fichier dans /run/secrets/service_token |
| Paramètre applicatif | APP_TOKEN_FILE | Indique au lecteur de l’exemple le chemin à ouvrir |
Déclarer un secret au premier niveau ne donne pas accès à tous les services. Le guide des secrets Compose décrit l’autorisation par service et précise que ce fonctionnement concerne les conteneurs Linux. Un hôte Windows exécutant des conteneurs Linux est un cas différent de l’exécution de conteneurs Windows.
Dans un nouveau répertoire, créez un sous-répertoire secrets. Placez le texte fictif demo-only-token-not-a-real-secret dans secrets/demo_token.txt. Aucun identifiant réel n’est nécessaire. Les deux services utilisent l’UID et le GID 1000 : cette identité doit pouvoir lire le fichier de test et le script Python à travers leurs montages. Vérifiez ces droits sur votre hôte de test.
Enregistrez ceci sous compose.yaml :
services:
app:
image: python:3.13-alpine
user: "1000:1000"
network_mode: none
command: ["python", "/app/check_secret.py"]
environment:
APP_TOKEN_FILE: /run/secrets/service_token
volumes:
- ./check_secret.py:/app/check_secret.py:ro
secrets:
- source: demo_token
target: service_token
observer:
image: alpine:3.22
user: "1000:1000"
network_mode: none
command: ["sh", "-c", "test ! -e /run/secrets/service_token && echo 'No secret mounted'"]
secrets:
demo_token:
file: ./secrets/demo_token.txt
Le service app reçoit le secret sous le nom cible service_token. observer n’a aucune autorisation de secret. Le réseau est désactivé pour les deux services, puisque l’exercice contrôle uniquement l’accès aux fichiers locaux. Le script applicatif est monté séparément en lecture seule.
Les tags d’image rendent l’exemple lisible. Pour un déploiement reproductible, utilisez des versions ou empreintes testées. L’UID et les permissions de cet exemple ne conviennent pas nécessairement à chaque image de production.
Enregistrez ce script sous check_secret.py, à côté du fichier Compose :
import os
from pathlib import Path
secret_path = os.environ.get("APP_TOKEN_FILE")
if not secret_path:
raise SystemExit("Secret file path is not configured")
try:
token = Path(secret_path).read_bytes()
except OSError:
raise SystemExit("Secret file could not be read")
if not token:
raise SystemExit("Secret file is empty")
print("Secret file loaded; value not logged")
Ce lecteur charge des octets, vérifie que le fichier n’est pas vide et affiche un état sans afficher la valeur. Il ne retire volontairement aucun espace : une intégration réelle doit respecter le format d’identifiant attendu par son fournisseur. Un retour à la ligne final peut avoir une importance.
Nous avons exécuté le lecteur localement avec un chemin valide, un fichier vide, un fichier absent et un chemin non défini. Le cas valide a réussi ; les autres ont échoué avec les messages prévus, sans exposer la valeur fictive. Ce test vérifie la lecture du fichier, pas la réussite d’une authentification.
Le suffixe _FILE est une convention applicative. Compose ne transforme pas automatiquement chaque variable NAME_FILE en secret chargé. Certaines images reconnaissent des noms précis ; ce script implémente explicitement APP_TOKEN_FILE. Consultez la documentation de l’image ou de l’application avant de choisir le nom.
Depuis le répertoire de l’exemple, examinez la configuration résolue :
docker compose -p secrets-demo config --quiet
docker compose -p secrets-demo config --format json
docker compose config valide et résout le modèle. Vérifiez que seul app reçoit le secret, que sa cible est correcte et que APP_TOKEN_FILE contient un chemin plutôt que la valeur fictive. Ces contrôles ont réussi avec Compose v5.1.4. Une référence volontairement non définie a aussi été rejetée.
Ne partagez que le modèle contenant les données fictives. Le modèle de confiance Compose explique que les références de fichiers et la résolution de l’environnement peuvent exposer des données de l’hôte pendant le chargement. Une configuration valide ne prouve pas que l’utilisateur du conteneur pourra lire le montage.
Avec un Docker Engine configuré pour les conteneurs Linux, lancez chaque contrôle ponctuel :
docker compose -p secrets-demo run --rm app
docker compose -p secrets-demo run --rm observer
Les messages attendus sont Secret file loaded; value not logged pour app et No secret mounted pour observer. Ce sont les résultats attendus des conteneurs, pas ceux d’une exécution effectuée par nos soins. La commande run --rm supprime chaque conteneur ponctuel à sa sortie.
Si app échoue, examinez la cible configurée, l’existence du fichier et les permissions de l’UID réel. Si observer trouve un fichier, recherchez un autre montage ou un fichier déjà présent dans l’image. Le contrôle d’absence vérifie le montage prévu ; il ne constitue pas un audit de sécurité de l’hôte.
Pour un secret provenant d’un fichier, Compose local utilise un bind mount. La référence des secrets de service précise que uid, gid et mode sont ignorés pour cette source. Ajouter mode: 0400 au YAML ne modifie donc pas les permissions du fichier hôte.
Protégez la source avec les propriétaires, permissions et contrôles d’accès de l’hôte, tout en permettant sa lecture par l’utilisateur applicatif prévu. Vérifiez le résultat dans un conteneur de test. N’élargissez pas l’accès à l’hôte simplement pour résoudre une erreur de lecture. Notre guide du stockage Docker distingue bind mounts et volumes nommés.
Un montage local ne transforme pas sa source en coffre chiffré et n’empêche pas un administrateur de l’hôte de la lire. La documentation des bind mounts décrit cette dépendance. Protégez aussi les sauvegardes de l’hôte et les chemins de provisionnement. Accordez chaque secret uniquement aux services concernés.
Pour cette arborescence, ajoutez secrets/ dans .gitignore, ainsi que dans .dockerignore si le répertoire devient un contexte de build. Les règles Git concernent les fichiers non suivis. Les règles Docker excluent les fichiers correspondants du contexte de build. Aucune ne retire un identifiant déjà commité ou intégré à une image.
Distinguez les paramètres ordinaires de la transmission des identifiants. Un fichier .env n’est pas un gestionnaire de secrets ; un jeton peut encore être exposé à des outils locaux ou dans une copie du projet. Notre guide des variables Compose explique l’interpolation, env_file et les valeurs d’environnement des conteneurs.
Compose peut aussi lire un secret depuis une variable d’environnement hôte avec secrets.<nom>.environment. Cela n’injecte pas automatiquement sa valeur dans l’environnement du conteneur. L’autorisation du service et la lecture applicative restent nécessaires. Protégez l’hôte et l’environnement CI d’origine.
Un identifiant nécessaire pendant la construction d’une image relève du mécanisme de secrets BuildKit. Fournissez-le comme secret de build et utilisez un montage secret dans l’étape concernée. Ne transmettez pas l’identifiant par un ARG ou ENV du Dockerfile. Vérifiez aussi que la commande de build ne copie pas la valeur montée dans un artefact de sortie.
Les secrets Docker Swarm utilisent un autre mécanisme, avec chiffrement en transit et au repos dans le swarm. Ces garanties ne s’appliquent pas à l’exemple Compose local fondé sur un fichier. De même, docker secret create est une commande Swarm, pas un prérequis de la procédure docker compose run présentée ici.
Modifier un fichier hôte ne prouve pas qu’une application en cours d’exécution a relu la valeur. Suivez sa procédure de rechargement ou recréez le service concerné si nécessaire. Docker Compose up permet de forcer la recréation, mais cela ne traite que le conteneur : le fournisseur de l’identifiant et l’application doivent aussi accepter le remplacement.
Si le fournisseur accepte temporairement plusieurs identifiants, introduisez le nouveau, vérifiez son authentification, puis révoquez le précédent. En cas de fuite, suivez sa procédure de révocation plutôt que de compter sur la suppression d’un fichier local.
Pour le diagnostic, notez le service, le nom du secret, la cible, l’utilisateur du conteneur et le résultat de lecture. N’affichez pas le jeton avec cat et ne l’incluez pas dans un lot de diagnostic. Notre guide Docker logs traite la lecture et la conservation des journaux. Un fichier monté et lisible est une étape ; l’authentification et la rotation vérifiée sont des contrôles distincts.
Choisissez une charge de travail d’IA, de calcul ou de stockage à tester sur Hivenet, ou échangez avec notre équipe sur sa mise en production.