RJ Systems
Linux System Administration
Home Tech Linux Links Consulting







Valid XHTML 1.0!

Valid CSS!

IPv6 test

OpenLDAP consumer on Debian squeeze

Introduction

These instructions describe 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, ldaps1.example.com. Such hosts were previously referred to as master and slave servers, but these terms were depricated after the functionality involved became more flexible.

Here, OpenLDAP is installed on a host running Debian 6.0 (squeeze). 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 squeeze 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

After that, the installation process for the OpenLDAP consumer server can begin.


1. Patching the source

Because of a bug in the current version of slapd, 2.4.23-6, the source code must first be patched. Without it, slapd will return errors regarding the olcDbURI attribute (necessary for the chaining configuration) and even refuse to (re)start if it is configured that way. So, prepare the new host for a package build by installing the following packages on the new host, ldaps2:

~# apt-get install dpkg-dev devscripts

This will result in 97 new packages being installed. Next, obtain the source:

~# cd /usr/src
~# apt-get source openldap

Three files will be downloaded and a directory, ./openldap-2.4.23/, will be created that contains the source code. Soon, seven Debian packages will be built from it, but first the various dependencies for these package must be downloaded and installed:

~# apt-get build-dep openldap

Some 76 new packages will be installed as a result. Next, download and apply the patch:

~# wget -q ftp://ftp.openldap.org/incoming/pierangelo-masarati-2010-04-29-chain.1.patch
~# patch openldap-2.4.23/servers/slapd/back-ldap/chain.c < pierangelo-masarati-2010-04-29-chain.1.patch
patching file openldap-2.4.23/servers/slapd/back-ldap/chain.c
Hunk #1 succeeded at 1137 (offset -3 lines).
Hunk #2 succeeded at 1148 (offset -3 lines).
~# _

Then, enter the source code directory, add a suffix to the Debian version number to distinguish the results of this build, and compile the binary package without signing the .changes file:

~# cd openldap-2.4.23/
~# dch -l patched 'Including a patch by Pierangelo Masarati, 2010-04-29.'
~# debuild -us -uc

This build can take a long time − perhaps over an hour − most of which is due to automated testing routines. Eventually, seven new Debian packages will be created in the parent directory, /usr/src/:

ldap-utils_2.4.23-6patched1_i386.deb
libldap-2.4-2-dbg_2.4.23-6patched1_i386.deb
libldap-2.4-2_2.4.23-6patched1_i386.deb
libldap2-dev_2.4.23-6patched1_i386.deb
slapd-dbg_2.4.23-6patched1_i386.deb
slapd-smbk5pwd_2.4.23-6patched1_i386.deb
slapd_2.4.23-6patched1_i386.deb

2. Package installation

On the new host, ldaps2, install three of the newly compiled packages:

~# dpkg -i /usr/src/slapd_2.4.23-6patched1_i386.deb \
/usr/src/ldap-utils_2.4.23-6patched1_i386.deb \
/usr/src/libldap-2.4-2_2.4.23-6patched1_i386.deb

During the install process, an administrator password will be requested for slapd. Here, contortrix is used:

Administrator password: contortrix
Confirm password: contortrix

This password, however, is only temporary and will never actually be used for anything.

Run the following command to test if the OpenLDAP server is actually running:

~# nmap -p 389 localhost

