Chapter 12. Centralized Network Directory with OpenLDAP

I believe that knowing how to administer a Lightweight Directory Access Protocol (LDAP) directory server has become an essential skill for a network administrator. An LDAP directory is your key to network simplicity. It is your universal directory across all platforms and applications, supporting simplified network authentication and a centralized company data store. The LDAP protocol is cross-platform, network-aware, and standards-based. There are a large number of LDAP implementations; in this chapter, we'll use the excellent free-of-cost, free-software OpenLDAP.

LDAP is widely supported by applications; for example, most email clients come with LDAP clients. Additionally, various databases, Content Management Systems (CMS), groupware and messaging servers, authentication servers, customer management applications, and application servers can all speak to an LDAP server.

Some folks like to argue about whether LDAP is a database. Strictly speaking, it is a protocol, not a database. It accesses a special kind of database that is optimized for very fast reads. Use it for relatively static information, such as company directories, user data, customer data, passwords, asset tracking, and security keys. OpenLDAP uses the Sleepycat Berkeley DB.

Why not use an ordinary relational database like PostgreSQL, Oracle, or MySQL? You can if you like, but then you'll lose the advantages of LDAP, which are:

You don't want to use OpenLDAP for for a retail or web site backend, for example, or any application that needs fast, frequent changes. That's where you want an RDBMS.

The structure of the Sleepycat BDB is different from a relational database. Rather than storing information in columns and rows, and having a rigid set of indexes and fields, data are stored in attribute-type/attribute-value pairs. This structure offers great flexibility in designing records. A particular user record, for example, can have new types of data added without having to redesign the entire database. You can store any kind of text or binary data. Because it is simple like a large flat file, adding new entries is easy—just tack them on. OpenLDAP supports a distributed architecture, replication, and encryption.

Let's take a run through the basic concepts and structure of an LDAP directory. This is more important than having an encyclopedic knowledge of configuration options, because if you don't have a clear idea of what you need and how everything fits together, LDAP will remain a mysterious mess. But it's not really all that mysterious; once you grasp the basics, you'll be in fine shape. As coaches always say, first master the fundamentals. An LDAP directory can be pictured as a standard upside-down tree structure, with the root portrayed as being the top, and the branches flowing downward. Figure 12-1 is a hierarchical namespace; it is also called the directory information tree (DIT).

The root of this example directory is the country entry. The next stop is the state entry, then the organizational unit (OU) entry, which is the company's name. This branches off into different company entries, which are also called organizational units. The lefthand branch terminates at a user ID (UID). The Quality Assurance (QA) OU could hold many more users than just the one in the example.

Now comes the important bit: Terry Jones has a distinguished name (DN), which consists of Terry's Relative Distinguished Name (RDN), which in this example is the UID, plus tacking on all the ancestor entries: uid=terryjones, ou=qa, ou=alrac's cookies, ou=or, c=us. Any attribute can be the RDN; it must be unique within the level that the entry belongs to. The UID is usually unique because it is a common practice to make it the user's login, but you could use any other attribute. Obviously, a little common sense goes a long way here; for example, there are many duplicate surnames, so using the SN attribute would cause problems. The most common RDN for people is a UID or common name (CN).

The basic unit of your directory is an entry. An entry is also called a record or directory object. Terry Jones' entry contains a number of attributes, such as name, phone number, email address, and so forth. You can't just invent attributes out of thin air; these must be already defined in OpenLDAP. An easy way to view them is with the GQ LDAP client (http://sourceforge.net/projects/gqclient/). You may also see them in the files in /etc/ldap/schema (on Fedora, /etc/openldap/schema) in the objectClass definitions.

You may create your own custom objectClass definitions and attribute types. I don't recommend this unless you absolutely need something that's not included. The default schema are extensive, and a lot of effort has gone into making them universal; there's no need to reinvent the wheel. On the other hand (there is always another hand, isn't there), this makes OpenLDAP flexible and extensible, and it's easy to share custom schema.

Each attribute is made up of an attribute type and an attribute value. Attributes can have multiple values. For example, Terry Jones' entry could look like this:

	uid=terryjones
	cn=Terry Jones
	gn=Terry
	sn=Jones
	telephoneNumber=123-456-7890
	telephoneNumber=123-456-7891
	mail=tjones@alrac.com

This shows a couple of duplicate attributes. You may use as many as you like. A common use for duplicate attributes is for people's names, like this:

	cn=Terry Jones
	cn=T. Jones
	cn=Terry "codefiend" Jones
	cn=Codefiend

The result of this is a search on any of these attribute values will succeed, so Terry Jones has nowhere to hide.

The suffix or naming context is the top of your LDAP hierarchy. In our simple example, the suffix is c=us. A common approach these days is to use your company's domain name, like dc=alrac, dc=net. DC stands for domain component.

When you create an entry in a DIT, its data are contained in attributes. These belong to objectClasses. Schemas can be thought of as big bags of organized objectClasses. So, when you hear someone talking about OpenLDAP schemas, you know they are referring to the files that define the organization and types of data that go into an OpenLDAP directory. In OpenLDAP, some schema are hardcoded into slapd itself.

