17

I'm trying to build a docker image from Dockerfile and one of the steps that need to be taken is installing a dependency that is only available via private Gitlab repository. This means the container will need to have access to SSH keys to do the clone. I know this isn't the most secure approach, however this is only going to be an intermediate container that is going to be removed once all of the components necessary to run the app are in place.

The problem is, that I cannot, whatever I try, get ssh agent inside docker to establish the connection. I get:

npm ERR! Host key verification failed.
npm ERR! fatal: Could not read from remote repository.
npm ERR! 
npm ERR! Please make sure you have the correct access rights
npm ERR! and the repository exists.

The same thing happens if I try to simply clone the repository without running npm install. Here is the Dockerfile I use:

FROM risingstack/alpine:3.4-v6.9.4-4.2.0


RUN apk update

RUN apk add openssh

ARG SSH_KEY

# Authorize SSH Host
RUN mkdir -p /root/.ssh && \
    chmod 700 /root/.ssh && \
    ssh-keyscan github.com > /root/.ssh/known_hosts

# Add the keys and set permissions
RUN echo "$SSH_KEY" > /root/.ssh/id_rsa && \
    chmod 700 /root/.ssh/id_rsa && \


RUN eval "$(ssh-agent -s)" && ssh-add /root/.ssh/id_rsa && ssh -o StrictHostKeyChecking=no git@github.com || true && npm install

and the command (I pass the private key as build argument):

docker build -t test  --build-arg SSH_KEY="$(cat ~/.ssh/id_rsa)" .
Michał Szydłowski
  • 3,261
  • 5
  • 33
  • 55

3 Answers3

16

This works for me :

Using this workaround : https://stackoverflow.com/a/47544999/3957754 to pass files as build args

Dockerfile

ARG SSH_KEY
ENV SSH_KEY=$SSH_KEY

# Make ssh dir
RUN mkdir /root/.ssh/
 
# Create id_rsa from string arg, and set permissions

RUN echo "$SSH_KEY" > /root/.ssh/id_rsa
RUN chmod 600 /root/.ssh/id_rsa
 
# Create known_hosts
RUN touch /root/.ssh/known_hosts

# Add git providers to known_hosts
RUN ssh-keyscan bitbucket.org >> /root/.ssh/known_hosts
RUN ssh-keyscan github.com >> /root/.ssh/known_hosts
RUN ssh-keyscan gitlab.com >> /root/.ssh/known_hosts

Build

docker build -t some-app --build-arg SSH_KEY="$(cat ~/file/outside/build/context/id_rsa)" .

With this, you can perform git clone git@github.com... (gitlab, or bitbucket) at build stage or at run stage using ENTRYPOINT ["docker-entrypoint.sh"].

This could works if you need to pass any file as parameter to your container

Security

As commenters said, to pass a file to a container at build time is not safe. The workaround and best practice is : clone the project in the c.i (jenkins, bamboo, circleci, etc) and the perform the docker build .... Clone the project inside of docker is usually just for old required libraries, not for the main source code.

JRichardsz
  • 14,356
  • 6
  • 59
  • 94
  • 2
    Be careful, your SSH private key will be visible to any user of the image with the docker history command. Refer to the [build images with BuildKit](https://docs.docker.com/develop/develop-images/build_enhancements/#using-ssh-to-access-private-data-in-builds) section to learn about secure ways to use secrets when building images. – hmartos Apr 14 '21 at 14:27
  • You are right. With **docker history** you will be able to see everything in the image. But the question needs to pass a file to a container at build. In this case that file must not be sensible – JRichardsz Apr 14 '21 at 15:14
  • This won't work out with Windows. – yashas123 Oct 10 '22 at 07:15
  • Yes you are right. Also remember that linux is used to build images in the 99% of requirements or clouds. Build on windows is just for demo or learning purposes , nor for production – JRichardsz Oct 10 '22 at 14:24
3

I'd clone it on the host, using the ssh-agent you already have running, before you run docker build.

If you really have to have the private key in the image (which you've acknowledged is dangerous) then you should be able to have it at its default location $HOME/.ssh/id_rsa where you have it in your code; don't try to launch an ssh-agent. You could also inject a $HOME/.ssh/config file if your problem is aggressive host key checking, or a $HOME/.ssh/known_hosts file that has the host key already. Since all of these are files you might find it easier to have them in the Docker build tree and COPY them into $HOME/.ssh.

David Maze
  • 130,717
  • 29
  • 175
  • 215
  • 1
    Thanks, will try it out. Note however I cannot COPY something that is out of my current context and ssh keys always will be. – Michał Szydłowski Aug 08 '18 at 06:16
  • 1
    Right, but you could `cp` them into the current context as part of your build sequence (on the host, before you `docker build`). – David Maze Aug 08 '18 at 13:08
2

build a docker image from Dockerfile and one of the steps that need to be taken is installing a dependency that is only available via private Gitlab repository

Like described in much more detail in my answer to How to mount host volumes into docker containers in Dockerfile during build, Docker also provides SSH agent forwarding. This uses the --ssh flag in the docker build command, along with --mount=type=ssh in any Dockerfile's RUN command for which you want SSH authentication to be delegated to the agent on the host.

Arjan
  • 22,808
  • 11
  • 61
  • 71