Ldap-check for LDAPS (636) doesn't work

We load balance LDAP / LDAPS connections (OpenLDAP 2.5.16) and have a mix for legacy reasons of LDAP 389 and much more used LDAPS 636 in our environment. These two protocols use separate frontend VIP’s and separate backends.

Because we do PROXY protocol for retaining the client IP, the port is 8636 and 8389 respectively for the backends. The frontends are essentially identical, just with port 389 and 636 respectively as bind ports.

backend be-ldap-test-8636-ro-PROXY from unnamed_defaults_1
  mode tcp
  option ldap-check
  balance roundrobin
  log global
  timeout server 300s
  default-server inter 3s rise 2 fall 3 # alctl: default check parameters
  server openldap-test-1 1.1.1.1:8636 maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-2 1.1.1.2:8636 maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-3 1.1.1.3:8636 maxconn 1000 weight 10 check send-proxy-v2


backend be-ldap-test-8389-PROXY from unnamed_defaults_1
  mode tcp
  balance roundrobin
  option ldap-check
  log global
  timeout server 300s # alctl: server inactivity timeout
  default-server inter 3s rise 2 fall 3 # alctl: default check parameters
  server openldap-test-1 1.1.1.1:8389 maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-2 1.1.1.2:8389 maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-3 1.1.1.3:8389 maxconn 1000 weight 10 check send-proxy-v2

I noticed that the check “ldap-check” exists, which is wonderful, and I enabled it for the two backends. It works no issue for the backend on 389 LDAP, but always fails for the 636 backend.

The OpenLDAP server reports “TLS negotiation failure” and “closes” the connection during the check for LDAPS, and a success for normal LDAP on 8389.

Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958503 fd=25 ACCEPT from IP=1.1.1.6:37536 (IP=1.1.1.6:8389)
Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958503 op=0 BIND dn="" method=128
Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958503 op=0 RESULT tag=97 err=0 qtime=0.000018 etime=0.000120 text=
Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958503 fd=25 closed (connection lost)
Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958504 fd=25 ACCEPT from IP=1.1.1.8:26648 (IP=1.1.1.6:8636)
Feb 17 15:36:09 openldap-test-1 slapd[1308]: conn=958504 fd=25 closed (TLS negotiation failure)

From what I can see, the option ldap-check has no further options to do SNI, or send a particular type of request. Can anyone help me with what might be going on ?

I found a solution, and I can thank ChatGPT for this.

We can use tcp-check send-binary and expect binary for sending the right anonymous LDAP bind commands to the OpenLDAP servers and to expect a specific “success” response, tcp-check connect send-proxy ssl will know to perform a TLS connection AND in our case to preface it with a proxy protocol header. If you don’t use the proxy-protocol remove send-proxy.

backend be-ldap-test-8636-ro-PROXY from unnamed_defaults_1
  mode tcp
  balance roundrobin
  option tcp-check
  tcp-check connect send-proxy ssl                      
  tcp-check send-binary 300c020101600702010304008000    
  tcp-check expect binary 0a0100                        
  log global
  timeout server 300s
  default-server inter 3s rise 2 fall 3 # alctl: default check parameters
  server openldap-test-1 X.X.X.X:8636 verify none maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-2 X.X.X.X:8636 verify none maxconn 1000 weight 10 check send-proxy-v2
  server openldap-test-3 X.X.X.X:8636 verify none maxconn 1000 weight 10 check send-proxy-v2

This worked for us and cleans up our OpenLDAP logs of “TLS negotiation failed“ messages AND does a proper LDAP check.

Well done HAProxy, such a powerful tool.