Last week I had to perform what seemed like a very simple task: clone a private Github repository inside a docker container. Outside the container, I had SSH set up, so that I could clone the private repo using git clone ssh:git@github.com/myuser/myrepo
.
As I dug deeper into documentation and forums, I've noticed that current documented solutions either relied on insecurely copying the hosts' ssh keys into the container or on hiding the copied ssh key through convoluted multi-stage builds.
However, as of version 18.09
, Docker build now supports a way to use the host system's ssh access while building the image. This avoids the issue of copying private keys into the image and risking exposing them publicly. You can read more about it here as well.
This guide will help you set up a Dockerfile
and a docker-compose.yml
to work with the host system's SSH.
You can find the code on my github.
Setting up the host system's SSH
First, make sure that you have an SSH client installed and that you have set up a Github SSH key on your machine. Please follow this guide to connect to GitHub with SSH.
Once that's done, you can test your Github SSH connection by running the ssh -T git@github.com
command on a terminal. If all works, you should see:
Hi jhonatan-lopes! You've successfully authenticated, but GitHub does not provide shell access.
Now, let's make sure that your SSH agent is running. We need to inspect the value of the environment variable SSH_AUTH_SOCK
. On bash, run echo $SSH_AUTH_SOCK
. If you see an output, the agent is running. Otherwise, you need to start the agent by running:
bash
eval `ssh-agent -s`
The next step is to add your credentials to the ssh-agent
. Check which credentials you have added with:
bash
ssh-add -l
If there aren't any credentials added, you need to add them to the agent. Let's add the id_ed25519
credential, which GitHub uses:
bash
ssh-add ~/.ssh/id_ed25519
Note that these two steps (starting the agent and adding credentials) need to be done every time that you start a shell session, as the agent can get disconnected. If you wish to, there are some scripts that you can add to your .bashrc
to auto-start the ssh-agent
and add the credentials.
A Dockefile with SSH
Now let's create our Dockerfile
:
```bash
Get a ubuntu image
FROM ubuntu
Update package databases
RUN apt-get update
Install ssh client
RUN apt install -y openssh-client
Download public key for github.com
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
Test the connection
RUN ssh -T git@github.com ```
If built successfully, this image should show the same message that we got when testing our SSH connection before.
Let's try to build this image:
bash
docker build .
gives:
bash
git@github.com: Permission denied (publickey).
For it to work, we need to make the RUN
command use the SSH agent that we set up:
```bash
Get a ubuntu image
FROM ubuntu
Update package databases
RUN apt-get update
Install ssh client
RUN apt install -y openssh-client
Download public key for github.com
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
Test the connection
RUN --mount=type=ssh ssh -T git@github.com ```
Now we only need to pass along the ssh-agent
to the docker build
command:
bash
docker build --ssh default .
You should now see:
Hi jhonatan-lopes! You've successfully authenticated, but GitHub does not provide shell access.
The build itself will fail, but we can ignore that. The ssh -T
command is returning an error code even when the authentication is successful.
If that doesn't work, you might have to enable the build kit with an environment variable:
bash
DOCKER_BUILDKIT=1 docker build --ssh default .
Now that we know that our connection is working, we can clone our repository:
```bash
Get a ubuntu image
FROM ubuntu
Update package databases
RUN apt-get update
Install ssh client
RUN apt install -y openssh-client git
Download public key for github.com
RUN mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com >> ~/.ssh/known_hosts
Clone the private repo
RUN --mount=type=ssh git clone ssh:git@github.com:myuser/myprivaterepo.git ```
That's it! You now have your private repo cloned on your docker image using SSH.