How To

Secure OpenLDAP Server with TLS/SSL on Ubuntu 24.04 / 22.04

An OpenLDAP server without TLS is sending credentials in cleartext across your network. Every bind operation, every password change, every query with sensitive data is visible to anyone with a packet sniffer on the same subnet. Securing OpenLDAP with TLS is not optional for any environment that takes security seriously.

Original content from computingforgeeks.com - post 12404

This guide walks through generating a private Certificate Authority, issuing a server certificate with Subject Alternative Names (SAN), configuring slapd for both STARTTLS (port 389) and LDAPS (port 636), and setting up a client machine to trust the CA and query over encrypted connections. We use self-signed certificates because LDAP servers are internal infrastructure. Unlike web servers, they don’t face the public internet, so Let’s Encrypt (which requires public DNS and HTTP validation) doesn’t apply here. Self-signed CA certs are the industry standard for internal LDAP deployments because you control both server and client and can distribute the CA cert to every machine that needs it.

Tested March 2026 | Ubuntu 24.04.4 LTS, OpenLDAP 2.6.10, two-node setup (server + client)

Prerequisites

Before starting, you need:

  • A working OpenLDAP server on Ubuntu 24.04 or 22.04 with at least one user entry. If you haven’t set this up yet, follow our OpenLDAP installation guide for Ubuntu first
  • A separate client machine (Ubuntu 24.04/22.04) with ldap-utils installed
  • Root or sudo access on both machines
  • Server IP: 192.168.1.150 | Client IP: 192.168.1.151 (adjust to match your environment)
  • OpenSSL installed on the server (included by default on Ubuntu)
  • Tested on: Ubuntu 24.04.4 LTS with OpenLDAP 2.6.10

Server Side: Generate TLS Certificates

All certificate generation happens on the LDAP server (192.168.1.150). We’ll create a private CA, then use it to sign a server certificate. This gives you full control over the trust chain without depending on any external certificate authority.

Create the Certificate Directory

Store all TLS files in /etc/ldap/tls/ to keep them separate from the main slapd configuration:

sudo mkdir -p /etc/ldap/tls
cd /etc/ldap/tls

Generate the CA Key and Certificate

The CA (Certificate Authority) is the root of trust. Every client that trusts this CA will automatically trust any certificate signed by it. Generate a 4096-bit RSA key and a self-signed CA certificate valid for 10 years:

sudo openssl genrsa -out ca.key 4096

Now create the CA certificate:

sudo openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
  -subj "/C=US/ST=State/L=City/O=Example Inc/CN=Example CA"

Replace the subject fields (C, ST, L, O, CN) with your organization’s actual details. The CN for the CA should identify it as a CA, not the server hostname.

Generate the Server Key and CSR with SAN

Modern OpenSSL versions have deprecated CN-only matching for certificate validation. You must include Subject Alternative Names (SAN) with both the hostname and IP address. Without SAN entries, TLS clients will reject the certificate.

Generate the server private key:

sudo openssl genrsa -out server.key 4096

Create an OpenSSL configuration file for the CSR that includes the SAN extension:

sudo vi /etc/ldap/tls/server.cnf

Add the following configuration. Update CN, DNS.1, and IP.1 to match your LDAP server’s hostname and IP:

[req]
default_bits = 4096
prompt = no
default_md = sha256
distinguished_name = dn
req_extensions = v3_req

[dn]
C = US
ST = State
L = City
O = Example Inc
CN = ldap.example.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = ldap.example.com
IP.1 = 192.168.1.150

Generate the Certificate Signing Request using this config file:

sudo openssl req -new -key server.key -out server.csr -config server.cnf

Sign the Server Certificate with the CA

Sign the CSR with your CA, copying the SAN extensions into the final certificate. The -extfile and -extensions flags ensure the SAN entries make it into the signed cert:

sudo openssl x509 -req -days 3650 -in server.csr \
  -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -extfile server.cnf -extensions v3_req

Verify the certificate has the correct subject, issuer, and SAN entries:

openssl x509 -in server.crt -noout -subject -issuer -dates -ext subjectAltName

The output should confirm the SAN includes both the DNS name and IP address:

subject=C = US, ST = State, L = City, O = Example Inc, CN = ldap.example.com
issuer=C = US, ST = State, L = City, O = Example Inc, CN = Example CA
notBefore=Mar 27 09:47:03 2026 GMT
notAfter=Mar 24 09:47:03 2036 GMT

