Securing LDAP traffic with TLS: the need for CA, server, and key certificates, the difference between StartTLS on port 389 and LDAPS on port 636, olcTLSCertificateFile configuration, and testing with ldapsearch -ZZ.

In episode 15 you realized that an unsecured simple bind sends passwords in the clear, and that olcSecurity: ssf=1 only makes sense if there's a security layer to enforce. Episode 16 installs that layer itself: TLS. You'll prepare certificates, decide between StartTLS and LDAPS, configure the server and the client, and prove the encryption works with ldapsearch -ZZ.
TLS turns LDAP from a text protocol into an encrypted channel. Four benefits:
Without TLS, the episode 15 threats — eavesdropping and man-in-the-middle — apply in full, even on internal networks.
To run TLS on slapd, you need a set of certificate files:
| Component | Contents | Example path |
|---|---|---|
| CA certificate | the issuing authority's certificate (or your own root CA) | /etc/ssl/certs/ca.crt |
| Server certificate | certificate for the server's hostname | /etc/ssl/certs/slapd.crt |
| Certificate key | the private key belonging to the server certificate | /etc/ssl/private/slapd.key |
| Certificate chain | intermediate CAs up to the root, if any | merged into the server cert |
| Validation | client checks the certificate against a trusted CA | via TLS_CACERT |
In a lab, you can be your own CA. Create a self-signed certificate for the server with openssl:
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout slapd.key -out slapd.crt -days 365 \
-subj "/CN=ldap.example.com"
sudo chown root:ssl-cert slapd.keyOn Debian and Ubuntu, the ssl-cert group lets slapd read /etc/ssl/private; make sure the private key is in that group. The common name (CN) or Subject Alternative Name must match the hostname clients use when connecting, otherwise validation will fail.
Two ways to put TLS on LDAP:
StartTLS command on the same connection.| Aspect | StartTLS (389) | LDAPS (636) |
|---|---|---|
| Port | 389 | 636 |
| Initiation | upgrade in the middle of the connection | encrypted immediately |
| Standard | LDAP standard, interoperable | legacy practice, not an RFC standard |
| Advantage | one port for everything, can serve non-TLS when enabled | mentally simple |
| When to use | modern default | legacy systems or connections that need explicit TLS from the start |
StartTLS is preferred because it uses only one port and can still serve non-TLS connections if olcSecurity allows. However, many legacy integrations demand LDAPS. OpenLDAP 2.5 supports both at once, so you don't have to choose.
Certificates and TLS settings go on the cn=config entry:
dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/slapd.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/slapd.key
-
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/ca.crt
-
replace: olcTLSVerifyClient
olcTLSVerifyClient: never
-
replace: olcTLSCipherSuite
olcTLSCipherSuite: HIGH:MEDIUM:+SSLv3olcTLSCertificateFile and olcTLSCertificateKeyFile — required; the server certificate and key pair.olcTLSCACertificateFile — the CA that validates clients when mutual TLS is enabled.olcTLSCipherSuite — the list of allowed ciphers; this is a common example, adjust to your organization's policy.olcTLSVerifyClient — never for one-way authentication; try or demand when clients must also present certificates.On the client side, configuration lives in /etc/ldap/ldap.conf (and per-user ~/.ldaprc):
BASE dc=example,dc=com
URI ldap://ldap.example.com
TLS_CACERT /etc/ssl/certs/ca.crt
TLS_REQCERT demandTLS_CACERT points to the CA the client trusts. TLS_REQCERT determines the attitude toward the server certificate:
| Value | Behavior |
|---|---|
never | doesn't verify the certificate at all |
allow | verifies if presented, continues if not |
try | verifies when possible, continues on failure |
demand | requires a valid certificate, drops the connection otherwise |
demand is the correct value for production — anything below it opens the door to man-in-the-middle attacks.
Prove the encryption actually works:
ldapsearch -x -H ldap://ldap.example.com -ZZ \
-b dc=example,dc=com cn
openssl s_client -connect ldap.example.com:636 \
-CAfile /etc/ssl/certs/ca.crtldapsearch -ZZ demands StartTLS — the connection fails if the server doesn't support the upgrade. openssl s_client -connect ...:636 checks the LDAPS handshake directly and shows the certificate chain; verify that verify return code reads ok. For negotiation debugging, run slapd with olcLogLevel: conns,stats and watch the TLS messages in the log.
Warning
Never deploy TLS_REQCERT never or -Z (singular, which only allows TLS) to production. -Z is optional — the connection still goes plain if TLS isn't available. Always use -ZZ when enforcing, and demand as TLS_REQCERT.
In this episode 16 you secured LDAP with TLS: the four benefits of transport encryption, preparing a CA, server certificate, key, and validation; the difference between StartTLS on port 389 and LDAPS on port 636; the olcTLSCertificateFile, olcTLSCertificateKeyFile, olcTLSCACertificateFile, olcTLSCipherSuite, and olcTLSVerifyClient configuration; client settings with TLS_CACERT and TLS_REQCERT; and testing with ldapsearch -ZZ and openssl s_client.
Key takeaways:
TLS_REQCERT demand and -ZZ — non-negotiable for production.ssl-cert group on Debian protects /etc/ssl/private.In the next episode, episode 17, the TLS layer you just installed becomes the stage for SASL & external authentication — Kerberos-based GSSAPI authentication and SASL EXTERNAL using client certificates, then integration with PAM, NSS, and SSSD.