Wednesday, December 10, 2008

#@%#$ user-customizable config files (AKA nss_ldap configuration)

I just finished configuring a RHEL system to pull its account information from a central LDAP directory. This shouldn't have been a big deal, I've done it many times before in a lot of different permutations. But this time, TLS certificate verification just would not work no matter what I did. I'd copied the certificate from the LDAP server, put in all of the possible configuration options possible and still nothing.

My tests worked with openssl:

# openssl s_client -connect hostname:636 -CAfile /etc/openldap/cacerts/

Verify return code: 0 (ok)

but not ldapsearch or getent passwd:

# ldapsearch -v -D "uid=user,ou=services,dc=domain,dc=com" -w password -H "ldaps://" -b "dc=domain,dc=com" -s sub -Z -x "(uid=b*)"
ldap_initialize( ldaps:// )
ldap_start_tls: Can't contact LDAP server (-1)
ldap_bind: Can't contact LDAP server (-1)

After scratching my head for a while, fiddling with a bunch of configuration options (which I'll talk more about later), I finally noticed the mention of .ldaprc files in the ldap.conf(5) man page. These are user-customizable config files similar to .bashrc or .netrc that sit in a user's home directory and override the global configuration values. I check the /root/.ldaprc file and bingo!!! There's a reference to a non-existent certificate for the TLS_CERT setting. I comment this out and everything starts working. It turns out that a developer had been experimenting with client certificate authentication to LDAP and had left this setting in after their PoC was done.

On a side note, nss_ldap configuration is confusing even without random .ldaprc files getting in your way because you have to deal with both the /etc/ldap.conf and /etc/openldap/ldap.conf files and it is not at all clear what should go in which file. Many of the configuration options overlap, so you will often see duplicate settings in both files. A benefit of all the experimentation that I had to do to solve this problem was that I have a much clearer idea of what needs to be set in which file. For our setup (RHEL 4 client, SSL LDAP server on port 636, no anonymous LDAP access) I configured the following:


# hostname

# search base
base dc=domain,dc=com

# service user to perform searches
binddn uid=user,ou=services,dc=domain,dc=com

# service user password
bindpw password

# port
port 636

# passwd file configuration
nss_base_passwd dc=domain,dc=com?sub

# enable ssl
ssl on

# Verify the certificate
tls_checkpeer yes

# disable SASL
sasl_secprops maxssf=0
use_sasl off

/etc/openldap/ldap.conf: (only one line, but it's vital!)
# The location of the trusted certificate (or its CA certificate)
TLS_CACERT /etc/openldap/cacerts/

No comments: