All the faces of ssh keys in Docker

Oh look! Another Docker post :). I really love Docker.
After all great Docker posts, you finally decided to give Docker a try. You realise how easy it is to create Dockerfile and docker-compose files to create awesome development environment. You are on the horse! Nothing can stop you! You have unlimited power…but then…

Oh the agony!

While running composer install and pulling packages from your private git repository, you have hit the wall! Something like this could be going through your mind: “It’s telling me that my public key has been declined. What do you mean by Permission denied (publickey)? What public key? How dare you to decline anything from me? I HAVE CREATED YOU!”. But you are not the only one.

Before we start

This post is intended for advanced users. I assume that you already know for some of the following things: ssh-agent, SSH_AUTH_SOCK, permissions with writing and reading to a SSH_AUTH_SOCK, docker, sharing folders and files between containers. For all people who don’t know this things, I would suggest you to learn them :). It would keep you busy at night ;).

Now lets get serious!

I am quite sure that all of you know what public and private keys are and how to handle them. But in a Docker container it’s quite a different story. A little bit annoying story actually. I would like to show you some of the solutions for the ssh keys problem. Starting from the worst one to the best one. The solutions don’t contain any real code. This are only the short descriptions on how to solve it. It’s on you to do the actual thing ;). I believe that way you will learn a bit more than following a tutorial (+ I am lazy to do so ;)).

Copy private and public keys to the image

If it looks stupid but works it ain’t stupid!

This is exactly the opposite of the quote :(. You can copy private and public key to the image. Your Dockerfile could look something like this:

FROM your-base-image
COPY /path/private_key /root/.ssh
COPY /path/public_key /root/.ssh

And it works. Why is it bad? Don’t get me started. First, this is huge security risk. You could accidentally push this image to the public Docker image repository (aka Docker hub) or even to your company’s private repository. Then you could get into the problems from the security officer. It’s the same as giving everybody your password. Somebody could download the image, run the container, extract your private key and connect to your production server using your credentials. This is bad. M’kay?

Another bad thing is that, with that solution you would need to copy private key to all your containers which are connecting to your private repository.
But how can we fix the first problem?

Mounting ssh keys instead of copying the keys

We could mount our ssh keys instead of copying the keys in the Docker image. This one is a little better solution, but not the solution we are looking for. Why not you may ask?
Definitely it’s better than the first solution and we would have to mount ssh keys to all running containers and some of the keys could contain passwords, so program would stop and ask for a password. But it’s still not really “dockery” solution (because it’s too easy 😉 ).

Example

While running your container you can write something like docker run ... -v /folder/containing/your/ssh/keys/and/configs:/home/your-user/.ssh ... or put the same thing into your docker-compose.yml file.

But nah…there is a better way, a way cooler way of doing things!

Mount your SSH_AUTH_SOCK from your host to the docker containers

This solution can be put into the “good solutions” bucket. It’s a little bit complicated to make it work, but it’s worth it! The trick is to mount your SSH_AUTH_SOCK from the host machine into the container. That’s the easy part: docker run ... -v ${SSH_AUTH_SOCK}:/sock -e SSH_AUTH_SOCK=/sock.... The hard part are user permissions. User’s id from container must match user id inside of a container for it to be able to read/write into that socket. Also, if you are on OSX (I can’t remember the exact version) the ssh-agent from OSX is not compatible with Linux ssh client inside the docker container. It worked on my Linux host machine, but it didn’t work on my OSX machine.
Also, not everybody has ssh-agent running on their host machine.

Create ssh-agent container and share socket across containers

The best solution (at least in my opinion) is to have custom container running ssh-agent, mounting your ssh-keys into that container, mounting SSH_AUTH_SOCK from that container to other containers. That way you are not depending on anyone. It doesn’t matter if the person is running ssh-agent in the host machine or not. You are creating your own. All the containers can share the same SSH_AUTH_SOCK. If some of the keys contain password, you only have to add keys once, enter the password and you are ready to go.

Some things to be careful with

  • If you are using one of the “bad” solutions, please logout out of the Docker Hub. It really is hard to accidentally push something into the public “Internet” but it’s possible to do so. It’s best to minimise the risk.
  • Also, if you are using the “bad” solution, it’s quite possible that it may not work on all computers. What I am trying to say is, everybody’s environment is configured differently (we all know that and it makes our lives a living hell) and to make it work on everybody’s computer is hard to do so.
 

Vizualni

Programmer. Passionate about algorithms and data structures. Enjoys clean and readable code. Loves hackerrank and similar pages.

 
%d bloggers like this: