Update: HAProxy can now handle SSL client certificate: SSL Client certificate management at application level

History

HAProxy is well know for its performance as a reverse-proxy and load-balancer and is widely deployed on web platforms where performance matters. It is sometimes even used to replace hardware load-balancers such as F5 appliances.
When the platform requires SSL, it is common to use nginx, Pound or http://www.stunnel.org/index.html. Recently, stud came in the dance with a major advantage over other software: support for HAProxy’s proxy protocol.

At HAProxy Technologies, we build our ALOHA load-balancers using HAProxy and we use stunnel as the SSL offloading software. Our clients wanted some new features on our SSL implementation we could not provide through stunnel.
By the way, you can find our stunnel patches here: //www.haproxy.com/download/free/patches/stunnel/
An other important thing to notice, is that stunnel does not scale very well: when managing a lot en encrypted connections, stud or nginx are far much better.
That’s why we decided to implement SSL directly in HAProxy. For now, it is still quite basic: SSL offloading with SNI support and wildcard certificates, ability to encrypt traffic to servers.
But at least, the performance are here!
We’ll keep on improving it later with new features, IE: client certificate management and some fun stuff with ACLs: stay tuned!

Remember that the job was done by HAProxy Technologies engineers.

Note that if you’re using the softwares listed above for other purpose than SSL, then you may still use them. For example, nginx performs very well on static content and on dynamic using php-fpm.

SSL offloading diagram

This is pretty simple, as shown on the picture below. The client will get connected on HAProxy using SSL, HAProxy will process SSL and get connected in clear to the server:
ssl offloading diagram

HAproxy installation

cd /usr/src
wget http://haproxy.1wt.eu/download/1.5/src/devel/haproxy-1.5-dev12.tar.gz
tar xzf haproxy-1.5-dev12.tar.gz
cd haproxy-1.5-dev12/
make TARGET=linux2628 USE_STATIC_PCRE=1 USE_OPENSSL=1
sudo make PREFIX=/opt/haproxy-ssl install

HAProxy configuration for SSL offloading

First of all, you have to generate a few keys and a certificates using openssl and concatenate them in a file, the certificate first, then the key.

HAProxy configuration, very basic, for test purpose, and just to let you know which lines are very important:

defaults
 log 127.0.0.1 local0
 option tcplog

frontend ft_test
  mode http
  bind 0.0.0.0:8443 ssl crt ./haproxy.pem crt ./certs/ prefer-server-ciphers
  # other (self described) options are: [ciphers <suite>] [nosslv3] [notlsv1]
  use_backend bk_cert1 if { ssl_fc_sni cert1 } # content switching based on SNI
  use_backend bk_cert2 if { ssl_fc_sni cert2 } # content switching based on SNI
  default_backend bk_www.haproxy.com

backend bk_www.haproxy.com
 mode http
 server srvxlc 127.0.0.1:80

backend bk_cert1
  mode http
  server srv1 127.0.0.1:80

backend bk_cert2
  mode http
  server srv2 127.0.0.1:80

As you can see, HAProxy load one cert haproxy.pem which will be default one, and all the certificates from the certs dir. Actually, I have only 2 for my tests: cert1 and cert2.

Running HAProxy

First, just test the configuration is valid:

/opt/haproxy-ssl/sbin/haproxy -c -f ./hassl.cfg 
[WARNING] 247/110924 (6497) : config : missing timeouts for frontend 'ft_test'.
   | While not properly invalid, you will certainly encounter various problems
   | with such a configuration. To fix this, please ensure that all following
   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.
[WARNING] 247/110924 (6497) : config : missing timeouts for backend 'bk_test'.
   | While not properly invalid, you will certainly encounter various problems
   | with such a configuration. To fix this, please ensure that all following
   | timeouts are set to a non-zero value: 'client', 'connect', 'server'.
Configuration file is valid

Don’t worry about warnings, I purposely wrote a very basic configuration.

Now, you can run HAProxy:

/opt/haproxy-ssl/sbin/haproxy  -f ./ha.cfg

Testing SSL provided by HAProxy

Check the default certificate server name:

openssl s_client -connect 127.0.0.1:8443 -servername www.haproxy.com
[...]
Certificate chain
 0 s:/CN=www.haproxy.com
   i:/CN=www.haproxy.com
[...]

HAProxy log line:

[...] ft_test bk_www.haproxy.com/srvxlc [...]

Checking cert1, loaded from ./certs/ dir:

openssl s_client -connect 127.0.0.1:8443 -servername cert1
[...]
Certificate chain
 0 s:/CN=cert1
   i:/CN=cert1
[...]

HAProxy log line:

[...] ft_test bk_cert1/srv1 [...]

Checking cert2, loaded from ./certs/ dir:

openssl s_client -connect 127.0.0.1:8443 -servername cert2
[...]
Certificate chain
 0 s:/CN=cert2
   i:/CN=cert2
[...]

HAProxy log line:

[...] ft_test bk_cert2/srv2 [...]

Checking with an unknown servername:

openssl s_client -connect 127.0.0.1:8443 -servername kemp
[...]
Certificate chain
 0 s:/CN=www.haproxy.com
   i:/CN=www.haproxy.com
[...]

HAProxy log line:

[...] ft_test bk_www.haproxy.com/srvxlc [...]

When the name is unknown, the failover is well done on the default certificate.

And voilà !!!
Since it has been released in the 1.5 branch, you can use it in production 🙂

Related articles

Links