SSH: Tunneling to remote servers
Tags: ssh
Published: 2019-12-24 16:59:32


When creating our infrastructure, either in the cloud or on prem, we ~~often~~ usually need a way to connect to machines running behind the scenes to do things, such as upgrades or fixing problems.

Typically the tool of choice for most remote system administration work is ssh. [openssh](https://www.openssh.com/) is probably the most common version of ssh that is used on systems today and is often pre-built and installed on your operating system.

When we need to connect to our web servers that are safely tucked behind a firewall on local IP addresses ( [RFC1918](https://tools.ietf.org/html/rfc1918) ) we can use SSH to tunnel through our bastion or jump-host, here's how:


Here's a basic diagram of how I'll be connecting to a web server:

```
  { Internet } ------ [ Jump-box ] ------ [ Web-server-1 ]

```

I need to connect to `web-server-1` to fix an issue but it doesn't have direct exposure to the internet. I can use the jump-box to make that connection like so:


```bash

ssh -J jump-box.example.com web-server-1

```

That's it. It really is that simple!


You may notice that the webserver isn't using a fully qualified domain name such as `web-server-1.example.com`. This is because the ssh client will make use of the DNS configuration of the jump host to find `web-server-1`. If the DNS isn't configured properly on the jump-box, or you make a typo, you'll get an error message back saying it couldn't be found.

You can add as many servers to the -J option as needed in a comma separated format. The highest number of jumps I've made is 3. The client will connect to each of the servers in order to establish a connection to the end point web-server-1. An example maybe:

```bash

ssh -J jump-box.example.com,jump-box-2 web-server-1

```

**_Note_** : _The `-J` option was [introduced in openssh version 7.3](https://www.openssh.com/txt/release-7.3). If you have an earlier version of the client the command line option may not be available to you._


The `-J` option is a shortcut for the `ProxyJump` configuration option. That you could find in your ssh client configuration files already ( `.ssh/config` for user configurations or `/etc/ssh/ssh_config` for system wide )

Example:
In my ssh client configuration it would look like this:

```ssh

host web-server-1
 ProxyJump jump-box.example.com

```

This would create an alias for `web-server-1` that the ssh client can use. Now I'd only have to type `ssh web-server-1` and ssh would take care of the rest.


But wait, there's more!


An alternative method for doing this would be to use the proxy-command option:

```bash

ssh -o ProxyCommand="ssh -W %h:%p jump-box.example.com" web-server-1

```

This first starts an ssh connection to the jump box and then, with the `-W` option, requests that standard input and output on the client be forwarded to host on port over the secure channel


Sometimes the ssh client you have may not have these features or they could be restricted in some fashion. For this we have to revert to good old fashioned port forwarding. 

In our first terminal we would run this command to setup a connection to the jump box but at the same time we ask it to listen on port 2222 on our local machine and pass those connections through to port 22 on web-server-1:

```bash

ssh -L 2222:web-server-1:22 jump-box.example.com

```

Then in our second terminal we would run this to initiate a connection to port 2222 on our local machine:

```bash

ssh -P 2222 localhost

```

Using port forwards in this way works well but becomes cumbersome if you need to connect to more than one jump-box or more than one endpoint within your network.


Ta-da! \o/


_tldr_: use `ssh -J jump-box.example.com web-server-1` to tunnel ssh connections to web-server-1 via jump-box.example.com