C.W.K.
Stream
Lesson 02 of 03 · published

Secrets — Don't Bake, Don't Commit

~14 min · security, secrets

Level 0Container Curious
0 XP0/36 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

Three things you must never do

  1. ENV API_KEY=... in a Dockerfile — bakes the secret into a layer of the image. Anyone with the image has the key.
  2. Hard-coded environment: in compose.yaml committed to git — the secret is now in your repo history forever.
  3. Pass secrets via --build-arg for runtime use — ARG values are visible in the build history of the image.

Three things you should do

  1. Local dev: a .env file referenced by compose, with .env in .gitignore.
  2. CI/CD: secrets injected by the pipeline (GitHub Actions secrets, GitLab CI variables) into the runtime environment, never into the image.
  3. Production: a real secrets manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault, sealed-secrets in k8s) — secrets fetched at startup, never written to disk.

Code

compose with .env (dev)·yaml
# .env (in .gitignore, never committed)
# DB_PASSWORD=secret
# API_KEY=sk-real-key-here

# compose.yaml
services:
  api:
    image: myapi:1.0
    environment:
      DB_PASSWORD: ${DB_PASSWORD}
      API_KEY: ${API_KEY}

# Compose auto-loads .env from the same directory.
BuildKit secrets — for build-time only·dockerfile
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app

COPY requirements.txt .
# Mount a secret only during this RUN — not stored in image
RUN --mount=type=secret,id=pip_creds \
    pip install --no-cache-dir -r requirements.txt \
      --index-url https://$(cat /run/secrets/pip_creds)@private.example.com/pypi

COPY . .
CMD ["python", "main.py"]

# Build with:
#   echo 'user:token' | docker build --secret id=pip_creds,src=/dev/stdin -t myapp .

External links

Exercise

Find a project of yours where credentials end up in a Dockerfile, compose.yaml, or anywhere committed to git. Move them into a .env (gitignored) for dev and document — in a README — how production should fetch them from a real secret store. Show the diff.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.