This topic has been discussed at length before, with different solutions1, but it still seems difficult re-assuring engineers that it's possible and safe to use secret environment variables during docker builds. It seems hotly debated if secrets should ever be in environment variables, with some saying all config goes in env2 and others doing their best to make it hard for people to use environment variables3.
Let's step through an example of how to use Docker secrets to create secure environment variables for npm during a Dockerfile build:
This example copies in a npm package.json and package-lock.json file, for use with npm ci
Note: The backslash in the echo command allows echo to write the environment variable name to disk, instead expanding it
FROM node:20
ARG NPM_REPOSITORY
RUN echo "//${NPM_REPOSITORY}:_authToken=\${NPM_TOKEN}" >> ~/.npmrc
RUN npm config set registry "https://${NPM_REPOSITORY}"
COPY package.json .
COPY package-lock.json .
RUN --mount=type=secret,id=npmtoken \
NPM_TOKEN=$(cat /run/secrets/npmtoken) npm ci --env=production
Note from Docker's build secret docs: "When you use secrets from environment variables, you can omit the env parameter to bind the secret to a file with the same name as the variable."
When building, you'll need your package.json and package-lock.json in the same directory as the Dockerfile.
docker build --build-arg NPM_REPOSITORY="$NPM_REPOSITORY" --secret id=NPM_TOKEN --tag testbuild .
- Check the contents of ~/.npmrc:
docker run testbuild /usr/bin/env bash -c 'cat ~/.npmrc'
- Check the Docker image layer history:
docker history --no-trunc testbuild
This flow gives you the flexibility of environment variables, without the risk of committing them to the Docker image.
Happy sailing!