raf/SSH puddle jumping with skyhook

Ever wanted to hop into a target machine using ssh going through a middle box, i.e. anything that beats having to repeatedly call ssh from one machine into the next. There are a couple of setups going around for using ProxyCommand+netcat, but what if you want the server to decide the next hop.

Simple use case: at work we wanted to give external SSH access to a developer, but the machine was inside a private network and we had to jump through a middlebox to get there.

The usual way to puddle jump over ssh is using a ProxyCommand in .ssh/config

Host target_over_proxy*
    Hostname target.domain.com
    ProxyCommand ssh -q proxybox nc -q0 %h %p

What this does is open an ssh connection to the proxy host, and runs a second ssh connection over the first one. The netcat(nc) command establishes the connection between the middlebox and the actual destination. The problem with this setup is that the client needs to know the target of the connection. If the destination lives inside a private network, then the user might not have this information or it might change over time, but the middlebox should know about it.

Another alternative is to setup a blind proxy that forwards all TCP connections to internal machines based on arbitrary parameters, e.g. HAProxy.

But I wanted neither of those solutions since I did no have any ports to use, and I wanted to enforce access control at the middle box. In a nutshell:

So I glued together some OpenSSH settings and bash scripts to make it possible (link at the bottom), here is a quick explanation of the setup.

Client setup

Add a proxycommand, in ~/.ssh/config

Host target
    User raf-devmachine
    ProxyCommand ssh -q %r@middlebox skyhook

For this example I just assumed the username is the same (%r) for both the middle box and the target machine, but you might want to adjust it to be different. The command skyhook doesn't actually exist, it is just there so that ssh assumes a proxy is in place.

Middlebox setup

The skyhook scripts are placed inside /usr/libexec. To enable it you need to add the following configuration to your sshd_config

Match Group skyhook
    ForceCommand /usr/libexec/skyhook-shell

This enforces that all users in the skyhook group will call the skyhook-shell command. The skyhook-shell is a bash script that will call a user hook script to forward the connection. But the original client does not know what is the actual destination.

Each user has its own hook script in /usr/libexec/skyhook/username. An example hook script would be to call netcat

nc -q0 22