Copyright © 2006-2010 Davor Ocelic
Last update: Mar 22, 2010. — Maintain everything up to date, add links to other documentation
This documentation is free; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Abstract
The purpose of this article is to give you a straight-forward, Debian-friendly way of installing and configuring OpenLDAP.
By the end of this guide, you will have a functional LDAP server that will serve as a central authentication system for user logins onto all machines in the network, without the need to manually create users' accounts on individual machines.
However, for improved authentication security and a true networked solution, it is recommended to use LDAP in combination with Kerberos, with a matching Kerberos setup explained in MIT Kerberos 5 Guide,
This article is part of Spinlock Solutions's practical 5-piece introductory series to infrastructure-based Unix networks, containing Debian GNU Guide, MIT Kerberos 5 Guide, OpenLDAP Guide, OpenAFS Guide and FreeRADIUS Guide.
Table of Contents
LDAP is a service that has been traditionally captivating system administrators' and advanced users' interest, but its (seemingly or not) high entry barrier and infrastructure requirements have been preventing many from using it.
LDAP has already been the topic of numerous publications. Here, we will present only the necessary summary; enough information to establish the context and to achieve practical results.
You do not need to follow any external links; however, the links have been provided both throughout the article and listed all together at the end, to serve as pointers to more precise technical treatment of individual topics.
OpenLDAP is an open source implementation of the Lightweight
Directory Access Protocol. Directory itself is a tree-structured,
read-optimized database. Yellow pages or a phonebook are good
associations to have in mind, even though LDAP is much more powerful.
We will use OpenLDAP to provide a central authentication location for user logins anywhere on the network, with their home directories being automatically created on their first access to individual machines.
This guide can be followed standalone to make OpenLDAP both perform authentication and serve user meta data. However, using LDAP for authentication as shown here is not secure due to plain text connections made to the LDAP server and passwords travelling over the wire. It is therefore advised to use LDAP in combination with a superior and secure network authentication mechanism Kerberos, which is explained in another article from the series, the MIT Kerberos 5 Guide.
That said, let's move onto our LDAP setup.
From a technical perspective, LDAP directory consists of a set of
hierarchically organized
entries.
Each entry belongs to certain Object Classes and
contains various
pairs called attributes.
key=value
Each entry is uniquely identified by a
Distinguished name ("DN"). DN is formed as a list of
components, separated by commas, that provide "full path" to the entry,
starting from the top of the tree. For example, company Example, Inc.
would have the root of the tree in
dc=. A person employed by Example, Inc.
would then have a corresponding LDAP entry with DN
example,dc=comcn=.
person,ou=People,dc=example,dc=com
Which attributes may or must be present in an entry is governed by the entry's objectClasses.
You might notice that the individual components of the DN, such as
cn= above, are also
formed as person pairs.
Those "keys", key=valuecn, ou
and dc, stand for Common Name,
Organizational Unit and
Domain Component. They are a part of every-day LDAP
terminology that you will get used to.
ObjectClasses, attributes, syntaxes, matching rules and other details
of the tree structure are configurable and loaded at LDAP server startup
by reading the schema files defined in
/etc/ldap/slapd.conf.
Let's quickly identify LDAP-specific elements in our setup:
LDAP is not in any way related to traditional system usernames
or other data. However, part of its functionality in our setup
will consist in storing information traditionally found in Unix files
/etc/passwd and /etc/group,
thus making that data network-accessible at a centralized location.
People's login names will be used in pairing people with the corresponding
information in the LDAP tree. For example, username
will map to an LDAP entry
personuid=.
person,ou=People,dc=example,dc=com
LDAP can be configured to contain user passwords. Passwords can be used both for authenticating as specific users and gaining access to protected entries, and for verifying whether the user knows the correct password.
When a user opens a LDAP client and moves to browse the directory, his DN and password are used to establish the identity and access privileges. When LDAP is configured to perform user authentication, his DN and password are only used to perform a connection to the LDAP directory — successful connection ("bind") implies the user knew the correct password.
You can find the complete OpenLDAP documentation at the OpenLDAP website.
For an authoritative OpenLDAP book, see Gerald Carter's
LDAP System Administration by O'Reilly.
On all GNU/Linux-based platforms, NSS is available for network data
retrieval configuration. NSS is an implementation of the
Name Service Switch mechanism.
NSS will allow for inclusion of LDAP into the "user data" path of all services, regardless of whether they natively support LDAP or not.
You can find the proper introduction (and complete documentation) on the NSS website. Also take a look at the nsswitch.conf(5) manual page.
Likewise, on all GNU/Linux-based platforms, another piece of the puzzle,
Linux-PAM, is available for service-specific authentication configuration.
Linux-PAM is an implementation of PAM
("Pluggable Authentication Modules") from Sun Microsystems.
Network services, instead of having hard-coded authentication interfaces and decision methods, invoke PAM through a standard, pre-defined interface. It is then up to PAM to perform any and all authentication-related work, and report the result back to the application.
Exactly how PAM reaches the decision is none of the service's business. In traditional set-ups, that is most often done by asking and verifying usernames and passwords. In advanced networks, that could be retina scans or — Kerberos tickets, as explained in another article from the series, MIT Kerberos 5 Guide.
You can find the proper introduction (and complete documentation) on the Linux-PAM website. Pay special attention to the PAM Configuration File Syntax page. Also take a look at the Linux-PAM(7) and pam(7) manual pages.
It's quite disappointing when you are not able to follow the instructions found in the documentation. Let's agree on a few points before going down to work:
Our platform of choice, where we will demonstrate a practical setup, will be Debian GNU.
Install sudo. Sudo is a program that will allow you to carry out system administrator tasks from your normal user account. All the examples in this article requiring root privileges use sudo, so you will be able to copy-paste them to your shell.
su -c 'apt-get install sudo'
If asked for a password, type in the root user's password.
To configure sudo, add the following line to your
/etc/sudoers, replacing $USERNAME
with your login name:
$USERNAME ALL=(ALL) NOPASSWD: ALL
Debian packages installed during the procedure will ask us a series of questions through the so-called debconf interface. To configure debconf to a known state, run:
sudo dpkg-reconfigure debconf
When asked, answer interface=Dialog
and priority=low.
Monitoring log files is crucial in detecting problems. The straight-forward, catch-all routine to this is opening a terminal and running:
cd /var/log; sudo tail -F daemon.log sulog user.log auth.log debug kern.log syslog dmesg messages kerberos/{krb5kdc,kadmin,krb5lib}.log
The command will keep printing log messages to the screen as they arrive.
Our test system will be called monarch.spinlock.hr and
have an IP address of 192.168.7.12. Both the server and
the client will be installed on the same machine. However, to differentiate
between client and server roles where relevant, the client will be referred
to as monarch.spinlock.hr and the server as
ldap1.spinlock.hr. The following addition will be
made to /etc/hosts to completely support this
scheme:
192.168.7.12monarch.spinlock.hrmonarchkrb1.spinlock.hrkrb1 ldap1.spinlock.hrldap1
Note that in some Debian installations the system's network hostname is
assigned to the localhost address 127.0.0.1. This can
and will cause problems for network operations, so make sure that your
"localhost" entry in /etc/hosts looks exactly like
the following (nothing more, nothing less):
127.0.0.1 localhost localhost.localdomain
Finally, test that the network setup is as expected. Pinging the hostnames should report proper FQDNs and IPs as shown:
ping -c1 localhostPING localhost (127.0.0.1) 56(84) bytes of data. ....ping -c1PINGmonarchmonarch.spinlock.hr(192.168.7.12) 56(84) bytes of data. ....ping -c1 ldap1PING krb1.spinlock.hr(192.168.7.12) 56(84) bytes of data. ....
OpenLDAP's server component is called slapd, and is basically all that we will need.
sudo apt-get install slapd ldap-utils
Debconf answers for reference:
Omit OpenLDAP server configuration?NoDNS domain name:Organization name?spinlock.hrAdministrator password:spinlock.hrConfirm password:PASSWORDDatabase backend to use:PASSWORDHDBDo you want the database to be removed when slapd is purged?NoAllow LDAPv2 protocol?No
As soon as the installation is done, the OpenLDAP server (command slapd) will start.
Our OpenLDAP server is already running, so let's first configure
/etc/ldap/ldap.conf, a common configuration file
for all LDAP clients. This will allow us to run
ldapsearch and other commands without having to list
all the basic parameters by hand each time.
Enable the following two lines in /etc/ldap/ldap.conf,
creating the file if necessary:
BASE dc=spinlock, dc=hrURI ldap://192.168.7.12/
Then, let's edit the server's configuration file in
/etc/ldap/slapd.conf to tune its behavior.
Make sure all the schema files are enabled:
include /etc/ldap/schema/core.schema include /etc/ldap/schema/cosine.schema include /etc/ldap/schema/nis.schema include /etc/ldap/schema/inetorgperson.schema
Change the verbosity level from 0 or
"none" to 256:
loglevel 256
Search for line "index objectClass eq" and
add another search index. In particular combinations, it may be possible
to receive no results when the searched entries are not indexed, so this
step is important:
index objectClass eq index uid eq
To make the new index option apply, run the following commands:
sudo invoke-rc.d slapd stop sudo slapindex sudo chown -R openldap:openldap /var/lib/ldap sudo invoke-rc.d slapd start
It's already the time to test the installation. Our OpenLDAP server does not contain much information, but a basic read operation can be performed normally.
In LDAP terms, read operation is called a "search". To perform a search using generic command-line utilities, we have ldapsearch and slapcat available.
Ldapsearch (and other LDAP utilities prefixed "ldap") perform operations "online", using the LDAP protocol.
Slapcat (and other OpenLDAP utilities prefixed "slap") perform operations "offline", directly by opening files on the local filesystem. For this reason, they can only be ran locally on the OpenLDAP server and they require administrator privileges. When they involve writing to the database, the OpenLDAP server usually needs to be stopped first.
In the output of the two search commands, you will notice two LDAP
entries, one representing the top level element in the three, and
another representing the LDAP administrator's entry.
In the slapcat output, notice the
extra attributes not printed with ldapsearch.
One of those is userPassword, which is not shown to
anonymous readers due to the appropriate default access restrictions in
/etc/ldap/slapd.conf.
ldapsearch -x# extended LDIF # # LDAPv3 # base <dc=spinlock, dc=hr> (default) with scope subtree # filter: (objectclass=*) # requesting: ALL # #spinlock.hrdn: dc=spinlock,dc=hrobjectClass: top objectClass: dcObject objectClass: organization o:spinlock.hrdc:spinlock# admin,spinlock.hrdn: cn=admin,dc=spinlock,dc=hrobjectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator # search result search: 2 result: 0 Success # numResponses: 3 # numEntries: 2
sudo slapcatdn: dc=spinlock,dc=hrobjectClass: top objectClass: dcObject objectClass: organization o:spinlock.hrdc:spinlockstructuralObjectClass: organization entryUUID: 350a2db6-87d3-102c-8c1c-1ffeac40db98 creatorsName: modifiersName: createTimestamp: 20080316183324Z modifyTimestamp: 20080316183324Z entryCSN: 20080316183324.797498Z#000000#000#000000 dn: cn=admin,dc=spinlock,dc=hrobjectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: e2NyeXB0fVdSZDJjRFdRODluNHM= structuralObjectClass: organizationalRole entryUUID: 350b330a-87d3-102c-8c1d-1ffeac40db98 creatorsName: modifiersName: createTimestamp: 20080316183324Z modifyTimestamp: 20080316183324Z entryCSN: 20080316183324.804398Z#000000#000#000000
As explained, the LDAP database is structured as a tree. The top level
element in the tree for your organization is often its domain
name. In case of a domain spinlock.hr, the toplevel
tree element would be dc=spinlock,dc=hr.
On the next level below, an organization is often divided into "organizational units", such as people, groups, hosts, services, networks, protocols, etc.
Accordingly, to support people's Unix "meta data" in our LDAP directory,
we will be interested in creating two of the mentioned organizational units,
People and Group. The two
will roughly correspond to the Unix
/etc/passwd and
/etc/group files.
Ldap data is interchanged in a textual format called LDIF. Command-line LDAP utilities receive and produce data in this format. Note that the LDIF stream can also contain commands, such as for adding, modifying or removing LDAP entries.
Knowing this, we'll put together a simple LDIF file,
/var/tmp/ou.ldif, that will instruct
the server to add the two organizational units.
Pay attention to the empty line separating the entries:
dn: ou=People,dc=spinlock,dc=hrou: People objectClass: organizationalUnit dn: ou=Group,dc=spinlock,dc=hrou: Group objectClass: organizationalUnit
To load the LDIF file into the server, let's show an example using the offline tool, slapadd:
sudo invoke-rc.d slapd stop sudo slapadd -c -v -l /var/tmp/ou.ldif sudo invoke-rc.d slapd start
Let's use ldapsearch to verify the entries have been created.
ldapsearch -x ou=people# extended LDIF # # LDAPv3 # base <dc=spinlock, dc=hr> (default) with scope subt # filter: ou=people # requesting: ALL # # People,spinlock.hrdn: ou=People,dc=spinlock,dc=hrou: People objectClass: organizationalUnit # search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1
In the same manner we've created the two organizational units, let's create
our first group and a person belonging to it. Again, we approach the
problem by constructing and loading an LDIF file,
/var/tmp/user1.ldif, paying attention to
the empty line separating the entries:
dn: cn=mirko,ou=group,dc=spinlock,dc=hrcn:mirkogidNumber:20000objectClass: top objectClass: posixGroup dn: uid=mirko,ou=people,dc=spinlock,dc=hruid:mirkouidNumber:20000gidNumber:20000cn:Mirkosn:MirkoobjectClass: top objectClass: person objectClass: posixAccount objectClass: shadowAccount loginShell: /bin/bash homeDirectory: /home/mirko
To load the LDIF file into the server, let's show an example using the online tool, ldapadd. Since, as said previously, ldapadd uses the LDAP protocol, we'll have to bind to the server as system administrator and type in the correct admin password (defined during slapd installation):
ldapadd -c -x -D cn=admin,dc=Enter LDAP Password:spinlock,dc=hr-W -f /var/tmp/user1.ldifadding new entry "cn=PASSWORDmirko,ou=group,dc=spinlock,dc=hr" adding new entry "uid=mirko,ou=people,dc=spinlock,dc=hr"
Now to define the new user's password, let's run an online tool ldappasswd. (This step is not needed if you plan to use LDAP in combination with Kerberos as explained in MIT Kerberos 5 Guide.)
ldappasswd -x -D cn=admin,dc=New password:spinlock,dc=hr-W -S uid=mirko,ou=people,dc=spinlock,dc=hrRe-enter new password:NEW USER PASSWORDEnter LDAP Password:NEW USER PASSWORDResult: Success (0)ADMIN PASSWORD
You might notice that all entries always have to be "fully qualified" and that
you cannot omit the suffix (dc=spinlock,dc=hr) or other components of the DN. This often leads to command line examples that are long and cryptic, and look just like boring, unnecessary
work. If you percieve that as a problem, you'll solve it by either getting accustomed to it to the point of not noticing it any more, or you'll switch to using graphical LDAP clients that fill in most of that information for you.
Now let's use ldapsearch to verify the user entry
has been created. Note that the password field, userPassword,
will not be shown even if we created it, due to the default access
restrictions in /etc/ldap/slapd.conf.
ldapsearch -x uid=# extended LDIF # # LDAPv3 # base <mirkodc=spinlock, dc=hr> (default) with scope subtree # filter: uid=mirko# requesting: ALL # #mirko, people,spinlock.hrdn: uid=mirko,ou=people,dc=spinlock,dc=hruid:mirkouidNumber:20000gidNumber:20000cn:Mirkosn:MirkoobjectClass: top objectClass: person objectClass: posixAccount loginShell: /bin/bash homeDirectory: /home/mirko# search result search: 2 result: 0 Success # numResponses: 2 # numEntries: 1
Congratulations! You now have a working LDAP setup.
Now that we have a new user created in LDAP, we should allow the system
to see it. For example, let's test for existence of users
root and mirko. The administrator
will be present, while mirko will not:
id rootuid=0(root) gid=0(root) groups=0(root)idid:mirkomirko: No such user
To enable the system see LDAP accounts, we need to install libnss-ldap (which may automatically install libpam-ldap as well) and nscd:
sudo apt-get install libnss-ldap nscd
All debconf answers for reference:
LDAP server URI:ldap://(Note the "ldap://", NOT "ldapi://"!) Distinguished name of the search base:192.168.7.12/LDAP version to use:dc=spinlock,dc=hr3Does the LDAP database require login?NoSpecial LDAP privileges for root?NoMake the configuration file readable/writeable by its owner only?NoAllow LDAP admin account to behave like local root?YesMake local root Database admin.NoDoes the LDAP database require login?NoLDAP administrative account:cn=admin,dc=h15,dc=riLDAP administrative password:Local crypt to use when changing passwords.PASSWORDmd5PAM profiles to enable: select all
To configure the NSS module further, open
/etc/libnss-ldap.conf.
Locate and adjust the configuration lines as shown:
base dc=spinlock,dc=hruri ldap://192.168.7.12/
Finally, to activate the LDAP NSS module, edit
/etc/nsswitch.conf by replacing the
two lines mentioning passwd and
group with the following:
passwd: files ldap group: files ldap
Nscd (the Name Service Caching Daemon) is used to cache metadata locally, instead of querying the LDAP server each time. It is a very efficient service in the long run, but we will stop it for for the moment, during testing, to always retrieve the data directly from the LDAP server:
sudo invoke-rc.d nscd stop
Now we can verify that LDAP users have become visible:
iduid=mirko20000(mirko) gid=20000(mirko) groups=20000(mirko)
The final step in this article pertains to integrating LDAP into the system authentication procedure.
Let's install and configure libpam-ldap. (You might have already done this step automatically, during libnss-ldap installation — in that case Debian will just report the package is already installed).
sudo apt-get install libpam-ldap
Debconf answers for reference:
Make local root Database admin.NoDoes the LDAP database require login?NoLocal crypt to use when changing passwords.md5
To configure the PAM module, open /etc/pam_ldap.conf.
Locate and adjust the configuration lines as shown:
base dc=spinlock,dc=hruri ldap://192.168.7.12/
Now let's configure Linux-PAM itself. PAM configuration is quite fragile, so use the provided examples that have been verified to work. For any modifications, you will want to look at PAM Configuration File Syntax and pay special attention to seemingly insignificant variations — with PAM, they often make a whole world of difference.
PAM will require the user to be present either in the local password file or in LDAP and to know the correct password, for the authentication process to continue.
Note that authentication through LDAP, as shown here, is not secure, due to connections to the LDAP server being made in plain text and passwords travelling over the wire.
Instead of encrypting the connection to the LDAP server, the PAM files shown below also support Kerberos for authentication, if you've installed Kerberos as explained in MIT Kerberos 5 Guide. In that case, modify the PAM lines as noted in file comments and the authentication will be performed in a completely secure and superior manner using Kerberos.
account sufficient pam_unix.so account required pam_ldap.so # Enable if using Kerberos: #account required pam_krb5.so
# Disable the three lines if using Kerberos: auth [success=1 default=ignore] pam_unix.so nullok_secure auth required pam_ldap.so use_first_pass auth required pam_permit.so # Enable the three lines if using Kerberos: #auth sufficient pam_unix.so nullok_secure #auth sufficient pam_krb5.so use_first_pass #auth required pam_deny.so
password sufficient pam_unix.so nullok obscure md5 # Disable if using Kerberos: password required pam_ldap.so use_first_pass # Enable if using Kerberos: #password required pam_krb5.so use_first_pass
Having everything adjusted as shown, login to the system should succeed
as user :
mirko
Login:Password:mirkoDebian GNU/Linux tty5 Creating directory '/home/PASSWORDmirko'. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.mirko@host:~$
At this point, you have a functional LDAP installation.
You can rely on LDAP for central network authentication and sharing of user metadata (user IDs, group IDs, real names, group memberships, etc.).
However, as said above, the authentication through LDAP is not done in a network-secure manner, due to plain text connections and passwords travelling over the wire. To solve that problem, using Kerberos for network authentication instead of LDAP is recommended, as explained in the previous article in the series, the MIT Kerberos 5 Guide.
Also, when users authenticate successfully, they will be logged in and placed
in their home directory. However, in a central network authentication scheme,
where users are not created on individual machines, their corresponding home
directories will not exist. This problem is taken care of by the
pam_mkhomedir module above, which automatically
creates missing home directories.
This means users' home directories will be created separately on all of the machines they log in. This may present a problem as people will have different files on different machines. It won't be completely unacceptable in itself if Kerberos is used, as the Kerberized network will allow secure and passwordless copying of files between the machines, but it will still be far from a perfect solution. To solve that problem with an advanced, secure, heavy-duty distributed network filesystem, see the next article in the series, the OpenAFS Guide.
With a good foundation we've built, for further information on LDAP, please refer to other available resources:
Official documentation: http://www.openldap.org/doc/admin24/
Mailing lists: http://www.openldap.org/lists/
IRC: channel #ldap at the FreeNode network (irc.freenode.net)
For commercial consultation and infrastructure-based networks containing AFS, contact Spinlock Solutions or organizations listed on the OpenLDAP support page.
Platforms:
GNU
Debian GNU
LDAP:
OpenLDAP
Gq — Gtk LDAP Client
Luma — QT LDAP Client
jXplorer — Java LDAP Client
Apache Directory Studio — Eclipse-based LDAP Client
web2ldap — web-based LDAP Client
Glue layer:
NSS
Linux-PAM
Related infrastructural technologies:
MIT Kerberos
OpenAFS
FreeRADIUS
Commercial support:
Spinlock Solutions
OpenLDAP support organizations
Misc:
DocBook