Setting up Stunnel for HAProxy SSL support

Stunnel requires OpenSSL

Solaris 10 already has OpenSSL, so skip the following part:

Download OpenSSL source here

$ cd /usr/local/util
$ wget ftp://ftp.sunfreeware.com/pub/freeware/intel/10/openssl-0.9.8k-sol10-x86-local.gz
$ gunzip openssl-0.9.8k-sol10-x86-local.gz
$ pkgadd -d openssl-0.9.8k-sol10-x86-local
$ rm openssl-0.9.8k-sol10-x86-local

If building from source:

OpenSSL requires Perl 5

$ perl -version
This is perl, v5.8.4 built for i86pc-solaris-64int
...


Build and install OpenSSL as follows:

$ ./config
$ make
$ make test
$ make install


OpenSSL installs in /usr/local/ssl by default.


Get Stunnel source here

The Stunnel version needs to be one that there is an HAProxy x-forwarded-for patch for, i.e., 4.22

$ cd /usr/local/util
$ wget http://www.stunnel.org/download/stunnel/src/stunnel-4.22.tar.gz
$ gunzip stunnel-4.22.tar.gz
$ tar -xvf stunnel-4.22.tar
$ rm stunnel-4.22.tar

Download appropriate Stunnel x-forwarded-for source IP patch from HAProxy site

$ wget http://haproxy.1wt.eu/download/patches/stunnel-4.22-xforwarded-for.diff
$ file stunnel-4.22-xforwarded-for.diff
$ gunzip stunnel-4.22-xforwarded-for.diff

If on Solaris, you want to download and install a better implementation of patch:

$ wget ftp://ftp.sunfreeware.com/pub/freeware/intel/10/patch-2.5.9-sol10-x86-local.gz
$ gunzip patch-2.5.9-sol10-x86-local.gz
$ pkgadd -d patch-2.5.9-sol10-x86-local
$ rm patch-2.5.9-sol10-x86-local
$ hash -r

Apply the patch

$ patch -p1 < {/path/to/patch/file}


$ patch -p1 < stunnel-4.22-xforwarded-for.diff
$ rm stunnel-4.22-xforwarded-for.diff

Stunnel compile instructions


$ cd stunnel-VERSION

On Solaris
$ ./configure --with-ssl=/usr/sfw --disable-libwrap
Elsewhere
$ ./configure

$ make
$ make install


HAProxy + Stunnel description

Create keys and self-signed certificate with keytool:

keytool -genkey -keyalg RSA -keysize 1024 -alias test_rsa -keystore myKeystore.jks


At this point we assume you created keys and CSR with Java keytool.
Extract cert and private key from Java Keystore .jks file with Portecle a simple Java GUI tool that can export keys and certificates.

Click open
Select the keystore
Enter the password
Right click on the key
Click Export
Select Private Key and Certificates
Select PEM Encoded
Click OK
Enter the password
Click OK
Don't enter a password unless you want to enter it every time when starting stunnel
Click OK
Enter a filename
Click Export

If the Cert in the keystore is just a CSR that was not signed and you received that back from the signing authority separate, replace the certificate in the file with the signed one you received from the signing authority.

Copy this .pem file to your server wherever your stunnel.conf points to or will point to for the keys and certificates.

Edit or create your stunnel.conf file possibly in /etc/stunnel per docs, but you can put it anywhere you like.

Example stunnel.conf:

cert=/etc/stunnel/some_key_cert_file.pem
;key = /usr/local/etc/stunnel/some_key_file_if_separate.pem
;setuid = nobody
;setgid = nogroup

pid = /etc/stunnel/stunnel.pid
debug = 3
output = /etc/stunnel/stunnel.log

socket=l:TCP_NODELAY=1
socket=r:TCP_NODELAY=1

[https]
accept=some-local-interface-name-or-ip:443
connect=some-local-interface-name-or-ip:80
TIMEOUTclose=0
xforwardedfor=yes


As an alternative to inet.d and services, you can start stunnel as a daemon with:

/usr/local/bin/stunnel /etc/stunnel/stunnel.conf

You will likely want to create a script to start, stop, and restart it and link it in the /etc/rc2.d dir so it auto-starts/stops at boot and shutdown.

In HAProxy config file be sure to add the except keyword in the listen section so that HAProxy does not overwrite the x-forwarded-for http header property injected by stunnel or you will lose the source ip and every connection will appear to come from the stunnel server in the access logs:


...
listen 192.168.1.1:80
mode http
balance roundrobin
option forwardfor except 192.168.1.1
...



If you want to use SSL between HAProxy and backend servers, create an stunnel configuration file for each server and start stunnel for each server. In each stunnel configuration file specify a different accept port and the appropriate connect address and port for its backend server, i.e.,


pid = /etc/stunnel/client-stunnel.pid
debug = 3
output = /etc/stunnel/client-stunnel.log

socket=l:TCP_NODELAY=1
socket=r:TCP_NODELAY=1

[pseudo-https]
accept=some-local-interface-name-or-ip:10123
connect=some-remote-interface-name-or-ip:8443
;TIMEOUTclose=0


In HAProxy update the server directives to forward to the new stunnel instances which will re-encrypt data before forwarding to the backend servers. Additionally, the backend servers must be configured for SSL on the port specified in the stunnel connect directive. This might be done by the service itself or another instance of stunnel.

Notes on certificates and browsers:

If the path in the certificate and the URL don't match:
Firefox defaults won't let you add the certificate as an exception
Internet Explorer defaults will let you add the certificate as an exception and let you navigate to the site. IE will display the URL field in red and show a Certificate Error in red next to the address field.

Shutdown script:

#!/bin/bash

DIRNAME=`dirname $0`

if [ "$1" = "" ]; then
echo
echo " usage: stopStunnel {stunnelName}"
echo
exit 1
fi

vpid=`cat $DIRNAME/$1.pid`
echo $vpid

# shutdown running stunnel
if [ -n "$vpid" ] ; then
echo "killing stunnel: $1"
kill $vpid
else
echo "stunnel not running: $1"
fi

Comments

Nosugref said…
Thanks for the writeup! If you're trying to do this on Fedora 8, in addition to installing openssl, you need:

yum install openssl-devel

or else you'll get the error:

"Couldn't find your SSL library installation dir"

Just posting this to help the next person...

Popular posts from this blog

Sites, Newsletters, and Blogs

Oracle JDBC ReadTimeout QueryTimeout

Locks held on Oracle for hours after sessions abnormally terminated by node failure