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.
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.
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.
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.
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.
Or fail ... since you probably have no user with an uid of "xxxx" in your LDAP directory.
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.
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
.
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 ...
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!
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
Nice post
Hasznos a poszt
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
Azért örülök, hogy legalább Te találsz hasznos dolgokat a blogomon. 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).