A common problem for folks working with Docker is accessing resources which require authentication during the image build step. A particularly common use case is getting access to private git repositories using ssh key-based authentication. Until recently there hasn’t been a great solution:
- you can embed secrets in your image, but now you can’t share the image with anybody.
- you can use build arguments, but this requires passing in an unenecrypted private key on the
docker buildcommand line, which is suboptimal for a number of reasons
- you can perform all the steps requiring authentication at runtime, but this can needlessly complicate your container startup process.
With Docker 18.09, there are some experimental features available that makes this much easier. You can read the official announcement here, but I wanted to highlight the support for ssh agent forwarding and private keys.
In order to use the new features, you first need to explicitly enable BuildKit support by setting
DOCKER_BUILDKIT=1 in your environment:
And to utilize the new
Dockerfile syntax, you need to start your
Dockerfile with this directive:
That instructs Docker to use the named image (
docker/dockerfile:1.0.0-experimental) to handle the image build process.
A simple example
The most common use case will probably be forwarding access to your local ssh agent. In order for the build process to get access to your agent, two things must happen:
RUNcommand that requires credentials must specify
--mount=type=sshin order to have access to the forwarded agent connection, and
You must pass an appropriate
--sshoption on the
docker buildcommand line. This is to prevent a Dockerfile from unexpectedly gaining access to your ssh credentials.
We can see this in action if we start with the following
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN apk add --update git openssh # This is necessary to prevent the "git clone" operation from failing # with an "unknown host key" error. RUN mkdir -m 700 /root/.ssh; \ touch -m 600 /root/.ssh/known_hosts; \ ssh-keyscan github.com > /root/.ssh/known_hosts # This command will have access to the forwarded agent (if one is # available) RUN --mount=type=ssh git clone email@example.com:moby/buildkit
If we run build the image like this…
export DOCKER_BUILDKIT=1 docker build --ssh default -t buildtest .
git clone operation will successfully authenticate with github using our ssh private key, assuming that we had one loaded into our local ssh agent.
But wait, there’s more
In the previous example line, the
--ssh default option requests
docker build to forward your default ssh agent. There may be situations in which this isn’t appropriate (for example, maybe you need to use a key that isn’t loaded into your default agent). You can provide the
--ssh option with one or more paths to ssh agent sockets or (unencrypted) private key files. Let’s say you have two service-specific private keys:
- For GitHub, you need to use
- For BitBucket, you need to use
You can provide the keys on the
docker build command line like this:
docker build --ssh github=$HOME/.ssh/github_rsa,bitbucket=$HOME/.ssh/bitbucket_rsa -t buildtest .
Then inside your
Dockerfile, you can use the
id=<name> parameter to the
--mount option to specify which key should be available to the
# syntax=docker/dockerfile:1.0.0-experimental FROM alpine RUN apk add --update git openssh # This is necessary to prevent the "git clone" operation from failing # with an "unknown host key" error. RUN mkdir -m 700 /root/.ssh; \ touch -m 600 /root/.ssh/known_hosts; \ ssh-keyscan github.com bitbucket.com > /root/.ssh/known_hosts # This command has access to the "github" key RUN --mount=type=ssh,id=github git clone firstname.lastname@example.org:some/project # This command has access to the "bitbucket" key RUN --mount=type=ssh,id=bitbucket git clone email@example.com:other/project
In this post I’ve looked specfically at providing
docker build with access to your ssh keys. Docker 18.09 also introduces support for exposing other secrets to the build process; see the official announcement (linked above) for details.