57

I am using Docker on Mac OS X with Docker Machine (with the default boot2docker machine), and I use docker-compose to setup my development environment.

Let's say that one of the containers is called "stack". Now what I want to do is call:

docker-composer run stack ssh user@stackoverflow.com

My public key (which has been added to stackoverflow.com and which will be used to authenticate me) is located on the host machine. I want this key to be available to the Docker Machine container so that I will be able to authenticate myself against stackoverflow using that key from within the container. Preferably without physically copying my key to Docker Machine.

Is there any way to do this? Also, if my key is password protected, is there any way to unlock it once so after every injection I will not have to manually enter the password?

jwodder
  • 54,758
  • 12
  • 108
  • 124
Ruslan
  • 1,208
  • 3
  • 17
  • 28

6 Answers6

70

You can add this to your docker-compose.yml (assuming your user inside container is root):

volumes:
    - ~/.ssh:/root/.ssh

Also you can check for more advanced solution with ssh agent (I did not tried it myself)

Anton Serdyuk
  • 1,208
  • 10
  • 13
  • 19
    Note this solution may fail if your SSH keys belong to a user on the host machine – Josh Bodah Sep 27 '16 at 14:17
  • 16
    Whilst you can do this at run time, you won't be able to access the volume at build time. – Daniel van Flymen Feb 08 '17 at 22:43
  • 5
    Not working on Windows either. `Permissions 0755 for '/root/.ssh/id_rsa' are too open.` – spirit Oct 03 '17 at 14:27
  • 2
    You can add `:ro` at the end of this snippet to mount the keys read-only, this typically bypasses the warning from SSH about permissions, but if your key has a passphrase (it really SHOULD) you still need to do some trickery with ssh-agent. – dragon788 Jul 20 '18 at 02:45
  • Another important note is that with this as a volume – ctatro85 Jan 28 '19 at 16:56
51

WARNING: This feature seems to have limited support in Docker Compose and is more designed for Docker Swarm.

