How to configure SSL (aka. ldaps) for libnss-ldap/auth-client-config in Ubuntu

The LDAPClientAuthentication page in the Ubuntu Community wiki describes the basic setup pretty well. However if you bring encryption (SSL/TLS) into the game, it's a quite different story.

If you think it's enough to set the uri parameter (in /etc/ldap.conf) to an ldaps URI (eg. uri ldaps://ldapserver.example.com/), then you're utterly wrong. Smile

I think it's safe to assume that most (or at least the smaller) companies use mostly self-signed certificates. Eg. this is the case if you follow the TLS and SSL chapter section of the OpenLDAP Server page of the Maverick Server Guide.

The first problem: you've set everything up (on the LDAP client, eg. ldapclient.example.com) and test by requesting the list of users ... expecting a merge of the local users and the LDAP server's (ldapserver.example.com) users. How else would you do this than via getent passwd. Of course you won't see any users from the LDAP database ... not that fast. Smile

Looking at the logs (particularily /var/log/auth.log will reveal the following, "very helpful" messages:
Mar 29 18:04:52 ldapclient getent: nss_ldap: could not connect to any LDAP server as cn=admin,dc=example,dc=com - Can't contact LDAP server
Mar 29 18:04:52 ldapclient getent: nss_ldap: failed to bind to LDAP server ldaps://ldapserver.example.com/: Can't contact LDAP server
Mar 29 18:04:52 ldapclient getent: nss_ldap: could not search LDAP server - Server is unavailable

Looking for help on the net you might stumble on the advice to try ldapsearch. Let's do that.

But first disable your caching daemon if you've set up any. Eg. nscd or nslcd. Since we're debugging, we'll be running the same LDAP queries over and over again. No need for any caching.

Now run the following (of course with the -d 1 switch which turns on debugging) on the LDAP client:
ldapsearch -d 1 -xLLL -H ldaps://ldapserver.example.com/ -b "dc=example,dc=com" uid=xxxx dn

It's irrelevant (at this stage) whether or not there's a user with an uid of "xxxx" in the LDAP directory. We get refused long before that:
ldap_url_parse_ext(ldaps://ldapserver.example.com/)
ldap_create
ldap_url_parse_ext(ldaps://ldapserver.example.com:636/??base)
ldap_sasl_bind
ldap_send_initial_request
ldap_new_connection 1 1 0
ldap_int_open_connection
ldap_connect_to_host: TCP ldapserver.example.com:636
ldap_new_socket: 3
ldap_prepare_socket: 3
ldap_connect_to_host: Trying 192.168.0.2:636
ldap_pvt_connect: fd: 3 tm: -1 async: 0
TLS: peer cert untrusted or revoked (0x42)
TLS: can't connect: (unknown error code).
ldap_err2string
ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)

That's much better. So the problem is that the LDAP server's SSL certificate is not trusted by the client.

Looking into the /etc/ldap.conf file you find this:
# OpenLDAP SSL options
# Require and verify server certificate (yes/no)
# Default is to use libldap's default behavior, which can be configured in
# /etc/openldap/ldap.conf using the TLS_REQCERT setting.  The default for
# OpenLDAP 2.0 and earlier is "no", for 2.1 and later is "yes".
#tls_checkpeer yes

# CA certificates for server certificate verification
# At least one of these are required if tls_checkpeer is "yes"
#tls_cacertfile /etc/ssl/ca.cert
#tls_cacertdir /etc/ssl/certs

There're a number of quite promising parameters that might be helpful. Or so you think. Smile

Try to remove the comment mark from the tls_checkpeer parameter and set it to no. Run ldapsearch again ... and watch as it fails. Obviously this parameter is not really respected. Let's try another one.

Since we used a self-signed certificate on the LDAP server, it means that we have the CA's (certificate authority) certificate somewhere on the LDAP server. If you follwed the Ubuntu OpenLDAP guide, then it's in /etc/ssl/certs/cacert.pem. Let's copy this to your LDAP client (eg. ldapclient.example.com) to the same location (ie. directory).

Now set the tls_cacertfile parameter to /etc/ssl/certs/cacert.pem and test with ldapsearch again. Still nothing. This is getting a bit annoying, isn't it?

Let's take a look at those comments/descriptions in /etc/ldap.conf again:
# OpenLDAP SSL options
# Require and verify server certificate (yes/no)
# Default is to use libldap's default behavior, which can be configured in
# /etc/openldap/ldap.conf using the TLS_REQCERT setting.
# (...)

Hmm. There's no /etc/openldap/ldap.conf file on the LDAP client, but there's a /etc/ldap/ldap.conf. There's no TLS_REQCERT parameter in it, so let's add it and use the value "allow" (this will accept the server certificate even if it's not trusted).

Try again the search and see it succeed. Now we're getting closer to the truth. Smile
We should not compromise our security by leaving things at this ... now add the parameter TLS_CACERT /etc/ssl/certs/cacert.pem to /etc/ldap/ldap.conf and remove TLS_REQCERT (which will make it fall back to the default "demand" value).
Test the search on the client again and see it succeed. Wink Or fail ... since you probably have no user with an uid of "xxxx" in your LDAP directory. Smile

To summerize what we've learnt:
  • the tls_* options in /etc/ldap.conf seem not to work
  • if you've no TLS_REQCERT allow option in /etc/ldap/ldap.conf, then your client will try to verify the server certificate's validity ... and if you used a self-signed certificate, it will fail
  • using ldapsearch -d 1 ... reveals a lot more about the real problem, then trying getent passwd
  • to set up authentication through ldaps://, you've to set the uri accordingly in /etc/ldap.conf, copy the CA certificate over to the client and specify it's location with the TLS_CACERT option in /etc/ldap/ldap.conf
Hopefully this will help you cut the corners in setting up LDAP + SSL. Smile

P.S.: I've tested these with Ubuntu Maverick (10.10). The ineffectiveness of the tls_* variables in /etc/ldap.conf might have been fixed in newer Ubuntu releases (btw. the file is used by libnss-ldap). As for /etc/ldap/ldap.conf ... it's used by libgnutls, which is called by libnss-ldap. Smile

P.S.2: Debian (Squeeze) users will find that their libnss-ldap uses the configfile /etc/libnss-ldap.conf and libpam-ldap uses the file /etc/pam_ldap.conf (optionally you can create one and use a symlink for the other to keep things synced). But most of my observations still apply.

P.S.3: just one more note ... Smile If you set up the LDAP client authentication on the LDAP server itself as well and specify uri ldaps://127.0.0.1/ in /etc/ldap.conf, then LDAP queries won't work. From the debug output of ldapsearch -d 1 -xLLL -H ldaps://127.0.0.1/ -b "dc=example,dc=com" uid=xxxx dn you get this:
TLS: hostname (127.0.0.1) does not match common name in certificate (ldapserver.example.com).
However if you run ldapsearch -d 1 -xLLL -H ldaps://localhost/ -b "dc=example,dc=com" uid=xxxx dn, then it will work! Shock And likewise ... specifying uri ldaps://localhost/ in /etc/ldap.conf will work too. I assume that either libnss-ldap or libgnutls interpret "localhost" and replace it with the FQDN of the host that the command was executed on. Interesting.

Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Nice post

I like your post. It is very useful to me. Thanks.

Hasznos a poszt

Szia Müzso!


A cégünknél lejárt a certificate és mivel a rendszergazánk lelépett, ezért nekem kellett megújítani Roland segítségével.
Pusztán a diagnózis felállítása tartott órákig, a megfelelő ismeretek hiányában.

De mivel itt megtaláltuk a legérdekesebb részeket, miszerint az "ldapsearch -d 1" még rendes hibaüzenetet is képes kiírni, ezért jár a pont ehhez a poszthoz.

Szóval köszi.
Továbbá az openldap szörnyen debuggolható.

Üdv:
Gyuri

Re: Hasznos a poszt

Mármint a rendszergazdátok, Java framework fejlesztőtök, Siebel CRM és Oracle RDBMS szakértőtök, ...? Átérzem a fájdalmat. Wink
Azért örülök, hogy legalább Te találsz hasznos dolgokat a blogomon. Smile Az Ubuntu buherálás rejtelmeiből sok mindent itt dokumentáltam, mivel ez a téma a cégnél túlzottan nem érdekelt senkit se (amíg ott voltam).