Starting Nmap 5.00 ( http://nmap.org ) at 2010-10-30 23:56 CEST
Warning: Hostname localhost resolves to 2 IPs. Using 127.0.0.1.
Interesting ports on localhost (127.0.0.1):
PORT    STATE SERVICE
389/tcp open  ldap

Nmap done: 1 IP address (1 host up) scanned in 0.09 seconds
~# _

The ldap service is made available by slapd on port 389. Note that the state of the port is open. Next, perform a quick test by generating an LDAP Data Interchange Format (LDIF) dump of the contents of a the database:

~# slapcat
hdb_db_open: database "dc=example,dc=com": unclean shutdown detected; 
attempting recovery.
hdb_db_open: database "dc=example,dc=com": recovery skipped in read-only 
mode. Run manual recovery if errors are encountered.
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: example.com
dc: example
structuralObjectClass: organization
entryUUID: 08945ec8-78bc-102f-84d8-05deb33bafe1
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20101030215437Z
entryCSN: 20101030215437.352643Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20101030215437Z

dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9M0pta2U1UkVPZ0kxSkNGNXFxcmQrNkdwa3hxNWU1STI=
structuralObjectClass: organizationalRole
entryUUID: 0894f932-78bc-102f-84d9-05deb33bafe1
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20101030215437Z
entryCSN: 20101030215437.356638Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20101030215437Z

~# _

At this point, the output should look something like the above.


3. ldap.conf

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.


4. cn=ldaps2

Over on the provider server, ldaps1, a new organizationalRole object must be created to represent the new consumer server. To do this, create an LDIF file, called ~/ldaps2.ldif, and copy this text into it:

dn: cn=ldaps2,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: ldaps2
description: LDAP server2 replicator
userPassword: bilineatus

On ldaps1, add this new entry to the DIT with the following command:

~# ldapadd -cxWD cn=admin,dc=example,dc=com -f ~/ldaps2.ldif
Enter LDAP Password: piscivorus
adding new entry "cn=ldaps2,dc=example,dc=com"

~# _

This new object, cn=ldaps2,dc=example,dc=com, along with its password, will be used to authenticate the new consumer server when it attempts to synchronize its copy of the DIT.


5. Syncprov

Still on ldaps1, the configuration on this machine needs to be altered to provide content synchronization (see RFC-4533) for the new consumer server, ldaps2. This requires a number of changes to be made to ldaps1's slapd configuration directory, the cn=config DIT. Two objects will be modified and one new one will be added. Their current state (and in one case absence) can be verified with a single command (see RFC-4515):

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config \
"(|(olcDatabase={1}hdb)(cn=module{0})(olcOverlay={0}syncprov))"
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou
 s auth by dn="cn=admin,dc=example,dc=com" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=com" write by * 
 read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=example,dc=com
olcRootPW: {SSHA}imRJJXAdFZhnknIUhK/SFREtFmE6KEfW
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcDbIndex: uid eq
olcDbIndex: cn eq
olcDbIndex: ou eq
olcDbIndex: dc eq

~# _

Here is a description of the changes that will be made to the cn=config DIT on ldaps1:

1.1.1. For the olcDatabase={1}hdb entry, the first olcAccess attribute (index 0), concerning access to all userPassword and shadowLastChange attributes, must be modified to authorize the new consumer server to read them. However, since the olcAccess attribute has multiple values, it cannot simply be replaced, but must first be deleted.
1.1.2. When the first olcAccess attribute is recreated (with index 0), it must include an additional ACL rule to allow cn=ldaps2 to read the entire DIT.
1.2. With syncrepl replication, the entryUUID attribute is added to all entries in the database. Use of the olcSpSessionlog option (see description below) requires searching for this attribute, so it is recommended (but not required) to set an equality index for it. Doing so on the provider server can improve session log performance considerably.
1.3. Similarly, it is recommended to add an eq index for the entryCSN attribute when making use of the olcSpCheckpoint option.
2. For the cn=module{0} entry, an extra olcModuleLoad attribute will be added to load the syncprov module into the slapd process. This is because it was not compiled statically into /usr/sbin/slapd.
3. A new entry, olcOverlay={0}syncprov, will be added to the cn=config DIT to activate and configure the syncprov module.

To make the above changes in the same order to the cn=config DIT, create an LDIF file on ldaps1, called ~/olc-mod2.ldif, with the following contents:

# 1.1.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=example,dc=com" write
  by * none
-
# 1.1.2.
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by dn="cn=admin,dc=example,dc=com" write
  by dn="cn=ldaps2,dc=example,dc=com" read
  by anonymous auth
  by * none
-
# 1.2.
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# 1.3.
add: olcDbIndex
olcDbIndex: entryCSN eq

# 2.
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}syncprov

