3
frontend  front
bind *:80
bind *:443 ssl crt /etc/haproxy/certs/server.pem ca-file /etc/haproxy/certs/id.crt verify required 
option tcplog
mode http    
default_backend app

backend app    
balance roundrobin
cookie SERVERID insert
option ssl-hello-chk
mode http
option httpclose
option forwardfor     
option httpchk get /WebApi/help
server  app1 1.1.1.1:443 check ssl fall 1 rise 3 verify none cookie webA
server  app2 1.1.1.2:443 check ssl fall 1 rise 3 verify none cookie webB

for certain page /login/idcard i need to require client certificate and send it to backend (IIS) which will use it for authentification, i can't find way to ask certificate on certain path and certificate forwarding to backend also not working, previous config was using "mode tcp" which forwards everything to IIS and it was working, but i need to use "acl" to forward request with certain path to another server, but "acl" is not working in https so it should be http

jetcarq q
  • 33
  • 1
  • 1
  • 4
  • @Michael - sqlbot 's answer might have helped you. I dont wan to add another answer as mine is very close to what he said. `http-request deny if { path_end /auth } !{ ssl_c_used }` is what I use along with `verify optional`. Browser will prompt for certificate. If not given, you get 403 for request ends at `/auth`. Other requests will just pass as there is already certificate in the session. This is my requirement and hence I used `ssl_c_used` instead of `ssl_fc_has_crt`. The latter will check for all requests. Find doc here https://www.haproxy.org/download/1.5/doc/configuration.txt – Winster Aug 17 '20 at 13:23

1 Answers1

7

You can't ask for a certificate for a certain path, because the TLS negotiation had already completed before the path is known, so once you know the path, it's too late.

Similarly, it isn't possible to "forward" a client certificate -- if this proxy is in mode http then there are two TLS sessions -- one between client and proxy, and another between proxy and back-end server. The proxy doesn't have the client cert's private key, so it can't negotiate TLS with the backend using the client's certificate. If it were possible to use someone's client certificate without being in possession of their private key, client certificated would be useless -- the certificate is also the public key, and public keys are "public" because, by themselves, they don't represent anything of value.

It is possible to forward the attributes of the certificate presented by the client, by setting them as HTTP request headers in the proxy using layer 5 fetches but that wouldn't likely satisfy a backend that needs to see the actual cert.

It's even possible to inject the entire client cert into a request header for the backend...

http-request set-header X-Client-Certificate %[ssl_c_der,base64]

...but it's unlikely this will be of use in the scenario you describe.

Similarly, you can use bind ... ssl ... verify optional instead of required, and then block requests for specific paths unless a certificate was already presented...

http-request deny if { path_beg /login/idcard } !{ ssl_fc_has_crt }

...this would make the cert optional, but deny requests with this path prefix if a certificate was not already presented.

Again, technically valid, but not necessarily what you really need.

Michael - sqlbot
  • 22,658
  • 2
  • 63
  • 86
  • thanks for good answer, looks like i can't do it using just haproxy configuration and should change a bit authentification, so client which want to login with certificate will connect to directly to IIS without haproxy or using different haproxy with tcp mode – jetcarq q Jul 05 '17 at 05:31
  • "You can't ask for a certificate for a certain path, because the TLS negotiation had already completed before the path is known" - with TLS-renegotiation this is possible. – Askin Geeks Jun 01 '23 at 07:25