Secrets with Docker and BuildKit (with NPM)

Posted Tuesday, April 6, 2021.

In a previous post, Docker with private NPM dependencies we discussed how to inject an NPM token into the Dockerfile for private dependency resolution.

Requirements can be found in previous post SSH with Docker and BuildKit. Here is how to adjust the previous project to use the --secret option for both local builds and on GitHub actions.

Dockerfile/Project Changes


From Docker with private NPM dependencies, our Dockerfile looked as such:

FROM node:14


COPY . ./
COPY ./.npmrc-deploy ./.npmrc
RUN yarn && yarn build

We created a file in the root of the project called .npmrc-deploy that looked as such:


This could be built using docker build --build-arg NPM_TOKEN="$(cat ~/.npm/github_token)" -t hiimtmac/cool-app .


Using the new --secret option, we can adjust our Dockerfile to look like this:

FROM node:14

COPY . ./
RUN --mount=type=secret,id=github,dst=/root/.npmrc yarn && yarn build

In this case we will adjust the .npmrc setup. Change .npmrc-deploy's filename to just .npmrc and delete the auth token line so it only specifies where the registries are located:


Additionally, make a new file at ~/.npm/github_npmrc with the contents of the old token file (~/.npm/github_token) but with the auth token line:


We are breaking these up so the secret can be leveraged on GitHub actions and locally without the need to be changed (unless you invalidate the token) as the project changes, and can remain in source control (no token in it, only the dependency locations). This way, if the dependencies change for this specific project and hence the project .npmrc changes, you can edit the project specific .npmrc file and not have to change the secret both locally and on GitHub.

This could be built using docker build --secret id=github,src=$HOME/.npm/github_npmrc -t hiimtmac/cool-app .. Any RUN command that needs secret access (in this case the RUN yarn && yarn build command) needs to have --mount=type=secret,id=... in the beginning.

The authorization token will be picked up from /root/.npmrc where it is by default expected to be found, and the dependency locations will be picked up from the local .npmrc file. The benefit here is that because the secret info was injected as a BuildKit secret, we dont have to worry about that file being leaked and part of a layer where it can be inspected later.

GitHub Actions


You will have to make a secret on GitHub called CICD_NPMRC with the contents: //


Similar to GitHub actions with private SPM dependencies, we can make an actions workflow that looks like this:

name: docker-deploy

- "*"

runs-on: ubuntu-latest
- name: Set Tag
run: echo "TAG=${GITHUB_REF##*/}" >> $GITHUB_ENV
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Login to DockerHub
uses: docker/login-action@v1
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
push: true
tags: |
hiimtmac/fake-repo:${{ env.TAG }}
secrets: |
github=${{ secrets.CICD_NPMRC }}
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

In Closing

Some further reading about NPM and secrets in the new BuildKit can be found here, I used these resources to put together this solution:

As always, if you know of a better way to do something, please let me know!

Tagged With: