13 November, 2008

OpenLDAP Security

Since I have been doing a lot of system administration blogging lately and not much on security, I decided I should post something related to security even if it is still in reference to system configuration and administration. Despite being years old, many of the pages I found about LDAP and security were still pertinent, for example Security with LDAP. The OpenLDAP documentation has a whole section titled Security Considerations in addition to other sections throughout that address security.

The TLDR version of this post is that some of the defaults for OpenLDAP may not be secure, it is easy to make other configuration mistakes, and you should make sure to examine configurations, permissions, ACLs, and schemas with security in mind. Different distributions can have different defaults. If you are using LDAP for account information in particular, you need to be careful.

I will go over some specifics that I noticed, but I certainly won't cover everything. OpenLDAP can be configured to get a similar level of protection for account information compared to the standard Unix/Linux shadow files and actually makes some security-related tasks easier for an administrator, such as disabling accounts or enforcing password policies.

Encryption of Data and Authentication

The first and most obvious problem is that the default OpenLDAP configuration does not encrypt network activity. Whether you're using LDAP for account information or not, it is very likely that most people will not want their LDAP traffic going over the network unencrypted. OpenLDAP has support for TLS that makes it relatively easy to implement. Also important to note is that, though network activity is not protected by default, the minimum recommended authentication mechanism is SASL DIGEST-MD5.

The DIGEST-MD5 mechanism is the mandatory-to-implement authentication mechanism for LDAPv3. Though DIGEST-MD5 is not a strong authentication mechanism in comparison with trusted third party authentication systems (such as Kerberos or public key systems), it does offer significant protections against a number of attacks.
Another option, Kerberos, is also "highly recommended" for strong authentication services.

Passwords

When using OpenLDAP with nss_ldap and centralized accounts, if you're storing passwords in LDAP they should be stored as hashes, not plain text. This seems obvious, but it's important to understand how to generate the hashes with the 'slappasswd' command and then use 'ldapadd', 'ldapmodify' or a GUI LDAP management tool to put the hashes into LDAP. This is done when creating or altering accounts. The 'passwd' command will hash passwords automatically when users change their own passwords.

Different distributions have different default ACLs, but RHEL for example allows anonymous reads of LDAP by default and allows authenticated users read access to everything in another sample ACL included in the openldap-servers package. If you're going to store account information and passwords with LDAP, the access controls need to be changed to prevent both anonymous and authenticated users from viewing password hashes. As we all should know, all it takes to crack a password hash is an appropriate tool and processing time. Depending on the attacker's computing power, the password hashing algorithm and the actual password, cracking passwords can be extremely fast or very slow.

OpenLDAP supports a number of hashing algorithms and the default is to use {SSHA}, which is SHA-1 with a seed.
-h scheme
If -h is specified, one of the following RFC 2307 schemes may be specified: {CRYPT}, {MD5}, {SMD5}, {SSHA}, and {SHA}. The default is {SSHA}.

Note that scheme names may need to be protected, due to { and }, from expansion by the user's command interpreter.

{SHA} and {SSHA} use the SHA-1 algorithm (FIPS 160-1), the latter with a seed.

{MD5} and {SMD5} use the MD5 algorithm (RFC 1321), the latter with a seed.

{CRYPT} uses the crypt(3).

{CLEARTEXT} indicates that the new password should be added to userPassword as clear text.

 This is fine when setting initial passwords, but you should note that the 'passwd' command on Linux systems will generally use MD5 or the 'crypt' function instead of SHA1, depending on system configuration.

ACL Problems

There can also be problems related to Access Control Lists for slapd. Red Hat's default configuration allows anonymous reads. Ubuntu's slapd.conf seems to have a much more secure default ACL. Below is RHEL5's default, which allows anonymous reads, user reads, but only the rootdn to write.
access to * by * read
The following is a sample configuration that is also included in the default slapd.conf on RHEL5, though it is commented out in favor of the above ACL. The danger with the following is that users still can read everything as well as write their own entries.
access to *
by self write
by users read
by anonymous auth
Allowing users 'self write' to change their own entries is obviously a big problem if you're using LDAP for account information. Any user can change his own uidNumber or gidNumber to become uid 0, gid 0, gid 10 (wheel), etc. Not good!

