28.5. FreeBSD and LDAP

LDAP, the Lightweight Directory Access Protocol, is an application layer protocol used to access, modify, and authenticate (bind) using a distributed directory information service. Think of it as a phone or record book which stores several levels of hierarchical, homogeneous information. It is often used in networks where users often need access to several levels of internal information utilizing a single account. For example, email authentication, pulling employee contact information, and internal website authentication might all make use of a single user in the LDAP server's record base.

This section will not provide a history or the implementation details of the protocol. These sections were authored to get an LDAP server and/or client configured both quickly and securely; however, any information base requires planning and this is no exception.

Planning should include what type of information will be stored, what that information will be used for, whom should have access to said information, and how to secure this information from prying eyes.

28.5.1. LDAP Terminology and Structure

Before continuing, several parts of LDAP must be explained to prevent confusion. And confusion with this configuration is relatively simple. To begin, all directory entries consist of a group of attributes. Each of these attribute sets contain a name, a unique identifier known as a DN or distinguished name normally built from several other attributes such as the RDN. The RDN or relative distinguished name, is a more common name for the attribute. Like directories have absolute and relative paths, consider a DN as an absolute path and the RDN as the relative path.

As an example, an entry might look like the following:

% ldapsearch -xb "uid=trhodes,ou=users,o=example.com"
# extended LDIF
#
# LDAPv3
# base <uid=trhodes,ou=users,o=example.com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# trhodes, users, example.com
dn: uid=trhodes,ou=users,o=example.com
mail: trhodes@example.com
cn: Tom Rhodes
uid: trhodes
telephoneNumber: (xxx) xxx-xxxx

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

In this example, it is very obvious what the various attributes are; however, the cn attribute should be noticed. This is the RDN discussed previously. In addition, there is a unique user id provided here. It is common practice to have specific uid or uuids for entries to ease in any future migration.

28.5.2. Configuring an LDAP Server

To configure FreeBSD to act as an LDAP server, the OpenLDAP port needs installed. This may be accomplished using the pkg_add command or by installing the net/openldap24-server port. Building the port is recommended as the administrator may select a great deal of options at this time and disable some options. In most cases, the defaults will be fine; however, this is the time to enable SQL support if needed.

A few directories will be required from this point on, at minimal, a data directory and a directory to store the certificates in. Create them both with the following commands:

# mkdir /var/db/openldap-data
# mkdir /usr/local/etc/openldap/private

Copy over the database configuration file:

# cp /usr/local/etc/openldap/DB_CONFIG.example /var/db/openldap-data/DB_CONFIG

The next phase is to configure the SSL certificates. While creating certificates is discussed in the OpenSSL section in this book, a certificate authority is needed so a different method will be used. It is recommended that this section be reviewed prior to configuring to ensure correct information is entered during the certificate creation process below.

The following commands must be executed in the /usr/local/etc/openldap/private directory. This is important as the file permissions will need to be restrictive and users should not have access to these files directly. To create the certificates, issues the following commands.

# openssl req -days 365 -nodes -new -x509 -keyout ca.key -out ../ca.crt

The entries for these may be completely generic except for the Common Name entry. This entry must have something different than the system hostname. If the entry is the hostname, it would be like the hostname is attempting to verify hostname. In cases with a self signed certificate like this example, just prefix the hostname with CA for certificate authority.

The next task is to create a certificate signing request and a private key. To do this, issue the following commands:

# openssl req -days 365 -nodes -new -keyout server.key -out server.csr

During the certificate generation process, be sure to correctly set the common name attribute. After this has been completed, the key will need signed:

# openssl x509 -req -days 365 -in server.csr -out ../server.crt -CA ../ca.crt -CAkey ca.key -CAcreateserial

The final part of the certificate generation process is to generate and sign the client certificates:

# openssl req -days 365 -nodes -new -keyout client.key -out client.csr
# openssl x509 -req -days 3650 -in client.csr -out ../client.crt -CA ../ca.crt -CAkey ca.key

Remember, again, to respect the common name attribute. This is a common cause for confusion during the first attempt to configure LDAP. In addition, ensure that a total of eight (8) new files have been generated through the proceeding commands. If so, the next step is to edit /usr/local/etc/openldap/slapd.conf and add the following options:

