6.9 Security

Up to this point, we haven't discussed security. You've put a lot of sensitive information into your directory, which is now controlling whether users can log into machines on your network. And you could certainly put a lot more information into the directory: telephone numbers, human resources information, etc. Some of this information might be genuinely useful to the public at large; some of it may be highly confidential. But you don't yet know how to keep users from accessing information they shouldn't have access to. In order to have any confidence in a solution, we must examine how certain security issues are addressed by both the PAM and NSS modules.

First, it is important to understand what level of security is desired and exactly what information is being protected. Are you concerned only with protecting passwords? What about usernames as well? From the perspective of system administration, the most important information to protect is related to user and group accounts. Few sysadmins worry about someone being able to snoop a hosts file as it is copied across the network from one machine to another. However, everyone should be concerned about using a clear-text protocol, such as FTP, to transfer /etc/passwd and /etc/shadow from one machine to another.

To protect user passwords, we must look at how the PAM module binds to the directory. pam_ldap always uses a simple bind to authenticate a user against an LDAP server. You should avoid sending account credentials across the network in a form that is readable by anyone viewing traffic.

LDAPv3 provides two mechanisms that can be used to protect passwords. One is to use SASL to support more secure methods of authentication such as Kerberos 5 or DIGEST-MD5. However, while this mechanism protects passwords, it doesn't necessarily protect information other than the user's password. It is not supported by pam_ldap at this time. The second solution is to negotiate a secure transport layer that will protect the information used in the LDAP bind request as well as all other information sent to and from the directory server.

Security must be implemented by both the server and the client. It makes no difference if one party is willing to communicate securely but the other is not. Recall the StartTLS-extended command added in RFC 2830. This command allows the client to request a secure transport layer prior to binding to an LDAP server. Both the pam_ldap and nss_ldap modules support using the StartTLS command to negotiate transport layer security. In addition, these modules also support the LDAPS (tcp/636) protocol, which is an older method for accessing an LDAP server securely.

The following ldap.conf directive instructs the PADL LDAP modules to issue a StartTLS command prior to binding to the server:

## Use the StartTLS command to negotiate an encrypted transport layer. A value of
## on defines the use of LDAPS when connecting to the directory server.
ssl     start_tls

Once you have configured the client, use a tool such as Ethereal or tcpdump to view the network traffic; it's a good idea to verify that things are working as expected.[6] After the initial LDAP Extended Request (i.e., StartTLS), you should see no clear-text traffic between the client and server. It is easy to spot an LDAP simple bind. The following is a bind request using the DN "uid=gcarter,ou=people,dc=plainjoe,dc=org" and the password testing:

[6] More information on Ethereal can be found at http://www.ethereal.com/. News regarding tcpdump can be found at http://www.tcpdump.org/.

00 30 f1 11 98 da 00 00 f4 d8 6c 0d 08 00 45 00   .0........l...E.
00 71 b9 a2 40 00 40 06 fd 21 c0 a8 01 4a c0 a8   .q..@.@..!...J..
01 28 a3 2f 01 85 26 8e 13 41 30 62 21 3a 80 18   .(./..&..A0b!:..
19 20 51 ef 00 00 01 01 08 0a 16 aa ab 72 16 ab   . Q..........r..
09 2f 30 3b 02 01 03 60 36 02 01 03 04 28 75 69   ./0;...`6....(ui
64 3d 67 63 61 72 74 65 72 2c 6f 75 3d 70 65 6f   d=gcarter,ou=peo
70 6c 65 2c 64 63 3d 70 6c 61 69 6e 6a 6f 65 2c   ple,dc=plainjoe,
64 63 3d 6f 72 67 80 07 74 65 73 74 69 6e 67      dc=org..testing

When the StartTLS command is working correctly, you will be able to notice the initial extended (OID request and the downloading of the server's certificate, but the remainder of the conversation will appear as gibberish (technically speaking).

Of course, encrypting all of the traffic between the clients and servers does no good if an unauthorized user can obtain information using normal means such as ldapsearch. To prevent access to information that could compromise an account (e.g., the userPassword attribute), you must specify access controls that secure account information. The following two access control entries (ACEs) in the database section of slapd.conf prevent users from viewing passwords belonging to accounts other than their own:

## Users can change their own passwords. Other users can attempt to authenticate, but
## can't read the userPassword value.
access to dn=".*,dc=plainjoe,dc=org" attr=userPassword
     by self write
     by * auth
## Default to read access.
access to dn=".*,dc=plainjoe,dc=org"
     by * read

It's worth looking at these ACEs in some detail to understand exactly what they say. The first ACE allows a user who has been authenticated by the directory to have write access to his password (self write). Write access implicitly includes read access, and is necessary to allow users to change their passwords. Other users are granted only the ability to authenticate against the given DN (* auth). This is not the same as read access because the client can never obtain the userPassword value. The server compares the password sent by the client in the bind request to the value stored in the directory entry; the password never leaves the server.

The second ACE grants read access to all directory information to all users. Unless you have configured a more privileged account for use by nss_ldap (binddn and bindpw), you must allow anonymous read access to clients using an anonymous bind. However, note that the clients can't obtain the userPassword attribute; the previous ACE blocks access to passwords other than their own.

Remember that access control entries follow the "first match wins" rule. Therefore, the more restrictive ACEs must be defined first. In this example, reversing the order of the ACEs has an ill effect: every read request will match the rule allowing anonymous reads, and the rule restricting access to passwords is never processed.

If you have configured a binddn (uid=nssldap,ou=people,dc=plainjoe,dc=org) for searching the directory, the last ACE can be changed to disallow anonymous reads altogether:

## Default to read access.
access to dn=".*,dc=plainjoe,dc=org"
   by dn="uid=nssldap,ou=people,dc=plainjoe,dc=org" read 
   by * none