AD FS 5.0 (Server 2022) and Certificate Authentication on port 49443 not working

Hello,

I’m having a hard time making this work.
My setup involves two Federation Servers that are now load balanced by another solution (that’s a Kemp LoadMaster) that I need to move off that to HAProxy.

AD FS uses port 443 for it’s portal and Forms/GSSAPI authentication and port 49443 for Certificate Authentication.
The problem I have is that the portal on port 443 works flawlessly while the endpoint on port 49443 doesn’t.
The client can access the service on port 49443 and talk to the backend but the application inside the portal fails stating that it didn’t receive the certificate information it needed. Point is the client is never asked to show a certificate (the browser never asks for it). If i point the clients directly to one of the servers or through the existing load balancer everything works.
It’s like if HA Proxy is dropping some information while doing the proxying and I can’t understand what.

Sorry I’m new to HAProxy and I can’t explain myself better. Can somebody help me shed some light on this?
Following is the configuration relevant to this:

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    stats                   show-desc
    stats                   show-legends
    option                  httplog
    option                  dontlognull
    option                  log-separate-errors
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000

#---------------------------------------------------------------------
#CavanaSystems Public Wildcard Certificate Store
#---------------------------------------------------------------------
crt-store cavanasystems_wildcard
    crt-base /etc/haproxy/certs
    key-base /etc/haproxy/certs
    load crt cavanasystems_wildcard_2025.pem key cavanasystems_wildcard_2025.key ocsp-update on alias cert_2025

#---------------------------------------------------------------------
#AD FS HTTP Frontend
#---------------------------------------------------------------------
frontend adfs_portal_internal_cavanasystems_com
    description Active Directory Federation Services Portal HTTP Frontend
    bind 10.88.18.222:443 ssl crt "@cavanasystems_wildcard/cert_2025"
    bind [2001:67c:d68:83::222]:443 ssl crt "@cavanasystems_wildcard/cert_2025"
    default_backend adfs_federation_servers
    option forwardfor if-none

#---------------------------------------------------------------------
#AD FS HTTP Backend
#---------------------------------------------------------------------
backend adfs_federation_servers
    description Active Directory Federation Services Portal HTTP Backend
    balance roundrobin
    server itmil01pstsv01 [2001:67c:d68:83::16]:443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni ssl_fc_sni # sni req.hdr(host)
#    server itmil01pstsv02 [2001:67c:d68:83::17]:443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni req.hdr(host) # sni ssl_fc_sni
    option forwardfor if-none
    option httpchk GET /adfs/probe

#---------------------------------------------------------------------
#AD FS Certauth HTTP Frontend
#---------------------------------------------------------------------
frontend adfs_certauth_internal_cavanasystems_com
    description Active Directory Federation Services Certauth HTTP Frontend
    bind 10.88.18.222:49443 ssl crt "@cavanasystems_wildcard/cert_2025"
    bind [2001:67c:d68:83::222]:49443 ssl crt "@cavanasystems_wildcard/cert_2025"
    default_backend adfs_federation_servers_certauth
    option forwardfor if-none

#---------------------------------------------------------------------
#AD FS Certauth HTTP Backend
#---------------------------------------------------------------------
backend adfs_federation_servers_certauth
    description Active Directory Federation Services Portal HTTP Backend
    balance roundrobin
    server itmil01pstsv01 [2001:67c:d68:83::16]:49443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni ssl_fc_sni
#    server itmil01pstsv02 [2001:67c:d68:83::17]:49443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ # sni req.hdr(host)
    option forwardfor if-none
    option httpchk GET /adfs/probe

Thank you for your help, any hints or help in troubleshooting is greatly appreciated.

Hello,

you are using “default_backend” twice. This isn’t possible and HAproxy only uses the first one.
You have to build routing decisions from frontend to backend based on the destination port.

#---------------------------------------------------------------------
#AD FS HTTP Frontend
#---------------------------------------------------------------------
frontend adfs_portal_internal_cavanasystems_com
    bind 10.88.18.222:443 ssl crt "@cavanasystems_wildcard/cert_2025"
    bind [2001:67c:d68:83::222]:443 ssl crt "@cavanasystems_wildcard/cert_2025"
	bind 10.88.18.222:49443 ssl crt "@cavanasystems_wildcard/cert_2025"
    bind [2001:67c:d68:83::222]:49443 ssl crt "@cavanasystems_wildcard/cert_2025"

	use backend adfs_federation_servers if { dst_port 443 }
	use backend adfs_federation_servers_certauth if { dst_port 49443 }


#---------------------------------------------------------------------
#AD FS HTTP Backend
#---------------------------------------------------------------------
backend adfs_federation_servers
    balance roundrobin
    server itmil01pstsv01 [2001:67c:d68:83::16]:443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni ssl_fc_sni # sni req.hdr(host)
#    server itmil01pstsv02 [2001:67c:d68:83::17]:443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni req.hdr(host) # sni ssl_fc_sni
    option forwardfor if-none
    option httpchk GET /adfs/probe

#---------------------------------------------------------------------
#AD FS Certauth HTTP Backend
#---------------------------------------------------------------------
backend adfs_federation_servers_certauth
    balance roundrobin
    server itmil01pstsv01 [2001:67c:d68:83::16]:49443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ sni ssl_fc_sni
#    server itmil01pstsv02 [2001:67c:d68:83::17]:49443 check port 80 ssl ca-file /etc/haproxy/certs/ca_store/ # sni req.hdr(host)
    option forwardfor if-none
    option httpchk GET /adfs/probe

best regards,
Markus

Hello Markus,

I’m using it into two distinct frontends to route requests into their respective backends.
I tried nonetheless changing to your configuration but it’s still not working.

The thing that I’m seeing is, also on another frontend/backend for a different application is that it always rejects POST if it is the first interaction with a backend.

And that’s peculiar…

Hello Markus,

I wanted to give a final feedback on this.
First, for the AD FS issue I decided to have it proxied at L4 with L7 checks. Funnily enough this is exactly what the existing LoadMaster does.
It’s a bit misleading since the template you use it’s labelled as “Layer 7” but in reality it’s just Layer 4 with Layer 7 health checks.
In AD FS architecture the Proxies are dedicated servers that live in a segregated zone that perform the layer 7 inspection and we already have those, so I call it a day.
I figure it’s something that has to do with how headers are written all lowercase when proxied and this is not liked by the client-side JavaScript that AD FS uses to have the client sign a payload for Certificate Authentication. I know I can have HA Proxy rewrite them with the correct case but since this system is slated to be replace by Shibboleth… the juice is not worth the squeeze.

Nevertheless I thank you for your suggestion on how to switch the backends by using ALCs, I’m using it with the Layer 4 proxying so I can save myself a frontend directive.

And the second issue, for another unrelated application I figured launching HA Proxy with -d that it was just an untrusted Root Certificate from a backend server.

Thank you for your time anyway,
Luca