# 3.
dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: {0}syncprov
olcSpCheckpoint: 100 10
olcSpSessionlog: 100

NB: According to the LDIF specification (RFC-2849), lines containing only a "-" character act as a separator between modifications that apply to the same directory entry. Empty lines separate tasks involving different directory entries. A line that begins with a space is treated as a continuation of the previous line, although that previous line may not be empty. When such folded lines are joined, note that the first space character at the beginning of each continued line is discarded. Lines that start with a "#" character are considered comments and are ignored.

Regarding the purpose of last two attributes of the olcOverlay={0}syncprov object:

olcSpCheckpoint After a write operation has succeeded, write the current contextCSN value to the underlying database if, in this case, either 100 write operations or more than 10 minutes have passed since the last checkpoint. Used to minimize recovery times after unclean shutdowns, this option is disabled by default.
olcSpSessionlog Specifies that a session log be maintained for recording information about operations written to the database. Here, the log may record a maximum of 100 operations. All LDAP Write operations (except Adds) are recorded in the log. Used to speed up LDAP Sync searches within the database.

Apply changes in the LDIF file with this command:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-mod2.ldif
modifying entry "olcDatabase={1}hdb,cn=config"

modifying entry "cn=module{0},cn=config"

adding new entry "olcOverlay=syncprov,olcDatabase={1}hdb,cn=config"

~# _

Rerun the previous ldapsearch command to verify that all of the changes have been made successfully. Note that an index number has been added automatically to the RDN for the syncprov overlay.

Note that when new indices are added for attribute types for which data already exists, as of OpenLDAP 2.4.23-3 it is no longer necessary to stop the slapd process and manually reindex the database. Instead, slapd will continue to run normally while an internal task generates the new index data. However, if slapd is stopped before the indexer can complete its work, then the task will have to be completed manually using the slapindex tool (as the openldap user and while slapd is not running).


6. Syncrepl

Returning to ldaps2, the configuration on this host must also be modified before it will synchronize (see RFC-4533) with the provider server, ldaps1. To this end, a number of changes will be made to the cn=config DIT on ldaps2. Two objects will be modified, the current states of which can be verified with this command:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config \
"(|(cn=config)(olcDatabase={1}hdb))"
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcLogLevel: none
olcPidFile: /var/run/slapd/slapd.pid
olcToolThreads: 1

dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymou
 s auth by dn="cn=admin,dc=example,dc=com" write by * none
olcAccess: {1}to dn.base="" by * read 
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=com" write by * 
 read
olcLastMod: TRUE
olcRootDN: cn=admin,dc=example,dc=com
olcRootPW: {SSHA}3Jmke5REOgI1JCF5qqrd+6Gpkxq5e5I2
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq

~# _

Here is a description of the changes that will be made to the cn=config DIT on ldaps2:

