This is a pracยญtiยญcal patยญtern I use when conยญtainerยญized apps expect enviยญronยญment variยญables but I want the secuยญriยญty benยญeยญfits of file-โmounted secrets. Drop the shell script below next to your Docker Compose files and you can do the same.
Quick overview
Secrets like passยญwords and API keys belong outยญside your reposยญiยญtoยญry and appliยญcaยญtion image layยญers. Docker Compose can mount such secrets in your conยญtainยญers as files under /run/secrets, which keeps them out of images and verยญsion conยญtrol. But many apps still expect conยญfigยญuยญraยญtion via enviยญronยญment variยญables. Rather than changยญing app code, I use a tiny wrapยญper script that:
- reads every file in
/run/secrets - exports each fileโs conยญtents as an enviยญronยญment variable
- then
execs the origยญiยญnal command
Itโs small, preยญdictable, portable, and keeps secrets from mixยญing with your verยญsioned .env enviยญronยญment files and out of your Compose files.
How it works
- Location: Docker Compose mounts secrets into the conยญtainยญer at
/run/secrets/<NAME>. - Mapping rule: The wrapยญper uses those file names as enviยญronยญment variยญable names; the file conยญtents become the valยญues. Secret names in your Compose file must be valid shell idenยญtiยญfiers (they become both the file names in
/run/secretsand the exportยญed variยญable names). - Execution: After exportยญing variยญables, the script uses
exec "$@"so that the wrapped process replaces the shell and inherยญits the exportยญed environment. - Security modยญel: Secrets remain files you can perยญmisยญsion approยญpriยญateยญly on the host; theyโre not baked into images or stored in your Compose YAML as plain text.
The script
Letโs call it with-secrets.sh:
#!/bin/sh
set -eu
for secret_file in /run/secrets/*; do
[ -e "$secret_file" ] || continue
if [ -f "$secret_file" ]; then
name=$(basename "$secret_file")
export "$name=$(cat "$secret_file")"
fi
done
exec "$@"
Notes about the script
set -eufails fast on unset variยญables or errors.- Since it exports each secret using the file name as the variยญable name, sanยญiยญtize the file name if you need difยญferยญent enviยญronยญment variยญable names.
- The final
exechands conยญtrol to your app withยญout leavยญing an extra shell process.
Example Compose snippet
services:
app:
image: your-app:latest
secrets:
- DB_PASS
- API_KEY
volumes:
- ./with-secrets.sh:/with-secrets.sh:ro
command: ["/with-secrets.sh", "your-original-command", "--with-args"]
secrets:
DB_PASS:
file: ./secrets/db_password.txt
API_KEY:
file: ./secrets/api_key.txt
Behavior: DB_PASS and API_KEY above appear as files (/run/secrets/DB_PASS, /run/secrets/API_KEY); the mountยญed with-secrets.sh wrapยญper script exports them as DB_PASS and API_KEY enviยญronยญment variยญables for your-original-command --with-args.
Decision points and alternatives
- Prefer native
*_FILEsupยญport if your app supยญports it (e.g., PostgreSQLโsPGPASSFILE). That avoids the wrapยญper entirely. - For multi-โhost or high-โcompliance deployยญments, use an exterยญnal secrets manยญagยญer (e.g., Hashicorp Vault, cloud KMS, SOPS) rather than Compose secrets.
- Build-โtime secrets are a sepยญaยญrate conยญcern; use BuildKit or dedยญiยญcatยญed build secret mechยญaยญnisms to avoid leakยญing creยญdenยญtials into your image layers.
Risks and mitigations
- Risk: Accidentally logยญging or dumpยญing enviยญronยญment variยญables
Mitigation: Never print enviยญronยญment variยญables in logs and restrict debug output - Risk: Secret file names that are not valid shell idenยญtiยญfiers
Mitigation: Normalize or map file names to safe enviยญronยญment variยญable names before exporting - Risk: Secrets checked into
gitor othยญer verยญsion conยญtrol
Mitigation: Keep secret files out of repos, add strict.gitignorerules, and inject secrets via CI/โCD or runยญtime provisioning
Final notes
This patยญtern is intenยญtionยญalยญly pragยญmatยญic: it preยญserves the secuยญriยญty advanยญtage of file-โmounted secrets while letยญting unmodยญiยญfied apps keep using enviยญronยญment variยญables. Itโs not a silยญver bulยญlet for every environmentโuse it where Compose secrets are approยญpriยญate and pair it with stronger secret stores for production-โgrade, multi-โhost deployments.

