Open this lesson in your favourite AI. It'll walk you through the why, explain the demo, and quiz you on the try-it list.
Twelve-factor config says "store config in the environment," and Docker gives you several ways to do that — ENV in the Dockerfile, -e on the command line, --env-file for bulk, and BuildKit secrets for build-time credentials. Mixing these up leaks AWS keys into image layers, which is one of the most common findings in image-scan tools. Knowing which mechanism is for what makes the difference between a clean container and a public-CVE waiting to happen.
Configure a containerized app with environment variables three ways and demonstrate why secrets should never go through ENV or --build-arg.
ENV API_KEY=hunter2 in a Dockerfile, build, then run docker history --no-trunc image — confirm the secret appears in plain text in the layer metadata.-e PORT=8080 and --env-file app.env together — note that -e flags override file values when both are present.docker run --rm cfg:v1 env to dump the environment and verify only the variables you set (plus PATH / HOSTNAME) are present.Use these three in order. Each builds on the one before.
In one paragraph, explain the four ways to get an environment variable into a container (ENV, -e, --env-file, BuildKit secret) and when to use each, like I'm new to it.
Walk me through how BuildKit's `--mount=type=secret` keeps a secret out of the final image even though `RUN` consumed it, step by step.
Given an existing image where a previous engineer baked an AWS access key into an `ENV` instruction, explain why rebuilding without it is not enough and what you must do to fully remediate the leak.
# A) Bake a default into the image (config, NOT secrets):
cat > Dockerfile <<'EOF'
FROM node:20-alpine
ENV PORT=3000 LOG_LEVEL=info
WORKDIR /app
COPY . .
CMD ["node", "server.js"]
EOF
docker build -t cfg:v1 .
# B) Override at run time with -e:
docker run --rm -e LOG_LEVEL=debug -e PORT=8080 -p 8080:8080 cfg:v1
# C) Bulk via --env-file (one VAR=value per line, no quotes):
cat > app.env <<'EOF'
LOG_LEVEL=warn
PORT=4000
DATABASE_URL=postgres://localhost:5432/app
EOF
docker run --rm --env-file app.env cfg:v1
# D) Secrets at BUILD time — use BuildKit secrets, NOT --build-arg:
echo "sk-prod-12345" > /tmp/api_key.txt
DOCKER_BUILDKIT=1 docker build \
--secret id=apikey,src=/tmp/api_key.txt \
-t cfg:withsecret -f - . <<'EOF'
# syntax=docker/dockerfile:1.7
FROM alpine:3.20
RUN --mount=type=secret,id=apikey cat /run/secrets/apikey | head -c4
EOF
# The secret is NOT in the final image:
docker history cfg:withsecret