To authenticate with nss_ldap, OpenLDAP must allow some sort of read access. Without anonymous reads, users can't authenticate unless there is a proxy user with read access. The proxy user's binddn and password must be in /etc/ldap.conf and /etc/openldap/ldap.conf in plain text and the files are world readable. This is somewhat mitigated because the ldap.conf files can only be accessed by authenticated users logged into the system, so if an attacker already gained access to the system the proxyuser password is a fairly trivial concern in the big scheme of things.

Another file with a plain text password is /etc/ldap.secret. This file must contain the rootdn password in plain text, but is again somewhat mitigated with file permissions. The permissions for the file must be set to 600 so only root can read the file, so the obvious way an attacker will get the rootdn password from the file is if he already has root privileges on that particular system. However, with the rootdn password the attacker could wreak havoc on all the LDAP entries, including all the account information stored in LDAP.

To prevent users from viewing the password hashes of others, two things are required. First, change the ACL in slapd.conf. Something like this would allow users to change their own passwords, but not any other attributes and not view other users' hashes. You can hide additional attributes from authenticated users if needed.
access to attrs=userpassword
by anonymous auth
by self write
by * none

access to *
by self read
by users read
by anonymous auth
Another important thing to do is put users in the objectclass 'shadowAccount', which is in the NIS schema along with the objectclass 'posixAccount' that stores most account information. This will prevent password hashes from displaying when using 'getent passwd'. This is similar to shadow passwords on the local system, which move the password hashes from the world-readable /etc/passwd to /etc/shadow, which is only readable by root. The 'getent' commands will fetch both local and LDAP information.

Password Policy Overlay

The password policy overlay for OpenLDAP allows password policies to be enforced on OpenLDAP accounts. Quoting from the documentation:
The key abilities of the password policy overlay are as follows:
  • Enforce a minimum length for new passwords
  • Make sure passwords are not changed too frequently
  • Cause passwords to expire, provide warnings before they need to be changed, and allow a fixed number of 'grace' logins to allow them to be changed after they have expired
  • Maintain a history of passwords to prevent password re-use
  • Prevent password guessing by locking a password for a specified period of time after repeated authentication failures
  • Force a password to be changed at the next authentication
  • Set an administrative lock on an account
  • Support multiple password policies on a default or a per-object basis.
  • Perform arbitrary quality checks using an external loadable module. This is a non-standard extension of the draft RFC.
Particularly for people that have specific company requirements for password policies, this overlay will do just about everything except complexity checking. For complexity checking, it's fairly easy to enable and configure pam_cracklib on each client. As far as I know, since only the hash crosses the wire when authenticating or changing passwords, it is not possible to centrally enforce complexity requirements.

Personally, for password expiration I prefer not to allow any grace logins, thereby enforcing a lockout if the password expires. As long as the policy is set to provide ample warning, this shouldn't cause problems. Consider if you allow some number of 'grace' logins after the password expires and for some reason a user does not login for an extended period of time. The account could conceivably remain active for as long as it takes to brute force the password rather than being disabled once the password expires.

Another password policy overlay feature is temporary lockouts after failed authentication. For instance, you could set a lockout after x login attempts in y seconds. The lockout can be z seconds. I don't know what the maximum number of seconds the overlay or OpenLDAP will accept, but it can definitely be zero up to months in seconds if needed for some fields like pwdMaxAge.

When enabing 'pwdReset' to require an immediate password change, I eventually found that the following line must be uncommented in slapd.conf.
pam_lookup_policy yes
After doing this, you can set 'pwdReset: TRUE' when generating temporary passwords, then the user will be required to change passwords immediately when logging in.

From my testing, the password policy overlay is definitely superior to the shadow password options within the nis.schema that comes with OpenLDAP. The biggest problem with the password policy overlay is that some distributions may not include it in the distribution's package for the OpenLDAP server, requiring compiling with support for the overlay instead of a standard OpenLDAP package from your distribution of choice.

