Lesson 6 of 30
Environment variables solve where config comes from. This lesson is narrower and sharper: which of Docker's several ways to get a value into a container also leaves that value sitting somewhere readable, permanently, by accident.
13 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
A Dockerfile writes a secret to a file with `RUN echo $TOKEN > .npmrc && npm install`, then a later instruction runs `RUN rm .npmrc`. Is the secret actually gone from the image?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
A general "environment variables let the same code behave differently per environment" answer is necessary but not sufficient once a container is involved — because a container adds a real, specific question earlier lessons in this track already brushed against: does this delivery mechanism leave the value recoverable from the image itself, after the fact?
Three mechanisms, three different answers:
ENV in a Dockerfile — baked into every layer from that point forward, in the image itself. Anyone who can pull or inspect the image can read it. Never the place for a secret, only for non-sensitive defaults.docker run -e KEY=value / --env-file — supplied at container-start time, not baked into the image. Better than ENV for anything sensitive, but still visible via docker inspect on the running container, and often visible in shell history or process listings depending on how it was passed.RUN --mount=type=secret) — a secret is made available only to one specific RUN instruction, during the build, and is never written to any layer, never appears in docker history, and isn't baked into the final image at all.# WRONG — this secret is now permanently in the image's layer history
ARG NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > .npmrc && npm install
# RIGHT — the secret exists only during this one instruction, in no layer
RUN --mount=type=secret,id=npm_token \
NPM_TOKEN=$(cat /run/secrets/npm_token) npm install
The first version's token ends up recoverable from the image forever — docker history --no-trunc (or simply pulling the image and inspecting its layers) reveals it, even if a later instruction deletes the .npmrc file, because that deletion is itself just another layer stacked on top of the one where the secret still exists underneath. The second version's secret is mounted as a file only for the duration of that one RUN, and BuildKit never persists it anywhere.
.env files should never be copied into an image (COPY .env . is a real, common mistake) — a .env file belongs in .dockerignore and gets supplied at runtime via --env-file or a Compose env_file: entry, never baked into the build.docker inspect on a running container reveals its runtime environment variables in plain text to anyone with access to the Docker daemon — runtime env vars are more contained than image-baked ones, but still not equivalent to a proper secret store with access control and rotation."We accidentally leaked an API key — it was in an ENV instruction in our Dockerfile" is a real, common incident category, and "how would you prevent that" is a genuine interview question in security-conscious teams. The strong answer names the specific mechanism (layers are cumulative, ENV/ARG persist in image history) and the specific fix (BuildKit secret mounts for build-time, orchestrator secrets for runtime) rather than a vague "use environment variables instead of hardcoding."