X509v3 Subject Alternative Name:
    DNS:ldap.example.com, IP Address:192.168.1.150

Set File Ownership

The slapd process runs as the openldap user. It must be able to read the certificate files and the private key:

sudo chown openldap:openldap /etc/ldap/tls/*
sudo chmod 600 /etc/ldap/tls/server.key
sudo chmod 644 /etc/ldap/tls/server.crt /etc/ldap/tls/ca.crt

The private key gets 600 (owner read/write only), while the certificate and CA cert can be world-readable since they contain no secrets.

Server Side: Configure slapd for TLS

With the certificates in place, tell slapd where to find them. OpenLDAP uses its cn=config database for runtime configuration, so we apply changes via an LDIF file.

Apply TLS Configuration to slapd

Create the LDIF file that sets the certificate paths:

sudo vi /tmp/tls-config.ldif

Add the following content:

dn: cn=config
changetype: modify
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/tls/ca.crt
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/tls/server.crt
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/tls/server.key

Apply it using ldapmodify with EXTERNAL SASL authentication (which authenticates as root via Unix socket):

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/tls-config.ldif

You should see the modification applied successfully:

SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"

If you get an error about the attributes already existing, use replace instead of add in the LDIF. This happens when TLS was partially configured before.

Enable LDAPS (Port 636)

By default, slapd only listens on ldap:// (port 389). To enable LDAPS on port 636, edit the slapd defaults file:

sudo vi /etc/default/slapd

Find the SLAPD_SERVICES line and add ldaps:///:

SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///"

Restart slapd to pick up the changes:

sudo systemctl restart slapd

Confirm slapd is now listening on both ports 389 and 636:

sudo ss -tlnp | grep slapd

Both LDAP and LDAPS ports should be active:

LISTEN 0  2048  0.0.0.0:636  0.0.0.0:*  users:(("slapd",pid=12702,fd=11))
LISTEN 0  2048  0.0.0.0:389  0.0.0.0:*  users:(("slapd",pid=12702,fd=8))

Configure the Server’s LDAP Client Settings

The LDAP client tools on the server itself (ldapsearch, ldapwhoami) also need to know about the CA certificate. Edit the system-wide LDAP client configuration:

sudo vi /etc/ldap/ldap.conf

Add or update these lines:

BASE    dc=example,dc=com
URI     ldap://192.168.1.150
TLS_CACERT /etc/ldap/tls/ca.crt

The TLS_CACERT directive tells all LDAP client tools to trust certificates signed by your CA.

Test TLS from the Server

Run a STARTTLS query (upgrades port 389 to encrypted):

ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150 -ZZ

The -ZZ flag requires STARTTLS to succeed or the command fails. Enter the admin password when prompted:

dn:cn=admin,dc=example,dc=com

Now test LDAPS (dedicated encrypted port 636):

ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150

Same result confirms LDAPS is working:

dn:cn=admin,dc=example,dc=com

Both protocols are functional. STARTTLS upgrades an existing connection on port 389, while LDAPS establishes a TLS connection from the start on port 636. Most modern setups prefer LDAPS because it’s simpler to firewall (just allow 636, block 389).

Client Side: Configure TLS

Switch to the client machine (192.168.1.151) for the remaining steps. The client needs the CA certificate to verify the server’s identity during the TLS handshake.

Copy the CA Certificate to the Client

From the client machine, pull the CA certificate from the server using scp:

scp [email protected]:/etc/ldap/tls/ca.crt /tmp/ldap-ca.crt

Install it into the system certificate store so all applications (not just LDAP tools) can use it:

sudo cp /tmp/ldap-ca.crt /usr/local/share/ca-certificates/ldap-ca.crt
sudo update-ca-certificates

This adds the CA to Ubuntu’s trusted certificate bundle. The update-ca-certificates command regenerates /etc/ssl/certs/ca-certificates.crt, which is the system-wide trust store.

Configure the LDAP Client

Install the LDAP client utilities if they’re not already present:

sudo apt install -y ldap-utils

Edit the client’s LDAP configuration file:

sudo vi /etc/ldap/ldap.conf

Set the base DN, server URI, and CA certificate path:

BASE    dc=example,dc=com
URI     ldaps://192.168.1.150
TLS_CACERT /usr/local/share/ca-certificates/ldap-ca.crt

Notice the URI uses ldaps:// here. The client will connect over encrypted LDAPS by default for all LDAP queries.

Test LDAPS from the Client

Verify admin authentication over LDAPS:

ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150

Enter the admin password. The response confirms encrypted authentication is working from the client:

dn:cn=admin,dc=example,dc=com

Test with a regular user account as well:

ldapwhoami -x -D "uid=jdoe,ou=people,dc=example,dc=com" -W -H ldaps://192.168.1.150

User authentication works over the encrypted channel:

dn:uid=jdoe,ou=people,dc=example,dc=com

Run a full search to confirm data retrieval over LDAPS:

ldapsearch -x -D "cn=admin,dc=example,dc=com" -W -H ldaps://192.168.1.150 \
  -b "dc=example,dc=com" "(uid=jdoe)" cn uid homeDirectory

The search returns the user’s attributes over the encrypted connection:

dn: uid=jdoe,ou=people,dc=example,dc=com
cn: John Doe
uid: jdoe
homeDirectory: /home/jdoe

Test STARTTLS from the Client

STARTTLS works from the client too. Use the -ZZ flag against port 389:

ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150 -ZZ

This should return the same admin DN, confirming STARTTLS negotiation succeeded from the client machine.

Verify the Certificate Chain with OpenSSL

For a deeper verification, connect with openssl s_client and inspect the TLS handshake directly:

openssl s_client -connect 192.168.1.150:636 -CAfile /usr/local/share/ca-certificates/ldap-ca.crt /dev/null | grep -E "subject=|issuer=|Verify"

A successful verification looks like this:

subject=C = US, ST = State, L = City, O = Example Inc, CN = ldap.example.com
issuer=C = US, ST = State, L = City, O = Example Inc, CN = Example CA
Verify return code: 0 (ok)

Verify return code: 0 (ok) means the entire certificate chain validated successfully. The server cert was signed by the CA, and the client trusts that CA.

Enforce TLS for All Connections (Optional)

At this point, TLS is available but not required. Clients can still bind over unencrypted LDAP on port 389 without STARTTLS. To force all connections to use encryption, set the olcSecurity attribute on the server.

Back on the server (192.168.1.150), create the enforcement LDIF:

sudo vi /tmp/enforce-tls.ldif

Add the following:

dn: cn=config
changetype: modify
add: olcSecurity
olcSecurity: tls=1

Apply it:

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /tmp/enforce-tls.ldif

After applying this, any client that attempts a simple bind on port 389 without first issuing STARTTLS will get a “Confidentiality required” error. LDAPS connections on port 636 are unaffected since they’re encrypted from the start.

Test that enforcement works by trying an unencrypted bind:

ldapwhoami -x -D "cn=admin,dc=example,dc=com" -W -H ldap://192.168.1.150

This should fail with ldap_bind: Confidentiality required (13). Adding -ZZ or switching to ldaps:// will succeed as before.

Important: Only enable enforcement after confirming that ALL clients have been updated with the CA certificate and are configured to use TLS. Otherwise, you’ll lock out applications that haven’t been migrated yet.

Ubuntu 22.04 Notes

The steps in this guide apply to Ubuntu 22.04 LTS as well. The main difference is that Ubuntu 22.04 ships with OpenLDAP 2.5.x instead of 2.6.10, but the TLS configuration directives (olcTLSCACertificateFile, olcTLSCertificateFile, olcTLSCertificateKeyFile) are identical across both versions. The file paths, ownership requirements, and /etc/default/slapd configuration are the same.

One thing to watch for: Ubuntu 22.04’s OpenSSL version (3.0.x) already enforces SAN validation, so the SAN configuration in the server.cnf file is equally critical on 22.04. Do not skip it, even on the older release.

Troubleshooting

Error: “TLS: can’t accept: No certificate was found.”

The openldap user cannot read the certificate or key files. Check ownership and permissions:

ls -la /etc/ldap/tls/

All files should be owned by openldap:openldap. The key file needs 600 permissions. Fix with sudo chown openldap:openldap /etc/ldap/tls/* and restart slapd.

Error: “ldap_sasl_bind: Can’t contact LDAP server (-1)” on port 636

slapd isn’t listening on port 636. Verify the SLAPD_SERVICES line in /etc/default/slapd includes ldaps:/// (with three slashes, not two). After editing, restart slapd and check with sudo ss -tlnp | grep 636.

Error: “TLS: hostname does not match CN in peer certificate”

The server certificate’s SAN doesn’t include the hostname or IP you’re connecting with. Regenerate the certificate with the correct DNS.1 and IP.1 entries in the server.cnf file. If you connect by IP, IP.1 must be present. If you connect by hostname, DNS.1 must match exactly.

Error: “TLS: peer cert untrusted or revoked”

The client doesn’t trust the CA that signed the server certificate. Verify that TLS_CACERT in /etc/ldap/ldap.conf points to the correct CA certificate file and that the file is readable. On the client, also confirm update-ca-certificates was run after copying the CA cert.

STARTTLS vs LDAPS: Which to Use

Both STARTTLS and LDAPS encrypt the connection. The difference is when encryption begins:

FeatureSTARTTLS (port 389)LDAPS (port 636)
Encryption startUpgrades after initial plaintext connectionEncrypted from the first byte
Port389 (shared with unencrypted LDAP)636 (dedicated)
Firewall simplicityHarder (same port for encrypted and unencrypted)Easier (block 389, allow only 636)
Downgrade riskPossible if client doesn’t enforce with -ZZNone
Industry trendBeing phased outPreferred for new deployments

For new deployments, LDAPS on port 636 is the cleaner choice. You can disable port 389 entirely by removing ldap:/// from SLAPD_SERVICES once all clients are migrated to LDAPS. Keep ldapi:/// (the Unix socket) for local administration.

Going Further

With TLS secured, here are logical next steps for hardening your LDAP infrastructure:

  • Client certificate authentication (mTLS) requires clients to present their own certificates, adding a second layer of verification beyond passwords
  • Restrict TLS versions by setting olcTLSProtocolMin to 3.3 (TLS 1.2) or 3.4 (TLS 1.3) to block older, weaker protocols
  • Cipher suite hardening with olcTLSCipherSuite to disable weak ciphers and enforce forward secrecy
  • LDAP access control lists (ACLs) to restrict who can read sensitive attributes like userPassword
  • Certificate rotation with a cron job or reminder system, since 10-year validity is convenient but shorter lifetimes (1-2 years) are more secure

Related Articles

Ubuntu Install Chromium Browser on Ubuntu 22.04/20.04 Security Automate Penetration Testing with Infection Monkey Backup LVM Snapshots for Consistent Server Backups on Linux Ubuntu Configure Postfix as Send-Only SMTP Server on Ubuntu 24.04 / 22.04

11 thoughts on “Secure OpenLDAP Server with TLS/SSL on Ubuntu 24.04 / 22.04”

  1. Running Ubuntu 20.04 I was having issues getting this to work.
    Got error: “wrong attributetype at line 5 entry cn=config”
    Modified the ldap_ssl.ldif file to separate the modify lines and it worked.

    # vim ldap_ssl.ldif
    dn: cn=config
    changetype: modify
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /etc/ldap/sasl2/ca-certificates.crt

    replace: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ldap/sasl2/ldap_server.crt

    replace: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ldap/sasl2/ldap_server.key

    Reply
  2. i am still having an issue with when trying to execute ” ldapmodify -Y EXTERNAL -H ldapi:/// -f fnc-ldap-ssl.ldif ”

    ERROR:
    SASL/EXTERNAL authentication started
    SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
    SASL SSF: 0
    ldapmodify: invalid format (line 5) entry: “cn=config”

    Reply
  3. From where does this file come from? – /etc/ldap/sasl2/ca-certificates.crt
    In the article, it only exists from the copy section.

    Reply
  4. kind of confused about the very last command.

    “Now configure OpenLDAP SSL mechanism by uncommenting the lines below”

    where can I find it sudo nano /etc/ldap.conf ?

    Reply
    • You might consider re-reading this part, it is well explained. Use nano if you prefer it to vim just like me, but you got the point:

      – edit the file /etc/ldap.conf
      – Uncomment THESES lines… ie:
      – ssl start_tls
      – ssl on

      Then save your file

      Reply
  5. Don’t get me wrong its a great article I defiantly learn from it but I never got it to work

    when I run
    $ ldapwhoami -x -H ldaps://ldap.example.com

    I get ldap_sasl_bind(SIMPLE): Can’t contact LDAP server (-1)

    Reply

Leave a Comment

Press ESC to close