·11 min read

Docker Secrets Management: Secure Credential Handling in Containers

Stop hardcoding passwords in Dockerfiles. Learn Docker secrets, environment variables, secret files, and integration with external vaults.

DockerPodmanSecuritySecretsDevOps

Hardcoding passwords in Docker images or compose files is a security disaster waiting to happen. Proper secrets management keeps credentials secure, rotatable, and auditable.

The Problem: Insecure Secrets

Bad Practice 1: Hardcoded in Dockerfile

# ❌ NEVER DO THIS
ENV DB_PASSWORD=supersecret123
ENV API_KEY=sk-1234567890abcdef

Why it's bad:

  • Secrets in image layers (visible with docker history)
  • Pushed to registries with secrets exposed
  • Can't rotate without rebuilding image

Bad Practice 2: Hardcoded in Compose File

# ❌ NEVER DO THIS
services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: supersecret123

Why it's bad:

  • Compose file in version control
  • Secrets visible to anyone with repo access
  • Same password across all environments

Bad Practice 3: .env File in Repo

# ❌ .env in git repo
DB_PASSWORD=supersecret123
API_KEY=sk-1234567890abcdef

Why it's bad:

  • Accidentally committed to git
  • Visible in pull requests
  • Shared with entire team

Docker Secrets (Swarm Mode)

Docker Swarm provides native secrets management.

Creating Secrets

# Create secret from string
echo "supersecret123" | docker secret create db_password -

# Create secret from file
docker secret create api_key ./api_key.txt

# List secrets
docker secret ls

# Inspect secret (metadata only, not value)
docker secret inspect db_password

Using Secrets in Services

# docker-compose.yml (Swarm mode)
version: '3.8'

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

  api:
    image: myapp
    environment:
      API_KEY_FILE: /run/secrets/api_key
    secrets:
      - api_key

secrets:
  db_password:
    external: true
  api_key:
    external: true

Deploy:

docker stack deploy -c docker-compose.yml myapp

How Secrets Work

  1. Secrets stored encrypted in Raft log
  2. Only sent to nodes running services that need them
  3. Mounted in memory at /run/secrets/<secret_name>
  4. Not written to disk
  5. Not visible in docker inspect

Accessing Secrets in Code

# Python example
def get_secret(secret_name):
    secret_path = f'/run/secrets/{secret_name}'
    with open(secret_path, 'r') as f:
        return f.read().strip()

db_password = get_secret('db_password')
api_key = get_secret('api_key')
// Node.js example
const fs = require('fs');

function getSecret(secretName) {
    return fs.readFileSync(`/run/secrets/${secretName}`, 'utf8').trim();
}

const dbPassword = getSecret('db_password');

Docker Compose Secrets (Non-Swarm)

Docker Compose supports secrets without Swarm.

File-Based Secrets

# docker-compose.yml
version: '3.8'

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./secrets/db_password.txt

Create the secret file:

mkdir -p secrets
echo "supersecret123" > secrets/db_password.txt
chmod 600 secrets/db_password.txt

Add to .gitignore:

# .gitignore
secrets/

External Secrets

version: '3.8'

services:
  db:
    image: postgres
    secrets:
      - db_password

secrets:
  db_password:
    external: true

Create secret first:

docker secret create db_password ./secrets/db_password.txt

Environment Variables (Better Than Nothing)

If you can't use Docker secrets, use environment variables with .env files.

.env File

# .env (NOT in git)
DB_PASSWORD=supersecret123
API_KEY=sk-1234567890abcdef

Compose File

# docker-compose.yml
version: '3'

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD: ${DB_PASSWORD}
  
  api:
    image: myapp
    environment:
      API_KEY: ${API_KEY}

Security Measures

# Restrict .env file permissions
chmod 600 .env

# Add to .gitignore
echo ".env" >> .gitignore

# Verify not in git
git check-ignore .env
# Should output: .env

Podman Secrets

Podman provides similar secrets management.

Creating Secrets

# Create secret
echo "supersecret123" | podman secret create db_password -

# List secrets
podman secret ls

# Inspect
podman secret inspect db_password

Using Secrets

# containers.conf or compose file
version: '3.8'

services:
  db:
    image: postgres
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - source: db_password
        target: db_password

External Secret Managers

For production, integrate with dedicated secret managers.

HashiCorp Vault

# Start Vault server
vault server -dev

# Store secret
vault kv put secret/myapp/db password=supersecret123

# Retrieve secret
vault kv get secret/myapp/db

Integration with Docker:

import hvac

client = hvac.Client(url='http://vault:8200', token='your-token')
secret = client.secrets.kv.v2.read_secret_version(path='myapp/db')
db_password = secret['data']['data']['password']

AWS Secrets Manager

import boto3

client = boto3.client('secretsmanager')
response = client.get_secret_value(SecretId='myapp/db-password')
db_password = response['SecretString']

Azure Key Vault

from azure.keyvault.secrets import SecretClient
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()
client = SecretClient(vault_url='https://myvault.vault.azure.net/', credential=credential)
db_password = client.get_secret('db-password').value

Google Secret Manager

from google.cloud import secretmanager

client = secretmanager.SecretManagerServiceClient()
name = f'projects/my-project/secrets/db-password/versions/latest'
response = client.access_secret_version(name=name)
db_password = response.payload.data.decode('UTF-8')

Secret Rotation

Rotate secrets regularly without downtime.

Manual Rotation

# 1. Create new secret
echo "newpassword123" | docker secret create db_password_v2 -

# 2. Update service to use new secret
docker service update \
  --secret-rm db_password \
  --secret-add db_password_v2 \
  myapp_db

# 3. Remove old secret
docker secret rm db_password

# 4. Rename new secret (optional)
docker secret create db_password - <<EOF
newpassword123
EOF

Automated Rotation

#!/bin/bash
# rotate-secrets.sh

# Generate new password
new_password=$(openssl rand -base64 32)

# Create new secret
echo "$new_password" | docker secret create db_password_new -

# Update service
docker service update \
  --secret-rm db_password \
  --secret-add db_password_new \
  myapp_db

# Wait for rollout
sleep 10

# Remove old secret
docker secret rm db_password

# Rename
docker secret create db_password - <<< "$new_password"
docker secret rm db_password_new

FoxTerm Secrets Management

FoxTerm simplifies secrets management for Docker/Podman.

Visual Secrets Editor

  • View all secrets in Compose stacks
  • Edit secret values securely
  • Rotate secrets with one click
  • Audit log of secret access

Secure Storage

  • Secrets stored in macOS Keychain
  • Encrypted at rest
  • Biometric authentication required
  • Never logged or displayed in plain text

Integration

  • Auto-detect secret references in compose files
  • Prompt to create missing secrets
  • Validate secret permissions
  • Sync secrets across environments

Best Practices

  1. Never hardcode secrets — Use Docker secrets or external managers
  2. Rotate regularly — Change passwords every 90 days
  3. Limit access — Only grant secrets to services that need them
  4. Audit access — Log who accessed what secrets when
  5. Use strong secrets — 32+ characters, random generation
  6. Separate environments — Different secrets for dev/staging/prod
  7. Encrypt at rest — Use encrypted storage for secret files
  8. Use secret managers — Vault, AWS Secrets Manager, etc. for production

Conclusion

Secure secrets management is non-negotiable for production containers. Docker secrets, Podman secrets, and external vaults provide the tools you need to keep credentials secure.

FoxTerm makes secrets management visual and secure, with Keychain integration and one-click rotation.


FoxTerm Pro includes secrets management for Docker/Podman. Download at foxterm.app.