Post Script

I have two previous posts about OpenLDAP. I would love to get any comments on what could be added or any mistakes that could be corrected.

Setting up OpenLDAP for centralized accounts
OpenLDAP continued

7 comments:

  1. Could you describe the process and steps taken to enable password policy overlay?

    ReplyDelete
  2. Dan, it depends on your distribution. For RHEL 5.3, which is the latest, they have a "openldap-servers-overlays" RPM available. This includes the password policy overlay. After installing that on your server(s), make sure you have a ppolicy.schema in your schema directory then edit your /etc/openldap/slapd.conf. The config needs to include your ppolicy.schema and load the ppolicy module, which by default should be in /usr/lib/openldap.

    You also need a couple configuration lines something like this:

    overlay ppolicy
    ppolicy_default "cn=ppolicy_defaults,ou=policies,dc=security,dc=test,dc=com"

    You will need to create and configure those default policies in your LDAP database, for instance by making a ppolicy.ldif and using slapadd or ldapadd. You can look at the man page for "slapo-ppolicy" for information on what can go in the LDIF.

    I'm not sure for RHEL4, but I think you would have to download the source RPM for OpenLDAP and change the spec file to use --enable-ppolicy, then build and install your own packages.

    I assume CentOS4 and 5 are very close or identical to the respective RHEL versions. Most distributions should be similar as far as configuration, it's just figuring out whether each distribution has support in the default packages or not.

    ReplyDelete
  3. For anyone who wants to do this, I can confirm that the CentOS 5.3 SRPM file will compile fine on CentOS 4.

    I have a distributed LDAP / Samba system that has several Domain Controllers (and LDAP replicas) located in different offices across the US. Some of the servers are CentOS-4, some are CentOS-5 and I wanted to roll in support for Windows 7 machines to be able to join the domains.

    To do this, I wanted the same version of Samba and OpenLDAP on all the servers ... I went to EnterpriseSamba.org to get the 3.4.1 version of Samba and compiled the latest version of OpenLDAP from CentOS-5.3 on CentOS-4.8 (Version of OpenLDAP is 2.3.43-5). This allows ppolicy support.

    What I am trying to figure out before I implement the ppolicy stuff is how do I exempt users like root or administrator from having their passwords expire.

    ReplyDelete
  4. Johnny,

    You can create additional policies for individual accounts or I believe even for groups, and these should override the defaults. I ran into this when I originally forgot to create a separate policy for the proxyuser, so the proxyuser's password expired and that broke authentication until I fixed it.

    For my proxyuser example, I created a policy something like this. It's just an example that I'm typing up pretty quickly, so check my work!

    dn: cn=ppolicy_proxy,ou=policies,dc=security,dc=test,dc=com
    cn: ppolicy_proxy
    objectClass: pwdPolicy
    objectClass: person
    objectClass: top
    pwdAllowUserChange: FALSE
    pwdGraceAuthNLimit: 0
    pwdInHistory: 0
    pwdLockout: FALSE
    pwdLockoutDuration: 0
    pwdMaxAge: 0
    pwdMaxFailure: 0
    pwdMinAge: 0
    pwdSafeModify: TRUE
    sn: ppolicy_proxy

    ReplyDelete
  5. Old post, but I'm having some trouble getting away from anonymous binds. It looks like I need to make a proxy user so that nss will work. Can anyone tell me how I can make this proxy user so that I can use binddn= instead of rootdn= to bind? When I use rootdn im getting errors that the system cant find the name associated with my uid.

    ReplyDelete
  6. I'm looking for a way to protect the openldap server from LAN brute force attacks but I'm kind of lost.

    It would be fine to prevent password guessing by locking a password for a specified period of time after repeated authentication failures. It doesn't matter if this can be turned into a DOS.

    Can you please point me on the right direction?

    Thank you!

    ReplyDelete
  7. with pwdCheckModule you can have serverside complexity checking if you happen to have(=build) a module.

    ReplyDelete