Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Socat-based approach #10

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

Conversation

djmaze
Copy link

@djmaze djmaze commented Feb 7, 2017

@avsm Thanks for the great idea you had here!

I changed this so it doesn't need local volumes anymore. This makes it work with boot2docker on Linux as well. Even more, it works with any remote docker host as long as the DOCKER_ variables are set up correctly.

Also, it forwards all keys available in the local agent.

Last but not least, it uses a named volume so it can be used with Docker Compose V3 syntax. See this example.

For me, this is now close to a perfect solution for SSH agent forwarding.

EDIT: Sorry for the bad PR name, I was unable to come up with a good one. Also, this could probably be split into multiple PRs. But for me this really is useful as a whole only.

docker-ssh-agent-forward

@BlinkyStitt
Copy link

BlinkyStitt commented Feb 8, 2017

On OSX, I'm getting an error:

base64: invalid option -- w
Usage:	base64 [-hvD] [-b num] [-i in_file] [-o out_file]
  -h, --help     display this message
  -D, --decode   decodes input
  -b, --break    break encoded string into num character lines
  -i, --input    input file (default: "-" for stdin)
  -o, --output   output file (default: "-" for stdout)

@Vanuan
Copy link

Vanuan commented Feb 8, 2017

What's the benefit of a volume based approach?
Is it because you need a hard-coded location?

What's the benefit of socat? It's still using sshd, right? Isn't that just increasing the size of an image without a clear benefit?

@Vanuan
Copy link

Vanuan commented Feb 8, 2017

Could you draw a picture similar to #11 to specify improvements?

@djmaze
Copy link
Author

djmaze commented Feb 8, 2017

@wysenynja Ah, forgot to add the fix for OSX. New version should work!

@djmaze
Copy link
Author

djmaze commented Feb 8, 2017

@Vanuan This approach has two benefits. Since it uses a named volume instead of a bind-mounted one, it doesn't need the user's home directory mounted into the docker machine (as it is needed with docker-machine/boot2docker on Linux, for example). The volume is shared between the (remote) containers only. That means it can work with any local or remote Docker host as long as client access is configured correctly (e.g. using docker-machine).

In order to share the socket (and because I didn't want share the whole /tmp directory as a volume) the socket had to be moved to a path inside the new shared volume. I first tried moving the socket file inside the container and changing the SSH_AUTH_SOCK variable accordingly. This didn't work (reliably) for me, so I just resorted to forwarding the given socket into another socket which is stored inside the volume.

I will try to draw a diagram in order to illustrate this in a spare moment.

@djmaze
Copy link
Author

djmaze commented Feb 9, 2017

@Vanuan I just added a diagram. Hope it is clear enough.

@pda
Copy link

pda commented Feb 13, 2017

Nice, looks good. I just came across this PR, having implemented the same thing in a private repo last Monday too, needing it working with Docker for Mac as well as docker-machine / boot2docker.

I didn't like the sshd container's /tmp leaking into every other container, confirmed it's non-configurable in OpenSSH and they don't want to change that, so used socat to proxy the socket to a predictable-path on a named volume.

And depending on ~/.ssh/id_rsa.pub didn't work across my team so I also used ssh-agent -L to authorize all loaded keys.

I wasn't sure about generating the SSH host keys (ssh-keygen -A) in Dockerfile vs an entrypoint; I wouldn't be comfortable distributing or using a distributed image with pre-generated host keys, so maybe entrypoint would be better?

So, this PR would mean I could delete my own code 👍

@BlinkyStitt
Copy link

BlinkyStitt commented Feb 13, 2017

I've included this and more in https://github.com/uber-common/docker-ssh-agent-forward

@BlinkyStitt
Copy link

BlinkyStitt commented Feb 14, 2017

Apparently mktemp is different on Yosemite and doesn't work without any args:

$ mktemp
usage: mktemp [-d] [-q] [-t prefix] [-u] template ...
       mktemp [-d] [-q] [-u] -t prefix

On my fork, I've changed it to mktemp -t dsaf

FIXME Find a way to ensure sshd is ready without waiting an arbitrary second.
@djmaze
Copy link
Author

djmaze commented Feb 14, 2017

I wasn't sure about generating the SSH host keys (ssh-keygen -A) in Dockerfile vs an entrypoint; I wouldn't be comfortable distributing or using a distributed image with pre-generated host keys, so maybe entrypoint would be better?

@pda Very valid point! Just changed this accordingly. I had to add a workaround in waiting for sshd to become readily available though.

Apparently mktemp is different on Yosemite and doesn't work without any args

@wysenynja Adjusted that, too.

@djmaze
Copy link
Author

djmaze commented May 9, 2018

I made my fork stand alone and added an example docker compose config: https://github.com/djmaze/docker-ssh-agent-forward

@tamsky
Copy link

tamsky commented Aug 4, 2018

@djmaze I'm curious about your diagram for the socat approach...

Not clear from it: where does ssh-agent run ?

Should the following part of the image:
image
actually read "Container with SSH Agent"?

Second:
Would I be correct in assuming that your socat approach runs a Linux ELF version of ssh-agent,
and not the Mach-O 64bit version of ssh-agent?

@djmaze
Copy link
Author

djmaze commented Aug 5, 2018

@tamsky The agent needs to be running on your host machine.

  1. After starting the "Container with SSH server", a permanent, long-running SSH connection is established from your host to the container, with SSH forwarding enabled (ssh -f -A).
  2. Because the client requested agent forwarding, the SSH server automatically creates a corresponding socket (/tmp/ssh-xxx/agent.xxx) and sets the SSH_AUTH_SOCK variable in the session.
  3. We then use this information and forward the socket to a well-known place on a volume (/ssh-agent/ssh-agent.sock) using socat.

@tamsky
Copy link

tamsky commented Aug 10, 2018

I think I get it.

For clarity's sake, I'll continue to suggest that the actual ssh-agent binary should appear somewhere in the diagram. Here's how I see it:

avsm-docker-ssh-agent-forward-pull-10

Is that correct?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants