In this tutorial we will learn how to secure OpenLDAP server with either TLS, Optional/Mandatory MTLS or STARTTLS. Now since we don't have a third party signed certificate so we will generate our own set of server and client certificates and use them with our OpenLDAP server and client.
Compare TLS Vs Mandatory MTLS Vs Optional MTLS Vs STARTTLS
TLS (Transport Layer Security)
Flow:
- Client Hello: The client sends a message to the server indicating it wants to establish a secure session.
- Server Hello: The server responds, providing its chosen cipher suite and its digital certificate.
- Key Exchange: The client and server exchange cryptographic keys.
- Client Finished: The client sends a message to indicate it has completed its part of the handshake.
- Server Finished: The server responds, completing the handshake.
Validation:
- Server Validation: The client validates the server's certificate against a trusted CA.
- Client Validation: Not required unless configured for mutual authentication.
Optional MTLS (Mutual TLS)
Flow:
- Client Hello: The client initiates the handshake.
- Server Hello: The server responds with its certificate and may request a client certificate.
- Client Certificate (optional): The client sends its certificate if requested.
- Key Exchange: Both parties exchange cryptographic keys.
- Finished Messages: Both client and server send finished messages to complete the handshake.
Validation:
- Server Validation: The client validates the server's certificate.
- Client Validation: The server attempts to validate the client's certificate if presented but does not abort if the client certificate is not provided.
Mandatory MTLS (Mutual TLS)
Flow:
- Client Hello: The client starts the secure session.
- Server Hello: The server responds with its certificate and requests the client's certificate.
- Client Certificate: The client must provide its certificate.
- Key Exchange: Both parties perform the key exchange.
- Finished Messages: Both client and server complete the handshake with finished messages.
Validation:
- Server Validation: The client validates the server's certificate.
- Client Validation: The server validates the client's certificate.
STARTTLS
Flow:
- Plaintext Connection: The client establishes a non-secure connection to the server.
- STARTTLS Command: The client sends the STARTTLS command to upgrade the connection to a secure one.
- TLS Handshake: The client and server perform the TLS handshake steps, including key exchange and certificate validation.
- Key Exchange: Both parties exchange cryptographic keys.
- Secure Connection: The connection is now secure, and communication can proceed encrypted.
Validation:
- Server Validation: The client validates the server's certificate.
- Client Validation: Can be optional or mandatory, depending on server configuration.
Now that you know little bit about different security mode and how they differ from each other, so you can plan to enable the respective security for your environment.
Generate Required Certificates
If you already have the required certificates then you can skip this step. In a nutshell you basically have to perform the following steps:
- How to create Self-Signed CA Certificate with OpenSSL
- Create SAN Certificate
- OpenSSL create Client Certificate & Server Certificate with Example
You can also refer The Only OpenSSL CheatSheet You Will Need! for more information.
I will store all my certs inside /certs
:
mkdir /certs
Generate CA private key:
openssl genrsa -out /certs/ca.key 4096
Generate CA certificate
openssl req -new -x509 -days 3650 -key /certs/ca.key -out /certs/ca.crt
Here is a shell script which will generate both server and client certificates inside /certs
. The script is very basic and I have not added too many checks, if you intend to use it then I would recommend you to modify the individual fields such as CSR, SAN Fields based on your environment.
You can add multiple DNS and IP Addresses using DNS.1, DNS.2, DNS.3,... and IP.1, IP.2, IP.3 and so on. These fields should contain the FQDN/Hostname and IP of your LDAP server which will be used by clients for communication. For example in my case I am planning to use server.example.com
to communication with LDAP server and the same has been updated to /etc/hosts
.
For client certificate the SAN Field is not required so we are not passing any custom extension or configuration.
#!/bin/bash
# Define directories and filenames
CERT_DIR="/certs"
CA_KEY="${CERT_DIR}/ca.key"
CA_CERT="${CERT_DIR}/ca.crt"
CLIENT_KEY="${CERT_DIR}/client.key"
CLIENT_CSR="${CERT_DIR}/client.csr"
CLIENT_CERT="${CERT_DIR}/client.crt"
SERVER_KEY="${CERT_DIR}/server.key"
SERVER_CSR="${CERT_DIR}/server.csr"
SERVER_CERT="${CERT_DIR}/server.crt"
# Create the certs directory if it doesn't exist
[[ ! -d $CERT_DIR ]] && mkdir -p $CERT_DIR
# Generate server private key and CSR
openssl req -new -sha512 -nodes -out $SERVER_CSR -newkey rsa:4096 -keyout $SERVER_KEY -subj "/C=IN/ST=KARNATAKA/L=BENGALURU/O=GoLinuxCloud/OU=Admin/CN=ldap-server"
# Define OpenSSL configuration file for server extensions
SERVER_EXT_CONF="${CERT_DIR}/server_ext.cnf"
cat > $SERVER_EXT_CONF << EOF
[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
[ alt_names ]
DNS.1 = server.example.com
IP.1 = 10.10.1.17
EOF
# Generate server certificate with the correct extensions
openssl x509 -req -in $SERVER_CSR -CA $CA_CERT -CAkey $CA_KEY -CAcreateserial -out $SERVER_CERT -days 3650 -sha512 -extfile $SERVER_EXT_CONF -extensions v3_req
# Generate client private key and CSR
openssl req -new -sha512 -nodes -out $CLIENT_CSR -newkey rsa:4096 -keyout $CLIENT_KEY -subj "/C=IN/ST=KARNATAKA/L=BENGALURU/O=GoLinuxCloud/OU=Admin/CN=ldap-client"
# Generate client certificate
openssl x509 -req -in $CLIENT_CSR -CA $CA_CERT -CAkey $CA_KEY -CAcreateserial -out $CLIENT_CERT -days 3650 -sha512
echo "Certificates generated successfully."
Verify if SAN field is properly updated on server certificate:
openssl x509 -noout -text -in /certs/server.crt | grep -A 2 "X509v3 Subject Alternative Name"
The script will generate both server and client certificate. You can copy the client certificates to your openldap client.
Since I am using same VM as master and client so I will copy all certificates inside /etc/openldap/certs
.
sudo cp /certs/* /etc/openldap/certs/
sudo chown -R ldap:ldap /etc/openldap/certs/
sudo chmod 600 /etc/openldap/certs/*
You can also choose to only copy certificate and key file as the CSR, ca.key
, server_ext.cnf
files are not required for securing LDAP server.
Configure Certificates on OpenLDAP Server
Configure your openldap server to consume the server certificates. Create an LDIF file (e.g., enable_tls.ldif
) with the following content:
dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/server.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/server.key
-
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/openldap/certs/ca.crt
Apply the configuration:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f enable_tls.ldif
Verify the changes:
sudo ldapsearch -Y EXTERNAL -H ldapi:/// -b cn=config olcTLSCACertificateFile olcTLSCertificateFile olcTLSCertificateKeyFile
Enable LDAPS on OpenLDAP Server
In Rocky Linux by default LDAP runs on both port 389 and 636. You can verify if slapd is running with LDAPS support or not using below command:
systemctl status slapd
Also check if LDAP server is listening on port 636 or not:
ss -ntlp | grep :636
If in case in your environment if slapd is not configured to use ldaps then you can edit /usr/lib/systemd/system/slapd.service
. Look for the ExecStart
line and modify it to include the desired port
ExecStart=/usr/sbin/slapd -u ldap -h "ldap:/// ldaps:/// ldapi:///"
After editing the slapd.service
file, reload the systemd configuration to apply the changes:
sudo systemctl daemon-reload
Restart the OpenLDAP service to apply the changes:
sudo systemctl restart slapd
Verify that OpenLDAP is now listening on the new ports using netstat
or ss
:
sudo netstat -tulnp | grep slapd
OR
sudo ss -tulnp | grep slapd
Configure Firewall and SELinux
Ensure that your firewall allows traffic on port 389 and 636, which is the default port for LDAP and LDAPS respectively.
Verify if firewalld
is running:
sudo systemctl status firewalld
If it is not running, you can start it with:
sudo systemctl start firewalld
Open port 389 and 636 to allow LDAP and LDAPS traffic. You can use the following command:
sudo firewall-cmd --permanent --add-port=389/tcp
sudo firewall-cmd --permanent --add-port=636/tcp
Apply the changes by reloading the firewall rules:
sudo firewall-cmd --reload
Ensure that the rule has been added correctly:
sudo firewall-cmd --list-all
If SELinux is enabled, make sure it is configured to allow OpenLDAP to use the certificates and the LDAPS port.
sudo setsebool -P allow_ldap_tls=on
sudo semanage port -a -t ldap_port_t -p tcp 636
sudo semanage port -a -t ldap_port_t -p tcp 389
To verify that the ports have been correctly added, you can use the following command:
sudo semanage port -l | grep ldap
Understanding olcTLSVerifyClient
and olcSecurity
Based on the type of security we will configure OpenLDAP server with two options olcTLSVerifyClient
and olcSecurity
to control the OpenLDAP security.
The olcSecurity
attribute in OpenLDAP is used to configure security-related policies for the LDAP server. Specifically, it can be used to enforce various levels of security on the LDAP connections, such as requiring encryption or stronger authentication mechanisms.
- tls=0: No security required.
- tls=1: Requires the use of TLS for all operations.
- ssf=128: Security Strength Factor of 128 bits required.
- transport=256: Requires a transport layer with a security strength factor of 256 bits.
The olcTLSVerifyClient
directive in OpenLDAP specifies the level of client certificate verification required during a TLS (SSL) handshake. Here's what the different settings mean:
demand
(orhard
): The server requires the client to provide a certificate. If the client does not provide a certificate or the certificate is not valid, the connection is aborted.never
: The server never asks the client for a certificate.allow
: The server asks the client for a certificate, but the client may choose not to provide one. If a certificate is provided, it will be checked.try
: The server asks the client for a certificate, but if the client does not provide one, the server proceeds with the connection anyway. If a certificate is provided, it will be checked.
We will be using these options in the next sections to configure OpenLDAP with TLS, MTLS or STARTTLS.
Secure OpenLDAP Server with TLS
For TLS communication we don't need any additional config on the OpenLDAP server. Simply adding the certificates is enough.
Configure your client to use the CA certificate for any LDAP communication. Add the following for client configuration (/etc/openldap/ldap.conf
):
TLS_CACERT /etc/openldap/certs/ca.crt
Test the LDAP client connection with TLS/SSL:
ldapsearch -H ldaps://server.example.com -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -W
Secure OpenLDAP with Optional MTLS
On OpenLDAP server, create an LDIF file (e.g., optional_mtls.ldif
) with the following content:
dn: cn=config
changetype: modify
replace: olcTLSVerifyClient
olcTLSVerifyClient: allow
Apply the changes using the ldapmodify
command:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f optional_mtls.ldif
Restart the OpenLDAP service to apply the changes:
sudo systemctl restart slapd
On OpenLDAP Client, edit the LDAP client configuration file /etc/openldap/ldap.conf
to include the TLS settings:
TLS_CACERT /etc/openldap/certs/ca.crt
TLS_CERT /etc/openldap/certs/client.crt
TLS_KEY /etc/openldap/certs/client.key
TLS_REQCERT allow
Use ldapsearch
to test the connection with optional MTLS. The server will request the client certificate, but it will not be mandatory:
sudo ldapsearch -H ldaps://server.example.com -x -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com"
Secure OpenLDAP with Mandatory MTLS
On OpenLDAP server, create an LDIF file (e.g., mandatory_mtls.ldif
) with the following content:
dn: cn=config
changetype: modify
replace: olcTLSVerifyClient
olcTLSVerifyClient: demand
Apply the changes using the ldapmodify
command:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f mandatory_mtls.ldif
Restart the OpenLDAP service to apply the changes:
sudo systemctl restart slapd
On OpenLDAP Client, edit the LDAP client configuration file /etc/openldap/ldap.conf
to include the TLS settings:
TLS_CACERT /etc/openldap/certs/ca.crt
TLS_CERT /etc/openldap/certs/client.crt
TLS_KEY /etc/openldap/certs/client.key
TLS_REQCERT demand
In some cases we also have to set the environment variable on the LDAP client:
export LDAPTLS_CACERT=/etc/openldap/certs/ca.crt
export LDAPTLS_CERT=/etc/openldap/certs/client.crt
export LDAPTLS_KEY=/etc/openldap/certs/client.key
Use ldapsearch
to test the connection with optional MTLS. The server will request the client certificate, but it will not be mandatory:
sudo ldapsearch -H ldaps://server.example.com -x -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com"
The query is successful which would mean that we are successfully able to establish communication with LDAP server over MTLS.
Secure OpenLDAP with STARTTLS
Configure OpenLDAP server to enable TLS for all communication. Create a file named enable_starttls.ldif
with the following content:
dn: cn=config
changetype: modify
replace: olcSecurity
olcSecurity: tls=1
Apply the changes using the ldapmodify
command:
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f enable_starttls.ldif
Restart the OpenLDAP service to apply the changes:
sudo systemctl restart slapd
On OpenLDAP client, Add the following lines in /etc/openldap/ldap.conf
:
TLS_CACERT /etc/openldap/certs/ca.crt
TLS_CERT /etc/openldap/certs/client.crt
TLS_KEY /etc/openldap/certs/client.key
TLS_REQCERT demand
The only difference here is that with STARTTLS we will perform the LDAP communication on a non-secure port i.e. port 389
unlike MTLS where we were using ldaps
with port 636
. For STARTLS you need not enable ldaps:/// in the server configuration because as explained earlier, It starts with a non-secure connection and upgrades to a secure connection using the STARTTLS command.
You can test STARTTLS using the ldapsearch
command, which attempts to start TLS on an LDAP connection:
ldapsearch -H ldap://server.example.com -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -W -x
Notice the error we get here:
ldap_bind: Confidentiality required (13)
additional info: TLS confidentiality required
This is because we have enforced TLS based communication. So we must add -ZZ
to initiate STARTTLS.
ldapsearch -H ldap://server.example.com -b "dc=example,dc=com" -D "cn=admin,dc=example,dc=com" -W -x -ZZ
Here if you notice I am using default LDAP port number with additional argument -ZZ
to enable STARTTLS.
To verify if encryption is working, I have collected tcpdump using tcpdump -i any -w /home/deepak/ldap_starttls.pcap port 389
. Here is the snippet from Wireshark:
- The
extendedReq
withLDAP_START_TLS_OID
is the client requesting to start TLS on the existing LDAP connection. Client Hello
: The client initiates the TLS handshake.Server Hello
: The server responds to the client's handshake request.
This sequence shows that the STARTTLS operation is initiated, and the TLS handshake process is starting as expected
With ldap's native commands we don't have too many options to debug any TLS related failures. So we can rely on openssl command to debug any TLS related issues.
For MTLS communication, pass the client certificate and key and observe the output:
openssl s_client -connect server.example.com:636 -CAfile /etc/openldap/certs/ca.crt -cert /etc/openldap/certs/client.crt -key /etc/openldap/certs/client.key
Check if the TLS handshake is completed successfully. Look for the following in the debug output:
SSL handshake has read xxx bytes and written xxx bytes
Verification: OK
Ensure the server is requesting and correctly validating the client certificate. Look for the Acceptable client certificate CA names
and Verify return code: 0 (ok)
.
The tls_write: want=24 error=Broken pipe
error indicates the connection was terminated unexpectedly. This could be due to the server rejecting the client certificate or an issue with the client configuration.
With Optional MTLS or TLS you only need to pass CA certificate:
openssl s_client -connect server.example.com:636 -CAfile /etc/openldap/certs/ca.crt
You can also refer official OpenLDAP troubleshooting manual to cover more scenarios.
In this tutorial we learned to create our own Certificate Authority certificate, and then used this CA certificate to create ldap client certificate. This CA and client certificate will be used across all the ldap clients for encrypted and secure communication. I have created SAN certificate here but you can choose to create individual client certificates for all your ldap client nodes.
Refer official OpenLDAP Administration document and setting up OpenLDAP with TLS/SSL mutual authentication for more information.
Next you can read How to decrypt HTTPS & LDAPS Traffic using WireShark
Hi Experts,
I want to change version from Version: 1 (0x0) to Version: 3 (0x2)
I am working on the following topic “Configure OpenLDAP over TLS with RootCA Issued Certificate”.
I have issued 3rd command on step 2.
After that I am trying to print the certificate content using the following command “
openssl req -text -noout -verify -in CSR.csr
”output :
openssl req -text -noout -verify -in test.csr verify OK
Certificate Request:
Data:
Version: 1 (0x0)
Subject: CN = 10.0.101.239, O = AMI
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (3072 bit)