How to access private Github repos when building Docker images?
If you landed on this page, it means you probably have the same issue I’ve stumbled upon as well: I need to access some private Github repos while building a docker image but I don’t want any ssh keys or credentials to end up in the final image.
While there’s already ways to achieve this, the recent additions of buildx (first release was back in April 2019) and experimental dockerfile syntaxes (available from v18.06 onwards) make it much easier to do it (or just more elegant).
Do note that you need to have Docker 18.09+ installed and you need to enable the experimental features for Docker (both for the CLI and the daemon).
To enable the experimental features for the CLI, you just need to add the following to your ~/.docker/config.json config:
{
"experimental": "enabled"
}Preferences > Command Line (see image below).
And to enable the experimental features for the daemon, you need to add the following to your /etc/docker/daemon.json config:
{
"experimental": true
}~/.docker/daemon.json. Or if you’re using the Desktop version, you’ll find these settings under Preferences > Docker Engine (see image below).
Furthermore, if you’re not using a Linux machine, you need to start the ssh-agent:
eval $(ssh-agent)And add your current SSH key to the agent:
ssh-add ~/.ssh/id_rsaWe also need to setup a known_hosts file to avoid prompts from SSH when cloning:
ssh-keyscan github.com >> ./known_hostsNow create a dockerfile that just clones a private repo:
# syntax = docker/dockerfile:1.1-experimental
# Dockerfile.priv-repo
FROM alpine
ARG PRIV_GIT_REPO
RUN apk add --update --no-cache ca-certificates \
git \
openssh-client \
rsync
ENV PRIV_SOURCE_CODE /code
RUN --mount=type=ssh \
--mount=type=secret,id=known_hosts,dst=/root/known_hosts \
mkdir -p -m 0700 /root/.ssh && \
cat /root/known_hosts >> /root/.ssh/known_hosts && \
git config --global url."git@github.com:".insteadOf "https://github.com/" && \
git clone $PRIV_GIT_REPO $PRIV_SOURCE_CODEAnd build a base image off that which we’ll use in another image:
docker buildx build -f Dockerfile.priv-repo \
--ssh default \
--secret id=known_hosts,src=./known_hosts \
--build-arg PRIV_GIT_REPO=<my private repo> \
--tag priv-repo \
.Lastly, create a dockerfile that copies whatever was in the private repo to the host:
# Dockerfile
FROM priv-repo AS builder
RUN rsync -rv --exclude '.git' $PRIV_SOURCE_CODE/ /tmp/
FROM scratch
COPY --from=builder /tmp/ /And build the image to get the output:
docker buildx build -f Dockerfile -o type=local,dest=./priv-code .If everything went well, you should see the private repo’s content under ./priv-code.
Things to note:
- The above guide will only work for Github, though, with slight changes it can work for GitLab or others
- We’re using the secret feature to pass the
known_hostsfile to the base image, but we can easily run thessh-keyscanjust before thegit clone ... - We’re configuring git to use SSH when cloning, but this might not work for everyone
- This guide has not been tested Windows
Finally, you can find this example at rolandjitsu/docker-ssh. The repo also includes examples of how to use the bake command and how a Github action that uses this approach would look like.