So we’ve got an OpenLDAP server (slapd) running and we’ve added some users.
Searching for or authenticating with or modifying passwords without TLS is unsafe. The following ldapsearch and wireshark capture shows the password in cleartext.
root@fangorn:~# ldapsearch -D uid=lobelia,ou=people,dc=telperion,dc=org -LLL -H ldap://barad-dur.telperion.org -w ihatebilbo -b uid=lobelia,ou=people,dc=telperion,dc=org -x userPassword dn: uid=lobelia,ou=people,dc=telperion,dc=org userPassword:: e1NTSEF9dmJ5N0Iwbk5IeEx1VXR0WjBXSWRUQVdrQWlXRlpsSzQ=
If we want to use it to authenticate, we should secure the traffic. The easiest way to do that is with SSL.
Setting up a certificate hierarchy is not trivial but it is best to either generate a self signed certificate authority or get a certificate signed by a reputable CA (e.g. LetsEncrypt). Because this sample is on a closed personal network, I’ve chosen to generate a self-signed domain certificate authority and an intermediate. The CA signs the intermediate CA and the intermediate CA signs the cert for each of the nodes in the network.
The default slapd package in debian stretch uses gnutls to perform it’s crypto operations by default so when pouring over the slapd manpages, keep that in mind (some options are meant for slapd built against Mozilla’s NSS and some are for OpenSSL). gnutls is pretty strict about self-signed CAs. If building the CA with OpenSSL, make sure you use the CA extensions. Also, if using Elliptic Curves, make sure you use named curves. I had trouble getting gnutls to parse OpenSSL generated certs that had curve parameters explicitly defined. Switching to using the named NIST curves solved the problem. Establishing an appropriate PKI can be done with the certtool command (from gnutls) or using OpenSSL’s command line suite. I’ve used OpenSSL to generate a CA PKI, loosely following this guide: OpenSSL Certificate Authority.
Configure the Keys and Certs
Now to configure slapd to use this cert. First copy your certs into an appropriate location. I copied my ca cert chain (a file consisting of the concatenation of the root CA and the intermediate CA) and the server cert into /etc/ssl/certs. I put the private key in /etc/ssl/private. Change the group ownership of the private key to ssl-cert to allow the openldap user (a member of the ssl-cert group) to use the key.
Configure the Server Keys (barad-dur)
Place keys in the appropriate locations and give them the appropriate permissions.
root@barad-dur:~# ls -ltr /etc/ssl/certs | tail -n2 -r--r--r-- 1 root root 1836 Feb 3 16:27 telperion.org.ca-chain.cert.pem -r--r--r-- 1 root root 1208 Feb 3 16:27 barad-dur.telperion.org.cert.pem root@barad-dur:~# ls -ltr /etc/ssl/private/ | tail -n1 -r--r----- 1 root ssl-cert 288 Feb 3 16:27 barad-dur.telperion.org.key.pem root@barad-dur:~# groups openldap openldap : openldap ssl-cert
Configure the Client Keys (fangorn)
Set up the keys:
root@fangorn:~# ls -ltr /etc/ssl/certs/ | grep telperion -r--r--r-- 1 root root 1200 Feb 3 17:09 fangorn.telperion.org.cert.pem -r--r--r-- 1 root root 1836 Feb 3 17:09 telperion.org.ca-chain.cert.pem root@fangorn:~# ls -ltr /etc/ssl/private/ | grep telperion -r--r----- 1 root ssl-cert 288 Feb 3 17:09 fangorn.telperion.org.key.pem
Configure LDAP to use TLS
Now that we have a PKI that makes sense, we can tell slapd and libldap to use the keys we’ve provided.
On the client, it is pretty easy. Configure the default ldap configuration file (/etc/ldap/ldap.conf) on the client machine (fangorn in this case) as follows:
# See ldap.conf(5) for details # This file should be world readable but not world writeable. BASE dc=telperion,dc=org URI ldap://barad-dur.telperion.org TLS_CACERT /etc/ssl/certs/telperion.org.ca-chain.cert.pem TLS_KEY /etc/ssl/private/fangorn.telperion.org.key.pem TLS_CERT /etc/ssl/certs/fangorn.telperion.org.cert.pem
Configuring the server is a little more involved because slapd uses its own directory as configuration. This means we need to use the ldapmodify command to update the config database. Create an ldif file called update-certs.ldif with the following contents:
dn: cn=config changetype: modify replace: olcTLSCACertificateFile olcTLSCACertificateFile: /etc/ssl/certs/telperion.org.ca-chain.cert.pem - replace: olcTLSCertificateFile olcTLSCertificateFile: /etc/ssl/certs/barad-dur.telperion.org.cert.pem - replace: olcTLSCertificateKeyFile olcTLSCertificateKeyFile: /etc/ssl/private/barad-dur.telperion.org.key.pem
Use ldapmodify to update the configuration:
root@barad-dur:~# ldapmodify -Y EXTERNAL -H ldapi:/// -f update-certs.ldif SASL/EXTERNAL authentication started SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth SASL SSF: 0 modifying entry "cn=config"
Verify that our addition “took”:
root@barad-dur:~# ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config "(objectClass=olcGlobal)" dn: cn=config objectClass: olcGlobal cn: config olcArgsFile: /var/run/slapd/slapd.args olcLogLevel: none olcPidFile: /var/run/slapd/slapd.pid olcToolThreads: 1 olcTLSCACertificateFile: /etc/ssl/certs/telperion.org.ca-chain.cert.pem olcTLSCertificateFile: /etc/ssl/certs/barad-dur.telperion.org.cert.pem olcTLSCertificateKeyFile: /etc/ssl/private/barad-dur.telperion.org.key.pem
Now we can use the “startTLS” version of ldapsearch to send ldap results over a secure channel.
Using the following command (-ZZ option forces TLS), we don’t see any cleartext passwords:
root@fangorn:~# ldapsearch -D uid=lobelia,ou=people,dc=telperion,dc=org -LLL -H ldap://barad-dur.telperion.org -w ihatebilbo -b uid=lobelia,ou=people,dc=telperion,dc=org -x -ZZ userPassword dn: uid=lobelia,ou=people,dc=telperion,dc=org userPassword:: e1NTSEF9dmJ5N0Iwbk5IeEx1VXR0WjBXSWRUQVdrQWlXRlpsSzQ=