HAProxy multi domain SSL termination

HAProxy is a free, very fast and reliable solution offering high availability, load balancing, and proxying for TCP and HTTP-based applications. It is suited also to handle SSL Termination for other services. So the WebServer (Apache/NGINX/any) can focus on the content, and the crypto Stuff is offloaded to HAProxy.

HAProxy binds to Port 80 and Port 443 and redirects the traffic depending of the requested URL to the WebServer Backends.

For Debian Strech there exists a package with the latest stable version 1.7 available for install.

apt-get update && apt-get install haproxy

The settings for HAProxy are edited in a single file.

root@haproxy:/etc/haproxy# vi haproxy.cfg

In the global section some settings should be adjusted to improve security. The Applied Crypto Hardening Handbook from https://bettercrypto.org/ has a section for HAProxy settings. Though they could be better, so we do not need IE6.0 support. This browser version should not be used anyways.

Here are the updated Ciphers which have also been used in my Apache post before.

 ssl-default-bind-ciphers DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA 
 ssl-default-bind-options no-sslv3 no-tls-tickets #disable SSLv3
 tune.ssl.default-dh-param 4096 #tune DH to 4096

This disables the use of ciphers/protocol combination without perfect forward secrecy. Clients that do not support Forward Secrecy are excluded when determining support for it.

The tune.ssl.default-dh-param sets the maximum size of the Diffie-Hellman parameters used for generating the ephemeral/temporary Diffie-Hellman key in case of DHE key exchange. The final size will try to match the size of the server’s RSA key (e.g,
a 2048 bits temporary DH key for a 2048 bits RSA key), but will not exceed
this maximum value. This value is not used if static Diffie-Hellman parameters are supplied either directly in the certificate file or by using the ssl-dh-param-file parameter.

Custom static parameters are known to be more secure and therefore their use is recommended. Custom DH parameters may be generated by using the OpenSSL command “openssl dhparam <size>”, where size should be at least 2048, as 1024-bit DH parameters should not be considered secure anymore.

For the DH-Params we will generate a 4096 bit file. This may take some time depending  cpu power.

openssl dhparam -out /etc/haproxy/certs/dhparams.pem 4096

The setting to point haproxy is the following ssl-dh-param-file

ssl-dh-param-file /etc/haproxy/certs/dhparams.pem

HAProxy needs the SSL Certificate and Key File in a single PEM File. A self signed Certificate is working fine for testing/production and can be replaced with a Let’s Encrypt signed certificate later on.

root@haproxy:/etc/ssl# mkdir haproxy
root@haproxy:/etc/ssl# openssl req -x509 -nodes -sha256 -days 365 -newkey rsa:4096 -keyout /etc/ssl/private/domain.tld.key -out /etc/ssl/certs/domain.tld.pem 
root@haproxy:/etc/ssl# cat /etc/ssl/certs/domain.tld.pem /etc/ssl/domain.tld.key > /etc/ssl/haproxy/domain.tld.pem

The frontend needs to be added to the config file.

frontend frontend_public
 bind *:80
#Add multiple certificates, one for each domain.tld
 bind *:443 ssl crt /etc/ssl/haproxy/sub1.domain.tld.pem crt /etc/ssl/haproxy/sub2.domain.tld.pem crt /etc/ssl/haproxy/sub3.domain2.tld.pem 
 
 mode http
#redirect http to https
 redirect scheme https code 301 if !{ ssl_fc }

#:::ACL:::Define ACL for each Subdomain to terminate
 acl webserver1-acl req_ssl_sni -i sub1.domain.tld
 acl webserver2-acl req_ssl_sni -i sub2.domain.tld
 acl webserver3-acl req_ssl_sni -i sub3.domain2.tld

#:::BACKEND:::Use Backend Section
 use_backend webserver1-backend if webserver1-acl
 use_backend webserver2-backend if webserver2-acl
 use_backend webserver3-backend if webserver3-acl

To enable SNI functionality, the crt setting must be specified for each certificate/domain combination. And the certificate is provided to the user depending of the URL.

An AccessControlList is created for each subdomain which is terminated with req_ssl_sni at HAProxy. And for each ACL a backend is defined.

Also the backend section needs to be added for each webserver/domain combination.

backend webserver1-backend
 mode http
 server webserver1 192.168.1.101:80 check
 http-request set-header X-Forwarded-Port %[dst_port]
 http-request add-header X-Forwarded-Proto https if { ssl_fc }

backend webserver2-backend
 mode http
 server webserver2 192.168.1.102:80 check
 http-request set-header X-Forwarded-Port %[dst_port]
 http-request add-header X-Forwarded-Proto https if { ssl_fc }

backend webserver3-backend
 mode http
 server webserver3 192.168.1.103:80 check
 http-request set-header X-Forwarded-Port %[dst_port]
 http-request add-header X-Forwarded-Proto https if { ssl_fc }

With these settings a HAProxy setup with three different backend WebServers should be working whithout any problems. SSL Termination is done at HAProxy and the WebServers focus serving content only.

The next time i’ll show how to install Let’s Encrypt certificates without any HAProxy downtime.

Comments are closed.