1. For the root object, cn=config, the value of the olcLogLevel attribute will be changed from none to stats. This will cause slapd to log more about what it does to /var/log/syslog, which is better for testing purposes, although its current setting is better for production environments.
2.1.1. For the olcDatabase={1}hdb entry, the first olcAccess attribute (index 0) must be modified to prevent anyone from making changes to the DIT; this database replica will be strictly read-only. However, since this attribute has multiple values, it cannot simply be replaced, but must first be deleted.
2.1.2. When the first olcAccess attribute is recreated (with index 0), those rules that would allow others to write to the DIT will be omitted. Later on, to allow LDAP clients of this host to write to the DIT anyway, arrangements will be made to allow the changes to be passed on to the provider server.
2.2.1. The third olcAccess attribute (index 2) must also be modified to prevent anyone from writing to the DIT. Again, it will first be deleted.
2.2.2. When the third olcAccess attribute is recreated (with index 2), it will not include any rules that allow clients to write to the DIT.
2.3. The value for the olcRootDN attribute, which indicates the administrative account for the database, will be changed to something completely arbitrary. That is because there is no need for it to be part of the directory. However, setting a value for this attribute is still 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.
2.4. Since the administrative account is no longer part of the dc=example,dc=com DIT, the olcRootPW attribute will be deleted.
2.5. An eq index will be set for the entryCSN attribute to speed up the replication process.
2.6. Idem for the entryUUID attribute.
2.7. An equality (eq) index will be set for the uid attribute to speed up the authentication process. It will also prevent "bdb_equality_candidates" errors...
2.8. An equality index will also be set for Common Name (cn) objects to prevent "bdb_equality_candidates" errors from appearing in the log file, /var/log/syslog. One such error will otherwise appear in the log for every search for an entry of this type.
2.9. Idem for Organizational Unit (ou) objects.
2.10. Idem for Domain Component (dc) objects.
2.11. The olcSyncrepl attribute will be added to configure LDAP Sync Replication engine. The options used for it are explained below.

To make the above changes to the cn=config DIT, create an LDIF file on ldaps2, called ~/olc-mod1.ldif, with the following contents:

# 1.
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

# 2.1.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by anonymous auth
  by dn="cn=admin,dc=example,dc=com" write
  by * none
-
# 2.1.2.
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by anonymous auth
  by * none
-
# 2.2.1.
delete: olcAccess
olcAccess: {2}to *
  by self write
  by dn="cn=admin,dc=example,dc=com" write
  by * read
-
# 2.2.2.
add: olcAccess
olcAccess: {2}to *
  by * read
-
# 2.3.
replace: olcRootDN
olcRootDN: cn=manager
-
# 2.4.
delete: olcRootPW
-
# 2.5.
add: olcDbIndex
olcDbIndex: entryCSN eq
-
# 2.6.
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# 2.7.
add: olcDbIndex
olcDbIndex: uid eq
-
# 2.8.
add: olcDbIndex
olcDbIndex: cn eq
-
# 2.9.
add: olcDbIndex
olcDbIndex: ou eq
-
# 2.10.
add: olcDbIndex
olcDbIndex: dc eq
-
# 2.11.
add: olcSyncrepl
olcSyncrepl: 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 presence of the olcSyncrepl attribute will indicate that the current database is a replica. This directive has many different options, a number of which are used here:

rid The replica ID of the current syncrepl directive on the consumer. This must be a non-negative three-digit integer. The choice here, 123, is arbitrary.
provider The name of the provider server with master content to synchrinize with. The name is written as an LDAP URI followed by a port number if necessary. Here, the alias is used that refers to the current provider server, ldaps1.
type The operation type. This can be either refreshOnly, which is polling pull-based synchronization, or refreshAndPersist, which is persistent push-based synchronization. If the latter type is used, the retry option is required.
retry In case of replication errors, this option determines both the amount of time in seconds to wait before the consumer attempts to reconnect to the provider, as well as the number of retries. Specified as a set of one or more interval-retry pairs, separated by spaces. A "+" indicates an indefinite number of retries. The setting used here means that, if a replication error occurs, the consumer will attempt to reconnect with the provider once every 60 seconds with 30 retries, and thereafter once every 300 seconds with an indefinite (+) number of retries.
searchbase The search base to use for replication, written as a DN. This option has no default and must always be specified.
bindmethod The security method to be used for authentication. This can be either simple or sasl. Since the first method are used here, the options binddn and credentials are required.
binddn The DN that the consumer will use to authenticate with the provider.
credentials The password that the consumer will use to authenticate with the provider. Because the bindmethod simple is used, the password must be in clear text.

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:

