SNI routing to servers - only ever sent to first server


#1

Hi there.

I’m trying to get HAProxy setup to receive requests on port 443 for a range of different subdomains, then use SNI based ACLs to direct them to an appropriate server for that domain.
The problem is that when I try going to support.domain.com.au it just sends my request to the webserver for cloud.domain.com.au.

I’ve followed this guide: https://www.haproxy.com/blog/enhanced-ssl-load-balancing-with-server-name-indication-sni-tls-extension/

My current (mildly santized) config is below, and any help would be greatly appreciated!

Thanks in advance.

global
        log /dev/log    local0
        log /dev/log    local1 notice
        chroot /var/lib/haproxy
        stats socket /run/haproxy/admin.sock mode 660 level admin
        stats timeout 30s
        user haproxy
        group haproxy
        daemon

        # Default SSL material locations
        ca-base /etc/ssl/certs
        crt-base /etc/ssl/private

        # Default ciphers to use on SSL-enabled listening sockets.
        # For more information, see ciphers(1SSL). This list is from:
        #  https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
        ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
        ssl-default-bind-options no-sslv3

defaults
        log     global
        mode    tcp
        option  tcplog
        option  dontlognull
        timeout connect 15s
        timeout client  15s
        timeout server  15s
        errorfile 400 /etc/haproxy/errors/400.http
        errorfile 403 /etc/haproxy/errors/403.http
        errorfile 408 /etc/haproxy/errors/408.http
        errorfile 500 /etc/haproxy/errors/500.http
        errorfile 502 /etc/haproxy/errors/502.http
        errorfile 503 /etc/haproxy/errors/503.http
        errorfile 504 /etc/haproxy/errors/504.http

#Define Frontends

frontend http-in
        bind 10.1.1.1:80
        mode http
        redirect scheme https code 301 if !{ ssl_fc }
		
frontend https-in
        bind 10.1.1.19:443
        mode tcp

		tcp-request inspect-delay 5s
		tcp-request content accept if { req.ssl_hello_type 1 }
		
		default_backend ssl_default

#Define Backends

backend ssl_default
        mode tcp
		
        acl servercloud_acl req.ssl_sni -i cloud.domain.com.au
	    acl serversupport_acl req.ssl_sni -i support.domain.com.au

        use-server servercloud_https if servercloud_acl
	    use-server serversupport_https if serversupport_acl

        option ssl-hello-chk		
        server servercloud_https 192.168.1.1:443 check
        server serversupport_https 192.168.1.2:443 check

#2

Please don’t use this configuration, using servers with different content in the same backend is a very bad idea and I honestly don’t know why the blog post suggest this.

Please use different backends for different content and SNI route in the frontend, choosing the proper backend (move the SNI ACLs to the frontend and configure the backend by using “use-backend” with the SNI ACLs).

Also, you will have to make sure that 192.168.1.1 and 192.168.1.2 have different certificates (not matching each others hostnames). Otherwise the browser will use existing TLS sessions to connect to the other domain, which will lead to this behavior.


#3

Hi there,

Thank you very much for your help.
I’ll make the changes you recommended and give it a go. The only problem is that all our subsites use the same wildcard certificate, as they are all subdomains of the main one.

Would I then have to switch to actually decrypting the traffic in order to get this working (http mode), so can I avoid that somehow?

Kind regards.


#4

Yes, if the certificates matches both hostnames (for example due to a wildcart certificate or multiple SAN’s), the browser will use the same TLS session for both hostnames. This is an important thing to keep in mind, when using SNI to route between backends.

If cloud.domain.com.au and support.domain.com.au are never requested from the same browser/client, this issue may not present itself. But if it is, its likely request will be routed to the wrong backend.

Indeed, terminating TLS on haproxy and using the Host header to route the traffic to the correct backend is what fixes this issue, regardless of the certificate.