How to pass securely SSH Keys to Docker Build?

4.7k Views Asked by At

I want to create a Docker image for devs that reproduces our production servers. Those servers are configured by Ansible.

My idea is to run an ansible-pull to apply all the configuration inside the container. The problem is that I need the SSH key to pull the playbook, but I don't want to share the SSH key on the Docker image.

So, there is a way to have the SSH keys on build time without having them on run time?

4

There are 4 best solutions below

1
On BEST ANSWER

Nice question. The simple way to do it is by removing the SSH keys after the Ansible stuff in the build - but because Docker stores images as layers, someone could still find the old layer with the keys in it.

If you build this Dockerfile:

FROM ubuntu                                                                       
COPY ansible-ssh-key.rsa /key.rsa                                                    
RUN [ansible stuff]
RUN rm /key.rsa

The final image will have all your Ansible state and the SSH key will be gone but someone could easily run docker history to look at all the image layers, and just start a container from an intermediate layer before the key was deleted, and grab the key.

The trick would be to do something like this and then use Jason Wilder's docker-squash tool to squash the final image. In the squashed image the intermediate layer is gone and there's no way to get at the deleted key.

0
On

This is another solution by using this repo, dockito/vault, Secret store to be used on Docker image building.

I create a service dockito/vault and Ubuntu image where I attach my private key to the volume and run it as a process using,

docker run -it -v ~/.ssh:/vault/.ssh ubuntu /bin/bash -c "echo mysupersecret > /vault/.ssh/key"

docker run -d -p 14242:3000 -v ~/.ssh:/vault/.ssh dockito/vault

And, here is my Dockerfile

FROM ubuntu:14.04
RUN apt-get update -y && \
      apt-get install -y curl && \
      curl -L $(ip route|awk '/default/{print $3}'):14242/ONVAULT >   
      /usr/local   
      /bin/ONVAULT && \
      chmod +x /usr/local/bin/ONVAULT
ENV REV_BREAK_CACHE=1
RUN ONVAULT echo ENV: && env && echo TOKEN ENV && echo $TOKEN
RUN ONVAULT ls -lha ~/.ssh/
RUN ONVAULT cat ~/.ssh/key

You can use the alpine linux to reduce final build size, and built the image as,

docker build -f Dockerfile -t mohan08p/VaultTest . 

And, you are done. You can inspect the image. Secrets has not stored inside the image as its empty.

docker run -it mohan08p/VaultTest ls /root/.ssh

This is good technique to pass the .ssh at the build time. Only disadvantage is I need to keep additional Vault service running.

1
On

I'd setup some local file serving facility available only in your build environment.
E.g. start lighttpd on your build host to serve your pem-files only to local clients.

And in your Dockerfile do add/pull/cleanup in a single run:

RUN curl -sO http://build-host:8888/key.pem && ansible-pull -U myrepo && rm -rf key.pem

In this case it should be done in a single layer, so there should be no trace of key.pem left after layer commit.

2
On

You could mount the SSH Keys into the Container on runtime.

docker run -v /path/to/ssh/key:/path/to/key/in/container image command