If you are reading this, you might be interested in the full list of my articles about doing SSH over SSL. I have been improving my configuration over the years, so the more recent, the better:
- 2010-11-12: Quick and minimal config
- 2010-11-15: Replacing proxytunnel with socat
- 2011-07-11: Avoiding using a patched Apache
- 2014-10-19: HAproxy based configuration
Last week, I wrote an article about how to quickly set up a server and a client for doing ssh over ssl. In this article, I was using proxytunnel, but I realized today that it could probably be replaced with socat (socat can do almost anything)...
The principle is simple: Following the first part of the tutorial, you make your server accept proxy_connect requests to its private port localhost:22 through its public port 443, encapsulating the whole thing in SSL (as a reminder, 22 and 443 are respectively the standard ports for ssh and ssl).
We now want to configure the ssh clients in order to connect through this ssl tunnel. I said I was configuring the clients with proxytunnel. The exact command (in .ssh/config) was:
proxytunnel -q -E -p server.com:443 -d 127.0.0.1:22
I'll explain it:
-qis for quiet
-Eis for encrypting between the proxy and us
-pis for choosing the proxy
-dis for requesting a destination (from the proxy point of view)
So basically, this means: "connect stdio to server.com on port 443 (-p server.com:443) , in an encrypted way (-E), then from this server, require to be connected to 127.0.0.1:22 (-d 127.0.0.1:22)".
For those who like to play with all sorts of streams, socat is really the best tool ever invented. I was wondering if I could reproduce proxytunnel's behavior with socat, and it turns out you can. Here is how to proceed: First, create an ssl tunnel between your client's localhost:1080 and server.com:443:
socat TCP-LISTEN:1080 OPENSSL:server.com:443
This way, the port 443 of server.com is now available unencrypted on localhost:1080 Then, use socat and its proxy mode to ask for localhost:1080 (which is actually server.com:443 unencrypted) to connect to localhost:22 (which is then server.com:22).
socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080
Bingo! You should see the ssh prompt. For the fun, I replaced in my .ssh/config the former
ProxyCommand proxytunnel -q -E -p server.com:443 -d 127.0.0.1:22
ProxyCommand socat TCP-LISTEN:1080 OPENSSL:server.com:443,verify=0 & socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080
Edit 2015-05-07: See Vincent's
for a cool idea to wrap the ssh command with the
It works just fine. There is however a flaw in what I did: I use a hardcoded port, thus I can't establish two ssh connections at the same time. Forwarding the server.com:443 on localhost:1080 fails the second time, since this port is already occupied by the first connection. The best way to fix that would be to use stdio for the proxy_connect requests, instead of a port of localhost (since the number of these port is limited). However, with my version of socat (18.104.22.168), I don't see how to proceed differently: the PROXY method requires three arguments and one of them is a port. If one of my readers has a suggestion, he/she's welcome. This remains a cool hack!
Edit: The great Marco Fontani gave a cool solution (see the comments). Here is how my .ssh/config looks like:
Host server.com ProxyCommand socat TCP-LISTEN:1080 OPENSSL:server.com:443,verify=0 & sleep 1 && socat - PROXY:127.0.0.1:127.0.0.1:22,proxyport=1080 DynamicForward 1080 ServerAliveInterval 60 ControlMaster auto ControlPath ~/.ssh/tmp/%h_%p_%r