BY Y!an - February 5, 2025

Securely and Elegantly Passing Sensitive Data with Build Secrets When Building Docker Images

Stay elegant, and stay safe.

It all started like this: I have a utils library written in Go, but this repository is currently private. Consequently, when other projects that reference this library are built, I need to solve the issue of authentication for access.

First, let’s look at a Dockerfile for building a Go project that doesn’t use private libraries:

# build api
FROM golang:1.23 AS builder

WORKDIR /src/app

COPY . ./ 

RUN --mount=type=cache,target=/go/pkg/mod \
    make

# build the final image
FROM ubuntu:24.04

COPY --from=builder /src/app/bin/api /app/bin/api

However, if a private library is used, you need to set the GOPRIVATE environment variable and authentication.

During local development, I use ssh to access git repositories, so I can just append the following configuration to ~/.gitconfig:

[url "git@github.com:"]
    insteadOf = https://github.com/

But continuing to use ssh during Docker builds is slightly troublesome (using a Deploy key) and insecure (using a personal account’s SSH key). Thus, a fine-grained Access Token would be a better choice.

Since an Access Token is sensitive data, we cannot write it directly in the Dockerfile. So, you might think of passing it in through build parameters:

+ARG GITHUB_TOKEN
+ENV TOKEN=$GITHUB_TOKEN

 WORKDIR /src/app

 COPY . ./ 

+RUN go env -w GOPRIVATE="github.com/YianAndCode/MY_PRIVATE_GO_PKG"

+RUN git config --global url."https://${TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/"

 RUN --mount=type=cache,target=/go/pkg/mod \
    make

Then build:

export GITHUB_TOKEN=xxx
docker build --build-arg GITHUB_TOKEN=${GITHUB_TOKEN} -t myapp:latest .

At this point, you’ll get a warning:

WARN: SecretsUsedInArgOrEnv: Do not use ARG or ENV instructions for sensitive data

Because by doing this, others can see the parameters used during your build process after obtaining the image, which is also insecure. Actually, the Docker official documentation introduces Build secrets. We can use this feature to pass sensitive data more securely and elegantly.

First, let’s learn some basics about build secrets:

1. How to pass secrets

Pass them via --secret when executing docker build. Format:

# Pass via file
--secret id={ID},src=/path/to/secret_file

# Pass via environment variable
--secret id={ID},env=SECRET_ENV_NAME

# If the id is the same as the environment variable name, it can be shortened
--secret id=SECRET_ENV_NAME

Complete example:

# Pass the environment variable KUBECONFIG as a secret, secret id is kube
docker build --secret id=kube,env=KUBECONFIG .

2. How to get secrets in the Dockerfile

The id from before is used in the Dockerfile to retrieve the secret. In the Dockerfile, you need to mount it first: RUN --mount=type=secret,id={ID}. By default, it will be placed as a file in /run/secrets/{ID}:

RUN --mount=type=secret,id={ID} \
    cat /run/secrets/{ID}

The output of cat in the above Dockerfile can be seen by adding --progress=plain:

HELLO="Hello world!" docker build --progress=plain --secret id=HELLO .

Remember to delete the useless image from this test build.

You can also specify the file location via the target option or make the passed secret an environment variable via the env option:

# Specify file
RUN --mount=type=secret,id={ID},target=/path/to/secret_file \
    cat /path/to/secret_file

# As environment variable
RUN --mount=type=secret,id={ID},env=SECRET_ENV_NAME \
    echo ${SECRET_ENV_NAME}

After learning about Build secrets, let’s modify the Dockerfile for building the Go project we had at the beginning:

# build api
FROM golang:1.23 AS builder

WORKDIR /src/app

COPY . ./ 

RUN go env -w GOPRIVATE="github.com/YianAndCode/MY_PRIVATE_GO_PKG"

RUN --mount=type=secret,id=GITHUB_TOKEN,env=GITHUB_TOKEN \
    git config --global url."https://${GITHUB_TOKEN}:x-oauth-basic@github.com/".insteadOf "https://github.com/"

RUN --mount=type=cache,target=/go/pkg/mod \
    make

# build the final image
FROM ubuntu:24.04

COPY --from=builder /src/app/bin/api /app/bin/api

If you found this article helpful, you can buy me a coffee ↓