SSH through jump hosts

I often need to connect to a server with ssh from another server because I don't have direct access. I even gave a small configuration example to use such jump hosts using ProxyCommands.

A while ago, I got fed up to have to add new entries for each host I wanted to join with a jump server, especially when I only need these entries sporadicly, and decided to write a generic configuration. I ended up with this setup:

Host *%*
ProxyCommand ssh $(echo %h | cut -d%% -f1) nc -w1 $(echo %h | cut -d%% -f2) %p

The trick here is that you can use subshell expansions in a ProxyCommand. So, when I ssh to "host1%host2", the first subshell expansion returns "host1" and the second "host2", this setup ends up being the equivalent of :

Host host1%host2
ProxyCommand ssh host1 nc -w1 host2 %p

which is quite similar to the setup from my previous post.

Later on, I came up with an even more powerful implementation:

Host *%*
ProxyCommand ssh $(echo %h | awk -F%% '{OFS="%%"; NF--; print $0}') nc $(echo %h | awk -F%% '{print $NF}') %p

Here, the first awk splits at the % characters and returns all fields except the last one, and the second awk returns only the last field. As a consequence, sshing to "host1%host2%host3%host4" will have the first subshell expansion return "host1%host2%host3" and the second "host4". The setup will then be equivalent to:

Host host1%host2%host3%host4
ProxyCommand ssh host1%host2%host3 nc -w1 host4 %p

The ssh in the ProxyCommand will, in turn, trigger the rule again so that the result is that host4 will be contacted from host3, which is contacted from host2 that we contacted from host1.

In the meanwhile, I decided % was not that nice a separator, and switched to using /, which also allows for a nicer setup with the same recursive effect:

Host */*
ProxyCommand ssh $(dirname %h) nc -w1 $(basename %h) %p

Finally, since some remote hosts don't have nc installed, I usually copy it in my $HOME on these servers and changed my setup to:

Host */*
ProxyCommand ssh $(dirname %h) PATH=.:\$PATH nc -w1 $(basename %h) %p

The main drawback of this method is that the more jump hosts you use, the more your ssh traffic is encapsulated (recursively) in other ssh traffic. The advantage, though, is that you don't need to forward an agent onto untrusted servers to use ssh key authentication on any of the jump or final servers, nor to forward X11 or tunnel multiple times.

2009-04-09 23:19:34+0900


Both comments and pings are currently closed.

8 Responses to “SSH through jump hosts”

  1. Vincent Bernat Says:

    Here is an “enhanced” version:

    Host */*
    ProxyCommand ssh ${$(dirname %h)/\%%/@} nc -w5 ${$(basename %h)#*%%} %p

    You can specify the login for each hop with “%” instead of “@”.

  2. Marius Gedminas Says:

    Quite ingenious!

    ‘/’ doesn’t work well as a separator if you want to use URL syntax in various applications, e.g. svn+ssh://host1%host2/path/to/svn/repo.

    If you used ‘!’, it would look like old-style UUCP email addresses (hop1!hop2!hop3!destination—extra points for the nostalgic effect!), but would be difficult to input (bash uses ! for history expansion by default).

  3. Gonzalo Says:

    It’s great! I’m using it already. Just one thing.. I’m wondering if it’s possible to have certificate based authentication work with this.

  4. Einar Lielmanis Says:

    Very, very nice!

    One caveat with “/” as a separator (it’s still a very nice separator) — you may wish to add “ControlMaster no” in ~/.ssh/config for */* host, if reusing ssh connections: ssh won’t be able to create the socket file it wants (muxserver_listen bind(): No such file or directory).

    Gonzalo, cert based authentication works just fine: you’re logging into each of the jump-hosts directly, so you need your pubkey (~/.ssh/ most probably) in the authorized_hosts of all the jump hosts.

  5. glandium Says:

    Einar: I wouldn’t advise to use DSA keys. This is where I’d like to point to as to why DSA keys are not safe, but it appears the post disappeared :(

  6. Says:

    Following up on SSH through jump hosts…

    I got interesting comments on my previous post about SSH through jump hosts, that made me think a bit.
    The first one of them suggested to use a syntax that unfortunately doesn’t work on anything other than zsh, but had the nice idea to add a logi…

  7. Einar Lielmanis Says:

    What’s with the DSA keys? Links that reference abovementioned article seem to revolve around the huge problem with Debian dsa random number generation, which I’m aware of (even though I’m not using debian or its derivatives), and no way that problem translates to “do not use dsa keys for ssh”. Is there something else I’m missing?

  8. glandium Says:

    Einar: basically, when you have a weak random number generator like it happened, and an attacker can get hold on a DSA signature (which is not difficult), he can get the private key. The math involved was on sesse’s blog, but the post disappeared.