I have two domain name test1 and test2
test1 needs to verify client certificate,
test2 is a normal https website
here’s the config for test1, but I don’t know how to merge test2 to it becase test2 does not need to verify client certificate, seems ‘verify required’ is a global option, how can I just let test1 to verify client certificate? Thanks for the help (I’m new to HAProxy, please correct me if anything wrong in my config, thanks a lot.).
frontend http_in
bind *:80
bind *:443 ssl crt /etc/ssl/certsforhaproxy/test1.pem crt /etc/ssl/certsforhaproxy/test2.pem ca-file /etc/ssl/certsforhaproxy/ca.pem verify required
redirect scheme https if !{ ssl_fc }
acs host_test1 hdr_beg(host) test1.demo.com
acs host_test2 hdr_beg(host) test2.demo.com
use_backend test1_back if host_test1
use_backend test2_back if host_test2
backend test1_back
mode http
default-server inter 2s fall 2 rise 2
server node1 10.10.0.1:1234 check port 1234
server node2 10.10.0.2:1234 check port 1234
server node3 10.10.0.3:1234 check port 1234
backend test2_back
mode http
default-server inter 2s fall 2 rise 2
server node1 10.10.0.1:2345 check port 2345
server node2 10.10.0.2:2345 check port 2345
server node3 10.10.0.3:2345 check port 2345
Only thing I can think of right now is to set the verify to optional so clients can connect with or without the client certificate and then restrict access using an ACL like so:
Use a TCP frontend withouth SSL termination, SNI route to different backends that recirculate to traffic to dedicated SSL frontends with different configurations.
The above simply says if the header host matches a specific domain deny request unless the client has provided a certificate and that certificate was verified.
You can improve on this by adding specific error pages, example:
redirect location /certmisiing.html if restricted !{ ssl_c_used 1 }
redirect location /certexpired.html if restricted { ssl_c_verify 10 }
redirect location /certrevoked.html if restricted { ssl_c_verify 23 }
redirect location /othererrors.html if restricted !{ ssl_c_verify 0 }
“verify optional” has a rather important disadvantage: it changes the SSL handshake, leading to different browser behavior for all of the websites.
For example, if you have a browser with a client certificate installed for a unrelated domain, and haproxy handles test1.demo.com and test2.demo.com, the browser will ask you for both test1.demo.com and test2.demo.com if and which client certificate you wanna send.
By SNI routing to different SSL termination endpoints like suggest above we avoid this problem. We also have a “proper” SSL handshake failure with “verify required”, instead of failure on the HTTP layer.
Thanks Lukas, I found this also in my testing, I was very much playing and reverse engineering how it works learning lots of new stuff for the first time. Yesterday I referenced your better solution with SNI in my Blog, I hope that’s okay, I gave you credit and linked it back here.
I was trying something very similar but path based ssl handshake. So far what I read is it is not possible with HAProxy. In this example, we have to use tcp mode. But in order to check the path, we need http mode.
frontend https-switch
bind *:8888
tcp-request inspect-delay 5s
tcp-request content accept if { req_ssl_hello_type 1 }
acl auth_request path_end -i /auth # this will always return false
use_backend recir_clientcertenabled if auth_request
default_backend recir_default
@lukastribus , hi there, this is an old post but I hope you can help me a bit
First, you mentioned that it needs to be mode tcp but my current env uses HTTP.
I have tried a few changes and the check had errors all over the place. Even the log format was not being accepted anymore.
Second, our CDN manages our certificate so I would need to contact them to provide the files instead of using the self-certificate one.
The idea is to deny/reject any HTTPS access that is not coming from our CDN.
Right now, someone can access our website via the LB IP outside our CDN and WAF.
I am not expert with the HaProxy so I am trying to find a solution that I can comprehend.
This thread is totally unrelated with the questions you have, let’s move the conversation to your actual thread, or open a new one if the topic is different, thanks.
@lukastribus I tride the config but with no success if I use the config where no SSL verification is needed everythings works well.
But if I want to use the https-client-ca-in route I get this error in my Browser and got never ask for an certificate:
ERR_BAD_SSL_CLIENT_AUTH_CERT
in the haproxy log I only see this:
Jun 25 19:20:02 haproxy haproxy[6435]: *.*.*.*:51812 [25/Jun/2023:19:20:02.522] http-in recir_clientcertenabled/loopback-for-tls 1/0/25 4777 SD 1/1/0/0/0 0/0
Jun 25 19:20:41 haproxy haproxy[6435]: *.*.*.*:51854 [25/Jun/2023:19:20:41.823] https-client-ca-in/1: SSL handshake failure (error:00000000:lib(0)::reason(0))
Jun 25 19:20:41 haproxy haproxy[6435]: *.*.*.*:51854 [25/Jun/2023:19:20:41.822] http-in recir_clientcertenabled/loopback-for-tls 1/0/19 4753 -- 1/1/0/0/0 0/0
Jun 25 19:20:42 haproxy haproxy[6435]: *.*.*.*:51858 [25/Jun/2023:19:20:42.165] https-client-ca-in/1: SSL handshake failure (error:0A0000C7:SSL routines::peer did not return a certificate)
Jun 25 19:20:42 haproxy haproxy[6435]: *.*.*.*:51858 [25/Jun/2023:19:20:42.164] http-in recir_clientcertenabled/loopback-for-tls 1/0/23 4777 SD 1/1/0/0/0 0/0
Im new to HAProxy, i hope that someone can help me.