Some time ago, we wrote an article that explained how to load-balance SSL services while maintaining affinity using the SSLID. The main limitation of this kind of architecture is that you must dedicate a public IP address and port per service.
If you’re hosting web or mail services, you could run out of public IP addresses quickly. TLS protocol was extended in 2003, RFC 3546, by an extension called SNI (Server Name Indication), which allows a client to announce the server name it is contacting clearly.
Two RFCs have obsoleted the one above, and the latest one is RFC 6066
The Aloha load balancer can use this information to choose a backend or a server. This allows people to share a single VIP for several services.
Of course, we can use SNI switching with SSLID affinity to build a smart and reliable SSL load-balanced platform.
Server Name information is sent with each SSL Handshake, whether you’re establishing a new session or you’re resuming an old one.
SNI is independent of the protocol used at layer 7. So basically, it will work with IMAP, HTTP, SMTP, POP, etc.
Limitation
Bear in mind that in 2012, not all clients are compatible with SNI. Concerning web browsers, a few of them used in 2012 are still not compatible with this TLS protocol extension.
We strongly recommend that you read the Wikipedia Server Name Indication page, which lists all the limitations of this extension.
Only HAProxy nightly snapshots from the 8th of April are compatible (with no bug known) with it.
Concerning ALOHA, it will be available by ALOHA Load-balancer firmware 5.0.2.
Diagram
The picture below shows a platform with a single VIP that hosts services for two applications:
We can use SNI information to choose a backend, and then, inside a backend, we can use SSLID affinity.
Configuration
Choose a backend using SNI TLS extension
The configuration below matches names provided by the SNI extension and chooses a farm based on it.
On the farm, it provides SSLID affinity.
If no SNI extension is sent, then we redirect the user to a server farm which can be used to tell the user to upgrade its software.
# Adjust the timeout to your needs
defaults
timeout client 30s
timeout server 30s
timeout connect 5s
# Single VIP with sni content switching
frontend ft_ssl_vip
bind 10.0.0.10:443
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl application_1 req_ssl_sni -i application1.domain.com
acl application_2 req_ssl_sni -i application2.domain.com
use_backend bk_ssl_application_1 if application_1
use_backend bk_ssl_application_2 if application_2
default_backend bk_ssl_default
# Application 1 farm description
backend bk_ssl_application_1
mode tcp
balance roundrobin
# maximum SSL session ID length is 32 bytes.
stick-table type binary len 32 size 30k expire 30m
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
# use tcp content accepts to detects ssl client and server hello.
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# no timeout on response inspect delay by default.
tcp-response content accept if serverhello
stick on payload_lv(43,1) if clienthello
# Learn on response if server hello.
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
server server1 192.168.1.1:443 check
server server2 192.168.1.2:443 check
# Application 2 farm description
backend bk_ssl_application_2
mode tcp
balance roundrobin
# maximum SSL session ID length is 32 bytes.
stick-table type binary len 32 size 30k expire 30m
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
# use tcp content accepts to detects ssl client and server hello.
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# no timeout on response inspect delay by default.
tcp-response content accept if serverhello
stick on payload_lv(43,1) if clienthello
# Learn on response if server hello.
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
server server1 192.168.2.1:443 check
server server2 192.168.2.2:443 check
# Sorry backend which should invite the user to update its client
backend bk_ssl_default
mode tcp
balance roundrobin
# maximum SSL session ID length is 32 bytes.
stick-table type binary len 32 size 30k expire 30m
acl clienthello req_ssl_hello_type 1
acl serverhello rep_ssl_hello_type 2
# use tcp content accepts to detects ssl client and server hello.
tcp-request inspect-delay 5s
tcp-request content accept if clienthello
# no timeout on response inspect delay by default.
tcp-response content accept if serverhello
stick on payload_lv(43,1) if clienthello
# Learn on response if server hello.
stick store-response payload_lv(43,1) if serverhello
option ssl-hello-chk
server server1 10.0.0.11:443 check
server server2 10.0.0.12:443 check
Choose a server using SNI: aka SSL routing
The configuration below matches names provided by the SNI extension and chooses a server based on it.
If no SNI is provided or we can’t find the expected name, then the traffic is forwarded to server3 which can be used to tell the user to upgrade its software.
# Adjust the timeout to your needs
defaults
timeout client 30s
timeout server 30s
timeout connect 5s
# Single VIP
frontend ft_ssl_vip
bind 10.0.0.10:443
mode tcp
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
default_backend bk_ssl_default
# Using SNI to take routing decision
backend bk_ssl_default
mode tcp
acl application_1 req_ssl_sni -i application1.domain.com
acl application_2 req_ssl_sni -i application2.domain.com
use-server server1 if application_1
use-server server2 if application_2
use-server server3 if !application_1 !application_2
option ssl-hello-chk
server server1 10.0.0.11:443 check
server server2 10.0.0.12:443 check
server server3 10.0.0.13:443 check
Related Links