Configure StartTLS to encrypt OpenLDAP connection on centos 7

October 02, 2022

By default, the communication between OpenLDAP server and client is unencrypted, which is vulnerable to man in the middle attack. By sniffing the LDAP traffic, attacker can see plaintext data, including password you send to OpenLDAP server for authentication. To secure this connection, we can encrypt the traffic to prevent attacker from intercepting the traffic, thus any sensitive data.

In this guide, I will share with you how to configure StartTLS on OpenLDAP server, enable clients to communicate with OpenLDAP server with StartTLS and use LDAP accounts to login the host over encrypted tunnel with the integration of nss-pam-ldapd.

Concepts

In general, there are 2 ways to encrypt LDAP traffic with SSL/TLS

First, we have LDAPS. Client and server will negotiate encryption cipher, exchange the key first. Then following LDAP communication will be encrypted by the key. This connection operates at port 636.

Second, we have StartTLS. Instead of cipher negotiation and key exchange at first, client will send a LDAP message to ask the server & see if the server support TLS of not. If yes, they will proceed cipher negotiation and key exchange and the following LDAP communication will be encrypted by the key. This connection will use the same port as traditional LDAP, port 389.

Compared to LDAPS, StartTLS allows you to use same port to support clients which use/don't use SSL/TLS. However, StartTLS is susceptible to downgrade attack, STRIPTLS, attacker will tamper the initial StartTLS response from the server to mislead the clients that the server doesn't support SSL/TLS. As a result, applications on the client may fallback to unencrypted LDAP connection and suffer from sniffing attack again.

Unencrypted LDAP traffic

As mentioned, LDAP traffic is transmitted in plain text by default. If the client does not request to initialize encrypted tunnel, i.e. LDAPS or StartTLS, the traffic will be in plain text and attacker can steal sensitive data, e.g. password in the bind request.

ldapsearch -D cn="admin,dc=abc,dc=local" -W -b "dc=abc,dc=local" objectClass=* -H ldap://ldap1.abc.local

Unencrypted LDAP traffic

Encrypted LDAP traffic - StartTLS

If the client request to initialize encrypted tunnel & the server supports it, the traffic will be encrypted. If you client chooses to adopt StartTLS, it will send StartTLS first to establish SSL/TLS tunnel, and following traffic will be encrypted

ldapsearch -D cn="admin,dc=abc,dc=local" -W -b "dc=abc,dc=local" objectClass=* -H ldap://ldap1.abc.local -Z # Z flag to initialize StartTLS

SSL/TLS tunnel establishment Encrypted LDAP traffic

Failed SSL/TLS handshake for StartTLS

If the client sends a StartTLS request to the server, but the server doesn't accept it, the SSL/TLS handshake will fail. Worth mentioning, it does not prevent the client from sending first unencrypted LDAP bind request to the server, subsequent data exchange will be terminated by the server as it doesn't support TLS.

ldapsearch -D cn="admin,dc=abc,dc=local" -W -b "dc=abc,dc=local" objectClass=* -H ldap://ldap3.abc.local -Z
# ldap3.abc.local is a LDAP server that doesn't support SSL/TLS

Failed SSL/TLS handshake Error Failed SSL/TLS handshake - WireShark First LDAP bind request containing sensitive data is still being sent. Unencrypted first LDAP bind request Due to SSL/TLS negotiation failure, the server closes the connection after the first LDAP bind request sent from the client. LDAP TCP connection terminated log LDAP TCP connection terminated - WireShark Depends on your application, it may initialize traditional LDAP request (i.e. unencrypted LDAP request) afterwards.

Prerequisites

You need to have

  1. a OpenLDAP server and an account which belongs to posixAccount and shadowAccount, which is documented at guide
  2. a Centos 7 client which use nss-pam-ldapd to authenticate to OpenLDAP server

Server Configuration

Generate private key and certificates for OpenLDAP server

Create root CA (Certificate Authority) key and certificate

cd /etc/openldap/certs/
openssl genrsa -out rootCA.key 2048
openssl req -x509 -new -nodes -subj "/CN=ldap-ca.abc.local" -key rootCA.key -sha256 -days 1024 -out rootCA.pem

Create Certificate Signing Request (CSR)

openssl genrsa -out ldap.key 2048
openssl req -new -subj "/CN=ldap1.abc.local" -key ldap.key -out ldap.csr

Sign the CSR & obtain ldap server certificate

