Hello list, I saw William Lallemand's announcement regarding the possibility of loading dynamic ssl certificates right here https://www.mail-archive.com/haproxy@formilux.org/msg36927.html and the idea of having so much control over the haproxy instance was intriguing.
I've set up a test instance of the latest 2.2-dev9 to test out this feature and I seem to have hit a bump in the road. I am an usure if I misunderstood what was supposed to happen, or if I've stumbled across a bug. In my configuration file, I'm instructing haproxy to load all existing certificates from a folder and I'm trying to load a new certificate using the new "new ssl cert/add ssl cert/commit ssl cert" commands through the haproxy socket. The domain with the certificate loaded manually seems to have SNI problems until haproxy is restarted and the certificate is read from the crt folder. I'm using foo.com and bar.com as example domains. The one that haproxy loads from the folder is generated and self-signed (foo.com), while the one I'm trying to load is valid and issued by let's encrypt (bar.com). I've used a slight variation of the config file found in reg-tests/ssl/set_ssl_cert.vtc as follows: ------------------------------------------------------[Start]------------------------------------------------------ global maxconn 4096 user root group root daemon log 127.0.0.1 local0 debug stats socket "/tmp/stats" level admin # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private tune.ssl.default-dh-param 2048 defaults log global mode http option httplog option dontlognull retries 3 option redispatch option http-server-close option forwardfor timeout connect 5000 timeout client 50000 timeout server 50000 listen https-in bind :443 transparent ssl strict-sni crt /etc/haproxy/ssl alpn h2,http/1.1 default_backend something backend something mode http server web 192.168.1.144:80 check ------------------------------------------------------[End]------------------------------------------------------ Haproxy starts succesfully and the pre-existing certificate in the /etc/haproxy/ssl is present and loaded: ------------------------------------------------------[Start]------------------------------------------------------ ]# haproxy -d -f /etc/haproxy/haproxy.cfg Available polling systems : epoll : pref=300, test result OK poll : pref=200, test result OK select : pref=150, test result FAILED Total: 3 (2 usable), will use epoll. Available filters : [SPOE] spoe [COMP] compression [TRACE] trace [CACHE] cache [FCGI] fcgi-app Using epoll() as the polling mechanism. ------------------------------------------------------[Middle]------------------------------------------------------ ]# echo -e "show ssl cert" | socat /tmp/stats stdio # filename /etc/haproxy/ssl/foo.com.pem ]# echo -e "show ssl cert /etc/haproxy/ssl/foo.com.pem" | socat /tmp/stats stdio Filename: /etc/haproxy/ssl/foo.com.pem *Status: Used* Serial: DA0AD0EC8F6C0C30 notBefore: Nov 8 15:31:08 2019 GMT notAfter: Dec 8 15:31:08 2019 GMT Subject Alternative Name: Algorithm: RSA2048 SHA1 FingerPrint: 81D4AF40722F5F7C704E3327C5695F78DA6DC1E0 Subject: /C=RO/ST=SomeState/L=Locality/O=OrganizationalOrg/OU=OrzanizatoricUnit/CN=foo.pem Issuer: /C=RO/ST=SomeState/L=Locality/O=OrganizationalOrg/OU=OrzanizatoricUnit/CN=foo.pem ------------------------------------------------------[End]------------------------------------------------------ Certificate status is "Used", browser loads "foo.com" with the proper certificate" Next I've tried inserting "bar.com" into a running haproxy: ------------------------------------------------------[Start]------------------------------------------------------ ]# cat /root/certificates/bar.com/fullchain.pem /root/certificates/bar.com/privkey.pem | sed '/^$/d' > /etc/haproxy/ssl/bar.com.pem ]# echo -e "new ssl cert /etc/haproxy/ssl/bar.com.pem" | socat /tmp/stats stdio New empty certificate store '/etc/haproxy/ssl/bar.com.pem'! # echo -e "set ssl cert /etc/haproxy/ssl/bar.com.pem <<\n$(cat /etc/haproxy/ssl/bar.com.pem)\n" | socat /tmp/stats stdio Transaction created for certificate /etc/haproxy/ssl/bar.com.pem! ]# echo -e "commit ssl cert /etc/haproxy/ssl/bar.com.pem" | socat /tmp/stats stdio Committing /etc/haproxy/ssl/bar.com.pem Success! ------------------------------------------------------[End]------------------------------------------------------ Everything seems to have worked successfully, although the certificate shows up as "Unused": ------------------------------------------------------[Start]------------------------------------------------------ ]# echo -e "show ssl cert /etc/haproxy/ssl/bar.com.pem" | socat /tmp/stats stdio Filename: /etc/haproxy/ssl/bar.com.pem *Status: Unused* Serial: 0315D3DD8EAB437293870474AB2B7055699B notBefore: Jun 16 20:30:03 2020 GMT notAfter: Sep 14 20:30:03 2020 GMT Subject Alternative Name: DNS:*.bar.com, DNS:bar.com Algorithm: RSA2048 SHA1 FingerPrint: 5AEECEA0218C07B8D9E4D1B248FB1614C32B79DE Subject: /CN=bar.com Issuer: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 Chain Subject: /C=US/O=Let's Encrypt/CN=Let's Encrypt Authority X3 Chain Issuer: /O=Digital Signature Trust Co./CN=DST Root CA X3 ------------------------------------------------------[End]------------------------------------------------------ When accessing bar.com in a firefox browser window, the following happens: ------------------------------------------------------[Start]------------------------------------------------------ Secure Connection Failed An error occurred during a connection to bar.com. SSL peer has no certificate for the requested DNS name. Error code: SSL_ERROR_UNRECOGNIZED_NAME_ALERT ------------------------------------------------------[End]------------------------------------------------------ The haproxy instance displays the following: ------------------------------------------------------[Start]------------------------------------------------------ fd[0013] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext: clienthello tlsext fd[0013] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext fd[0012] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext: clienthello tlsext fd[0012] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext fd[0012] OpenSSL error[0x1412e0e2] ssl_parse_clienthello_tlsext: clienthello tlsext fd[0012] OpenSSL error[0x1408a0e3] ssl3_get_client_hello: parse tlsext ------------------------------------------------------[End]------------------------------------------------------ probably because of the "strict-sni" present in the haproxy configuration file. If I remove "strict-sni" then bar.com will load with the certificate for foo.com and browsers will complain about the mismatching domain name. What throws me off, is that in the documentation, "commit ssl cert" *is* supposed to generate all context and SNI's it needs: ------------------------------------------------------[Start]------------------------------------------------------ commit ssl cert <filename> Commit and apply a temporary SSL certificate update transaction. Generate every SSL contextes and SNIs it needs, insert them, and remove the previous ones. Replace in memory the previous SSL certificates everywhere the <filename> was used in the configuration. Upon failure it doesn't remove or insert anything. Once the temporary transaction is committed, it is destroyed. ------------------------------------------------------[End]------------------------------------------------------ Does anyone have any thoughts on this ? Regards. -tbn