Docs / Containers & Docker / Managing Docker Compose Secrets

Managing Docker Compose Secrets

By Admin · Mar 15, 2026 · Updated Apr 23, 2026 · 250 views · 3 min read

Docker Compose secrets provide a secure way to pass sensitive data (passwords, API keys, certificates) to containers without embedding them in images, environment variables, or Compose files. Secrets are mounted as files inside containers and are never exposed in logs or inspect output. This guide covers secrets management for both Swarm mode and standalone Compose.

Secrets in Docker Compose (Standalone)

# docker-compose.yml
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

  app:
    build: .
    secrets:
      - db_password
      - api_key
      - source: tls_cert
        target: /etc/ssl/app/cert.pem
        mode: 0444

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    file: ./secrets/api_key.txt
  tls_cert:
    file: ./secrets/tls_cert.pem

Reading Secrets in Applications

# Secrets are mounted at /run/secrets/

# Bash
DB_PASSWORD=$(cat /run/secrets/db_password)

# Python
with open('/run/secrets/db_password') as f:
    db_password = f.read().strip()

# Node.js
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();

# PHP
$dbPassword = trim(file_get_contents('/run/secrets/db_password'));

# Many official images support _FILE suffix for environment variables
# PostgreSQL, MySQL, MariaDB all support this pattern:
environment:
  POSTGRES_PASSWORD_FILE: /run/secrets/db_password
  # Instead of: POSTGRES_PASSWORD: plaintext_password

Docker Swarm Secrets

# Create secrets in Swarm
echo "MyDBPassword" | docker secret create db_password -
docker secret create tls_key /path/to/key.pem

# List secrets
docker secret ls

# Use in stack
secrets:
  db_password:
    external: true   # References existing Swarm secret

# Rotate a secret
echo "NewPassword" | docker secret create db_password_v2 -
docker service update --secret-rm db_password --secret-add db_password_v2 myservice

Environment Variables vs Secrets

# BAD: Sensitive data in environment variables
services:
  app:
    environment:
      DB_PASSWORD: "plaintext_visible_in_inspect_and_logs"
      # Visible in: docker inspect, docker compose config, process listing

# GOOD: Sensitive data as secrets
services:
  app:
    secrets:
      - db_password
    # Only accessible via /run/secrets/db_password inside container
    # Not visible in inspect, logs, or process listing

Secret File Management

# Project structure
project/
├── docker-compose.yml
├── secrets/
│   ├── .gitignore          # Contains: *
│   ├── db_password.txt
│   ├── api_key.txt
│   └── tls_cert.pem
└── ...

# secrets/.gitignore
*
!.gitignore

# Never commit secrets to version control
# Use .env files for non-sensitive configuration only

Advanced: HashiCorp Vault Integration

# Use Vault to populate secrets at deployment time
#!/bin/bash
# deploy.sh
vault kv get -field=password secret/myapp/db > secrets/db_password.txt
vault kv get -field=key secret/myapp/api > secrets/api_key.txt
docker compose up -d
# Clean up plaintext files after containers read them
rm -f secrets/db_password.txt secrets/api_key.txt

Best Practices

  • Never store secrets in environment variables, Dockerfiles, or image layers
  • Use the _FILE suffix pattern supported by official database images
  • Add secrets/ to .gitignore to prevent accidental commits
  • Set restrictive file permissions on secret files (mode: 0400)
  • In Swarm mode, use external secrets for production deployments
  • Rotate secrets regularly and update services to use new versions
  • Use a secrets manager (Vault, AWS Secrets Manager) for enterprise deployments

Was this article helpful?