openssl x509 -req -in ldap.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out ldap.crt -days 3650 -sha256

Keys and certificates generated

Generate private key and certificates for another OpenLDAP server

If you have another OpenLDAP server, you just need to create a new CSR, use the same CA certificate to sign the CSR and obtain certificate with different CN, e.g. ldap2.abc.local For example,

openssl genrsa -out ldap.key 2048
openssl req -new -subj "/CN=ldap2.abc.local" -key ldap.key -out ldap.csr # Generate CSR
openssl x509 -req -in ldap.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out ldap.crt -days 3650 -sha256 # Sign the CSR

Configure OpenLDAP server to use certificates and private key for LDAP traffic encryption

Configure OpenLDAP server to use root CA certificates, its own private key and certificate for SSL/TLS establishment.

# Configure root CA certificate
cat > ca_certificate.ldif << EOF
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/openldap/certs/rootCA.pem
EOF

# Configure root CA certificate
cat > key_ and_certificate.ldif << EOF
dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/ldap.crt

dn: cn=config
changetype: modify
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/ldap.key
EOF

# Apply setting for root CA certificate configuration
sudo ldapmodify -Y EXTERNAL  -H ldapi:/// -f ca_certificate.ldif

# Apply setting for its own key and certificate configuration
sudo ldapmodify -Y EXTERNAL  -H ldapi:/// -f and_certificate.ldif

Remark: If I merge these 2 ldif configuration file into a single ldif file and apply this single ldif file, I will encounter "ldap_modify: Other (e.g., implementation specific) error (80)", not sure if it's a bug or something

Test StartTLS on CentOS 7 client

DNS Configuration on CentOS 7 client

You need to make sure that you can resolve your OpenLDAP server ip from the common name stated in the certificate, you can do it by adding a DNS entry in the DNS server or add it in DNS host file as below

echo "<<your-openldap-server-ip>> <<ldap-common-name>>" | sudo tee -a /etc/hosts

Host file

Upload Root CA certificate to CentOS 7 client

Next, upload the root CA certificate to the client, you may put the certificate under /etc/openldap/certs

sudo scp user@ldap1.abc.local:/etc/openldap/certs/rootCA.pem /etc/openldap/certs

Upload Root CA certificate

Configure LDAP client TLS certificate on CentOS 7 client

Ask LDAP to use your Root CA certificate for SSL/TLS establishment

echo "TLS_CACERT /etc/openldap/certs/rootCA.pem" | sudo tee -a /etc/openldap/ldap.conf

Initialize StartTLS LDAP test from the CentOS 7 client

Perform ldapwhoami with StartTLS.

ldapwhoami -x -D cn="admin,dc=abc,dc=local" -W -H ldap://ldap1.abc.local -Z # Z flag for StartTLS

If you can see the response, then you successfully talk to OpenLDAP over SSL/TLS Successful StartTLS LDAP test

Enable StartTLS for OpenLDAP account login on CentOS 7 client with nss-pam-ldapd

If your client uses nss-pam-ldapd to login LDAP accounts, you can follow below guide to configure StartTLS for it.

Configure StartTLS setting for nslcd

sudo authconfig  --enableldaptls --update # Specify StartTLS
echo "tls_cacertfile  /etc/openldap/certs/rootCA.pem" | sudo tee -a /etc/nslcd.conf # Specify Root CA certificate
# Use common name of the certificate, otherwise you will encounter connection error due to mismatch between hostname and the common name in the certificate (More in the below)
sudo authconfig --ldapserver=ldap1.abc.local --update
sudo systemctl restart nslcd

nss-pam-ldapd config

Test StartTLS for OpenLDAP account login on CentOS 7 client

A terminal to run nslcd in debug mode (Optional), it can help you debug and understand what is happening under the hood

sudo systemctl stop nslcd
sudo nslcd -d

nslcd debug mode The error due to mismatch between hostname and the common name in the certificate nslcd connection error Another terminal to login LDAP account

su - joe

Login LDAP accouns successfully

Conclusion

This guide covers benefits of using StartTLS for LDAP, how StartTLS LDAP works, how to configure OpenLDAP server to accept StartTLS, how to establish StartTLS LDAP connection and how to let your clients use StartTLS during authentication to LDAP server.

Blog: https://joeho.xyz

LinkedIn: https://www.linkedin.com/in/ho-cho-tai-0260758a

© 2021 — created by Joe