SSH Jumphosts tunneling and other curiosities
almost 5 years ago
The IT department is in love with their brand new proxy server. They are so in love with it that they decreed that all connections to the Internets must go via the proxy server, no exceptions.
My brand new web 2.0 intranet application must also live behind this proxy server. I think it makes perfect sense, except for one minor issue. How do I support this thing? I discussed my solution with the IT department and they were fine with it. So here you go.
“Corkscrew”:http://www.agroman.net/corkscrew/ is a tool for tunneling through http proxies. Its a little bit like netcat which in turn is a little bit like telnet. It connects to a proxy and gives it your input stream in base64.
Corkscrew and ssh are friends, all you have to do is add the following line to the ~/.ssh/config file
Host * ProxyCommand corkscrew http://user:pass@theawsomeproxy 8080 %h %p
And magic, you can start sshing out of the firewall, through the proxy server.
h2. Setting up a stable reverse tunnel
“Quite”:http://www.revsys.com/writings/quicktips/ssh-tunnel.html “a”:http://wiki.mt-daapd.org/wiki/SSH_Tunnel “lot”:http://gentoo-wiki.com/TIP_SSH_Reverse_Tunnel has been written about SSH tunneling. The concept is fairly straight forward, using SSH and a few switches you can either push a port from your local machine to a remote host (reverse tunnel) or pull a port from a remote machine locally (tunnel).
I wanted to be able to ssh into the firewall from the internets. So I had to push port 22 on my intranet server to my public server.
The command to do this is fairly trivial, something along the lines of the following will do:
ssh -R 8888:localhost:22 public_server
Once this is done I can ssh into public_server on port 8888 to access ssh on my server which is behind the firewall.
The big problem is that ssh tunnels behind NATs and Proxies die. Death of the ssh tunnel means I no longer have remote access, which means I have to drive to the client to fire it off again. This is obviously not acceptable.
So the internet has quite a few solutions to this problem, the most popular one seems to be a tool called “autossh”:http://www.harding.motd.ca/autossh/.
This tool will restart your tunnels if they die. I set this tool up and it seemed to work fine for a day or two. But somewhere between me not configuring the tool right and the almighty proxy, autossh seemed to fail on me. So, I decided that instead of spending a week debugging this I might as well write a simple script in ruby to monitor my ssh tunnel.
h2. Super SSH
I chucked my “in progress script”:http://github.com/sambo99/super-ssh/tree/master on github for your enjoyment. What it does is fairly simple. It forwards the ssh port to the public server and tries to connect back to itself from the public server every minute. If the connection fails it assumes something went wrong and it will restart the tunnel.
It still needs a bunch of command line switches and a fair bit of work, but it seems to be doing the job for me.
A key to getting anything along these lines to work is ensuring your ssh connection uses public/private keys for authentication. If you use ssh on a regular basis and passwordless ssh authentication sounds foreign, stop reading this and look it up on the internet. The two commands, “ssh-keygen”:http://www.openbsd.org/cgi-bin/man.cgi?query=ssh-keygen and “ssh-copy-id”:http://www.math.ucla.edu/computing/docindex/openssh-man-6.html are your friends, use them.
h2. Working from home, jumphosts
In order to deploy my application from home I need to connect to the server behind the firewall via my public server. I can always ssh twice, but it seems like a little bit of a headache.
I wanted to type “ssh work” and have my dev box connect to the production box. I also wanted http://localhost:9999 to take me to the production web site, so I can test it.
Here is how I achieve this with my ~/.ssh/config file
Host work ProxyCommand ssh public_server nc -w 1 localhost 8888 LocalForward 9999 localhost:80
The ProxyCommand directive chains my ssh tunnels (using netcat), the LocalForward command forwards a remote port locally.
Hope this helps someone else out there.