Intro
Port forwarding is a common technique used to access some service behind jump host from your local machine. It is a daily bread of many administrative tasks. In this post I'll show how to create such connections on demand from within Raku or Rust code (without relying on ssh -L
system command).
Theory
Before jumping to implementation let me go briefly through operating principle.
There is service host that exposes something on port 7878
. However you cannot access it directly from local machine because it is in different network.
Luckily there is jump host in that network that exposes SSH service on port 22
, which you can connect to (1).
It is time to open any free port on your local machine (2), let's say 8080
, and start listening for incoming connections. Note that those connections can be made from different thread of the same program, which is case we are interested in here.
Whenever connection arrives to local machine (3) we ask jump host using SSH connection (1) to create SSH channel (4) that will pass TCP packets with source port 8080
to jump machine to port 7878
.
To complete puzzle we must pass traffic (5) between connection made to our local port 8080
(3) and SSH channel (4) in both ways using existing SSH connection (1).
Now to connect to service:7878
you actually connect to local:8080
and your data goes like this.
Important! You need another set of yellow arrows (4) and (5) for every forwarded connection you want to make, you cannot push packets from two connections through single SSH channel. Channel only knows that it should pass TCP packet with source port 8080
, it has no knowledge that it came from specific connection (3) on local machine.
SSH key based authentication setup
In pretty much every case where SSH port forwarding is used SSH keys are preferred over interactive user/password login. If your local to jump connection is not already configured please perform following steps.
Generate new key on local machine:
ssh-keygen -t ed25519 -C "me@example.com"
When asked for location choose some meaningful file name and remember the path, in my case it will be /home/me/.ssh/jump
.
Enter key password and remember it - in my case it will be s3cret!
.
Append content of generated public key /home/me/.ssh/jump.pub
to ./ssh/authorized_keys
file on jump host in your home directory there. Create file if needed. You can do it manually or you can use ssh-copy-id -i /home/me/.ssh/jump me@jump
if you can already login to jump using login/password method and have ssh-copy-id
installed on your local machine.
Test your setup by invoking ssh -i /home/me/.ssh/jump me@jump
, enter your key password and if it connects you are good to go.
Security concerns
- You should never store SSH key password directly in your code. I'll do it here purely for demonstration purposes, but in real life scenario I recommend storing and fetching it from remote vault. Just to have manageable "lockdown" procedure in case of security breach.
- You should always confirm your jump host identity in case of man-in-the-middle attack, when someone redirects your DNS to a fake jump host. I'll explain later how to do it in Raku and Rust.
Let's start coding
Jump to:
Top comments (0)