As we started getting more users into our network, it became obvious that an authentication solution was required---all users had accounts on multiple machines, and were finding it difficult to change passwords on all the hosts easily. After looking around it became obvious that a centralised authentication scheme was necessary. There were a few options:
NIS was out of the question, as there were problems with Linux's implementation, and NIS+ had only started being worked on. After a web search to see what other products were available that solved this problem returned only alpha- or beta-quality software, the search narrowed to LDAP.
Further searches were promising, with many useful results, such as David Begley's Authentication Project Report1, and many others. However, the real find was PADL2 who have an open sourced PAM3 and NSS4 authentication module, as well as a commercial NIS / LDAP gateway5. (They also had some migration scripts6 that take existing flat files and create a basic LDAP schema.)
This solved the question of the client side - now remained the server side. There were a few options here:
All of our servers were run Linux, putting Microsoft and Novell out of the race. The OpenLDAP server seemed much better maintained than the UMICH software.
LDAP (Lightweight Directory Access Protocol) is a directory service defined in RFC 177712, which runs over TCP/IP. It stores information, similar to a database, but contains more descriptive, attribute based data. The data is optimised for reading, so it doesn't handle frequently changing data well. The information is arranged in a hierarchical structure, which allows for separation of the data based on different criteria.
LDAP uses a client-server model, where one or more LDAP servers present a consistent view of the data---either by answering the request, or by pointing to a server that contains the data. Each entry is referenced by its distinguished name, or DN---see RFC 177913 for the full format. It is created by taking the name of the entry (or RDN - relative distinguished name), and tracing back through its ancestors, concatenating them together.
As well as providing ways of adding, deleting and modifying data, search filters are provided to search the LDAP database. These allow you to specify criteria for the attributes, and what part of the directory to check. See RFC 225414 for complete details about the search filters. LDAP implements client authentication and access control lists (ACLs) to prevent the data being both seen or modified by unwanted people.
LDIF (or LDAP Data Interchange Format) is a representation of the database in a text format. The format is line delimited, colon separated attribute value pairs, as follows:
dn: cn=bmarshal,ou=People,dc=pisoftware,dc=com
uid: bmarshal
cn: Brad Marshall
objectClass: account
objectClass: posixAccount
objectClass: top
....
This format is good for transferring data between LDAP servers, for backups, and for bulk changes to data.
We still had to decide how to use LDAP to solve our user authentication problems---would a given process query LDAP directly, or would some other process run to dump out the necessary authentication details to flat file (eg, /etc/passwd)?
The architecture we chose is pretty simple - applications on the machine pass their query through to either a PAM (Pluggable Authentication Modules) or NSS (Name Service Switch), which then queries the LDAP server. Additionally, it does not take advantage of all the other information that can be provided---the only files migrated initially were /etc/passwd and /etc/group.
PADL provides tools to help migrate from flat file databases to LDAP. These include the following:
Script | Migrates |
---|---|
migrate_fstab.pl | /etc/fstab |
migrate_group.pl | /etc/group |
migrate_hosts.pl | /etc/hosts |
migrate_networks.pl | /etc/networks |
migrate_passwd.pl | /etc/passwd |
migrate_protocols.pl | /etc/protocols |
migrate_rpc.pl | /etc/rpc |
migrate_services.pl | /etc/services |
These scripts are called on the appropriate file in /etc in the following manner:
# ./migrate_passwd.pl /etc/passwd ./passwd.ldif
Also provided are migration shell scripts that call the perl scripts for each file that it can migrate. They come in a version for when you have the LDAP database up and running, or online, and one for when the database is offline. The offline scripts use ldif2ldbm, and the online scripts use ldapadd.
See the README provided with the MigrationTools for more information on these tools.
The Openldap server consists of two daemons - slapd, which is the stand alone ldap daemon, and slurpd, the stand alone replication daemon. The server is configured by slapd.conf, which is divided into two main sections - global configuration options, and zero or more database definitions and configuration options.
The configuration file begins with global options, which
can optionally be overridden in a back end. Lines beginning
with white space continue previous lines,
and it uses standard #-style comments. For full details of
all possible options, see slapd.conf(5)
, which
is included in the distribution.
OpenLDAP has several installation options; the easiest is to down load a precompiled package for your operating system / distribution---there are packages available for Redhat, Debian and many others. If you can't find a precompiled package for your chosen operating system, it is a simple matter of downloading the source from the OpenLDAP website and compiling it. Further details about installation are left for the reader to discover---see the README distributed with the source for more details.
The root DN, which is specified in slapd.conf, is equivalent to the root account under unix, or the Administrator account under Windows. It is allowed to read and write to all entries in the database, so it is important to choose a secure password for it.
Now it's a simple matter of generating the data structure - or schema - for the server. This is mostly generated by PADL's Migration tools, all you need to decide on initially is the base DN. As per RFC237715, it should be set from the dns domain name of your location - ie, for Plugged In, we used dc=pisoftware,dc=com.
The OpenLDAP server provides an access control syntax for protecting access to the various fields. This is very important in this case where we are storing passwords in an attribute, albeit in a crypted form.
access to attr=userpassword
by self write
by * read
access to *
by self write
by dn=".+" read
by * read
As you can see from the slapd.conf extract above, the ACL syntax is quite easy. It shows how you specify access to an attribute, and the different ways of allowing reading and writing.
As mentioned previously, LDAP has a global directory view with it being possible for data to exist on multiple servers. This increases the availability of the system, by allowing queries to go to the server that is closest, reducing response time. One of the design decisions was that it was ok for different servers to have different, conflicting views of this data while replication was taking place, as long as it eventually came into sync.
The next obvious question is how the data is transferred between the servers. It happens by a process called replication, which is managed by slurpd, the replication daemon. After a modify operation, slapd writes the changes to a replication logfile, which slurpd notices and sends to the slave slapd, which then actually performs the modification on the slave database.
The configuration on the client side for this is almost trivial - there are 3 locations that need things changed - /etc/pam.d/*, /etc/nsswitch.conf, and /etc/ldap.conf. There are also a few packages that are required to be installed - OpenLDAP client utilities, pam_ldap and nss_ldap.
PAM, or Pluggable Authentication Modules, frees applications
from the requirement of dealing with authentication by providing
an API that allows them to pass authentication requirements off
to the library. The main advantage of this is it is easy to
configure applications to use different authentication modules
by simply modifying the configuration files. See
pam(8)
and associated man pages for more
information.
Configuring PAM is reasonably straight forward - all that was necessary was to add a line to the pam configuration for each program that we desired to use LDAP.
Linux stores its PAM configuration in /etc/pam.d in a file named after the program. An example configuration for ssh follows:
#%PAM-1.0
auth sufficient /lib/security/pam_ldap.so
auth required /lib/security/pam_pwdb.so shadow try_first_pass
auth required /lib/security/pam_nologin.so
account sufficient /lib/security/pam_ldap.so
account required /lib/security/pam_pwdb.so
password required /lib/security/pam_cracklib.so
password sufficient /lib/security/pam_ldap.so
password required /lib/security/pam_pwdb.so shadow nullok use_authtok
session sufficient /lib/security/pam_ldap.so
session required /lib/security/pam_pwdb.so
Name Service Switch (or NSS) is used by various functions in the C library to control where information was looked for. GNU's C library 2.x (or glibc), which is used in Linux, is modelled after Sun's C library from Solaris 2. The configuration file, /etc/nsswitch.conf, specifies the sources for the ``databases'' and their lookup order.
To allow these databases to use LDAP, we require PADL's nss_ldap which gives us a source to use in nsswitch.conf that queries LDAP. To use this with user accounts and passwords from LDAP, use the following nsswitch.conf:
passwd: ldap files nisplus nis
shadow: ldap files nisplus nis
group: ldap files nisplus nis
This configuration shows that LDAP is queried first, then it falls back to files, then NIS / NIS+. This allows for certain accounts to be local.
Both PAM and Name Service Switch need certain information before being able to query LDAP - namely the base DN, and the host. This information is contained in /etc/ldap.conf, as follows:
BASE dc=pisoftware,dc=com
HOST ldap
pam_crypt local
The pam_crypt line specifies that the passwords are crypted locally before being transferred over the network rather than passing them in clear text.
OpenLDAP comes with many utilities for modifying the LDAP database, including ldapmodify, ldappasswd, ldapsearch, ldapadd, and ldapdelete, which do as their name suggests. Additionally, there are Perl modules (eg Net::LDAP, available from CPAN) which allow access to LDAP which facilitate writing of local programs.
To change passwords, it is simply a matter of running the following command:
$ ldappasswd -W -D 'cn=bmarshal,ou=People,dc=pisoftware,dc=com' 'uid=bmarshal'
This command binds as the user specified, asks for a password, then applies the search filter 'uid=bmarshal', which will find the appropriate account then changes the password.
For more generic modifications, or for bulk data changes ldapmodify is more useful. It is used in the following manner:
$ ldapmodify -W -r -D "cn=Manager,dc=pisoftware,dc=com" < bmarshal.ldif
As above, this binds as the given distinguished name, asks for a password, and then replaces the entries with the data in the ldif file.
To view the data in LDIF format, for example for doing backups, or creating a skeleton for bulk modifications, ldapsearch is used as follows:
$ ldapsearch -L -W -D "cn=Manager,dc=pisoftware,dc=com" 'uid=*'
This binds as the manager, prompts for the password, outputs in LDIF format, and applies the search filter (in this case 'uid=*').
If you need more flexibility than this, the Perl module Net::LDAP allows you to use the full power of Perl's text processing with the queries. It is certain possible, in fact the author has, to write scripts that replicate the standard adduser etc functionality in Perl.
LDAP can be used for much more than simple user authentication and this allows for much future expansion room. For sites with multiple locations, the ability to allow each location to administer its authentication by running a LDAP server that replicates back to the ``master'' would be a good way of allowing local administrators to control their part of the network, yet allow the users access from the other locations, if necessary.
Perhaps the most interesting possibility is that of LDAP routing of email, which the latest (8.10.x) version of Sendmail has just started supporting. This would allow much easier additions of email accounts, and the ability to allow others to administer it. Apache can also use LDAP for authentication - this would simplify restricting access to certain areas of the company intranet, for example. Another possibility is to use LDAP for authentication for Squid, which would ensure only local users could use the proxy. LDAP can also be used as a company wide contact database as well, as there are many APIs available for a wide variety of languages.
An important part of this migration was to ensure that it didn't simply trade off the problems - that is, make creation of accounts easier while making some other facet much difficult. While there has been some learning curve, it has generally been worth while, as the usefulness of creating accounts in one location has definitely outweighed any problems that have occurred.
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /etc/openldap/slapd.at.conf
include /etc/openldap/slapd.oc.conf
schemacheck off
pidfile /var/run/slapd.pid
argsfile /var/run/slapd.args
defaultaccess read
access to attr=userpassword
by self write
by * read
access to *
by self write
by dn=".+" read
by * read
#######################################################################
# ldbm database definitions
#######################################################################
database ldbm
suffix "dc=pisoftware, dc=com"
rootdn "cn=Manager, dc=pisoftware, dc=com"
rootpw {crypt}sefjKaLm7zybE
replica host=cox.staff.plugged.com.au:389
binddn="cn=Manager,dc=pisoftware,dc=com"
bindmethod=simple credentials=secret
replogfile /var/lib/openldap/replication.log
# cleartext passwords, especially for the rootdn, should
# be avoid. See slapd.conf(5) for details.
directory /var/lib/openldap/
dn: uid=bmarshal,ou=People,dc=pisoftware,dc=com
uid: bmarshal
cn: Brad Marshall
objectclass: account
objectclass: posixAccount
objectclass: top
loginshell: /bin/bash
uidnumber: 500
gidnumber: 120
homedirectory: /mnt/home/bmarshal
gecos: Brad Marshall,,,,
userpassword: {crypt}lnbDaz4nb9aQp
#%PAM-1.0
auth sufficient /lib/security/pam_ldap.so
auth required /lib/security/pam_pwdb.so shadow
auth required /lib/security/pam_nologin.so
account sufficient /lib/security/pam_ldap.so
account required /lib/security/pam_pwdb.so
password required /lib/security/pam_cracklib.so
password sufficient /lib/security/pam_ldap.so
password required /lib/security/pam_pwdb.so shadow nullok use_authtok
session sufficient /lib/security/pam_ldap.so
session required /lib/security/pam_pwdb.so
passwd: ldap files nisplus nis
shadow: ldap files nisplus nis
group: ldap files nisplus nis
BASE dc=pisoftware,dc=com
HOST ldap
pam_crypt local
[1] David Begley, Authentication Project Report
QUESTnet99, http://www.nepean.uws.edu.au/users/david/qn99/
[2] PADL,
http://www.padl.com/
[3] PADL's pam_ldap,
http://www.padl.com/pam_ldap.html
[4] PADL's nss_ldap,
http://www.padl.com/nss_ldap.html
[5] PADL's Ypldapd,
http://www.padl.com/ldap-nis_gateway.html
[6] PADL's Migration scripts,
http://www.padl.com/tools.html
[7] Netscape Directory Server,
http://www.iplanet.com/products/infrastructure/dir_security/dir_srvr/index.html
[8] Microsoft Active Directory Server,
http://www.microsoft.com/
[9] Novell NDS,
http://www.novell.com/products/nds/ldap.html
[10] University of Michigan LDAP Server,
http://www.umich.edu/~dirsvcs/ldap/
[11] Openldap,
http://www.openldap.org/
[12] RFC 1777 - Lightweight Directory Access Protocol,
http://www.ietf.org/rfc/rfc1777.txt
[13] RFC 1779 - A String Representation of Distinguished Names,
http://www.ietf.org/rfc/rfc1779.txt
[14] RFC 2254 - The String Representation of LDAP Search Filters,
http://www.ietf.org/rfc/rfc2254.txt
[15] RFC 2377 - Naming Plan for Internet Directory-Enabled Applications,
http://www.ietf.org/rfc/rfc2377.txt
RFC 2307 - An Approach for Using LDAP as a Network Information Service,
http://www.ietf.org/rfc/rfc2307.txt
The SLAPD and SLURPD Administrators Guide,
http://www.umich.edu/~dirsvcs/ldap/doc/guides/slapd/
The Linux-PAM System Administrators' Guide,
http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/pam.html
A System Administrator's View of LDAP,
http://people.netscape.com/bjm/whyLDAP.html
Linux Directory Services,
http://www.rage.net/ldap/