Objective
Source a database password from a file rather than an env var,
so it does not appear in docker inspect or process listings.
Tasks
Task 1: Project setup
mkdir -p ~/compose-secret-lab && cd ~/compose-secret-lab
echo 'supersecretpassword' > db_pw.txt
chmod 0400 db_pw.txt
Task 2: Compose file
# compose.yml
services:
db:
image: postgres:16
environment:
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD_FILE: /run/secrets/db_pw
secrets:
- db_pw
volumes:
- pgdata:/var/lib/postgresql/data
secrets:
db_pw:
file: ./db_pw.txt
volumes:
pgdata:
Task 3: Bring up and verify
docker compose up -d
sleep 10
docker compose exec db ls -la /run/secrets/
docker compose exec db cat /run/secrets/db_pw
# supersecretpassword
Task 4: Confirm the secret is not in docker inspect
docker inspect compose-secret-lab-db-1 | grep -i password
# No output — the password is not in the inspect JSON
docker inspect compose-secret-lab-db-1 --format '{{json .Config.Env}}' | jq -r '.[]'
# POSTGRES_DB=app
# POSTGRES_USER=app
# POSTGRES_PASSWORD_FILE=/run/secrets/db_pw
# PATH=/usr/local/sbin:/usr/local/bin:...
The password itself never appears. Only the path to its file.
Task 5: Confirm world-readability
docker compose exec db ls -la /run/secrets/db_pw
# -r--r--r-- 1 root root 21 Aug 9 12:00 /run/secrets/db_pw
By default, secrets are readable by anyone in the container. If your application’s UID is not root, run the container as a specific user:
services:
db:
user: "70:70" # postgres user in the container
Task 6: Cleanup
docker compose down --volumes