How to master SSL termination in HAProxy: considerations and configurations
How-tos Published on •7 minsSSL termination (or TLS if you prefer the newfangled term!) is a standard requirement these days. But how do you actually configure this on your HAProxy load balancer? And how does a 'listen' configuration differ from a 'frontend and backend' configuration?
Here's a simple introduction to SSL offload and SSL termination in HAProxy to get you started.
The basics of SSL/TLS connections
In today's security focussed world, SSL connections (alright, alright, TLS connections...) have quickly become not just the norm but a requirement. Almost all browsers attempt to upgrade connections to HTTPS, and plain old HTTP is getting the cold shoulder. However, this isn't just the case for HTTP connections. We're now seeing the majority of TCP load balancing also requiring SSL termination/offload in modern applications.
Yep, you read right. I just stuck SSL termination and offload together in the same sentence like they're the same; they're definitely not. They are however close enough to each other that we use them interchangeably quite often. Although we really shouldn't. So, what is the difference between the two?
What is SSL/TLS termination?
SSL termination is when the load balancer is terminating the SSL connection. That is, it is the end of the SSL connection and the onward connection to the back-end is conducted via unencrypted means.
What is SSL/TLS offload?
SSL offload is when the burden of SSL related functions pertaining to the connection is offloaded to the load balancer. This relieves the cryptographic strain from the real servers.
OK, that makes it simpler, right? Good. Now that we understand that, it's probably worth pointing out that SSL termination is a specific function of SSL offload. That means that all SSL termination is SSL offload but not all SSL offload is SSL termination.
Got it? Great! Moving on 🤪.
In this particular article we are going to cover the main features and functionality, as well as the configuration of SSL termination.
Why use SSL/TLS termination?
SSL termination is the most regularly implemented kind of SSL offload. As we have already covered it is terminating the SSL traffic at the load balancer and sending it on as plain text. As the real servers are not having to perform any cryptographic functions on top of whatever services they are providing, it reduces the burden upon them freeing up resources to better perform their intended function.
What are the benefits of SSL/TLS termination at the load balancer?
When you terminate SSL at your load balancer you also simplify your certificate management. Instead of having to create, update, and maintain certificates for all your real servers, you only have to do that work for the certificate(s) installed on the load balancer.
Centralising your SSL processing also allows you to manage your SSL policies from one place. You can define the permitted ciphers and cipher suites and ensure that your configuration is consistent amongst all backend servers.
If you are operating a microservices architecture on your backend servers or you require some advanced content switching to happen at the load balancer you will need to unencrypt that traffic first. Once the traffic is unencrypted it can be run through your ACLs (Access Control Lists) and sent on it's merry way.
How to configure SSL/TLS termination in HAProxy
There are two main way to go about configuring HAProxy for SSL termination:
- You can add it as a listen configuration; or
- You can split it into frontend and backend configurations.
Both are valid, but splitting into frontend and backend configurations allows for much more flexibility of implementation.
If you are just performing SSL termination for a single pool of web servers then this could be simply achieved with a listen configuration.
Listen configuration for SSL termination in HAProxy
Before you are able to start with any of this, you will of course need an SSL certificate to perform the encryption. We already have a blog post about that if you need some help with it, you can find that here: How to create an SSL certificate in Linux.
Here's what you need for a listen configuration:
listen SSL_Termination
bind 172.16.1.10:443 transparent ssl crt /etc/ssl/your_domain.pem
mode http
balance leastconn
option http-keep-alive
timeout http-request 5s
option forwardfor
timeout tunnel 1h
option redispatch
option abortonclose
maxconn 40000
option httplog
server web-server-1 172.16.1.11:80 id 1 weight 100 check
server web-server-2 172.16.1.12:80 id 2 weight 100 check
To take it back to absolute basics, this bit here is about as simple as you can make it whilst still being functional:
listen SSL_Termination
bind 172.16.1.10:443 ssl crt /etc/ssl/your_domain.pem
server web-server-01 172.16.1.11:80
The above configuration will listen for requests coming in on 172.16.1.10, unencrypt that traffic, and pass it on to web-server-01 as plain HTTP.
Frontend and backend configuration for SSL/TLS termination in HAProxy
There is slightly more to do when you split the configuration into frontend and backend blocks, but this does offer some advantages over the simple listen block which make this approach worthwhile. Specifically, using frontends and backends allows for complex routing or content switching.
Using ACLs you are able to achieve some very clever setups and implementations of HAProxy. This is particularly useful in microservices architectures where different parts of a URL path may actually need to go to entirely different servers to form the complete response. This control can be extremely granular and ACLs are available to make direct requests in a myriad of ways.
So ultimately you achieve simplicity through complexity. I know this sounds like (and, ok, actually is) an oxymoron but the more complex your infrastructure and requirements, the simpler it becomes to administer by separating things out into different backend configuration blocks. In other words, you're able to structure your configuration so that it becomes obvious what config is performing what actions!
Here's what you need to do...
So, let's start with a simple version of a frontend backend configuration. And it really is pretty simple:
frontend SSL_Termination
bind *:443 ssl crt /etc/ssl/your_domain.pem
default_backend web_servers
backend web_servers
server web_server_1 172.16.1.11:80
The frontend SSL_Termination
has a bind that is listening on all IP addresses on port 443, and any matching traffic that comes into HAProxy is dealt with by this frontend.
There are no other rules or configurations in place so it needs a default to send all relevant traffic to. In this case, that is the web_servers
backend. The default_backend web_servers
receives the unencrypted traffic from the frontend and sends it to the configured web server.
Next, is a slightly more complex implementation where SNI (Server Name Identification) is being used. In this instance, requests will be sent to different backends based on the server name:
frontend SSL_Termination
bind *:443 ssl crt /etc/ssl/your_domain.pem
acl sni_website req_ssl_sni -i www.loadbalancer.org
acl sni_docsite req_ssl_sni -i pdfs.loadbalancer.org
use_backend web_servers if sni_website
use_backend doc_servers if sni_docsite
default_backend default
backend web_servers
server web_server_1 172.16.1.11:80
backend doc_servers
server doc_server_1 172.16.1.21:80
backend default
server default 127.0.0.1:80
So now we have some ACL rules that are going to do the traffic matching, and some additional rules that define where the traffic will go if an ACL match is made.
If a request for the website www.loadbalancer.org comes into HAProxy it is going to be handled by the frontend SSL_Termination
and unencrypted. As the traffic is now unencrypted it can be parsed and routed based on things like the URL path.
In the above example, we are using the SNI information which does not need to be unencrypted to be parsed. HAProxy runs the request through its configuration and then we hit the first ACL rule sni_website
. As the request is going to have an SNI value of www.loadbalancer.org, this will evaluate to TRUE.
As the request then runs through the rest of the configuration it hits the use_backend
rule, which it matches as it passes the IF condition of sni_website
being TRUE. The request is then passed on to the web_servers
backend and sent onto the configured real server.
And there you have it. That's what the configuration looks like in HAProxy! It's pretty simple to configure, but it performs an increasingly necessary function.
How to configure SSL/TLS termination in Loadbalancer Enterprise
Want to make things even easier?
Whilst it is simple enough to configure SSL termination in HAProxy, it is however even easier to do this on your Loadbalancer.org appliance, as you can see from this quick video which shows that this can be done in just a few clicks:
- Go to 'Cluster Configuration', then click 'Layer 7 - Virtual Services'.
- Click the 'Add a new Virtual Service' button.
- Add a label ('SSL_Termination'), the IP address, and your port.
- Click 'Advanced +' .
- In the Termination section, tick the 'Create SSL Termination' box and click 'Update'.
- On the left hand side, then click 'Layer 7 - Real Servers'.
- Click the 'Add a new Real Server' button.
- Add a label ('WebServer1'), add the web server IP address and click 'Update'.
- On the left hand side, then click on 'System Overview'
- Click the 'Reload HAProxy' button.
How easy was that?!!
What other types of SSL/TLS offload are there?
SSL termination is something that is pretty simple to implement both in HAProxy, and with Loadbalancer Enterprise. And, as the world moves to being HTTPS/SSL first, you should now have the information you need to move with this trend and keep your applications secured.
This has been a taster and an introduction to SSL offload, but there are many more things that can be achieved with SSL offload such as mTLS. If you'd like to know more about mTLS, check out the links below:
In the meantime, let me know in the comments below if there are any other topics you'd like me to do an explainer on.