# 2.11. (alternative)
add: olcSyncrepl
olcSyncrepl: 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
interval The replication interval specified in dd:hh:mm:ss. Limited to use with refreshOnly synchronization. The default is one day.

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.

Apply all of the above changes with this command:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-mod1.ldif
modifying entry "cn=config"

modifying entry "olcDatabase={1}hdb,cn=config"

~# _

Rerun the previous ldapsearch command to verify that all of the changes have been made successfully.

Having applied the above changes, stop the LDAP service, delete the local database, and restart the service. This will cause the consumer to resynchronize its database with the provider:

~# /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.


7. Replication test

At this point, proper synchronization with the provider, ldaps1, will have taken place. This can be verified to a limited degree by executing a simple search command on ldaps2:

~# 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

~# _

On the surface, it seems that the database has synchronized, since all of the entries after the first two were created on the OpenLDAP provider server. However, the only way to tell for sure that everything has synchronized correctly is to run the slapcat command on both the consumer and the provider and compare the results. In both cases, the output should be exactly the same.


8. Referrals

LDAP Sync Replication does present one important problem for LDAP clients: the database containing the DIT on a consumer server is always read-only. To allow clients to make modifications to the DIT anyway, the consumer must either refer its clients on to the provider, or proxy their requests. Both of these options will be arranged by modifying two existing entries in the consumer server's configuration DIT and adding two new ones. The following search command on ldaps2 will verify their current status/absence:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config "(|(cn=module{0})\
(olcDatabase={1}hdb)(olcOverlay={0}chain)(olcDatabase={0}ldap))"
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_hdb

dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=example,dc=com
olcAccess: {0}to attrs=userPassword,shadowLastChange by anonymous auth by * no
 ne
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by * read
olcLastMod: TRUE
olcRootDN: cn=manager
olcSyncrepl: {0}rid=123 provider="ldap://ldaps.example.com:389/" type=refreshA
 ndPersist retry="60 30 300 +" searchbase="dc=example,dc=com" bindmethod=simpl
 e binddn="cn=ldaps2,dc=example,dc=com" credentials=bilineatus
olcDbCheckpoint: 512 30
olcDbConfig: {0}set_cachesize 0 2097152 0
olcDbConfig: {1}set_lk_max_objects 1500
olcDbConfig: {2}set_lk_max_locks 1500
olcDbConfig: {3}set_lk_max_lockers 1500
olcDbIndex: objectClass eq
olcDbIndex: entryCSN eq
olcDbIndex: entryUUID eq
olcDbIndex: uid eq
olcDbIndex: cn eq
olcDbIndex: ou eq
olcDbIndex: dc eq

~# _

Here is a description of the changes that will be made to the cn=config DIT on ldaps2:

1. For the olcDatabase={1}hdb entry, the olcUpdateref attribute will be added with a URL for the provider server. This referral will then be passed directly on to clients whenever they ask slapd to modify the read-only replica, e.g. to change a password. Unfortunately, although this is the preferred method, not all LDAP clients understand referrals. Therefore, it is also a good idea to configure the chain overlay, which allows automatic referral chasing, i.e. for the consumer to act as a proxy.
2. For the cn=module{0} entry, an additional olcModuleLoad attribute will be added to load the back_ldap (LDAP backend database) module into the slapd process. This will make the chain overlay available, which happens to be built into the back_ldap module.
3. A new entry, olcOverlay={0}chain, will be added to activate and configure the chain overlay. This will allow slapd to act as a proxy, automatically chasing referrals on behalf of clients. Although this overlay has very few directives of its own, those belonging to the LDAP backend assume a special meaning when used in conjunction with it.
4. Another new entry, olcDatabase={0}ldap, will be added to configure the LDAP backend database. This is not an actual database, but provides basic proxying functionality, in this case for the chain overlay, including configuration directives necessary for it to contact the provider server.

To make the above changes to the cn=config DIT on ldaps2, create an LDIF file, called ~/olc-mod2.ldif, with the following contents:

# 1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcUpdateref
olcUpdateref: "ldap://ldaps.example.com:389/"

# 2.
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}back_ldap

# 3.
dn: olcOverlay=chain,olcDatabase={-1}frontend,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcChainConfig
olcOverlay: {0}chain
olcChainReturnError: TRUE

# 4.
dn: olcDatabase=ldap,olcOverlay={0}chain,olcDatabase={-1}frontend,
 cn=config
changetype: add
objectClass: olcLDAPConfig
objectClass: olcChainDatabase
olcDatabase: {0}ldap
olcDbURI: "ldap://ldaps.example.com:389/"
olcDbRebindAsUser: TRUE
olcDbIDAssertBind: bindmethod=simple
  binddn="cn=ldaps2,dc=example,dc=com"
  credentials=bilineatus
  mode=self

Here, the olcDbIDAssertBind directive defines the parameters of the authentication method used by ldaps2 to authorize connections from authenticated users. It has a number of different options, a few of which are used here:

bindmethod The method with which the consumer server authenticates to the provider. Here, the simple authentication method is used, in which case a password is also required.
binddn The Distinguished Name of the database entry, in this case cn=ldaps2,dc=example,dc=com, that will be used to authenticate to the provider server.
credentials The password associated with the binddn that will used to authenticate to the provider server.
mode When the mode self is used, the client's identity will be asserted when a request is proxied.

Apply the above changes with this command:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-mod2.ldif
modifying entry "olcDatabase={1}hdb,cn=config"

modifying entry "cn=module{0},cn=config"

adding new entry "olcOverlay=chain,olcDatabase={1}hdb,cn=config"

adding new entry "olcDatabase=ldap,olcOverlay={0}chain,olcDatabase={1}hdb,cn=config"

~# _

Rerun the previous ldapsearch command to verify that all of the changes have been made successfully.


9. Proxy authorization

Over on ldaps1, a few more changes need to be made before the above proxy configuration will work. These changes are to both the DIT and to ldaps1's configuration. What needs to be configured is proxy authorization. Once arranged, a certain object, in this case cn=ldaps2, will be authorized to relay write requests on to the provider server, in the process assuming the identities of the individual clients. The latter is important, because it would otherwise not be possible to enforce existing access rules.

Two changes are required to enable proxy authorization. First, the entry for the consumer server, ldaps2, will be modified so that it will act as an authorization proxy, but only for certain users. Second, the provider server, ldaps1, will be configured to accept such proxy requests.

Starting with the entry for ldaps2, here is what it looks like from ldaps1 at the moment:

~# ldapsearch -xWLLLD "cn=admin,dc=example,dc=com" cn=ldaps2
Enter LDAP Password: piscivorus
dn: cn=ldaps2,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: ldaps2
description: LDAP server2 replicator
userPassword:: YmlsaW5lYXR1cw==

~# _

To make the required modification, first create a new file on ldaps1, called ~/ldaps2-authzto.ldif, and add to it the following contents:

dn: cn=ldaps2,dc=example,dc=com
changetype: modify
add: authzTo
authzTo: {0}dn.regex:^uid=[^,]+,ou=people,dc=example,dc=com$
authzTo: {1}dn.exact:cn=admin,dc=example,dc=com

The authzTo directive is a source rule used to determine those for whom a particular DN may proxy. It is also a multivalued attribute and the above modification will add two such rules to the ldaps2 entry: the first a regular expression to match all users in ou=people, the second an exact match for the admin user.

To apply the modification, run this command on ldaps1:

~# ldapmodify -xWD "cn=admin,dc=example,dc=com" -f ~/ldaps2-authzto.ldif
Enter LDAP Password: piscivorus
modifying entry "cn=ldaps2,dc=example,dc=com"

~# _

Rerun the previous search command to verify that the change has been made correctly.