An objectClass is part of an objectClass hierarchy. It inherits all the properties of its parents. For example, the inetOrgPerson objectClass is one you'll use a lot. If you look inside /etc/ldap/schema/inetorgperson. schema, you'll find this definition:

	objectclass ( 2.16.840.1.113730.3.2.2
	    NAME 'inetOrgPerson'
   	    DESC 'RFC2798: Internet Organizational Person'
	    SUP organizationalPerson
	    STRUCTURAL

This snippet shows that the long objectClass number is an official Object ID (OID) number. All of the LDAP OIDs are globally unique; you can't just make them up. This only matters when you create a custom schema and need some new OIDs. Then, find a registrar to assign some to you, such as Internet Assigned Numbers Authority (IANA).

The SUP (superior) organizationalPerson line tells you that its parent objectClass is organizationalPerson, which is a child of person, which is a top-level objectClass. The objectClass defines the required and optional attributes of all of its children, which you can read in any LDAP browser.

STRUCTURAL means this objectClass can be used to create entries in your DIT. You'll also see AUXILARY objectClasses; these cannot stand alone, but must be used along-side a STRUCTURAL objectClass.

An objectClass is also an attribute.

Don't worry if this doesn't make a lot of sense right now. After you create a simple directory, you'll see how it all fits together.

One more thing you should know about: the rootDSE. This is one of those clever self-referential geek names: DSE stands for DSA Specific Entry, and DSA means Directory System Agent. This is the invisible topmost entry in your LDAP hierarchy; the built-in attributes of your LDAP server. To see these, run these two commands on your LDAP server:

	$ ldapsearch -x -s base -b "" + 
	# extended LDIF
	#
	# LDAPv3
	# base <> with scope baseObject
	# filter: (objectclass=*)
	# requesting: +
	#


	#
	dn:
	structuralObjectClass: OpenLDAProotDSE
	configContext: cn=config
	namingContexts: dc=alrac,dc=net
	supportedControl: 2.16.840.1.113730.3.4.18
	supportedControl: 2.16.840.1.113730.3.4.2
	[...]
	supportedFeatures: 1.3.6.1.4.1.4203.1.5.4
	supportedFeatures: 1.3.6.1.4.1.4203.1.5.5
	supportedLDAPVersion: 3
	supportedSASLMechanisms: DIGEST-MD5
	supportedSASLMechanisms: CRAM-MD5
	supportedSASLMechanisms: NTLM
	entryDN:
	subschemaSubentry: cn=Subschema


	# search result
	search: 2
	result: 0 Success


	# numResponses: 2
	# numEntries: 1

All those long numbers are official Object Identifiers (OIDs). To learn more about these, visithttp://www.alvestrand.no/objectid/. This includes a searchable database, so you can see what a particular OID means.

This shows the same output, plus a bale of subschema:

	$ ldapsearch -x -s base -b "cn=subschema" objectclasses
	[...]
	# Subschema 
	dn: cn=Subschema 
	objectClasses: ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRAC
	 T MUST objectClass )
	objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' DESC 'RF 
     C2252:extensible object' SUP top AUXILIARY ) 
	objectClasses: ( 2.5.6.1 NAME 'alias' DESC 'RFC2256: an alias' SUP top STRUCTU 
     RAL MUST aliasedObjectName ) 
	objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'namedref: named 
      subordinate referral' SUP top STRUCTURAL MUST ref ) 
	objectClasses: ( 1.3.6.1.4.1.4203.1.4.1 NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' 
      ) DESC 'OpenLDAP Root DSE object' SUP top STRUCTURAL MAY cn ) 
	objectClasses: ( 2.5.17.0 NAME 'subentry' SUP top STRUCTURAL MUST ( cn $ subtr 
     eeSpecification ) ) 
	[...]

That's all the same information you have in/etc/ldap/schema. You don't need to do anything with the rootDSE; this is just to show it's there, and what it looks like. The rootDSE is sometimes confused with the root DN, but they are not the same thing. The rootDSE is your bare OpenLDAP server; i.e., the schema and supported protocols. You'll see root DN in a lot of documentation as your suffix name, or the base name of your data hierarchy. I avoid using the term root DN; it's too confusing. Oh, and then there is the rootdn. That's your directory superuser; the rootdn and rootpw directives go in slapd.conf. Yes, it is a bit confusing. The rootdn is all-powerful; many admins prefer to not have a rootdn at all, but instead create some sort of admin user that is defined inside the directory itself.

You're trying to plan for the future, and you want to design your DIT so smartly that it will seamlessly expand as your organization grows. It's a noble goal, for sure! So, you're wondering if you should structure it widely and shallowly, or more narrowly and deeply. This is the problem that all LDAP administrators face, and as always, the definitive answer is "it depends." My own preference is toward a shallower directory structure because it's easier to maintain, and because LDAP is optimized for searches along a level, rather than up and down the hierarchy.

Figure 12-2 shows a DIT with three OUs.

This seems all nice and organized, doesn't it? Three separate departments each with their own OU, which feels all satisfying, like a tidy filing cabinet. But think about it—what if Jenn from Upstairs gets moved to Downstairs? You'll have remove her entry from Upstairs and create a new one in Downstairs, which is several steps, no matter how efficient you are.

Now, take a look at Figure 12-3.

All users are lumped into the People OU. How do we know what departments they belongto? By giving them an extra OU attribute, like this:

	dn: cn=Jenn Dancer,ou=people,dc=foo,dc=com
	objectClass: inetOrgPerson
	cn: Jenn Dancer
	ou=Upstairs
	[...]

Jenn wants to move Downstairs? Piece of cake. All I do is run ldapmodify or a graphical LDAP browser to change ou=Upstairs to ou=Downstairs, and anything else that changes (e.g., phone number and title). This is less than half the work of moving her entry to a new OU, which requires these steps:

You might also think in terms of delegating responsibility to junior admins, or figuring out how to protect sensitive data. This might mean storing some data in different subtrees or separate databases, which makes administration a bit more complex, but gives you more control over who has read and write access.

This is never an easy subject, and if you ask five other LDAP admins for their advice, you'll get eight different opinions. LDAP System Administration, by Gerald Carter (O'Reilly), is especially helpful with figuring out your directory topology.