TLDR: Ignore this post if you are using a private certificate authority to issue your client certificates - as is commonly done and recommended.
On 15/06/2023 8:23 am, Sean Gallagher wrote:
I'd like to propose a new feature to substantially strengthen the existing access controls in slapd. This follows on from comments made in the discussion around Issue 10065. In particular Comment 17 and Comment 19.
The objective here is to validate the credentials supplied by external security mechanisms BEFORE the main server loop starts, and terminate the connection if the client is not "known".
If the reader has been following along on this discussion and is considering installing a proxy in front of their slapd instance but is not sure how, I have posted here a genericised version of my haproxy.cfg file. This does more than is strictly necessary. I have precisely no expertise in haproxy and make no warranties about this whatsoever but if you find it useful, that's great. If you have questions, I'm not the one to answer them. I suggest a haproxy user's forum. Comments on improvements are welcome.
I have set up slapd to listen on unix domain sockets, so I can identify which client I am talking to in the ACL ruleset. This is an ugly implementation but works. It may be possible to configure haproxy to re-use the client's certificate presented to the front end, again on the back end. This would undoubtedly lead to a cleaner ruleset - but is not what I have done, simply because I don't know how.
The slapd.conf ACL rules look like this:
access to * by dn.base="cn=managersock,dc=example,dc=com" manage stop by * sockname.exact="PATH=/var/run/openldap/c1.sock" none break by * sockname.exact="PATH=/var/run/openldap/c2.sock" none break by * sockname.exact="PATH=/var/run/openldap/c3.sock" none break by * sockname.exact="PATH=/var/run/openldap/c4.sock" none break
The haproxy.cfg file
global # pidfile /var/run/haproxy.pid maxconn 4000 user haproxy group haproxy daemon
# turn on stats unix socket stats socket /var/lib/haproxy/stats #log /dev/log local0 warning log /dev/log local0 debug
ssl-default-bind-options ssl-min-ver TLSv1.2 ssl-default-bind-options ssl-max-ver TLSv1.3 ssl-dh-param-file /etc/ssl/private/dhparam
defaults mode tcp log global retries 3 timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout check 10s maxconn 3000
frontend main option tcplog bind ipv4@10.0.0.10:636 ssl verify required ciphers DHE-RSA-AES256-GCM-SHA384 ciphersuites TLS_AES_256_GCM_SHA384 ca-verify-file /etc/ssl/select_ca_ldapclients.pem crt /etc/ssl/ttldap.example.com.crt
tcp-request inspect-delay 2s tcp-request content accept if { req.ssl_hello_type 1 }
acl c1_sip src 10.0.0.1 acl c1_sdn ssl_c_s_dn -m str "/CN=client1.example.com" acl c1_idn ssl_c_i_dn -m str "/C=US/O=Let's Encrypt/CN=R3" acl c1_sni ssl_fc_sni -m str "ldap.example.com"
acl c2_sip src 10.0.0.2 acl c2_sdn ssl_c_s_dn -m str "/CN=client2.example.com" acl c2_idn ssl_c_i_dn -m str "/C=US/O=Let's Encrypt/CN=R3" acl c2_sni ssl_fc_sni -m str "ldap.example.com"
acl c3_sip src 10.0.0.3 acl c3_sdn ssl_c_s_dn -m str "/CN=client3.example.com" acl c3_idn ssl_c_i_dn -m str "/C=US/O=Let's Encrypt/CN=R3" acl c3_sni ssl_fc_sni -m str "ldap.example.com"
acl c4_sip src 10.0.0.4 acl c4_sdn ssl_c_s_dn -m str "/CN=client4.example.com" acl c4_idn ssl_c_i_dn -m str "/C=US/O=Let's Encrypt/CN=R3" acl c4_sni ssl_fc_sni -m str "ldap.example.com"
use_backend c1_be if c1_sip c1_sdn c1_idn c1_sni use_backend c2_be if c2_sip c2_sdn c2_idn c2_sni use_backend c3_be if c3_sip c3_sdn c3_idn c3_sni use_backend c4_be if c4_sip c4_sdn c4_idn c4_sni
backend c1_be server smtps unix@/var/run/openldap/c1.sock
backend c2_be server pwgui unix@/var/run/openldap/c2.sock
backend c3_be server imaps unix@/var/run/openldap/c3.sock
backend c4_be server samba unix@/var/run/openldap/c4.sock
Sean.