(I haven't checked to make sure, but) My current impression is that:

  • In Docker Compose secrets are just bind mount volumes, so there's no additional security compared to volumes
  • Ability to change secrets permissions with Linux host may be limited

See answer comments for more details.


Docker has a feature called secrets, which can be helpful here. To use it one could add the following code to docker-compose.yml:

---
version: '3.1' # Note the minimum file version for this feature to work
services:
  stack:
    ...
    secrets:
      - host_ssh_key

secrets:
  host_ssh_key:
    file: ~/.ssh/id_rsa

Then the new secret file can be accessed in Dockerfile like this:

RUN mkdir ~/.ssh && ln -s /run/secrets/host_ssh_key ~/.ssh/id_rsa

Secret files won't be copied into container:

When you grant a newly-created or running service access to a secret, the decrypted secret is mounted into the container in an in-memory filesystem

For more details please refer to:

Anton Styagun
  • 1,112
  • 14
  • 10
  • 1
    Hi astyagun : I agree that using the Secrets feature is a good way to approach this, but to make your answer better it would be useful to include the essential parts of the answer here and provide the links for reference. – Vince Bowdren Dec 05 '17 at 11:30
  • 1
    Thanks. added examples – Anton Styagun Dec 05 '17 at 15:00
  • 1
    Unfortunately linking id_rsa will not work, SSH will return with error, as link has different permissions. So, you still will need to copy the file, and keep RO permissions. But the good point is, that you can use `ssh -i /run/secrets/host_ssh_key ...` parameter, as the secret file has RO permission – Kostanos Jul 30 '18 at 23:16
  • 1
    @Kostanos Will adding `chown -h $(id -u):$(id -g) ~/.ssh/id_rsa` after creating a link help? – Anton Styagun Aug 01 '18 at 10:18
  • no, already tried. For now I'm copying the file instead of making link. anyway the image is in my PC, and I don't plan to publish it. So, I'm ok with security here – Kostanos Aug 01 '18 at 14:12
  • Really puzzled by this answer. According to the docs secrets didn't come about until v3.5. https://docs.docker.com/compose/compose-file/compose-versioning/#version-33 Also trying this locally secrets don't seem to be available during build. ls: cannot access '/run/secrets': No such file or directory – Hawxby Oct 17 '18 at 19:59
  • 1
    According to the "Long Syntax" version of the documentation, you can set the permissions of the secrets file in the `docker-compose.yml` using the key `mode`. https://docs.docker.com/compose/compose-file/#secrets – aquaflamingo Apr 06 '20 at 13:42
  • 2
    Note that secrets are a "swarm mode feature" as pointed in https://github.com/docker/compose/issues/4994 and https://stackoverflow.com/questions/49955542/how-to-read-external-secrets-when-using-docker-compose . It will not mount the secrets in docker-compose up. – Roxana Tapia May 22 '20 at 12:40
  • SWARM ONLY! Arrrrgh – jim smith May 11 '21 at 12:41
  • Updated the answer to reflect mentioned limitations – Anton Styagun May 12 '21 at 09:51
  • 1
    @AntonStyagun updated link for secrets docs: https://docs.docker.com/compose/compose-file/compose-file-v3/#secrets – Jack Westmore Jan 31 '22 at 12:26
38

If you're using OS X and encrypted keys this is going to be PITA. Here are the steps I went through figuring this out.

Straightforward approach

One might think that there’s no problem. Just mount your ssh folder:

...
volumes:
  - ~/.ssh:/root/.ssh:ro
...

This should be working, right?

User problem

Next thing we’ll notice is that we’re using the wrong user id. Fine, we’ll write a script to copy and change the owner of ssh keys. We’ll also set ssh user in config so that ssh server knows who’s connecting.

...
volumes:
  - ~/.ssh:/root/.ssh-keys:ro
command: sh -c ‘./.ssh-keys.sh && ...’
environment:
  SSH_USER: $USER
...

# ssh-keys.sh
mkdir -p ~/.ssh
cp -r /root/.ssh-keys/* ~/.ssh/
chown -R $(id -u):$(id -g) ~/.ssh

cat <<EOF >> ~/.ssh/config
  User $SSH_USER
EOF

SSH key passphrase problem

In our company we protect SSH keys using a passphrase. That wouldn’t work in docker since it’s impractical to enter a passphrase each time we start a container. We could remove a passphrase (see example below), but there’s a security concern.

openssl rsa -in id_rsa -out id_rsa2
# enter passphrase
# replace passphrase-encrypted key with plaintext key:
mv id_rsa2 id_rsa

SSH agent solution

You may have noticed that locally you don’t need to enter a passphrase each time you need ssh access. Why is that? That’s what SSH agent is for. SSH agent is basically a server which listens to a special file, unix socket, called “ssh auth sock”. You can see its location on your system:

echo $SSH_AUTH_SOCK
# /run/user/1000/keyring-AvTfL3/ssh

SSH client communicates with SSH agent through this file so that you’d enter passphrase only once. Once it’s unencrypted, SSH agent will store it in memory and send to SSH client on request. Can we use that in Docker? Sure, just mount that special file and specify a corresponding environment variable:

environment:
  SSH_AUTH_SOCK: $SSH_AUTH_SOCK
  ...
volumes:
  - $SSH_AUTH_SOCK:$SSH_AUTH_SOCK

We don’t even need to copy keys in this case. To confirm that keys are available we can use ssh-add utility:

if [ -z "$SSH_AUTH_SOCK" ]; then
  echo "No ssh agent detected"
else
  echo $SSH_AUTH_SOCK
  ssh-add -l
fi

The problem of unix socket mount support in Docker for Mac

Unfortunately for OS X users, Docker for Mac has a number of shortcomings, one of which is its inability to share Unix sockets between Mac and Linux. There’s an open issue in D4M Github. As of February 2019 it’s still open.

So, is that a dead end? No, there is a hacky workaround.

SSH agent forwarding solution

Luckily, this issue isn’t new. Long before Docker there was a way to use local ssh keys within a remote ssh session. This is called ssh agent forwarding. The idea is simple: you connect to a remote server through ssh and you can use all the same remote servers there, thus sharing your keys.

With Docker for Mac we can use a smart trick: share ssh agent to the docker virtual machine using TCP ssh connection, and mount that file from virtual machine to another container where we need that SSH connection. Here’s a picture to demonstrate the solution:

SSH forwarding

First, we create an ssh session to the ssh server inside a container inside a linux VM through a TCP port. We use a real ssh auth sock here.

Next, ssh server forwards our ssh keys to ssh agent on that container. SSH agent has a Unix socket which uses a location mounted to Linux VM. I.e. Unix socket works in Linux. Non-working Unix socket file in Mac has no effect.

After that we create our useful container with an SSH client. We share the Unix socket file which our local SSH session uses.

There’s a bunch of scripts that simplifies that process: https://github.com/avsm/docker-ssh-agent-forward

Conclusion

Getting SSH to work in Docker could’ve been easier. But it can be done. And it’ll likely to be improved in the future. At least Docker developers are aware of this issue. And even solved it for Dockerfiles with build time secrets. And there's a suggestion how to support Unix domain sockets.

Vanuan
  • 31,770
  • 10
  • 98
  • 102
7

You can forward SSH agent:

something:
    container_name: something
    volumes:
        - $SSH_AUTH_SOCK:/ssh-agent # Forward local machine SSH key to docker
    environment:
        SSH_AUTH_SOCK: /ssh-agent
Aistis
  • 3,695
  • 2
  • 34
  • 34
  • 7
    You already gave that answer here http://stackoverflow.com/a/36648428/228370 And one note: This doesn't work for mac as @joe-saw pointed out, because unix domain sockets aren't proxied – 23tux Oct 28 '16 at 07:00
  • How to get the local machine ssh agent directroy /ssh-agent? – famas23 Jun 06 '20 at 21:52
  • @famas23 this is the answer to your question: https://medium.com/trabe/use-your-local-ssh-keys-inside-a-docker-container-ea1d117515dc#3b26 – ismailarilik Jan 05 '23 at 07:37
5

You can use multi stage build to build containers This is the approach you can take :-

Stage 1 building an image with ssh

FROM ubuntu as sshImage
LABEL stage=sshImage
ARG SSH_PRIVATE_KEY
WORKDIR /root/temp

RUN apt-get update && \
    apt-get install -y git npm 

RUN mkdir /root/.ssh/ &&\
    echo "${SSH_PRIVATE_KEY}" > /root/.ssh/id_rsa &&\
    chmod 600 /root/.ssh/id_rsa &&\
    touch /root/.ssh/known_hosts &&\
    ssh-keyscan github.com >> /root/.ssh/known_hosts

COPY package*.json ./

RUN npm install

RUN cp -R node_modules prod_node_modules

Stage 2: build your container

FROM node:10-alpine

RUN mkdir -p /usr/app

WORKDIR /usr/app

COPY ./ ./

COPY --from=sshImage /root/temp/prod_node_modules ./node_modules

EXPOSE 3006

CMD ["npm", "run", "dev"] 

add env attribute in your compose file:

environment:
      - SSH_PRIVATE_KEY=${SSH_PRIVATE_KEY}

then pass args from build script like this:

docker-compose build --build-arg SSH_PRIVATE_KEY="$(cat ~/.ssh/id_rsa)"

And remove the intermediate container it for security. This Will help you cheers.

Devesh
  • 929
  • 12
  • 10
  • Last part can be added to docker_compose.yml `build.args` – Keto Sep 23 '20 at 21:53
  • 3
    Be aware though the keys are now stored in the image and even if you are using multistage, the key is still there in one of the layers. potential security risk. – SomeOne_1 Oct 09 '20 at 13:29
  • should add one more step to delete the key after cloning the repository from github – Dung Le Jul 15 '22 at 09:35
4

Docker for Mac now supports mounting the ssh agent socket on macOS.

sandinmyjoints
  • 1,976
  • 1
  • 14
  • 20
  • 3
    Unfortunately, the documentation on Docker's side has changed and no mention of `osxfs` can be found. Typical for Docker, poorly maintained or redirected documentation. Here at least is the archive.org version of your link: https://web.archive.org/web/20200414203352/https://docs.docker.com/docker-for-mac/osxfs/#ssh-agent-forwarding For posterity, key point: Requires `type: bind` in the volume mount. – patricknelson Jan 01 '21 at 03:31