In my work, I have one single host with public access to ssh port (i.e. 22). The rest of my hosts have the ssh port filtered. Moreover, I have one cloud platform in which I can create virtual machines (VM) with private IP addresses (e.g. 10.0.0.1). I want to start one web server in a VM and have access to that web server from my machine at home.
The structure of hosts is in the next picture:
So this time I learned…
How to use SSH with Proxies and Port Forwarding to get access to my Private Network
In first place I have to mention that this usage of proxy jumping is described as a real use case, and it is intended for legal purposes only.
TL;DR$ ssh -L 10080:localhost:80 -J main-ui.myorg.com -J cloud-ui.myorg.com email@example.com
My first attempt to achieve this was to chain ssh calls (will forget about port forwarding for the moment):
$ ssh -t firstname.lastname@example.org ssh -t email@example.com ssh firstname.lastname@example.org
And this works, but has some problems…
- I am asked for a password at every stage (for main-ui, cloud-ui and web.internal). I want to use passwordless access (using my private key), but if I try to use ‘-i <private key>’ flag, the path to the files is always relative to the specific machine. So I would need to copy my private key to every machine (weird).
- I need to chain port forwarding by chaining individual port forwards.
- I will not work for scp.
I tried SSHProxyCommand options, but I found easier to use ProxyJump option (i.e. -J). So my attempt was:
$ ssh -J email@example.com -J firstname.lastname@example.org email@example.com
And this works, but I have not found any way to provide my private key in the command line but for the target host (web.internal).
And now I figured out how to configure this by using ssh-config files (i.e. $HOME/.ssh/config). I wrote the next entries in that file:
Host main-ui.myorg.com IdentityFile ~/.ssh/key-for-main-ui.key Host cloud-ui.myorg.com IdentityFile ~/.ssh/key-for-cloud-ui.key ProxyJump main-ui.myorg.com Host *.internal ProxyJump could-ui.myorg.com
Using that configuration I can access to web.internal by issuing the next simple command:
$ ssh -i keyfor-web.key firstname.lastname@example.org
And each file with each identity key written in the .ssh/config file y relative to my laptop, so I do not need to distribute my private key (nor create artificial intermediate keys).
The config file is also for the scp command, so I can issue commands like the next one:
$ scp -i keyfor-web.key ./myfile email@example.com:.
And ssh will make the magic!
But remember that I also wanted to access to my web server in web.internal. So the easies way is to port forward port 80 to a port (e.g. 10080) in my laptop.
So using the previous configuration I can issue a command like the next one:
$ ssh -i keyfor-web.key -L 10080:localhost:80 firstname.lastname@example.org
And now I will be able to open other terminal and issue the next command:
$ curl localhost:10080
and I will get the contents from web.internal.
Flag -L can be interpreted as (using the previous ssh call): connect using ssh to email@example.com and forward to ‘localhost:80’ any traffic received in port 10080 from the client host.
If I had no ssh access to web.internal, I could issue the next alternate command:
$ ssh -L 10080:web.internal:80 firstname.lastname@example.org
In this case, -L flag will be interpreted as: connect using ssh to email@example.com and forward to ‘web.internal:80’ any traffic received in port 10080 from the client host.
Using these commands I will need to keep the ssh session opened. In case that I wanted to forget about that session, and run port forwarding in background, I could use -f flag:
$ ssh -i keyfor-web.key -f -L 10080:localhost:80 firstname.lastname@example.org 'while true; do sleep 60; done'