|Linux System Administration|
OpenLDAP consumer on Debian lenny
This page describes how to set up an OpenLDAP consumer server with the LDAP Sync Replication engine (syncrepl) for integration in a network with a previously installed OpenLDAP provider server, called ldaps1.example.com. Hosts such as these were previously referred to as master and slave servers, but these terms were depricated after the roles of these systems became more flexible.
In this example, OpenLDAP is installed on a host running Debian 5.0 (lenny). If followed properly, the step-by-step process should produce a consumer with a copy of the DIT from the provider.
Before the actual OpenLDAP installation process can begin, it will first be necessary to install Debian lenny on a new host called ldaps2.example.com. A DNS server must also be available on the network with a zone file to which forward and reverse mappings can be added for this host. After the initial installation of the operating system, make sure these packages are installed on the system as well:
~# apt-get install ssh nmap
Now the installation process for the OpenLDAP master server can begin:
1. Package installation
On the new host, ldaps2.example.com, start by installing these two packages:
~# apt-get install slapd ldap-utils
A total of ten packages are installed as a result, including eight dependencies:
ldap-utils 2.4.11-1 OpenLDAP utilities libdb4.2 4.2.52+dfsg-5 Berkeley v4.2 Database Libraries [runtime] libltdl3 1.5.26-4 A system independent dlopen wrapper for GNU libtool libperl5.10 5.10.0-19lenny2 Shared Perl library libsasl2-modules 2.1.22.dfsg1-23+lenny1 Cyrus SASL - pluggable authentication modules libslp1 1.2.1-7.5 OpenSLP libraries odbcinst1debian1 2.2.11-16 Support library and helper program for accessing odbc ini file psmisc 22.6-1 Utilities that use the proc filesystem slapd 2.4.11-1 OpenLDAP server (slapd) unixodbc 2.2.11-16 ODBC tools libraries
During the install process, an administrator password will be requested for slapd. Use contortrix, although it will be temporary:
Administrator password: contortrix Confirm password: contortrix
Run the following command to test if the OpenLDAP server is actually running:
~# nmap ldaps2.example.com
This should be among the results:
PORT STATE SERVICE 389/tcp open ldap
Perform a quick test by generating an LDIF dump of the contents of a the (temporary) local database:
~# slapcat dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example structuralObjectClass: organization entryUUID: a2c24128-7547-102e-8bd7-41184906bd68 creatorsName: createTimestamp: 20091204173853Z entryCSN: 20091204173853.745401Z#000000#000#000000 modifiersName: modifyTimestamp: 20091204173853Z dn: cn=admin,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator userPassword:: e2NyeXB0fWNlTlNMeFNxRmgzNFU= structuralObjectClass: organizationalRole entryUUID: a2c2d6ba-7547-102e-8bd8-41184906bd68 creatorsName: createTimestamp: 20091204173853Z entryCSN: 20091204173853.749560Z#000000#000#000000 modifiersName: modifyTimestamp: 20091204173853Z ~# _
If the output looks something like the above, continue with the next step.
Edit /etc/ldap/ldap.conf and add these two lines to the end of the file:
BASE dc=example,dc=com URI ldap://ldaps2.example.com/
This configuration file is used to set system-wide defaults for LDAP clients.
First, over on the provider server, ldaps1.example.com, create an LDIF file, called ~/ldaps2.ldif, with which to create a new organizationalRole object, and add this information to it:
dn: cn=ldaps2,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: ldaps2 description: LDAP server2 replicator userPassword: bilineatus
Add it to the DIT with this command:
root@ldaps1:~# ldapadd -cxWD cn=admin,dc=example,dc=com -f ~/ldaps2.ldif Enter LDAP Password: piscivorus adding new entry "cn=ldaps2,dc=example,dc=com" root@ldaps1:~# _
This new DN, cn=ldaps2,dc=example,dc=com, along with its matching password, will be used to authenticate the new consumer server when it attempts to synchronize its copy of the DIT.
Still on ldaps1, edit /etc/ldap/slapd.conf and make three changes to it. First, add a single line to the following ACL:
access to attrs=userPassword,shadowLastChange by dn="cn=admin,dc=example,dc=com" write by dn="cn=ldaps2,dc=example,dc=com" read by anonymous auth by self write by * none
This will authorize the new consumer to read the entire DIT, including all passwords, when it attempts to synchronize with the provider.
Second, add these four lines to the end of the file to load, activate and configure the Sync Provider overlay:
moduleload syncprov overlay syncprov syncprov-checkpoint 100 10 syncprov-sessionlog 100
The module for it, syncprov, is dynamically loaded into the active slapd process (since it was not compiled statically into /usr/sbin/slapd) and then activated with the overlay directive to enable provider-side support for syncrepl replication. It adds a contextCSN attribute to the root entry of the DIT and can be used with any database backend that maintains entryCSN and entryUUID attributes for all its entries, but works best when the bdb or hdb backend is used. Two syncprov options are configured:
See also man slapo-syncprov for more options.
Third, add two new eq index entries:
index objectClass eq index uid eq index entryUUID eq index entryCSN eq
Regarding these two additions, using the syncprov-sessionlog option requires searching for the entryUUID attribute. While not a requirement, setting an eq index for it on the provider can improve the performance of the session log considerably. For the same reason, setting an eq index for the entryCSN attribute when using the syncprov-checkpoint option is also recommended.
Having committed these changes to the slapd.conf file on ldaps1, it becomes necessary to reindex the database. Since it is best to run the appropriate command as the openldap user, first make this possible by altering the following line (that may not have the same UID and GID numbers) in the /etc/passwd file:
openldap:x:105:107:OpenLDAP Server Account,,,:/var/lib/ldap:/bin/sh
Now stop the LDAP service, regenerate the database indices as the openldap user, and restart the LDAP service:
root@ldaps1:~# /etc/init.d/slapd stop Stopping OpenLDAP: slapd. root@ldaps1:~# su -c /usr/sbin/slapindex openldap root@ldaps1:~# /etc/init.d/slapd start Starting OpenLDAP: slapd. root@ldaps1:~# _
Because there are existing entries in the database that include the attribute for which the new eq indices have been added, it is necessary to regenerate the indices in order to maintain database consistency. This procedure is unnecessary when there are not yet any entries that include the relevant attributes.
Now, back on ldaps2, edit its /etc/ldap/slapd.conf file as well, making a series of changes to it. The first modification is to comment out the line that prevents anything being written to the logs:
This allows slapd to use the default loglevel, which is 256 (stats). Basically, the value for loglevel is set to an integer (1, 2, 4, 8, 16, etc.), all of which are additive and cause slapd to log different kinds of information. However, certain keywords that represent the different values, can also be used instead (see man slapd.conf).
Then, specify a root DN:
# rootdn "cn=admin,dc=example,dc=com" rootdn "cn=manager"
The name used here for rootdn is completely arbitrary, since there is no need for it to be part of the directory, but the setting is mandatory for an OpenLDAP consumer in order to allow it to store anything in the database that it receives, regardless of how the ACLs are set.
Next, add eq indices for three more attributes:
index objectClass eq index uid eq index entryCSN eq index entryUUID eq
Setting an eq index on the uid attribute speeds up the authentication process, while doing the same for entryCSN and entryUUID will speed up the replication process.
Then, modify the ACLs to reflect the fact that the replicated database is strictly read-only. The ACLs should end up looking like this:
access to attrs=userPassword,shadowLastChange by anonymous auth by * none access to dn.base="" by * read access to * by * read
Should any clients attempt to write to this database replica, these ACLs will be bypassed and the clients will instead be given a referral to the OpenLDAP provider, the method for which is described below.
Now add the following stanza for the LDAP Sync Replication engine to the end of the first database section:
syncrepl rid=123 provider=ldap://ldaps.example.com:389/ type=refreshAndPersist retry="60 30 300 +" searchbase="dc=example,dc=com" bindmethod=simple binddn="cn=ldaps2,dc=example,dc=com" credentials=bilineatus
The syncrepl directive indicates that the current database is a replica. Indeed, it is strictly a database option and applies to the database for which it is defined. This directive has many different options of its own, a number of which are used here:
The above syncrepl configuration uses persistent push-based synchronization in which the provider keeps track of the consumer, sending it the necessary updates whenever its own database is modified. This is often desirable when modifications are frequent, but if not, use the refreshOnly operation type instead:
syncrepl rid=123 provider=ldap://ldaps.example.com:389/ type=refreshOnly interval=00:00:05:00 searchbase="dc=example,dc=com" bindmethod=simple binddn="cn=ldaps2,dc=example,dc=com" credentials=bilineatus
This alternative configuration features the polling, pull-based refreshOnly operation type. The interval setting used here, 00:00:05:00, means that replication will occur once every five minutes.
LDAP Sync Replication does present one important problem for LDAP clients: the resultant database is always read-only. To allow clients to make modifications to it, the consumer server must somehow inform them that this is only done via the provider. This can be arranged by adding the following line to the end of /etc/ldap/slapd.conf, below the syncrepl stanza:
The updateref directive is a referral that a consumer passes back to clients when slapd is asked to modify the replicated local database, e.g. to change a password. Unfortunately, although this is the preferred solution to the problem, not all LDAP clients understand referrals, which is why it is also a good idea to use the chain overlay.
The chain overlay (see man slapo-chain), which is built into the back_ldap module, (see man slapd-ldap) allows slapd to automatically chase referrals on behalf of clients. So, for the last change, add the following lines to the global section of slapd.conf, before any database definitions:
moduleload back_ldap overlay chain chain-uri ldap://ldaps.example.com:389/ chain-rebind-as-user TRUE chain-idassert-bind bindmethod=simple binddn="cn=ldaps2,dc=example,dc=com" credentials=bilineatus mode=self chain-return-error TRUE
Having saved all of the previous changes to /etc/slapd.conf, stop the LDAP service, delete the now-redundant local database, and restart the service. This will cause the consumer to synchronize its database with the provider for the first time:
~# /etc/init.d/slapd stop Stopping OpenLDAP: slapd. ~# rm /var/lib/ldap/* ~# /etc/init.d/slapd start Starting OpenLDAP: slapd. ~# _
If the original copy of the local database is not deleted, its existing entries, for the domain component and the administrative user, will not be replaced with those of the provider, even though the rest of the DIT will be synchronized. As a result the operation will only appear successful. For instance, on this consumer system the administrative password will still be contortrix, as opposed to piscivorus as it is on the provider.
6. Replication test
Now that slapd has been restarted, if everything has gone as planned, replication with the provider, ldaps1, wil have taken place for the first time. Verify this with a simple ldapsearch command:
~# ldapsearch -x -LLL dn: dc=example,dc=com objectClass: top objectClass: dcObject objectClass: organization o: example.com dc: example dn: cn=admin,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: admin description: LDAP administrator dn: ou=people,dc=example,dc=com ou: people objectClass: organizationalUnit dn: ou=groups,dc=example,dc=com ou: groups objectClass: organizationalUnit dn: cn=ccolumbus,ou=groups,dc=example,dc=com cn: ccolumbus gidNumber: 20000 objectClass: top objectClass: posixGroup dn: uid=ccolumbus,ou=people,dc=example,dc=com uid: ccolumbus uidNumber: 20000 gidNumber: 20000 cn: Christopher sn: Columbus objectClass: top objectClass: person objectClass: posixAccount objectClass: shadowAccount loginShell: /bin/bash homeDirectory: /home/ccolumbus dn: cn=ldaps2,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: ldaps2 description: LDAP server2 replicator ~# _
Obviously, success should look like this, since all of the entries after the first two were created on the OpenLDAP provider server. A more precise way to check that everything has worked as expected, is to run the slapcat command on both the consumer and the provider; in both cases the output in exactly the same.
7. Proxy authorization
Before the chaining configuration added in step 5 will work, a few more changes will have to be made, one of them to the OpenLDAP provider server, ldaps1.example.com. What is required is something called proxy authorization. With this mechanism, it is possible to allow an authenticated user, such as the consumer server in this example, to assume the identities of other users and use that to relay their write requests on to the provider server. The ability to assume another user's identity is important, as it would otherwise not be possible to enforce existing access rules.
Two changes are required to enable proxy authorization. First, the existing LDAP entry for the consumer server, ldaps2, must be modified to include an authzTo attribute, so that it will be allowed to act as an authorization proxy for certain users. Second, an authz-policy directive must be added to the slapd.conf on the provider server, so that it will accept such proxy requests.
To modify the LDAP entry for the consumer server, cn=ldaps2,dc=example,dc=com, first create a new file, called ~/ldaps2-authzto.ldif, on the provider, ldaps1, and give it the following contents:
dn: cn=ldaps2,dc=example,dc=com changetype: modify add: authzTo authzTo: dn.regex:^uid=[^,]+,ou=people,dc=example,dc=com$ authzTo: dn.exact:cn=admin,dc=example,dc=com -
NB: Make sure ldaps2-authzto.ldif does not contain any DOS-style carriage return and line feed pairs (^M characters)! If it does, ldapmodify will interpret the contents as one long destinguished name and consequently declare it invalid.
The authzTo attribute is a source rule, used here to determine those for whom ldaps2 may proxy. It can also be multivalued. Here, the first value is a regular expression that matches all users in ou=people. The second one is an exact match for the administrative user.
To apply the modification, run this command:
root@ldaps1:~# ldapmodify -x -D "cn=admin,dc=example,dc=com" \ -w piscivorus -f ~/ldaps2-authzto.ldif modifying entry "cn=ldaps2,dc=example,dc=com" root@ldaps1:~# _
Next, on the provider server, ldaps1, edit /etc/ldap/slapd.conf and add this line to the end of the Global directives section:
tool-threads 1 authz-policy to
This statement enables proxy authorization using rules associated with the authzTo attribute of the authentication DN (in this case cn=ldaps2). Without this, the provider would otherwise ignore all authzTo attributes, such as the one added to the cn=ldaps2 entry.
Having committed the above change to slapd.conf, restart the provider's LDAP service:
root@ldaps1:~# /etc/init.d/slapd restart Stopping OpenLDAP: slapd. Starting OpenLDAP: slapd. root@ldaps1:~# _
8. Proxy auth test
This last step will test whether the proxy authorization actually works. This is easily done on the consumer server using the ldapadd command. If it works, the changes will be immediately available on the consumer server (or within five minutes if refreshOnly replication is used). First, create a file, called ~/ldaps2-desc.ldif, and add this information to it:
dn: cn=ldaps2,dc=example,dc=com changetype: modify replace: description description: LDAP consumer -
Then apply this change with the ldapmodify command:
~# ldapmodify -x -D "cn=admin,dc=example,dc=com" \ -w piscivorus -f ~/ldaps2-desc.ldif modifying entry "cn=ldaps2,dc=example,dc=com" ~# _
That was a success. Afterwards, a search for cn=ldaps2 should show that this change has been replicated to the consumer database:
~# ldapsearch -x -LLL cn=ldaps2 dn: cn=ldaps2,dc=example,dc=com objectClass: simpleSecurityObject objectClass: organizationalRole cn: ldaps2 description: LDAP consumer ~# _
9. See also
10. Further reading