SSH reverse tunneling
Want an easy way to SSH to a device behind a firewall but don’t want to set up a VPN? Welcome to the pragmatic man’s approach - Reverse SSH tunneling
Concepts
Skip the concepts, jump to the example.
Secure SHell
We’ve all used that. By formal definition a
cryptographic network protocol
Or simpler
a way to safely connect to a machine that (usually) isn’t the one you’re typing on
For example when I run ssh alan@32.42.53.12
I’m creating an SSH connection to 32.42.52.12
as the user alan
.
SSH tunnel
So what’s an SSH tunnel and how does it differ from a connection?
The analogy with traffic can help here to a certain point. A road (connection) is the thing you build to connect two towns. You don’t build tunnels for the sake of tunnels but for the sake of roads.
You construct a tunnel to help the road pass an obstacle it couldn’t pass alone.
Let’s try to see what else can fit that definition of a tunnel except a whole in a mountain.
How about a ferry?
When you board a ferry it’s acting as a tunnel for the road. It’s extending the road to where it normally couldn’t go. So the ferry is a tunnel from the point of view of the road.
But the ferry is also running on its own naval route (connection) between two docks. So a connection (road) is being tunneled through another connection (naval route of the ferry).
An SSH tunnel is an SSH connection that serves as a ferry for other SSH connections allowing them to reach places they normally couldn’t.
Reverse SSH tunnel
What defines a direction of a tunnel?
The direction of a tunnel is defined by the direction of the ferry compared to the dock which created the naval route.
Say dock A wants to have a ferry line with dock B. They buy a ferry, do all the bureaucracy and cars are now flowing from A->B. This is a normal tunnel.
A reverse tunnel is when the dock A set’s everything up but the ferry is only taking people from B->A.
+-------->
Set up the ferry
Maintain the naval route
Keep the ferry running
+-------->
Dock A The sea Dock B
+---------------------+ +------------------+ +------------------+
| | FERRY | | | |
| +----------------------------------> | |
| | |
| <----------------------------------------------+ |
| | |
| +----------------------------------> | |
| | | | | |
+---------------------+ +------------------+ +------------------+
<--------------+
Cars riding towards the
original ferry dock
Does it make sense for Dock A to do this?
Yes if it’s surrounded by cannons that will shoot down every ferry or car that tries to reach it by any other means.
Well… That’s at least why it makes sense in computer networking :)
In more technical terms:
A reverse ssh tunnel is a method of SSH-ing to a computer (dock A) behind a NAT (cannons) by using an external server (the sea) the computer (dock A again) created a reverse tunnel on (naval route).
Hm…
That doesn’t seem tremendously clear. Let’s try with an example.
Example
Goal: SSH to a machine behind a NAT from the outside.
I prepared my example machines to show the concepts.
Local machine
- The machine we want to SSH to behind a NAT
- A virtual machine in bridge mode with Lubuntu 18.04
External machine
- Something that can’t ssh to the local machine because of a firewall
- It could connect if it was in the same network
- External machine’s
~./ssh/id_rsa.pub
is in Local machine’s~./ssh/authorized_keys
- External machine’s
- A cloud server instance, can’t access the local subnet
Tunneling server
- The server with a routable address
- Accessible from the local machine
/~.ssh/id_rsa.pub
from the local machine is in~/.ssh/authorized_keys
on the server
- A cloud server instance, can’t access the local subnet
Commands
External machine (IP not important)
ssh-keygen
Local machine (192.168.1.118)
ssh-keygen
# Move External machine:/~.ssh/id_rsa.pub to ~/.ssh/authorized_keys
Tunneling server (159.65.115.142)
# Move Local machine:/~.ssh/id_rsa.pub to ~/.ssh/authorized_keys
echo "GatewayPorts yes" >> /etc/ssh/sshd_config
systemctl restart sshd
Local machine (192.168.1.118)
sudo apt-get install ssh
# This is the user we'll be logging in from the External machine
echo $USER
# user
ssh -nNT -R 9000:localhost:22 root@159.65.115.142
External machine (46.101.239.231)
ssh -p 9000 user@159.65.115.142
Graphically presented
Local machine Tunneling server External machine
(behind a firewall) (routable address) (IP not important)
192.168.1.118 159.65.115.142
+---------------------+ +------------------+ +------------------+
| | TUNNEL|:22 | | |
| |----------------------------------> | |
| :9000 | |
| localhost:22 <----------------------------------------------+ |
| | |
| +----------------------------------> | |
| | | | | |
+---------------------+ +------------------+ +------------------+
Debugging connections
For debugging or insightful experimentation try checking the command below before or during an active connection.
~# netstat -plant4 | grep ssh
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1749/sshd
tcp 0 36 95.179.161.87:22 85.179.40.72:57218 ESTABLISHED 1483/sshd: root@pts