I've got a HAProxy 1.5.9 server that will serve either a certificate signed by a self signed CA or a Let's Encrypt certificate depending on which 'servername' is provided. This is my configuration file:
defaults
mode tcp
option clitcpka
listen ft_app
bind *:5000 ssl crt /certs/private.pem ca-file /app/certs/self-signed-ca.pem crt /certs/self-signed.pem crt /app/certs/lets-encrypt.pem ciphers AES:ALL:!aNULL:!eNULL:!3DES:!DES:!RC4:!DHE:!EDH:!MD5:!PSK:!aECDH:@STRENGTH no-sslv3 no-tlsv10 no-tlsv11
mode tcp
option tcplog
tcp-request inspect-delay 10s
use_backend app_http if HTTP
default_backend app_tcp
backend app_http
mode http
option httplog
balance roundrobin
reqadd X-Forwarded-Proto:\ https
cookie SRVID insert indirect nocache
http-check expect status 200
server app_4 10.10.10.4:15672 cookie app_4 check inter 10s rise 2 fall 2
server app_3 10.10.10.3:15672 cookie app_3 check inter 10s rise 2 fall 2
server app_2 10.10.10.2:15672 cookie app_2 check inter 10s rise 2 fall 2
backend app_tcp
option tcp-check
server app_4 10.10.10.4:5672 check inter 10s rise 2 fall 2
server app_3 10.10.10.3:5672 check inter 10s rise 2 fall 2
server app_2 10.10.10.2:5672 check inter 10s rise 2 fall 2
It works. What I don't understand here is exactly how HAProxy selects which certificate to serve up. I assume that is grabbing the 'servername' from the certificate metadata. If so exactly which field, and how do I examine it, openssl x509 -in ca.pem -text -noout
doesn't seem to have any likely suspects.
I figured it out. RTFM. From the HAProxy docs:
https://cbonte.github.io/haproxy-dconv/1.7/configuration.html#5.1-crt
So, it used the CN or alt name, or defaults to the first provided certificate. I checked the CN, which doesn't match, but then I found the alt name:
That matches the domain I connect with when I get that certificate! So in my case Haproxy selects the certificate using alt names as the CN isn't a FQDN.
The server name in a TLS certificate is first the “Common Name” displayed as
Subject: ... CN=www.example.com
When you have a certificate that contains more than 1 server name it is called SAN certificate https://en.m.wikipedia.org/wiki/Subject_Alternative_Name
And the additional server names that are valid with that certificate are
Entries.
With Server Name Indication from the client HAProxy can match the requested url with the available certificates.
If no sni is used by the client or no certificate matches HAProxy probably uses the first certificate as the default (and the client gets a certificate mismatch error