SSH – Port Forwarding via Jump Host with ssh_config

opensshport-forwardingssh-tunneling

NB: The OpenSSH clients I am using are all at version 7.2, so no RemoteCommand available.

Assume the following setting:

  1. machine foo is a jump host and provides access to host bar via its localhost:10022
  2. bar sits inside a network inside of which we can access host rdp and access its RDP port (3389). I actually give the IP of rdp inside my command lines and configuration, but I presume that it is legit to use its name as long as name lookup works. For brevity I am using rdp here.

The goal is now to gain access to rdp:3389 by connecting to bar via jump host foo and forward that to localhost:33389 on the local machine from which I am invoking ssh bar.

[local:33389] --> {foo} --> {bar} --> [rdp:3389]

Interlude

I have solved this previously with PuTTY as follows:

  1. create a connection to foo and configure a local forwarding -L 33389:localhost:33389, thus tying localhost:33389 on the local machine to localhost:33389 on foo.
  2. use the following remote command to carry the port forwarding into the network inside of which bar sits by passing ssh -L 33389:rdp:3389 -A bar.
  3. Host bar is configured on foo inside of .ssh/config to connect to localhost:10022 and thereby end up on bar via the jump host.

The PuTTY configuration works like a charm, but it relies on a remote command to be executed. While a shell alias would be one way of going about this, I was wondering if there's a way to keep everything inside the ssh_config(5) used by my client, using ProxyCommand?


A rough equivalent of the above PuTTY configuration is this:

ssh -L 33389:localhost:33389 foo ssh -t -L 33389:rdp:3389 -p 10022 localhost

or, provided that Host bar is configured on foo to go through localhost:10022 of foo:

ssh -L 33389:localhost:33389 foo ssh -t -L 33389:rdp:3389 bar

And this seems to get the job done.

But of course this is plenty to type and it would be neater to be able to put this all into the configuration file and simply type ssh bar on the local machine.

With RemoteCommand as introduced in OpenSSH 7.6 this seems to be rather trivial:

Host bar
    HostName foo
    RemoteCommand ssh -L 33389:rdp:3389 -A -p 10022 localhost
    LocalForward 33389 localhost:33389

… which should roughly translate to the ssh invocation shown above. But as mentioned before, I am using an older (packaged) version of OpenSSH without support for the RemoteCommand stanza.

Here's the attempt that seems to come closest to what I want to achieve.

Host bar
    HostName localhost
    Port 10022
    ProxyCommand ssh -L 33389:localhost:33389 -W %h:%p foo
    LocalForward 33389 rdp:3389

The idea being that on the local machine I will simply invoke ssh bar. In fact it works in that I end up on the shell prompt of bar, but the port forwarding doesn't work at all. While sudo lsof -i|grep 3389 on the local machine gives me:

ssh       15271        accden    6u  IPv6 7933201      0t0  TCP localhost:33389 (LISTEN)
ssh       15271        accden    7u  IPv4 7933202      0t0  TCP localhost:33389 (LISTEN)

On the jump host I see nothing listening on any port containing 3389.

Since ProxyCommand establishes the connection to foo and I am giving a LocalForward for the connection to bar, I'd expect this to work.

What am I doing wrong?


Goal is to use ssh bar to connect to bar and at the same time make rdp:3389 available on the local machine as localhost:33389. Tweaking the ssh_config(5) files on the local machine and foo are allowed. Passing remote commands is not a valid answer, though.

Best Answer

First, with your kind of setting, what would work, requiring anyway two ssh:

Host foo
    LocalForward 10022:bar:22

Host bar
    Hostname localhost
    Port 10022
    LocalForward 33389 rdp:3389

term1$ ssh foo # or use ssh -f -N -o ExitOnForwardFailure=yes foo for background task
term2$ ssh bar

What you'd really need wouldn't be RemoteCommand but ProxyJump, really simplifying your configuration, with goal reached only with:

ssh -L 33389:rdp:3389 -J foo bar

Or the equivalent (only) configuration:

Host bar
    ProxyJump foo
    LocalForward 33389 rdp:3389

With zero intermediate port needed.

Unfortunately ProxyJump is available only starting from openssh 7.3

But it's easily replaced with the ProxyCommand/-W combo you were using before.

ssh -L 33389:rdp:3389 -o 'ProxyCommand=ssh foo -W %h:%p' bar 

or as configuration file:

Host bar
    ProxyCommand ssh -W %h:%p foo
    LocalForward 33389 rdp:3389

There are still two ssh running: the hidden one is the one as ProxyCommand parameter still running on the local host doing the link using a pair of pipes with the main ssh, instead of an extra tcp port. Trying to involve the intermediate host in participating with the port forwarding is insecure or can clash (other users of foo can access the tunnel or use the same port), and prone to errors. Tunnel ends should always be kept on the client host if possible, where there's full control. Intermediate tunnels should either not exist or point to the next ssh entry point (that's the -W 's usage here).