Managing Secrets

Keep passwords and API keys out of images; inject them at runtime through environment variables, mounted files or secret stores.

Credentials such as passwords, API keys and certificates are secrets. They must never be baked into an image, where anyone who pulls it can read them.

What not to do

  • Do not put secrets in ENV or ARG in a Dockerfile — they persist in image layers.
  • Do not commit .env files to source control.

Safer approaches

  • Pass secrets at runtime with --env-file or the orchestrator's secret system.
  • Mount secrets as files with Docker/Compose secrets, which appear under /run/secrets.
  • Use a dedicated secret manager (Vault, cloud secret stores).

Example

Example · yaml
services:
  db:
    image: postgres:16
    environment:
      POSTGRES_PASSWORD_FILE: /run/secrets/db_password
    secrets:
      - db_password

secrets:
  db_password:
    file: ./db_password.txt

When to use it

  • A developer uses a .env file for local development secrets but ensures it is listed in both .gitignore and .dockerignore.
  • A production team uses Docker Swarm secrets to mount a database password as a file at /run/secrets/db_password inside the container.
  • A CI pipeline injects API keys as environment variables from a secrets manager at deploy time, never baking them into the image.

More examples

Inject secret via environment variable

Fetches the secret from AWS Secrets Manager at deploy time and passes it as an env var, never storing it in the image.

Example · bash
# Read secret from a secrets manager at deploy time
export DB_PASSWORD=$(aws secretsmanager get-secret-value \
  --secret-id prod/db-password --query SecretString --output text)

docker run -d \
  -e DB_PASSWORD="$DB_PASSWORD" \
  myapp:latest

Use Docker Swarm secret

Stores the password encrypted in Swarm and mounts it as a file in the container's /run/secrets directory.

Example · bash
# Create the secret
echo 'supersecret' | docker secret create db_password -

# Reference it in a service
docker service create \
  --name api \
  --secret db_password \
  myapp:latest
# Available inside container at /run/secrets/db_password

Never bake secrets in image (anti-pattern)

Illustrates the anti-pattern of setting secrets in ARG/ENV during build, and the correct approach of injecting at runtime.

Example · dockerfile
# WRONG: secret is burned into image layer history
# ARG DB_PASSWORD
# ENV DB_PASSWORD=$DB_PASSWORD
# RUN echo "password: $DB_PASSWORD" > /config.yaml

# CORRECT: leave placeholder, inject at runtime
ENV DB_PASSWORD=''
CMD ["node", "index.js"]

Discussion

  • Be the first to comment on this lesson.