[HowTo] Install OpenLDAP 2.4+ with TLS support

Hi all. For this new post, I will explain how to install an OpenLDAP 2.4+ server on a Ubuntu Linux environment. For information, my current configuration is the following:

root@ldapserver:~# lsb_release -a && uname -a Distributor ID: Ubuntu Description: Ubuntu 12.04.4 LTS Release: 12.04 Codename: precise Linux ldapserver 3.8.0-41-generic #60~precise1-Ubuntu SMP Fri May 16 00:17:33 UTC 2014 i686 i686 i386 GNU/Linux

My hostname is ldaps.gremaud.local

cat /etc/hosts
127.0.0.1       localhost

127.0.1.1       ldaps.gremaud.local     ldaps
192.168.109.148 ldaps.gremaud.local     ldaps


# The following lines are desirable for IPv6 capable hosts
::1     localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters

 

Installation

To start, simply install OpenLDAP and tools from Ubuntu repositories

apt-get install slapd ldap-utils

 You will be asked to find an LDAP administrator password. For this tutorial I will use “psecret“. You must keep in mind that OpenLDAP is installed under /etc/ldap/.

Looking base configuration

Before starting the first configuration step, I just will give some information about the default configuration. By default with Ubuntu, openLDAP is installed under /etc/ldap/.

ls -Al /etc/ldap/
total 16
-rw-r--r-- 1 root     root      332 Mar 18 00:30 ldap.conf
drwxr-xr-x 2 root     root     4096 Mar 18 00:30 sasl2
drwxr-xr-x 2 root     root     4096 Sep 12 09:53 schema
drwxr-xr-x 3 openldap openldap 4096 Sep 12 09:53 slapd.d

 ldap.conf is the first file that we need to edit to set up basic configuration. sasl2 folder is dedicated to authentication mechanism but we will don’t use it here. Schema folder contains all loaded ldap schema. If you want to load additional schema, the new one will be placed in this folder. Finally the slapd.d folder contains all ldif files which contain OpenLDAP dynamic configuration (cn=config) and all other database like data (hdb, frontend etc).

Base configuration

