Docker build secrets – first impressions

Docker is a powerful tool that can solve many problems. However, when you need secrets during docker build time, you will often face some difficulty. To provide a solution to this, docker has introduced build secrets. In this blog post, I introduce the basic usage of docker build secrets and share some first impressions.

The utility of docker comes from it’s ability to replicate the same environment wherever it runs. This is typically a great advantage as you get rid of the nasty “works on my machine” situations. But when you need user access credentials or other similar secrets, it becomes a disadvantage. While you want to share your environment with others, you don’t want to share your credentials.

If you need credentials only during run-time, you have many convenient options to choose from. For example, you can inject credentials as environment variables or mount a file or folder containing them. However, when the credentials are required during build time, you will have a harder time because docker preserves all data on every image layer.

Docker build secrets are a BuildKit extension. Therefore, you will need to enable the extension by setting the DOCKER_BUILDKIT environment variable:

DOCKER_BUILDKIT=1 docker build .

The secrets are shared using files. Insert your secret into a file:

echo "VERY_SECRET_DATA" > mysecret

Instruct docker build to provide the secret for layers that use it:

docker build --secret id=the_secret,src=mysecret .

To use the secret in a layer in a Dockerfile, pass --mount to a RUN:

RUN --mount=type=secret,id=the_secret cat /run/secret/the_secret

By default, the secret will be available in a file located at /run/secret/<id>. You can change the location by providing the extra specifier dst=<path>.

Note that the secret is ephemeral by nature and is accessible only during the build time of the layer. It will not persist in the generated image layer. You can write it to a file, but that would be pointless as that’s what we wanted to avoid in the first place.

So, how can you use this for something productive? At work we needed to clone a private repository during build time. As we didn’t want to leave any credentials in the generated docker image layers, we decided to use docker build secrets. First, we setup a git credentials helper:

RUN git config --global credential.helper \ '!f() { \ echo "username=x-access-token"; \ echo "password=$(cat /run/secrets/github_token)"; \ }; \ f'

Note that the configuration of the credentials helper is set to retrieve the secret when it is needed. Therefore, we don’t need to pass the secret at this stage. More importantly, even though we store the configuration into the filesystem, we don’t store the secret itself.

Next, we do the clone itself:

RUN --mount=type=secret,id=github_token git clone https://github.com/omoroifi/

During run-time of this layer, the secret is accessible. However, git clone will only retrieve the secret when it is needed, but does not store it into any logs or similar. This way we were able to securely clone a private git repository without leaving the credentials in the image layers.

My first impression using the docker build secrets is that it is a powerful feature, but rather inconvenient. The risk of failure seems rather high and I would not risk using important secrets without having a secondary check in place that ensures the images are clean of secrets before upload. Then again, if you already have automatic scanning for your images, docker build secrets can be of good use!

You can find our example repository at https://github.com/omoroifi/docker-build-secrets-public.

Previous
Previous

Software Testing Blog Series – The Beginning

Next
Next

Delphi 25 v!