To replicate my results:
Generate 3 ssl certificates (letsenc? I used a dns-01 challenge...)..
default.example.ca
working.example.ca
should-be-broken.example.ca
Configure an apache instance to serve only the first two via https.
default.example.ca and working.example.ca; don't configure any
virtualhost for should-be-broken.example.ca.
Configure the haproxy instance with all 3 certificates in the haproxy
format with the intermediates and private keys included in a single
file. Name the files like default.example.ca.pem,
working.example.ca.pem, should-be-broken.example.ca.pem and toss em in
/etc/haproxy/certs...
Install the ca-certificates package if you're on debian/ubuntu
(otherwise adjust the ca-certificates location to whatever distro you're
running)...
Then:
haproxy.cfg:
frontend www-https
bind :::443 v4v6 ssl crt /etc/haproxy/certs/default.example.ca.pem
crt /etc/haproxy/certs/
use_backend www-backend-https
backend www-backend-https
server app default.example.ca:443 ssl verify required sni
ssl_fc_sni ca-file /etc/ssl/certs/ca-certificates.crt check check-ssl
If you visit https://should-be-broken.example.ca you will get the page
for default.example.ca, but the browser/visitor will show the
should-be-broken.example.ca cert from the haproxy and the page will
appear secure, despite the backend apache instance having no access to
should-be-broken's virtual host or certificate and serving a certificate
for default.example.ca to the haproxy.
--
Kevin
On 2017-07-24 3:25 PM, Kevin McArthur wrote:
Hi Willy,
I can confirm the following line does _not_ verify the hostname on the
backend.
server app2 ssltest.example.ca:443 ssl verify required sni
ssl_fc_sni ca-file /etc/ssl/certs/ca-certificates.crt check check-ssl
I setup a default https vhost on the backend server, that responds to
ssltest.example.ca ... in the above configuration the health checks
pass and if you visit a sni-configured site (otherhost.example.ca) it
will also work. However, you load another SNI virtualhost that only
the haproxy has a cert for but for which the backend responds with a
mismatching ssltest certificate, it will happily load that site,
present it as TLS protected to the web browser and *NOT check the
verifyhost against the backend SNI. *
That is to say, without verifyhost <something> no hostname
verification is done between the haproxy and the cert presented by the
backend and any valid certificate (even the default-configured ssltest
one) will work on the backend.
--
Kevin McArthur
On 2017-07-23 9:40 PM, Willy Tarreau wrote:
Hi Kevin,
On Fri, Jul 21, 2017 at 02:06:52PM -0700, Kevin McArthur wrote:
Further... the odd/broken behavior might be being caused related to no sni
indication on the health checks...
This config sort of works:
*server app2 ssltest.example.ca:443 ssl verify required /verifyhost
ssltest.example.ca/ sni ssl_fc_sni ca-file
/etc/ssl/certs/ca-certificates.crt check check-ssl*
This lets me load ssltest.example.ca via the proxy.
*server app2 anotherdomain.example.ca:443 ssl verify required /verifyhost
anotherdomain.example.ca/ sni ssl_fc_sni ca-file
/etc/ssl/certs/ca-certificates.crt check check-ssl*
Jul 21 20:57:55 haproxy1 haproxy[8371]: Health check for server
www-backend-https/app2 failed, reason: Layer6 invalid response, info: "SSL
handshake failure", check duration: 3ms, status: 0/2 DOWN.
Fails health check (no sni) verifyhost match (anotherdomain.example.ca isnt
the default on the backend server). So ends up in "No server is available to
handle this request."
*server app2 ssltest.example.ca:443 ssl verify required /verifyhost
ssl_fc_sni/ sni ssl_fc_sni ca-file /etc/ssl/certs/ca-certificates.crt check
check-ssl*
Jul 21 20:57:55 haproxy1 haproxy[8371]: Health check for server
www-backend-https/app2 failed, reason: Layer6 invalid response, info: "SSL
handshake failure", check duration: 3ms, status: 0/2 DOWN.
This fails health check.
*server app2 ssltest.example.ca:443 ssl verify required sni ssl_fc_sni
ca-file /etc/ssl/certs/ca-certificates.crt check check-ssl*
This works, but without verifying the host properly. Can load
anotherdomain.example.ca and the sni is passed along properly.
Perhaps its the host checks sni support and not this patch that are not
working correctly?
The "verifyhost" directive *forces* the host name to be checked and ignores
the SNI. By just removing it from your "server" lines, it must be OK. Your
last example above suggests it works. Why do you say that the host is not
properly verified ? Have you checked that you can connect to a server
presenting the wrong cert ? For me it refuses it and only accepts the
correct cert (the one having the same name as asked in the SNI).
Willy