As mentioned, after the installation, the first file to configure is /etc/ldap/ldap.conf. This file is used to set system-wide default to be applied when running ldap clients. For the moment only 2 parameters are important to set: BASE and URI.

  • BASE specify the default base DN to use when performing ldap operations . In many tutorials, this value is set to dc=example,dc=com. For this article, I decided to use dc=gremaud,dc=local.
  • URI specify the URI(s)  of an LDAP server(s) to which LDAP library (client) should connect. Each entries can be specified as a domain-style name or an IP address. Optionally, the server’s name can followed by a “:” and the port number the LDAP server is listening on. Default ports are used if no value is set. (389 for ldap://, 636 for ldaps://)
  • TLS_CACERT specify the file that contains the client certificate. This option is uncommented only if openLDAP has been built with TLS support. This is the case with Ubuntu.

Note : be sure to delete the “#” symbol before BASE and URI keyword.

BASE	dc=gremaud,dc=local
URI	ldap:// ldaps:// ldapi://

#SIZELIMIT	12
#TIMELIMIT	15
#DEREF		never

# TLS certificates (needed for GnuTLS)
TLS_CACERT	/etc/ssl/certs/ca-certificates.crt

If you want more information about ldap.conf, please consult man pages. It is important to understand that this file is only used by clients like ldapmodify, ldapsearch etc and never by the server (slapd).

man ldap.conf

Now, to specify on which IP and ports the server must listen, we need to edit the file /etc/default/slapd. Just change the option SLAPD_SERVICES. We don’t add ldaps:/// because since OpenLDAP 2.0, the extended operation startTLS is supported which allow to set TLS channel on an existing TCP connection established on ldap port 389.

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

Then restart the server and verify that the server is listen correctly.

/etc/init.d/slapd restart
 * Stopping OpenLDAP slapd                                    [ OK ]
 * Starting OpenLDAP slapd                                    [ OK ]
netstat -altn | egrep ":389"
tcp        0      0 127.0.0.1:389           0.0.0.0:*               LISTEN
tcp6       0      0 :::389                  :::*                    LISTEN

We can see that the host listen on LDAP (TCP 389) on all interfaces.

Load additional schemas

Before continu, we must to load additional schemas. These schemas are present with the installation of OpenLDAP but not loaded by default (That depend of the version of the distribution, simply try). To see which schemas are loaded by default, you can make a ldap search like this one:

ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config

 In my case, I only have 4 schemas loaded. Just for this example, I decide to load java.schema. Warning : You need to use java.ldif as parameter not java.schema.

ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/java.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
adding new entry "cn=java,cn=schema,cn=config"

 If you re-run the command to display all loaded schema, you should see java.schema.

ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: cn={4}java,cn=schema,cn=config

 Ok. Now you know how to load new schema. You can imagine to create your own using ldif format but this is out of the scope of this post.

Configure logging

A good things to do is to configure log level for rsyslog. First, create setLogLevel.ldif file and past this content:

dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

The value “stats” is good for the moment. Now, just use this command to add this to the cn=config.

ldapmodify -Y EXTERNAL -H ldapi:// -f setLogLevel.ldif

You can examine continuously the syslog like this:

tail -f /var/log/syslog | egrep "slapd"

 

Testing local and remote access

Now it is time to test the local and remote access to OpenLDAP server (Network only). For this test, we will use telnet tool to connect in the server with differents ways. For remote test, I will simply use another computer. In the remote computer, I just need to edit /etc/hosts to allow DNS resolution. For example:

cat /etc/hosts
127.0.0.1        localhost
127.0.0.1        cyrill-vm-mint
192.168.109.129  cyrill-vm-mint
192.168.109.148  ldaps.gremaud.local ldaps

Test 1 : Test LDAP (tcp 389) from localhost (should pass)

telnet 127.0.0.1 389
Trying 127.0.0.1...
Connected to 127.0.0.1
Escape character is '^].

We are connected, great.

Test 2 : Test LDAP (tcp 389) from remote host (should pass)

To to simpler, just try to open connection from the remote host to ldap server using tcp port 389.

telnet ldaps.gremaud.local 389
Trying 192.168.109.148...
Connected to 192.168.109.148

 Great ! The server listen correctly on localhost and public interface on port 389 only.

Configure access to configuration database

An important thing to do is to create a rootDN and password for olcDatabase={0}config,cn=config. With Ubuntu, you have nothing by default but with debian you have the RootDN set but no password. To create a salted and hashed password, please execute this command:

slappasswd
New password:
Re-enter new password:
{SSHA}SGq737yNactRCyMY70TDTQs6V1wzMRD6

 It’s important to run this command on all servers and not simply copy the result value even you set the same password on all servers. Now set this password to the configuration with the new rootDN.

dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootDN
olcRootDN: cn=admin,cn=config
-
add: olcRootPW
olcRootPW: {SSHA}SGq737yNactRCyMY70TDTQs6V1wzMRD6

Normally you can connect to this database using this command:

ldapmodify -H ldap://ldaps.gremaud.local -D "cn=admin,cn=config" -W

Configure TLS on server

In the previous step, we have seen that IP connections work correctly. Now we must configure TLS stack on LDAP server to allow TLS communication. To do this, we must create a self-signed certificate on the server. The first thing to do is to check with SSL library your openLDAP use because the certificates generated by OpenSSL are not compatible with GnuTLS for example.

ldd /usr/sbin/slapd
...
libgssapi.so.3 => /usr/lib/x86_64-linux-gnu/libgssapi.so.3 (0x00007f7068786000)
libgnutls.so.26 => /usr/lib/x86_64-linux-gnu/libgnutls.so.26 (0x00007f70684c8000)
libgcrypt.so.11 => /lib/x86_64-linux-gnu/libgcrypt.so.11 (0x00007f7068249000)
...

In my case, OpenLDAP uses GnuTLS then we must use certtool utility from the gnutls-bin package.

apt-get install gnutls-bin ssl-cert

Now just create working directory for certificates, keys and other stuff.

cd /etc/ssl
mkdir myKey
cd myKey/

 

Create self-signed CA certificate and server certificate

The first thing to do is to create the CA certificate. To do this, we need to generate the private key for the CA. (yes we are our own CA 🙂 ).

certtool --generate-privkey > ./cakey.pem
Generating a 2432 bit RSA private key...

Now, create a template file ca.info to define the CA certificate.

cn = gremaud.local
ca
cert_signing_key

I’m not sure but I believe that cn must match with your domain name. Now, we can create the CA self-signed certificate using the CA private key (cakey.pem) and the template (ca.info).

certtool --generate-self-signed \
--load-privkey ./cakey.pem \ 
--template ./ca.info \
--outfile ./cacert.pem

Now we have your own CA certificate. With this certificate, you be able to sign server certificate. The next step is to create server private key and certificate.

certtool --generate-privkey \
--bits 2048 \
--outfile ./ldaps_slapd_key.pem
Generating a 2048 bit RSA private key...

Just create the template for server certificate ldaps.info. It’s very important that the cn match with your hostname.

organization = my company
cn = ldaps.gremaud.local
tls_www_server
encryption_key
signing_key
expiration_days = 3650

And finally create the server certificate.

certtool --generate-certificate \
--load-privkey ./ldaps_slapd_key.pem \
--load-ca-certificate ./cacert.pem \
--load-ca-privkey ./cakey.pem \
--template ./ldaps.info \
--outfile ./ldaps_slapd_cert.pem

That done. For resume you have  these important files:

  • cacert.pem : CA certificate. Useful to sign server certificate
  • cakey.pem : CA private key
  • ldaps_slapd_cert.pem : Server certificate
  • ldaps_slapd_key.pem : Server private key

Now you are ready to configure OpenLDAP server to use these files.

Configure slapd to use certificates

We must add some entries on cn=config. An important point is that there is a difference if you use a self-signed certificate or if you have a certificate signed by a real CA like VeriSign. Create the file setTLSConfig.ldif.

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/myKey/cacert.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/myKey/ldaps_slapd_cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/myKey/ldaps_slapd_key.pem

If you use a self-signed certificate, please don’t add olcTLSCACertificateFile.

Use ldapmodify to apply this ldif.

ldapmodify -Y EXTERNAL -H ldapi:/// -f ./setTLSConfig.ldif

 

Secure access to server private key

It’s important to secure access to the server private key.

adduser openldap ssl-cert
chgrp ssl-cert /etc/ssl/myKey/ldaps_slapd_key.pem
chmod g+r /etc/ssl/myKey/ldaps_slapd_key.pem
chmod o-r /etc/ssl/myKey/ldaps_slapd_key.pem

Now you can try to restart your server

/etc/init.d/slapd restart

In my case, I have and error and I was not able to restart server correctly due to an error of apparmor. If you check kernel log and you have this :

apparmor="DENIED" operation="open" profile="/usr/sbin/slapd" name="/etc/ssl/myKey/ldaps_slapd_key.pem"

That mean that slapd cannot open the server key. To solve this problem, you must edit /etc/apparmor.d/usr.sbin.slapd and add these lines at the end.

/etc/ssl/myKey/ r,
/etc/ssl/myKey/* r,

And reload appArmor.

service apparmor reload

Now re-try to restart slapd. Normally, it’s work.

 

Configure clients (ldap.conf)

The next step is to configure correctly the ldap.conf to allow tools like ldapmodify, ldapsearch etc to use TLS. Add or modify these entries.

# TLS certificates (needed for GnuTLS)
TLS_CACERT      /etc/ssl/myKey/cacert.pem
TLS_REQCERT     demand
  • TLS_CACERT : Specifies the file that contains certificate for all of CA the client will recognize
  • TLS_REQCERT: With keyword “demand” the server certificate is requested and if it is not provided or bad, the session is terminated

That mean that all clients that want to communicate with the server need to have cacert.pem.

 

Test the connection

It’s time to test the configuration. To do these tests, we will use ldapsearch tool. From the server directly, use this command:

ldapsearch -ZZ -x

The option ZZ will force to use startTLS extension. You must have results back. Check your log to have more information.

tail -f /var/log/syslog | egrep "slapd"
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 fd=19 ACCEPT from IP=[::1]:44795 (IP=[::]:389)
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=0 EXT oid=1.3.6.1.4.1.1466.20037
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=0 STARTTLS
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=0 RESULT oid= err=0 text=
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 fd=19 TLS established tls_ssf=128 ssf=128
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=1 BIND dn="" method=128
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=1 RESULT tag=97 err=0 text=
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=2 SRCH base="dc=gremaud,dc=local" scope=2 deref=0 filter="(objectClass=*)"
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=2 SEARCH RESULT tag=101 err=0 nentries=2 text=
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 op=3 UNBIND
Sep 17 11:44:21 ldaps slapd[11743]: conn=1009 fd=19 closed

You can see with line 4 and 6 that StartTLS extension is correctly used and the TLS connection is made correctly. Now you can try to do this from a remote host like this:

ldapsearch -ZZ -x -h ldaps.gremaud.local
ldap_start_tls: Connect error (-11)
additional_info: (unknown error code)

 You will probably have an error like this one of you don’t have configured the /etc/ldap/ldap.conf in the remote host! Configure it like this:

BASE dc=gremaud,dc=local
URI ldap:/// ldapi:///

TLS_CACERT /etc/ssl/certs/cacert.pem
TLS_REQCERT demand

 It’s really important to set the TLS_CACERT correctly. Of course you must copy cacert.pem created on the openldap host to the remote host. You can use this command to do this easily.

scp ldap@ldaps.gremaud.local:/etc/ssl/myKey/cacert.pem ./
mv ./cacert.pem /etc/ssl/certs/

 Now you can retry the ldapsearch command and it must be successful.

 ldaps

Optimize your configuration

In this last chapter, I will add some tips to tune your configuration. Each time I discover a new useful tip, I will explain it here.

Force to use TLS

Actually, if you have followed this [howTo], you must be able to communication with OpenLDAP server using -ZZ option but if you don’t specify this flag, you can always execute correctly your request. I think it’s a good way to allow only request to be processed if TLS is enabled. To do this, you must add a security parameter in your configuration. For this example, I just want to force to use TLS for cn=config. Create and execute this ldif file.

cn=config
add: olcSecurity
olcSecurity: tls=1

Now execute it

ldapmodify -Y EXTERNAL -H ldapi:/// -f forceTLS_cnConfig.ldif

Now if you try to make a non-TLS search request, you have a error message.

ldapsearch -x -h ldaps.gremaud.local
ldap_bind: Confidentiality required (13)
        additional info: TLS confidentiality required

But if you enable startTLS extension with -ZZ flag,

ldapsearch -ZZ -x -h ldaps.gremaud.local
# extended LDIF
#
# LDAPv3
# base <dc=gremaud,dc=local> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# gremaud.local
dn: dc=gremaud,dc=local
objectClass: top
objectClass: dcObject

....

# search result
search: 3
result: 0 Success

# numResponses: 3
# numEntries: 2

Now, if you want to execute ldapmodify, you must use -ZZ flag too like this:

ldapmodify -ZZ -h ldaps.gremaud.local -D "cn=admin,cn=config" -W

 

Use phpldapdmin to manage your HDB

This application is a web interface which permits easily to add data to the HDB. To install it, simply run this command

apt-get install phpldapadmin

 Now, just configure it with minimal requirement. Edit /etc/phpldapadmin/config.php.

$config->custom->appearance['hide_template_warning'] = true;
$servers->setValue('server','name','My LDAPS Server');
$servers->setValue('server','host','ldaps.gremaud.local');
$servers->setValue('server','port',389);
$servers->setValue('server','base',array('dc=gremaud,dc=local'));
$servers->setValue('login','bind_id','cn=admin,dc=gremaud,dc=local');

 Restart the webserver

/etc/init.d/apache2 restart

 Now you can try to access to your phpldapadmin using a classical browser.

pla

Enter your password and you will be connected.

Note : If you have forced to use TLS (look the previous chapter), you must add this settings in /etc/phpldapadmin/config.php

$servers->setValue('server','tls',true);

Be sure that your /etc/ldap/ldap.conf file is configured correctly to communicate with the openldap server with TLS. In my case, I have already this file configured because my webserver is in the same server that ldap server…

Note : You have an encrypted channel between your webserver and your ldap server but the password you write in phpldapadmin is send by HTTP in plaintext !! Enable mod_ssl in your apache server to avoid this issue. Look my next tip to learn how to configure Apache2 to enable HTTPS.

Enable TLS on Apache2 (HTTPS)

To enable HTTPS protocol on Apache2 webserver, you must install and configure mod_ssl. Execute the following command from a terminal prompt to enable the mod_ssl module:

a2enmod ssl

 There is a default HTTPS configuration file in /etc/apache2/sites-available/default-ssl. In order for Apache2 to provide HTTPS, a certificate and key file are also needed. The default HTTPS configuration will use a certificate and key generated by the ssl-cert package. They are good for testing, but the auto-generated certificate and key should be replaced by a certificate specific to the site or server. Of course, we can use the server certificate that we have created for OpenLDAP (only if this webserver is installed on the same host that openLDAP of course).

Edit the file /etc/apache2/sites-available/default-ssl

#SSLCertificateFile     /etc/ssl/certs/ssl-cert-snakeoil.pem
#SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

SSLCertificateFile      /etc/ssl/myKey/ldaps_slapd_cert.pem
SSLCertificateKeyFile   /etc/ssl/myKey/ldaps_slapd_key.pem

 Now, apply this configuration and reload the server.

a2ensite default-ssl
service apache2 reload

 Now try to access to phpldapadmin with HTTPS protocol. You will have a warning (here with Chrome).

https_warning

It simply because the server certificate is signed by a unknow CA (self-signed) for Chrome. You can click “Advanced“, and “Proceed to 192.168.109.150 (unsafe)“. If you capture your traffic, it is encrypted.

Conclusion

So this [HowTo] is now terminated and I hope that it will be useful for you. Please, I’m not an LDAP expert, then do not hesitate to send me your feedback to help me to improve this post.

Bookmark the permalink.

6 Comments

  1. Pingback: [HowTo] Setup N-Way Multi-Master replication with OpenLDAP | ./Blog("Cyrill Gremaud")

  2. Hello. Thanks for the tutorial.
    In step “Configure access to configuration database” which is the exactly file that needs modifications?
    I opened /etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif but in the top says “# AUTO-GENERATED FILE – DO NOT EDIT!! Use ldapmodify.” I think this files was left from an old installation. If this is the file then do you know how to reset it?

    • Hello Ignacio and thank you for your comment. No file needs modification. You must create a new ldif file which will modify the configuration. To apply this file, you must use ldapmodify command line tool.

  3. Avatar
    Jose Raul Arana

    Hey!!
    This is a great article. I have learned a lot with it.
    I have seen that there is a little error in the forceTLS_cnConfig.ldif, it should be like this:
    dn: cn=config
    add: olcSecurity
    olcSecurity: tls=1

    Because it is missing the dn:

    Thank you very much!

  4. This article should be updated on a number of points.

    Use of ldaps (port 636) is officially deprecated, so best not to use it all, and do not include ldaps in the list of URI — just ldap on 389 (with starttls recommended for security) and ldapi via the socket under /run/slapd.

    For security, yes create the certificates as described, and require starttls on the port 389 ldap.

    Now the important thing concerning slapd on Ubuntu 16.04 and later is that the configuration database cn=config is set up to only be accessible by the root user (uid=0) and there is no username/password access.

    Therefore if you will need to create an administrator username + password if the olcSecurity: tls=1 is applied at the config level, because without it, access to the config database will no longer be possible. This is also necessary if you want to do config changes “remotely” via port 389.

    To maintain the security of changing config only by user root on the host machine, but to require clients to use tls to access the ldap database, the oclSecurity: tls=1 setting must be applied not to the config database, but to the LDAP data datbase(s) viz

    dn: olcDatabase=mdb,cn=config

    olcSecurity: tls=1
    olcSuffix: dc=example,dc=COM

    With that arrangement

    ldapsearch -b “cn=config” -H “ldapi:///” -LLL -Y EXTERNAL

    (and associated commands) will continue to work on the config database whereas connections for searching the ldap data database will need to be encrypted (-Z for encrypted connection and -ZZ to fail if encrypted connection setup fails)

    ldapsearch -b “dc=example,dc=COM” -H “ldap://yourhost:389/” -x -ZZ

    A combination of -Y EXTERNAL and -Z{Z} will not work

    Authentication method not supported (7)
    additional info: SASL(-4): no mechanism available

    Also you may consider requiring a minimum TLS protocol level (these settings can go in the config database)

    olcTLSProtocolMin: 3.3

    and perhaps ensuting the Ciphers setting is the default (accoring to the manual page) to disallow broken SSL3.0 and a higher level of encryption, rather than just specifying NORMAL, eg

    olcTLSCipherSuite: SECURE256:-VERS-SSL3.0

    Exercise caution in the settings for the CipherSuite — Ubuntu uses GNUtls so do not apply openSSL settings (MEDIUM, HIGH) which appear in HowTos for other non-(Debian/Ubuntu/Mint)
    distributions.

    Available Cipher Suites can be listed with

    gnutls-cli -l

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.