Mikko Kortelainen

Tunneling SSH over HTTPS with stunnel

I was faced with a firewall denying access to the outside world using ssh. All I had was http/https access via a proxy server which required authentication. I had an Ubuntu jump host outside the network connected to the internet with a free 443 port. I tried accessing that with httptunnel and proxytunnel, but could get neither to work with this proxy server.

The solution that worked in this particular case was stunnel. It can wrap any TCP connection into an https session which was not rejected by the proxy server I was facing.

Client

Install stunnel on laptop (mine is Ubuntu 18.04), and use openssl to generate a key and a certificate:

sudo su -
apt-get install stunnel4
cd /etc/stunnel
openssl genrsa 1024 > stunnel.key
openssl req -new -key stunnel.key -x509 -days 1000 -out stunnel.crt
# (you can accept openssl defaults)
cat stunnel.crt stunnel.key >stunnel.pem

The values you enter in the client certificate request do not matter.

Next, create stunnel configuration. You should replace the variables with your own values.

PROXY_ADDRESS="<your proxy_address:proxy_port>"
PROXY_USERNAME="<your proxy username>"
PROXY_PASSWORD="<your proxy password>"
JUMP_HOST_ADDRESS="<your jump host address>"

cat >/etc/stunnel/stunnel.conf <<EOF
pid=/var/run/stunnel.pid
cert=/etc/stunnel/stunnel.pem

[ssh]
client=yes
libwrap=no
accept=2222
connect=$PROXY_ADDRESS
protocolUsername=$PROXY_USERNAME
protocolPassword=$PROXY_PASSWORD
protocolHost=$JUMP_HOST_ADDRESS:443
EOF

systemctl start stunnel4

Stunnel should now be running on your laptop. It will forward any connection you make to localhost:2222 to your $JUMP_HOST port 443 and wrap it in an https request.

Jump host

The proxy server did not accept self-signed certificates, so I installed certbot to get a working certificate on the jump host (mine is Ubuntu 19.10):

sudo su -
add-apt-repository ppa:certbot/certbot
apt-get install certbot
certbot certonly --standalone

# Make note where certbot installs the private key
# and the full certificate chain

Install stunnel on server and configure it:

JUMP_HOST_DNS_NAME="<your jump host DNS name>"

apt-get install stunnel4

cat >/etc/stunnel/stunnel.conf <<EOF
pid=/var/run/stunnel.pid
key=/etc/letsencrypt/live/$JUMP_HOST_DNS_NAME/privkey.pem
cert=/etc/letsencrypt/live/$JUMP_HOST_DNS_NAME/fullchain.pem

[ssh]
accept=443
connect=127.0.0.1:22
EOF

systemctl start stunnel4

Make sure the key and cert paths are pointing to correct certbot files.

Stunnel should now be running on the jump host as well. It will listen on port 443, unwrap the https and redirect the connection to localhost port 22, where sshd should be listening.

Test From Client

Now you should be able to ssh to your jump host by connecting to the local stunnel instance:

ssh localhost -p 2222