To ensure that the provider server, ldaps1, will accept proxy requests associated with the authzTo attribute, the cn=config entry in its configuration directory must be modified to include an olcAuthzPolicy attribute set to "to". Without it, the provider will ignore all authzTo proxy requests. The entry currently looks like this:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config cn=config
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcPidFile: /var/run/slapd/slapd.pid
olcToolThreads: 1
olcLogLevel: stats

~# _

To modify it, first create a new file on ldaps1, called ~/olc-AuthzPolicy.ldif, with the following contents:

dn: cn=config
changetype: modify
add: olcAuthzPolicy
olcAuthzPolicy: to

Run this command on ldaps1 to apply the change:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-AuthzPolicy.ldif
modifying entry "cn=config"

~# _

Rerun the previous search command to verify that the change has been made correctly.


10. 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 immediately be available on the consumer server (or within five minutes if the suggested refreshOnly configuration is used). First, create a file, called ~/ldaps2-desc.ldif, on ldaps2 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 -xWD "cn=admin,dc=example,dc=com" -f ~/ldaps2-desc.ldif
Enter LDAP Password: piscivorus
modifying entry "cn=ldaps2,dc=example,dc=com"

~# _

This indicates that the chaining configuration works, since ldapmodify does not understand referrals.

As a result, entries similar to the following will appear in /var/log/syslog on ldaps1:

Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 fd=18 ACCEPT from IP=192.168.2.52:34724 (IP=0.0.0.0:389)
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=0 BIND dn="cn=ldaps2,dc=example,dc=com" method=128
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=0 BIND dn="cn=ldaps2,dc=example,dc=com" mech=SIMPLE ssf=0
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=0 RESULT tag=97 err=0 text=
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=1 PROXYAUTHZ dn="cn=admin,dc=example,dc=com"
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=1 MOD dn="cn=ldaps2,dc=example,dc=com"
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=1 MOD attr=description
Nov 13 22:02:35 ldaps1 slapd[877]: conn=1008 op=1 RESULT tag=103 err=0 text=

At this point, on ldaps2, a search for the cn=ldaps2 entry in the DIT will show that the change has been copied 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

~# _

11. See also
12. Further reading
  • Eastlake D, Panitz A. 1999. RFC2606 − Reserved Top Level DNS Names. The Internet Society. HTML at the Internet FAQ Archives.
  • Good G. 2000. RFC2849 − The LDAP Data Interchange Format (LDIF): Technical Specification. HTML at the Internet FAQ Archives.
  • Hodges J, Morgan R. 2002. RFC3377 − Lightweight Directory Access Protocol (v3): Technical Specification. The Internet Society. HTML at the Internet FAQ Archives.
  • Smith M, Howes T. 2006. RFC4515 − Lightweight Directory Access Protocol (LDAP): String Representation of Search Filters. The Internet Society. HTML at the Internet FAQ Archives.
  • Wahl M, Howes T, Kille S. 1997. RFC2251 − Lightweight Directory Access Protocol (v3). The Internet Society. HTML at the Internet FAQ Archives.
  • Yeong W, Howes T, Kille S. 1993. RFC1487 − X.500 Lightweight Directory Access Protocol. The Internet Society. HTML at the Internet FAQ Archives.
  • Zeilenga K, Choi JH. 2006. RFC4533 − The Lightweight Directory Access Protocol (LDAP): Content Synchronization Operation. HTML at the Internet FAQ Archives.

13. Sources
  • Carter G. 2003. LDAP System Administration. O'Reilly & Associates, Inc. ISBN 1-56592-491-6. 294 pp.
  • OpenLDAP Project. 2009. OpenLDAP Software 2.4 Administrator's Guide. HTML at OpenLDAP.


Last modified: 2010-12-22, 18:49

©2003-2014 RJ Systems. Permission is granted to copy, distribute and/or modify the
content of this page under the terms of the OpenContent License, version 1.0.