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

Original

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

FROM node:14

ARG NPM_TOKEN

WORKDIR /app
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:

//npm.pkg.github.com/:_authToken=${NPM_TOKEN}
@hiimtmac:registry=https://npm.pkg.github.com

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

Updated

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

FROM node:14

WORKDIR /app
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:

@hiimtmac:registry=https://npm.pkg.github.com

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:

//npm.pkg.github.com/:_authToken=SECRET_FROM_GITHUB_TOKEN_FILE_HERE

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

Secret

You will have to make a secret on GitHub called CICD_NPMRC with the contents: //npm.pkg.github.com/:_authToken=SECRET_FROM_GITHUB_TOKEN_FILE_HERE

Workflow

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

name: docker-deploy

on:
push:
tags:
- "*"

jobs:
release:
runs-on: ubuntu-latest
steps:
- 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
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
id: docker_build
uses: docker/build-push-action@v2
with:
push: true
tags: |
hiimtmac/fake-repo:${{ env.TAG }}
hiimtmac/fake-repo:develop
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: