Secrets: Never Bake Them In
Build-time ARG and ENV values are stored in image layers forever; use BuildKit secret mounts for build secrets and runtime injection for the rest.
The most common Docker security mistake is putting a secret in the Dockerfile. Anything in an ARG, ENV, or a RUN that echoes a token is permanently visible in the image history — anyone with the image can run docker history and read it.
Build-time secrets: use BuildKit mounts
When you genuinely need a secret during the build (a private registry token, an SSH key to pull a private repo), use RUN --mount=type=secret. The secret is mounted into that one command's filesystem and never written to any layer.
Runtime secrets: inject, don't bake
- Pass them at
docker runtime via--env-fileor your orchestrator's secret store. - In Compose and Swarm, use the
secrets:block, which mounts them at/run/secrets/. - In Kubernetes, use Secrets or an external manager (Vault, cloud secret managers).
Example
# syntax=docker/dockerfile:1
FROM alpine:3.20
# The secret is mounted only for THIS command and never stored in a layer
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) \
&& echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > ~/.npmrc \
&& npm ci \
&& rm ~/.npmrc
# Build it by passing the secret from a file or env var:
# docker build --secret id=npm_token,src=./npm_token.txt -t myapp .
# docker build --secret id=npm_token,env=NPM_TOKEN -t myapp .When to use it
- A developer uses a BuildKit secret mount to pass an npm token to npm install without storing it in any image layer.
- A CI pipeline injects SSH keys via BuildKit ssh agent forwarding so private Git dependencies can be cloned during build without baking keys.
- A production team uses Docker Swarm secrets to provide a TLS private key to a container as a file, never as an environment variable.
More examples
BuildKit secret mount for npm token
Mounts the npm token as a BuildKit secret that is available only during this RUN step and never stored in the image.
# syntax=docker/dockerfile:1
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) \
npm config set //registry.npmjs.org/:_authToken $NPM_TOKEN \
&& npm ci --omit=devPass secret during docker build
Injects an environment variable as a BuildKit build secret, making it available to RUN --mount=type=secret steps.
# Pass the secret from an environment variable
docker buildx build \
--secret id=npm_token,env=NPM_TOKEN \
-t myapp:latest .SSH agent forwarding during build
Forwards the host SSH agent into the build so private Git repos can be cloned without copying any key files.
# Ensure the ssh-agent is running with a key loaded
ssh-add ~/.ssh/id_rsa
docker buildx build \
--ssh default=$SSH_AUTH_SOCK \
-t myapp:latest .
Discussion