2

I am new to HAProxy and got most parts working as expected. The current setup is: If I add a new site to one of the balanced (behind the LB) servers, the certificate is issued and served by the Load Balancer. So SSL Termination is working fine with regular Let's Encrypt certificates, but I have a limitation in this setup by the service I am using:

If I add a new site to a balanced server and want to use a wildcard *.wilddomain.com certificate, it is not issued by the Load Balancer, but by the balanced server (10.0.0.10). As LE validation is done over DNS, the wildcard certificate is valid and available on the balanced server now.

So now I have a Load Balancer with several "regular" LE certs which are used corretly, and a server behind which holds the wildcard certificate.

My question is: How can I set up HAProxy to passthrough to the wildcard certificate only for a specific domain (wilddomain.com) while serving all other certificates directly from the LB with SSL Termination.

My current config is this:

global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners 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/ # An alternative list with additional directives can be obtained from # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy ssl-default-bind-ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-> ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 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 # Default Let's Encrypt backend server used for renewals and requesting certificates backend letsencrypt-backend server letsencrypt 127.0.0.1:8888 # Load balancer settings frontend load-balancer bind *:80 bind *:443 ssl crt /etc/ssl/domain1.com/domain1.com.pem crt /etc/ssl/domain2.com/domain1.com.pem redirect scheme https code 301 if !{ ssl_fc } # See if its an letsencrypt request acl letsencrypt-acl path_beg /.well-known/acme-challenge/ use_backend letsencrypt-backend if letsencrypt-acl mode http default_backend webservers # Backend webservers (the attached servers to the load balancer) backend webservers balance roundrobin option forwardfor cookie SRVNAME insert http-request set-header X-Forwarded-Port %[dst_port] http-request add-header X-Forwarded-Proto https if { ssl_fc } # Server www1 server www1 10.0.0.10:80 weight 1 check # Server www2 server www2 10.0.0.11:80 weight 1 check 

EDIT I

I came a bit further by adding the following to the above config, but this produces "load-balancer/2: SSL handshake failure" in the HAProxy logs.

frontend wildcard_tcp bind *:443 option tcplog mode tcp tcp-request inspect-delay 5s tcp-request content accept if { req_ssl_hello_type 1 } acl is_wilddomain req_ssl_sni -m end wilddomain.com use_backend wildcard_server_tcp if is_wilddomain backend wildcard_server_tcp mode tcp server ssl-wildcard-server 10.0.0.10:443 

Is this a suitable and correct solution? Or is there a better / more performant one? Would it be even possible to have a very basic backend server that is only responsible for the ssl-offload? So only for issuing, renewing and serving the certificates?

Thanks so much!

2
  • Just to double check if I understood you correctly: you do most of the ssl-offload in haproxy and, if wilddomain.com is provided, you want haproxy to build a L4 tunnel that leaves the backend server do the ssl-offload? Commented Oct 9, 2020 at 0:54
  • @JoaoMorais thanks for the L4 Tunnel hint. Yes, I think that sounds like what I am trying to do without knowing the L4 Tunnel concept... To clarify a bit more: I have a multisite website, all subsites need to share the same wildcard certificate which is issued for *.wilddomain.com. As my LB can not handle wildcard certificates but my backend servers can, I want the LB to let the backend server do the ssl-offload but only for *.wilddomain.com. All other ssl-offload should be done by the LB, because I allow Domain Mapping and the LB handles regular certificates as required. Thanks!!! Commented Oct 9, 2020 at 8:40

1 Answer 1

2

tl;dr this can be done configuring a TCP proxy listening all requests and using the SNI extension to either: 1) call a TCP backend which leaves the ssl-offload to the server, or 2) call a HAProxy's HTTP frontend that does the ssl-offload.


HAProxy can be configured to use distinct certificates for distinct domains in the same IP/port, hence in the same bind line, when performing a TLS handshake. This configuration can be fine tuned using the crt-list keyword in the bind line.

Such configuration however doesn't have an option to passthrough the ssl-offload to a backend server. A HAProxy frontend should be configured to either perform the ssl-offload, or should be configured as mode tcp and leave the ssl-offload to the backend.

In order to achieve mixed local and remote ssl-offload in the same IP/port, for distinct domains, another proxy should be added to the HAProxy configuration:

 +-----------------+ | | +------+ (TCP request) | wildcard server | O | | === *.wildcard.com ===> | | -|- ==> | mode | +-----------------+ / \ | tcp | (local socket) +-------------+ | | === others ===> | | +------+ | https front | | ssl-offload | | | +-------------+ | | (plain http request) | v +---------------+ | | | other servers | | | +---------------+ 

The following snippet has the fronting TCP proxy and a local ssl-offload frontend. Note that this will consume twice the number of connections, tune global maxconn accordingly.

defaults timeout server 1s timeout client 1s timeout connect 1s listen public mode tcp bind :443,:::443 tcp-request inspect-delay 5s tcp-request content accept if { req.ssl_hello_type 1 } acl wildcard req.ssl_sni wildcard.local acl wildcard req.ssl_sni -m end .wildcard.local use_backend passthrough if wildcard server local_offload unix@/var/run/local.sock send-proxy-v2 backend passthrough mode tcp server ssl 10.0.0.10:443 listen local_offload mode http bind unix@/var/run/local.sock ssl crt /var/haproxy/crt.pem accept-proxy server plain0 10.0.0.10:80 server plain1 10.0.0.11:80 
1
  • Thank you so much! A very comprehensive and details answer. That is very useful, I changed the setup a bit but so far it seems to wwork quite well. I will test a bit further. :) Commented Oct 10, 2020 at 16:41

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.