Introduction
Lightweight Directory Access Protocol, better known as LDAP, is a great way to store any kind of data you can think of. Address books, user accounts, system groups, network data, and much more can all be stored in an LDAP database. The reason for that versatility stems from the way that LDAP stores data. An LDAP database functions in the same way as any other directory service, such as telephone directories. It uses a tree structure to organize data and is optimized for reading that data. Consequently, it is designated as “high read, low write.” Due to it’s ease of use, LDAP has become the standard for storing data for networks of users big or small. However, just because it’s easy doesn’t mean you can jump right in without some planning.
Designing Your Directory
Planning your directory structure depends mostly on how you intend to use it. There are many different ways to organize your data, so in order to set up the most efficient and useful directory possible you need to know what you’re going to put in it. If you want to use it to store phone numbers, you’ll want to simply store records of people. However, if you want to use it to store user accounts, Linux groups, hostnames, and network information, you’ll want to split it up into different categories to make it easier to locate the data you want quickly. Before I get into how to organize your data though, there’s one detail that is very important to understand. Every record in an LDAP database must have a unique Distinguished Name, or DN. A DN is just like a primary key in a relational database table. It’s the way LDAP can uniquely identify a record that you are searching for. This is critical when using LDAP to store things like user accounts that have to be unique. As I’ll show you in a minute, DNs are based on the hierarchy that a record can be found in. That will make more sense when I give you an example below.
In order to make our example more meaningful, we’ll need a bit more than just a single record. So lets take a look at one way to organize your records for a small business. Lets say we’re a small business named My-Company. At our company, we have several departments. These include Human Resources, Information Technology, Marketing, and Senior Management. There are several different ways to organize data about this company, but one way to do it is to have a branch, or subtree, for each department. These subtrees are called organizational units. An organization unit in LDAP is simply a category of records that you’ll be storing. Organizational units are the second tier records in an LDAP database. The topmost record is called a Base Distinguished Name, or base DN. The base DN is the trunk of the entire tree, and the organizational units, or OUs, are the first branches. LDAP conventions say you should use your company name or a Fully Qualified Domain Name (FQDN) as your base DN, but it can really be anything you want. For instance, our company might have a website called my-company.com. Our base DN could be ‘dc=my-company,dc=com’, and our basic directory might look like this:
dc=my-company,dc=com<br /> |<br /> +-- ou=HumanResources<br /> |<br /> +-- ou=InformationTechnology<br /> |<br /> +-- ou=Marketing<br /> |<br /> +-- ou=SeniorManagement
Lets take a second to look at that DN before we go any farther. You’re probably wondering where the dc comes from, and why it has two parts. DC stands for domain component. So, in our case, the domain is my-company.com. The period between my-company and com indicates that the two are separate components of that domain. So our base DN has both of them separated. Think of this just like a reverse DNS record. If you have subdomain.syntaxtechnology.com, the reverse DNS is com.syntaxtechnology.subdomain. This indicates that com is the highest level of the hierarchy. In our case, my-company is technically the level above our OUs. However, to simplify searching and navigating the tree, we combine com and my-company into one level instead of having only a single subtree (my-company) underneath the base domain component (com).
So now that you understand the base DN, lets look at the OUs. As previously stated, OUs are simply logical methods of grouping similar kinds of data. Every OU will likely have many records underneath it. Each may also be further subdivided into additional OUs. To keep track of it all, each OU has its own DN to uniquely identify that subtree. In the case of Information Technology, it’s full DN would be ‘ou=InformationTechnology,dc=homenet,dc=com’. You can see how we took the base DN and simply prepended the OU name. We will do this for each level of our tree. Each child record takes it’s own unique identifier, which can be whatever you wish it to be, and adds the DN of the parent record to the end of it. So for another example, in Human Resources, you can have many child records for users, computers, network segments, employee records, payroll information, or any other kind of data you can think of. These other pieces of information can also be subdivided down into more OUs. If we were to break it down, it might look something like this:
dc=my-company,dc=com<br />
|<br />
+-- ou=HumanResources<br />
|<br />
+-- ou=Users<br />
|<br />
+-- ou=Computers<br />
|<br />
+-- ou=EmployeeData
So the DN for the Users OU would be ‘ou=Users,ou=HumanResources,dc=my-company,dc=com’.
Object Classes
When you are creating records in LDAP, you need to have some way of indicating to the server what kind of record you’re creating. This is done through the use of object classes. Every OpenLDAP server comes with a predefined set of schemas, or record templates, that you can use to set up your directory. You can also write your own schemas, but for now we’ll use the ones that it comes with. Each of these schemas defines a particular object class. An object class is a definition of what attributes the record can have. Some attributes are required, others are optional. A record can have multiple object classes to allow the combining of different attributes. Object classes can also inherit from other object classes, in which case the attributes from the parent object classes also become part of the child object class. In both of these cases, all required attributes for all inherited or combined object classes must be present. So if you have a record with objectClass1, which requires fields A and B, and objectClass2, which requires fields C and D, your record must have A, B, C, and D all defined for LDAP to accept that record.
One other detail to remember is that there are two different types of object classes. There are auxiliary object classes and structural object classes. Any record can have multiple auxiliary object classes, but it must have one and only one structural object class. A structural object class defines the base structure for that record. It also usually indicates what kind of information is going to be used to uniquely identify a record, such as common name (CN), user ID (uid), or IP address.
Lets take a look at our base DN. A base DN technically has three object classes. The three are top, dcObject, and organization. The structural object class is organization, which requires just a single attribute. That attribute is organization name, shortened to O. The dcObject object class is an auxiliary object class. It also has only one required attribute, and that is dc. This is an example of the structural class not containing the information that we will use to uniquely identify that record. Dc is the attribute that is included in our DN, not o. The third object class, top, is a parent object class. Both organization and dcObject inherit from top. In fact, top is a rather unique object class. It is the parent to all other object classes. It is technically just an abstract object class and cannot be the sole object class for an object. It only requires one attribute, an attribute called objectClass. That means that you have to specify an objectClass for every record you enter into LDAP. This fits what we already knew about LDAP requiring an object class for a record, and now you know why that is. Top can be specifically included in your record definition as an objectClass value, but it does not need to be included. By putting one of its child object classes, top is automatically included. This is the case with any inherited class.
I covered all that to get to one key design decision. For the purposes of this tutorial, we’ll be assuming that you’ll be setting up user accounts, Linux groups, and other records for managing users on a network. For that reason, you need to decide what kind of object class to use for your user accounts and groups. There are a handful of different options that come with OpenLDAP, so you need to decide which ones best suit your uses. Notice I said “ones” instead of “one” because you can apply multiple object classes to each record. When you migrate from using the /etc/passwd file on a Linux system, the migration script uses the posixAccount object class. This is a good default option since it contains user ID, user ID number, user password, default group, and a handful of other useful options. It is not the only choice though, so this is something that you must consider. To simplify this tutorial, we will be using posixAccount for users and posixGroup for groups.
This Tutorial
Now that you have an idea of some of the options available, I’ll show you how I’m going to demonstrate the LDAP setup. My directory that I’ll be basing this tutorial off of will look like this:
dc=example,dc=com<br /> |<br /> +-- ou=Users<br /> |<br /> +-- ou=Groups<br /> |<br /> +-- ou=Hosts
The users OU will contain all of our user accounts, and the groups OU will contain our Linux groups. You can decide to either add all your existing users and groups into the directory or only add new users and groups there. Now that you know how the directory will be laid out, it’s on to part 2: the technical setup!
To see part 2 of this tutorial, where I demonstrate how to install and configure the OpenLDAP server, click here.