TLSCipherSuite HIGH:MEDIUM:+SSLv3
TLSCertificateFile /usr/local/etc/openldap/server.crt
TLSCertificateKeyFile /usr/local/etc/openldap/private/server.key
TLSCACertificateFile /usr/local/etc/openldap/ca.crt

In addition, edit /usr/local/etc/openldap/ldap.conf and add the following lines:

TLS_CACERT /usr/local/etc/openldap/ca.crt
TLS_CIPHER_SUITE HIGH:MEDIUM:+SSLv3

While editing these this file, set the BASE to the desired values, and uncomment all three of the URI, SIZELIMIT and TIMELIMIT options. In addition, set the URI to contain ldap:// and ldaps://.

The resulting file should look similar to the following shown here:

BASE    dc=example,dc=com
URI     ldap:// ldaps://

SIZELIMIT       12
TIMELIMIT       15
#DEREF          never

TLS_CACERT /usr/local/etc/openldap/ca.crt
TLS_CIPHER_SUITE HIGH:MEDIUM:+SSLv3

A password for the server will need to be created as the default is extremely poor as is normal in this industry. To do this, issue the following command, sending the output to slapd.conf:

# slappasswd -h "{SHA}" >> /usr/local/etc/openldap/slapd.conf

There will be a prompt for entering the password and, if the process does not fail, a password hash will be added to the end of slapd.conf. slappasswd understands several hashing formats, refer to its manual page for more information.

Edit /usr/local/etc/openldap/slapd.conf and add the following lines:

password-hash {sha}
allow bind_v2

In addition, the suffix in this file must be updated to match the BASE from the previous configuration. The rootdn option should also be set. A good recommendation is something like cn=Manager. Before saving this file, place the rootpw option in front of the password output from the slappasswd and delete the old rootpw option above. The end result should look similar to this:

TLSCipherSuite HIGH:MEDIUM:+SSLv3
TLSCertificateFile /usr/local/etc/openldap/server.crt
TLSCertificateKeyFile /usr/local/etc/openldap/private/server.key
TLSCACertificateFile /usr/local/etc/openldap/ca.crt
rootpw  {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=

Finally, enable the OpenLDAP service in rc.conf. At this time, setting up a URI and providing the group and user to run as may be useful. Edit /etc/rc.conf and add the following lines:

slapd_enable="YES"
slapd_flags="-4 -h ldaps:///"

At this point the server should be ready to be brought up and tested. To perform this task, issue the following command:

# service slapd start

If everything was configured correctly, a search of the directory should show a successful connection with a single response as in this example:

# ldapsearch -Z
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# search result
search: 3
result: 32 No such object

# numResponses: 1

Considering the service should now be responding, as it is above, the directory may be populated using the ldapadd command. In this example, there is a file containing a list of users to be added to this particular directory. First, create a file to be imported with the following dataset:

dn: dc=example,dc=com
objectclass: dcObject
objectclass: organization
o: Example
dc: Example

dn: cn=Manager,dc=example,dc=com
objectclass: organizationalRole
cn: Manager

Note:

To debug any of the following, stop the slapd service using the service command and start it using with debugging options. To accomplish this, issue the following command:

# /usr/local/libexec/slapd -d -1

To import this datafile, issue the following command, assuming the file is import.ldif:

# ldapadd -Z -D "cn=Manager,dc=example,dc=com" -W -f import.ldif

There will be a request for the password specified earlier, and the output should look like this:

Enter LDAP Password:
adding new entry "dc=example,dc=com"

adding new entry "cn=Manager,dc=example,dc=com"

Verify the data was added by issuing a search on the server using ldapsearch. In this case the output should look like this:

% ldapsearch -Z
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> (default) with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
objectClass: dcObject
objectClass: organization
o: Example
dc: Example

# Manager, example.com
dn: cn=Manager,dc=example,dc=com
objectClass: organizationalRole
cn: Manager

# search result
search: 3
result: 0 Success

# numResponses: 3
# numEntries: 2

It is of course advisable to read about the structure of LDAP directories and the various manual pages mentioned in this section. At this point, the server should be configured and functioning properly.

All FreeBSD documents are available for download at http://ftp.FreeBSD.org/pub/FreeBSD/doc/

Questions that are not answered by the documentation may be sent to <freebsd-questions@FreeBSD.org>.
Send questions about this document to <freebsd-doc@FreeBSD.org>.