SSH is ubiquitous with network communication. It’s everywhere. Almost every platform you can think of has an SSH client that you can use. iPhone? Yep! Android? Yep! Linux? obviously! Windows, macOS, FreeBSD, Android, Solaris? You know it! Hell, even your web browser can be used as a remote terminal session. SSH is a powerful tool, and can do so much more than just connecting to a remote machine. Knowing how use these advanced features can really help you in your IT or development career. There are other nefarious reasons why this is useful knowledge as well. But for the purposes of this post, we’ll be using the example of a corporate network.

Let’s take a look at our network setup!

Here’s the Situation

You’re a Data Engineer working at Acme Co. Your daily activies involve data processing on an Apache Nifi instance, along with doing some work on a PostgreSQL database. All of these services are on your internal corporate network and cannot be accessed directly from the internet. You happen to be at your local coffee shop and your boss calls and tells you that somethings wrong and you need to investigate.

In our fictitious example, we’re going to assume there’s a corporate firewall that allows you to get SSH access to the Nifi server from a public IP address. However, the Nifi Web UI runs on port 8080, and the you can only manage the service through the command line, not work with the actual application.

Our example has four components:

  • Your computer
  • Corporate Firewall with SSH access only
  • Server running Apache Nifi (running on port 8080)
  • PostgreSQL Database on a separate internal network (port 5432)
Diagram of the system architecture

Trying to access Nifi at http://35.207.39.7:8080/nifi will timeout and fail. The only thing we have access to is sshing into the Nifi server. Thats great, but again, Nifi is a web application and cannot be used directly through the command line. Fortunately, ssh has a feature we can leverage to allow us access to the Nifi service running on the remote server.

Local Port Forwarding

Local port forwarding allows one to route traffic on a specific port through the SSH session on port 22 and forwards it to a specific port on the remote machine.

According to the SSH man page:

Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side. This works by allocating a socket to listen to either a TCP port on the local side, optionally bound to the specified bind_address, or to a Unix socket. Whenever a connection is made to the local port or socket, the connection is forwarded over the secure channel, and a connection is made to either host port, or the Unix socket remote_socket, from the remote machine.

Basically, we can route traffic through our SSH session. We can tell SSH, any traffic designated for port XXXX on our local machine, should go to port YYYY on the remote machine. Cool! So how can we actually use this to access our Nifi web interface?

Accessing the Nifi Instance

To do this, we use the -L switch in our SSH command. For the sake of verbosity, I’ll be mapping different ports on my local machine, compared to the normal ports on the remote machines. This will help illustrate which part is the local and which is the remote machine.

ssh -L 127.0.0.1:9090:127.0.0.1:8080 drt@35.207.39.7

Let’s break this down a little bit. We’re telling ssh to execute a local port forward (-L) on port 9090 of our local machine (127.0.0.1:9090), and any traffic should go to port 8080 on the loopback address of the remote machine (127.0.0.1:8080). The reason we’re using the loopback address is because the Nifi instance is binding to the loopback address of the remote server. The reason we cannot specifiy the internal IP address is because we might not be aware of what IP address is assigned to the Nifi server. The only IP address we are aware of is the firewall IP address, which is why we are still establishing a connection with drt@35.207.39.7.

Remember that the address 35.207.39.7 is the firewall blocking all traffic except port 22.

After establishing an ssh connection on our Nifi box, we can go to http://localhost:9090/nifi in our web browser to access our Nifi instance!

Crazy right?! Accessing and internal web service through SSH on our corporate network. Let’s take this one step further and access the database from our local machine as well.

Accessing the Database

So far, we’ve only mapped ports on the local machine to loop-back address on the remote machine. We can actually tell ssh to route traffic to a different host once the connection is made to the remote machine. If you look back at the system architecture, we have a PostgreSQL database that Nifi connects to over port 5432.

By changing our ssh command slightly, it will allow us to connect to the PostgreSQL database.

ssh -L 127.0.0.1:2345:10.73.48.3:5432 drt@35.207.39.7

Let’s break this command down as well. We’re telling ssh to execute a local port forward (-L) on port 2345 of our local machine (127.0.0.1:2345), and any traffic should go to port 5432 on another machine accessible by the remote machine (10.73.48.3:8080).

We can now direct our database traffic to our local machine on port 2345.

psql -h 127.0.0.1 -p 2345 -U postgres

We ran a connection to a PostgreSQL database on our localhost, ssh then routed that traffic through the connection to the Nifi server, and is forwarding it to the database server on the internal network. Remember, this is a database instance that is not sitting in front of a firewall, but only exposed in an internal corporate network! We’re able to access it because of ssh tunneling!

My initial reaction when I learned about about SSH tunneling/port forwarding

What If I Need Both?

Need to forward more than one connection? Not a problem! ssh can handle multiple -L connections, so long as the port is not already bound on your local machine.

NOTE: You’ll need elevated privileges if you want to map any ports below 1024. This only applies to your local machine, because you’re binding locally, but forwarding on the remote machine.

Running the following will allow you to connect to both services over localhost.

ssh \
  -L 127.0.0.1:9090:127.0.0.1:8080 \
  -L 127.0.0.1:2345:10.73.48.3:5432 \
  drt@35.207.39.7

Connecting to both Nifi and PostgreSQL DB over the same SSH session

Conclusion

In this post, we went over how you can connect to a server over SSH and forward traffic from your local machine to the remote host. We also covered how you can leverage SSH local port forwarding to redirect traffic to other servers on the network. Next time we’ll go over SSH remote port forwarding, which is the inverse of this topic, and a bit more complex.

References