RJ Systems
Linux System Administration
Home Tech Linux Links Consulting







Valid XHTML 1.0!

Valid CSS!

IPv6 test

Integrated Kerberos-OpenLDAP consumer on Debian squeeze

Introduction

This page describes how to set up an OpenLDAP consumer server and an MIT Kerberos V slave server on the same host so that Kerberos uses LDAP as it back-end database. It depends on a previously installed Kerberos-OpenLDAP provider server, kls1.example.com. The system also relies heavily on timestamps, so reasonably accurate time synchronization among all participating hosts is essential.

In this example, OpenLDAP and MIT Kerberos V are installed on a host running Debian 6.0 (squeeze). If followed properly, the step-by-step process should produce an OpenLDAP provider server with a new DIT, followed by a Kerberos master server that stores its database in that same DIT.

But, before the interesting parts can begin, it will first be necessary to install the operating system on a new host called kls2.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 ntp ntpdate nmap

Afterwards, edit /etc/ntp.conf so that the machine synchronizes to a common NTP server (preferably a local one) and edit /etc/default/ntpdate to use the same host also. Now the installation of the new server can begin.


1. Patching the source

Because of a bug in the current version of slapd, 2.4.23-7, 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, kls2:

~# apt-get install dpkg-dev devscripts

This will result in 100 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

70 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-7patched1_i386.deb
libldap-2.4-2-dbg_2.4.23-7patched1_i386.deb
libldap-2.4-2_2.4.23-7patched1_i386.deb
libldap2-dev_2.4.23-7patched1_i386.deb
slapd-dbg_2.4.23-7patched1_i386.deb
slapd-smbk5pwd_2.4.23-7patched1_i386.deb
slapd_2.4.23-7patched1_i386.deb

2. Kerberos client install

First, run the following command to test if the MIT Kerberos V server installed previously is available on the network:

~# nmap -sU -sT -p U:88,464,T:464,749 kls1.example.com

Starting Nmap 5.00 ( http://nmap.org ) at 2010-12-28 22:58 CET
Interesting ports on kls1.example.com (192.168.2.58):
PORT    STATE         SERVICE
464/tcp open          kpasswd5
749/tcp open          kerberos-adm
88/udp  open|filtered kerberos-sec
464/udp open|filtered kpasswd5
MAC Address: 08:00:27:3C:87:C9 (Cadmus Computer Systems)

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

If not all of the above ports are shown as open, fix that problem first. If they are, continue by installing these three packages:

~# apt-get install krb5-{config,user} libpam-krb5

A total of three packages are installed as a result with no dependencies:

krb5-config           2.2                            Configuration files for Kerberos Version 5
krb5-user             1.8.3+dfsg-4                   Basic programs to authenticate using MIT Kerberos
libpam-krb5           4.3-1                          PAM module for MIT Kerberos

During the installation, krb5-config will require that a few questions be answered:

Default Kerberos version 5 realm: EXAMPLE.COM
Kerberos servers for your realm: kls1.example.com
Administrative server for your Kerberos realm: kls.example.com

These settings are saved in the Kerberos realm configuration file, /etc/krb5.conf.

Use kadmin to create a Kerberos principal for the LDAP service and a matching keytab file by issuing a few commands:

~# kadmin -p admin
Authenticating as principal admin with password.
Password for admin@EXAMPLE.COM: ammodytes
kadmin:  addprinc -randkey ldap/kls2.example.com
WARNING: no policy specified for ldap/kls2.example.com@EXAMPLE.COM; defaulting to no policy
Principal "ldap/kls2.example.com@EXAMPLE.COM" created.
kadmin:  ktadd ldap/kls2.example.com
Entry for principal ldap/kls2.example.com with kvno 2, encryption type AES-256 CTS mode with 96-bit SHA-1 HMAC 
added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal ldap/kls2.example.com with kvno 2, encryption type ArcFour with HMAC/md5 added to keytab 
WRFILE:/etc/krb5.keytab.
Entry for principal ldap/kls2.example.com with kvno 2, encryption type Triple DES cbc mode with HMAC/sha1 added 
to keytab WRFILE:/etc/krb5.keytab.
Entry for principal ldap/kls2.example.com with kvno 2, encryption type DES cbc mode with CRC-32 added to keytab 
WRFILE:/etc/krb5.keytab.
kadmin:  q
~# _

The -randkey switch is used to avoid having to use a password. To list the keys in /etc/krb5.keytab, use the klist -ke command. A host (or service) principal and a keytab file should be created for and saved on all of the various client machines that are part of a Kerberos realm.


3. OpenLDAP install

Before starting the install process, run the following command to test if the previously installed OpenLDAP provider server is actually available on the network:

~# nmap -p 389 kls1.example.com

Starting Nmap 5.00 ( http://nmap.org ) at 2010-12-29 00:29 CET
Interesting ports on kls1.example.com (192.168.2.58):
PORT    STATE SERVICE
389/tcp open  ldap
MAC Address: 08:00:27:3C:87:C9 (Cadmus Computer Systems)

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

If TCP port 389 is not open, as shown above, fix that problem first. Otherwise, install three of the newly compiled packages:

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

The following three packages will be installed:

ldap-utils            2.4.23-7patched1               OpenLDAP utilities
libldap-2.4-2         2.4.23-7patched1               OpenLDAP libraries
slapd                 2.4.23-7patched1               OpenLDAP server (slapd)

During the install process, an administrator password will be requested for slapd. Use somalica:

Administrator password: somalica
Confirm password: somalica

This password is actually inconsequential, as it will not be needed again.

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 2011-01-06 01:11 CET
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.07 seconds
~# _

Perform a quick test by generating an 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: 91e70e90-ad74-102f-938c-c3d454483fbd
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20110106000635Z
entryCSN: 20110106000635.605081Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20110106000635Z

dn: cn=admin,dc=example,dc=com
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9akp4SW9CKzFzWC85dzc0WDk3c0w4TEFDVjlNdjBrMmI=
structuralObjectClass: organizationalRole
entryUUID: 91e79f36-ad74-102f-938d-c3d454483fbd
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20110106000635Z
entryCSN: 20110106000635.608824Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20110106000635Z

~# _

Edit /etc/ldap/ldap.conf and use these two lines:

BASE    dc=example,dc=com
URI     ldap://kls2.example.com/

This configuration file is used to set local, system-wide defaults for LDAP clients.


4. Kerberos slave install

To set up a Kerberos slave server, install these two packages:

~# apt-get install krb5-{kdc,kdc-ldap}

These are also the only two packages that are installed as a result:

krb5-kdc                    1.8.3+dfsg-4                         MIT Kerberos key server (KDC)
krb5-kdc-ldap               1.8.3+dfsg-4                         MIT Kerberos key server (KDC) LDAP plugin

Towards the end of the automated configuration sequence for these packages, a problem appears:

Setting up krb5-kdc (1.8.3+dfsg-4) ...
krb5kdc: cannot initialize realm EXAMPLE.COM - see log file for details

This is because the realm, or rather the database for it, has not yet been created. However, this issue will be dealt with later.

For now, edit /etc/krb5kdc/kdc.conf and modify these two lines − the same as the Kerberos master server is configured:

        max_life = 1d 0h 0m 0s
        max_renewable_life = 90d 0h 0m 0s

Since the idea is for Kerberos to use OpenLDAP as its back-end database, see to it that the Kerberos KDC service starts up after slapd and stops before it. To do this, edit /etc/init.d/krb5-kdc and modify it as follows:

# Required-Start:       $local_fs $remote_fs $network $syslog slapd
# Required-Stop:        $local_fs $remote_fs $network $syslog slapd

Apply the above change:

~# insserv /etc/init.d/krb5-kdc
~# _

5. Kerberos schema

Prepair the OpenLDAP server to function as a back-end database for a Kerberos KDC. To do this, the Kerberos schema file, installed in the previous step, needs to be converted to LDIF format. However, since that task was already completed on kls1, save some time by simply copying that file over to this server:

~# scp kls1.example.com:~/kerberos.ldif ~/
root@kls1.example.com's password:
kerberos.ldif                                         100% 9082     8.9KB/s   00:00
~# _

Add the Kerberos schema to the cn=config DIT on kls2 with this command:

~# ldapadd -QY EXTERNAL -H ldapi:/// -f ~/kerberos.ldif
adding new entry "cn=kerberos,cn=schema,cn=config"

~# _

Verify that the new schema has been added with this command:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config cn={4}kerberos

6. cn=config

Besides the addition of the Kerberos schema, a number of other modifications need to be made to the OpenLDAP configuration directory on kls2 regarding two existing entries. First consider the current state of these objects:

~# 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}tSxjq+cZV9oomtD78vd/c2zy1wHXLL++
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 kls2:

1. For the root object, cn=config, the value for olcLogLevel is currently set to none (the Debian default). This prevents slapd from writing almost anything to the syslog. This is okay for production environments, but less desirable for educational purposes, so it is going to be changed to stats (the value recommended by the OpenLDAP project). This way, slapd will log more about what it does to /var/log/syslog.
2.1. For the database definition, olcDatabase={1}hdb,cn=config, 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.2. Since the administrative account is no longer part of the dc=example,dc=com DIT, the olcRootPW attribute will be deleted.
2.3.x. All three of the current ACLs, each one being a value of an olcAccess attribute, will be deleted. For clarity, this will be done in reverse order, or else the index numbers would all have to be zero.
2.4.1. The first new olcAccess attribute will determine access to password information stored in the DIT. The OpenLDAP admin account will have read access, anonymous users will have auth access and all other users will have no access. This type of authentication may seem like a security issue, but since only IPC connections (i.e. Unix domain sockets) will be used for this − no network connections − there is nothing to worry about.
2.4.2. The second new olcAccess attribute will determine access to the ou=krb5 subtree, which will contain the Kerberos database. The OpenLDAP admin user and the entry for the Kerberos administration server will have read access to it, while the future entry for the Kerberos KDC will have read access.
2.4.3. The fourth new olcAccess attribute will allow read access to the base of the tree for things like supportedSASLMechanisms. This allows clients to discover which SASL mechanisms an LDAP server supports.
2.4.4. The fifth and last new olcAccess attribute is the default ACL that will determines access to everything else in the tree. The OpenLDAP admin user will have read access, authenticated users will have read access and anonymous users will have no access.
2.5. An extra equality (eq) index will be added for User ID (uid) objects. olcDbIndex directives are used to specify the attributes on which slapd should maintain indices to optimize directory searches. This new equality index will speed up searches for entries based on exact matches of the uid attribute. At the moment it is not really necessary to add any extra indices, since the new directory tree contains almost no data. However, it is recommended to add an eq index for uid entries, because these are used for storing user account names and later on, as the DIT grows in size, this index can significantly decrease the time it takes for users to log in. The same eq will also prevent "bdb_equality_candidates" errors...
2.6. 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.7. Idem for Organizational Unit (ou) objects.
2.8. Idem for Domain Component (dc) objects.
2.9. Idem for the uidNumber attribute.
2.10. Idem for the gidNumber attribute.
2.11. Idem for the memberUid attribute.
2.12. Idem for the uniqueMember attribute.
2.13. An equality, presence and substring index will be set for the krbPrincipalName attribute.
2.14. An equality index will be set for the krbPwdPolicyReference attribute.

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

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

# 2.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=manager
-
# 2.2.
delete: olcRootPW
-
# 2.3.1.
delete: olcAccess
olcAccess: {2}to *
  by self write
  by dn="cn=admin,dc=example,dc=com" write
  by * read
-
# 2.3.2.
delete: olcAccess
olcAccess: {1}to dn.base=""
  by * read
-
# 2.3.3.
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.4.1.
add: olcAccess
olcAccess: to attrs=userPassword,shadowLastChange
  by anonymous auth
  by * none
-
# 2.4.2.
add: olcAccess
olcAccess: to dn.subtree="ou=krb5,dc=example,dc=com"
  by dn="cn=adm-srv,ou=krb5,dc=example,dc=com" read
  by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" read
  by * none
-
# 2.4.3.
add: olcAccess
olcAccess: to dn.base=""
  by * read
-
# 2.4.4.
add: olcAccess
olcAccess: to *
  by users read
  by * none
-
# 2.5.
add: olcDbIndex
olcDbIndex: uid eq
-
# 2.6.
add: olcDbIndex
olcDbIndex: cn eq
-
# 2.7.
add: olcDbIndex
olcDbIndex: ou eq
-
# 2.8.
add: olcDbIndex
olcDbIndex: dc eq
-
# 2.9.
add: olcDbIndex
olcDbIndex: uidNumber eq
-
# 2.10.
add: olcDbIndex
olcDbIndex: gidNumber eq
-
# 2.11.
add: olcDbIndex
olcDbIndex: memberUid eq
-
# 2.12.
add: olcDbIndex
olcDbIndex: uniqueMember eq
-
# 2.13.
add: olcDbIndex
olcDbIndex: krbPrincipalName eq,pres,sub
-
# 2.14.
add: olcDbIndex
olcDbIndex: krbPwdPolicyReference eq

After the file has been saved on kls2, 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.


7. krb5.conf

Edit the Kerberos realm configuration file, /etc/krb5.conf. This file is initially created by the Debian installer and contains information about the realms of a number of famous institutions, but none of that is necessary in this case. Instead, replace its contents with this:

[libdefaults]
	default_realm = EXAMPLE.COM
	forwardable = true
	proxiable = true

[realms]
	EXAMPLE.COM = {
		kdc = kls2.example.com
		admin_server = kls.example.com
		database_module = openldap_ldapconf
	}

[domain_realm]
	.example.com = EXAMPLE.COM
	example.com = EXAMPLE.COM

[dbdefaults]
	ldap_kerberos_container_dn = ou=krb5,dc=example,dc=com

[dbmodules]
	openldap_ldapconf = {
		db_library = kldap
		ldap_kdc_dn = cn=kdc-srv,ou=krb5,dc=example,dc=com
		ldap_kadmind_dn = cn=adm-srv,ou=krb5,dc=example,dc=com
		ldap_service_password_file = /etc/krb5kdc/service.keyfile
		ldap_conns_per_server = 5
	}

[logging]
	kdc = FILE:/var/log/krb5/kdc.log
	admin_server = FILE:/var/log/krb5/kadmin.log
	default = FILE:/var/log/krb5/kadmin.log

See this section for a more detailed explanation of this file.

Note the absence of the ldap_servers statement from the list of openldap_ldapconf options. This is possible because the Kerberos daemons use IPC (Unix domain sockets) to connect to the LDAP back-end by default.

After /etc/krb5.conf has been saved, create the Kerberos log directory:

~# mkdir /var/log/krb5
~# _

To prevent the log file from growing too large, create a logrotate configuration file. Edit /etc/logrotate.d/krb5-kdc and give it the following contents:

/var/log/krb5/kdc.log {
	daily
	missingok
	rotate 7
	compress
	delaycompress
	notifempty
	postrotate
		/etc/init.d/krb5-kdc restart > /dev/null
	endscript
}

The various password stashes that were created previously on the provider − for the KDC database master key, the KDC service (for cn=kdc-srv) and the Kerberos administration server (cn=adm-srv) − are also required on this host. However, instead of creating them from scratch as was done before, simply copy them from the provider:

~# scp kls1.example.com:/etc/krb5kdc/s* /etc/krb5kdc/
root@kls1.example.com's password:
service.keyfile                                       100%  122     0.1KB/s   00:00
stash                                                 100%   64     0.1KB/s   00:00
~# _

Two files will be copied as a result: stash contains the KDC database master key, while service.keyfile contains the two service passwords.


8. Provider modifications

Switch over to the provider server, kls1.example.com, to make some changes there. Start by creating a new LDAP entry that will be used to represent and authorize kls2 to read the entire DIT. Start by creating a file, ~/kls2.ldif, with the following contents:

dn: ou=consumers,dc=example,dc=com
ou: consumers
objectClass: organizationalUnit

dn: cn=kls2,ou=consumers,dc=example,dc=com
cn: kls2
objectClass: simpleSecurityObject
objectClass: organizationalRole
description: LDAP server2 replicator
userPassword: {CRYPT}*

Add this new object, along with its container, to the DIT on kls1 with these commands:

root@kls1:~# kinit admin
Password for admin@EXAMPLE.COM: ammodytes
root@kls1:~# ldapadd -Qf ~/kls2.ldif
adding new entry "ou=consumers,dc=example,dc=com"

adding new entry "cn=kls2,ou=consumers,dc=example,dc=com"

root@kls1:~# _

Next, a number of changes will be made to the LDAP configuration database on kls1. Three existing entries will be modified and one new one added. Their current status/absence is as follows:

root@kls1:~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config \
"(|(cn=config)(olcDatabase={1}hdb)(cn=module{0})(olcOverlay={0}syncprov))"
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcAuthzRegexp: {0}uid=([^,]+),cn=example.com,cn=gssapi,cn=auth uid=$1,ou=peop
 le,dc=example,dc=com
olcLogLevel: stats
olcPidFile: /var/run/slapd/slapd.pid
olcSaslRealm: EXAMPLE.COM
olcToolThreads: 1

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.subtree="ou=krb5,dc=example,dc=com" by dn="cn=adm-srv,ou=k
 rb5,dc=example,dc=com" write by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" rea
 d by * none
olcAccess: {2}to attrs=loginShell by self write by users read by * none
olcAccess: {3}to dn.base="" by * read
olcAccess: {4}to * by users read by * none
olcLastMod: TRUE
olcRootDN: uid=admin,ou=people,dc=example,dc=com
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
olcDbIndex: krbPrincipalName eq,pres,sub

root@kls1:~# _

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

1.1. For the root object, cn=config, a statement needs to be added to map LDAP service principals from their SASL/GSSAPI names to their matching Common Name objects in ou=consumers. However, to position it before the default mapping, ou=people, the latter must first be deleted.
1.2.1. Then the statement to map LDAP service principals from their SASL/GSSAPI names to their matching Common Name objects in ou=consumers is added.
1.2.2. Then the default mapping for ou=people is restored unchange, but importantly still positioned last.
2.1. For the database definition, olcDatabase={1}hdb,cn=config, an equality index is set for the entryUUID attribute. That is because, with syncrepl replication, this 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.
2.2. Similarly, it is recommended to add an eq index for the entryCSN attribute when making use of the olcSpCheckpoint option.
2.3.x. All five of the current ACLs, each one a value of an olcAccess attribute, will be deleted. For the sake of clarity, this will be done in reverse order, or else the index numbers used to match them would all have to be zero.
2.4.1. The first ACL, for accessing password information stored in the DIT, will be restored, but with added read access for all members of ou=consumers.
2.4.2. The second ACL, for access to the ou=krb5 subtree, will be restored, but with added read access for all members of ou=consumers.
2.4.3. The third ACL, for access to the loginShell attribute, will be restored unchanged.
2.4.4. The fourth ACL, to allow read access to the base of the tree for everyone, will be restored unchanged.
2.4.5. The fifth ACL − the default − will also be restored unchanged.
3. 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.
4. A new entry, olcOverlay={0}syncprov, will be added to the cn=config DIT to activate and configure the syncprov module.

To make both of the above changes to the cn=config DIT, first create an LDIF file on kls1, called ~/olc-mod3.ldif, with the following contents:

# 1.1.
dn: cn=config
changetype: modify
delete: olcAuthzRegexp
olcAuthzRegexp: {0}uid=([^,]+),cn=example.com,cn=gssapi,cn=auth
  uid=$1,ou=people,dc=example,dc=com
-
# 1.2.1.
add: olcAuthzRegexp
olcAuthzRegexp: uid=ldap/([^/\.]+).example.com,cn=example.com,cn=gssapi,cn=auth
  cn=$1,ou=consumers,dc=example,dc=com
-
# 1.2.2.
add: olcAuthzRegexp
olcAuthzRegexp: uid=([^,]+),cn=example.com,cn=gssapi,cn=auth
  uid=$1,ou=people,dc=example,dc=com

# 2.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# 2.2.
add: olcDbIndex
olcDbIndex: entryCSN eq
-
# 2.3.1.
delete: olcAccess
olcAccess: {4}to *
  by users read
  by * none
-
# 2.3.2.
delete: olcAccess
olcAccess: {3}to dn.base=""
  by * read
-
# 2.3.3.
delete: olcAccess
olcAccess: {2}to attrs=loginShell
  by self write
  by users read
  by * none
-
# 2.3.4.
delete: olcAccess
olcAccess: {1}to dn.subtree="ou=krb5,dc=example,dc=com"
  by dn="cn=adm-srv,ou=krb5,dc=example,dc=com" write
  by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" read
  by * none
-
# 2.3.5.
delete: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by anonymous auth
  by * none
-
# 2.4.1.
add: olcAccess
olcAccess: to attrs=userPassword,shadowLastChange
  by dn.one="ou=consumers,dc=example,dc=com" read
  by anonymous auth
  by * none
-
# 2.4.2.
add: olcAccess
olcAccess: to dn.subtree="ou=krb5,dc=example,dc=com"
  by dn="cn=adm-srv,ou=krb5,dc=example,dc=com" write
  by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" read
  by dn.one="ou=consumers,dc=example,dc=com" read
  by * none
-
# 2.4.3.
add: olcAccess
olcAccess: to attrs=loginShell
  by self write
  by users read
  by * none
-
# 2.4.4.
add: olcAccess
olcAccess: to dn.base=""
  by * read
-
# 2.4.5.
add: olcAccess
olcAccess: to *
  by users read
  by * none

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

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

See this section for an explanation of the last two modifications.

Apply the changes in the LDIF file on kls1 with this command:

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

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 index numbers have been added automatically to the RDNs for the syncprov overlay, as well as to the various olcAuthzRegexp and olcAccess attributes.

For some reason, despite the runtime configuration, the provider still has to be restarted at this point, or later on it will not properly map SASL-GSSAPI service principals to ou=consumers and consequently not allow the entire DIT (including the ou=krb5 subtree) to be replicated:

~# /etc/init.d/slapd restart
Starting OpenLDAP: slapd.
~# _

9. Kstart

Return to kls2. To keep its copy of the LDAP database in sync, the consumer must contact the provider and authenticate itself just like any other client. It has previously been shown how to do this with a simple bind and a password, but in this case Kerberos will be used to take care of both slapd consumer authentication to the provider and encryption of the entire replication process. To make this possible, an initial Kerberos ticket (a TGT) must be obtained automatically on behalf of the openldap user, which owns the slapd process, and it must be renewed regularly. One way to do this is to run kinit -k with a cron job, but a better solution is to use a modified version of kinit, called k5start. Install it with:

~# apt-get install kstart

This is the only package that gets installed as a result:

kstart                   3.16-3                     Kerberos kinit supporting AFS and ticket refreshing

To configure it, just add this one line to the end of the /etc/inittab file to start running k5start in the background soon after the system boots up:

KS:2345:respawn:/usr/bin/k5start -U -f /etc/krb5.keytab -K 10 -l 24h -k /tmp/krb5cc_105 -o openldap

A number of options have been used for this command:

-U Determine the principal to authenticate based on the first entry in the Kerberos keytab file. Must be used with the -f option.
-f /etc/krb5.keytab Specifies the full path of the Kerberos keytab file.
-K 10 Reawaken the daemon every 10 minutes to check if the ticket needs to be renewed.
-l 24h Set the ticket lifetime to 24 hours (to match the actual ticket lifetime used in this example).
-k /tmp/krb5cc_105 Use the file /tmp/krb5cc_105 as the ticket cache. The number at the end of the file name *must match* the UID (105 in this example) of the user on behalf of whom the ticket is maintained (see option -o). Otherwise this slapd server will not authenticate properly and the result will be a ldap_sasl_interactive_bind_s failed (-2) error.
-o openldap The name of the user account that is to become the owner of the ticket cache file (see option -k).

After saving this modification to /etc/inittab, start k5start for the first time by forcing init to reload its configuration file:

~# kill -HUP 1

A new ticket cache file, /tmp/krb5cc_105, should be created almost immediately as a consequence.


10. Slapd kerberization

Just as kls1 has already been configured to require Kerberos authentication for all LDAP communication over the network, so the same must now be done for kls2. A number of requirements have already been met, but there are still a few things left to do. First, install this one package:

~# apt-get install libsasl2-modules-gssapi-mit

Only one package is installed as a result with no dependencies:

libsasl2-modules-gssapi-mit       2.1.23.dfsg1-6                Cyrus SASL - pluggable authentication modules (GSSAPI)

Change the permissions and ownership of the Kerberos service keytab file to allow slapd to read it:

~# chmod 640 /etc/krb5.keytab
~# chown root.openldap /etc/krb5.keytab
~# _

Edit /etc/default/slapd and and uncomment a line near the end of the file that will export the location of the Kerberos system keytab file as a variable:

export KRB5_KTNAME=/etc/krb5.keytab

Edit /etc/ldap/ldap.conf and add the following line, which specifies the authentication mechanism, to the end of the file:

SASL_MECH GSSAPI

Last, a number of changes must be made to the root object of the LDAP configuration database on kls2. Here is its present state:

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

~# _

What follows is a list of changes that will be made to the LDAP runtime configuration on kls2:

1.1. For the root object, cn=config, an olcAuthzRegexp attribute will be added to act as a default, mapping the SASL-GSSAPI names of all authenticated users to names in ou=people, whether matching LDAP entries exist there or not.
1.2. An olcSaslRealm attribute will be added to specify the SASL realm, in this case a Kerberos realm.

To make the above changes to the slapd runtime configuration on kls2, create an LDIF file, called ~/olc-mod2.ldif, with the following contents:

# 1.1.
dn: cn=config
changetype: modify
add: olcAuthzRegexp
olcAuthzRegexp: uid=([^,]+),cn=example.com,cn=gssapi,cn=auth
  uid=$1,ou=people,dc=example,dc=com
-
# 1.2.
add: olcSaslRealm
olcSaslRealm: EXAMPLE.COM

All of the above changes have already been made to the LDAP runtime configuration on kls1, except that this server will not have an olcAuthzRegexp mapping for ou=consumers to support incoming connections from other servers.

Apply the changes in the LDIF file on kls2 with this command:

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

~# _

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

Because of the new software that has been added and the changes that have also been made outside of the slapd server, it must be restarted before they will all have the desired effect:

~# /etc/init.d/slapd restart
Stopping OpenLDAP: slapd.
Starting OpenLDAP: slapd.
~# _


11. Syncrepl

To enable syncrepl replication on kls2, some changes must be made to the slapd database definition. Here is what it looks like now:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config olcDatabase={1}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.subtree="ou=krb5,dc=example,dc=com" by dn="cn=adm-srv,ou=k
 rb5,dc=example,dc=com" read by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" read
  by * none
olcAccess: {2}to dn.base="" by * read
olcAccess: {3}to * by users read by * none
olcLastMod: TRUE
olcRootDN: cn=manager
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
olcDbIndex: krbPrincipalName eq,pres,sub

~# _

Only three changes will be made to the slapd database definition on kls2:

1.1. 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.2. Similarly, it is recommended to add an eq index for the entryCSN attribute when making use of the olcSpCheckpoint option.
1.3. The olcSyncrepl attribute will be added to configure the LDAP Sync Replication engine using SASL and GSSAPI.

To make the above changes to the slapd runtime configuration on kls2, create an LDIF file, called ~/olc-mod3.ldif, with the following contents:

# 1.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# 1.2.
add: olcDbIndex
olcDbIndex: entryCSN eq
-
# 1.3.
add: olcSyncrepl
olcSyncrepl: rid=123
  provider="ldap://kls.example.com:389/"
  type=refreshAndPersist
  retry="60 30 300 +"
  searchbase="dc=example,dc=com"
  bindmethod=sasl
  saslmech=gssapi

See this section for more information regarding the olcSyncrepl options used above.

Apply the changes in the LDIF file on kls2 with this command:

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

~# _

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

At this point, the consumer will already have synchronized its database with the provider. A quick slapcat will confirm this. However, the two copies of the database are not really in sync: the domain component and the admin user object (with password somalica) have not been replaced with their alter egos from the provider. To fix this, the consumer's database must resynchronized with the provider:

~# /etc/init.d/slapd stop
Stopping OpenLDAP: slapd.
~# rm /var/lib/ldap/*
~# /etc/init.d/slapd start
Starting OpenLDAP: slapd.
~# _

This will stop the LDAP service on kls2, delete its copy of the database and restart the service, at which point it will fetch a fresh copy from the provider. Run slapcat once more to see the difference.


12. Kerberos server start

Start the Kerberos slave KDC server for the first time:

~# /etc/init.d/krb5-kdc start
~# _

If there are no errors, run the following command to verify that the new MIT Kerberos V master server is indeed available on the network:

~# nmap -sU -p U:88 localhost

Starting Nmap 5.00 ( http://nmap.org ) at 2010-12-30 03:11 CET
Warning: Hostname localhost resolves to 2 IPs. Using 127.0.0.1.
Interesting ports on localhost (127.0.0.1):
PORT    STATE         SERVICE
88/udp  open|filtered kerberos-sec

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

On this slave KDC, only UDP port 88 needs to be available.


13. Authentication test

Run some tests. First try a simple unauthenticated (-x) LDAP query:

~# ldapsearch -x -LLL cn=kls2
No such object (32)
~# _

As on kls1, this no longer works. The authenticated version will also give an error:

~# ldapsearch -LLL cn=kls2
SASL/GSSAPI authentication started
ldap_sasl_interactive_bind_s: Local error (-2)
	additional info: SASL(-1): generic failure: GSSAPI Error: 
Unspecified GSS failure.  Minor code may provide more information 
(Credentials cache file '/tmp/krb5cc_0' not found)
~# _

Acquire a Kerberos ticket for the admin user (password ammodytes):

~# kinit admin
Password for admin@EXAMPLE.COM: ammodytes
~# _

A verification of the ticket should show a success:

~# klist
Ticket cache: FILE:/tmp/krb5cc_0
Default principal: admin@EXAMPLE.COM

Valid starting     Expires            Service principal
01/06/11 15:05:45  01/07/11 15:05:44  krbtgt/EXAMPLE.COM@EXAMPLE.COM
~# _

Now the authenticated version of the query should also work:

~# ldapsearch -LLL cn=kls2
SASL/GSSAPI authentication started
SASL username: admin@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
dn: cn=kls2,ou=consumers,dc=example,dc=com
cn: kls2
objectClass: simpleSecurityObject
objectClass: organizationalRole
description: LDAP server2 replicator

~# _

14. 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 kls2 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.subtree="ou=krb5,dc=example,dc=com" by dn="cn=adm-srv,ou=k
 rb5,dc=example,dc=com" read by dn="cn=kdc-srv,ou=krb5,dc=example,dc=com" read
  by * none
olcAccess: {2}to dn.base="" by * read
olcAccess: {3}to * by users read by * none
olcLastMod: TRUE
olcRootDN: cn=manager
olcSyncrepl: {0}rid=123 provider="ldap://kls.example.com:389/" type=refreshAnd
 Persist retry="60 30 300 +" searchbase="dc=example,dc=com" bindmethod=sasl sa
 slmech=gssapi
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
olcDbIndex: krbPrincipalName eq,pres,sub
olcDbIndex: entryUUID eq
olcDbIndex: entryCSN eq

~# _

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

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 their shell type. Unfortunately, although this is the preferred method, not all LDAP clients understand referrals. Therefore, it is a good idea to also 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. Some of its details are explained below.

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

# 1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcUpdateref
olcUpdateref: "ldap://kls.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://kls.example.com:389/"
olcDbRebindAsUser: TRUE
olcDbIDAssertBind: bindmethod=sasl
  saslmech=gssapi
  mode=self

Here, the olcDbIDAssertBind directive defines the parameters of the authentication method used by kls2 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 sasl authentication method is used, in which case the saslmech attribute is also required.
saslmech This option, for SASL mechanisms, can have any of a number of different values, depending on the authentication mechanism used. Here, gssapi is specified.
mode When the mode self is used, the client's identity will be asserted when a request is proxied.

Apply the above changes on kls2 with this command:

~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/olc-mod4.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.


15. Proxy authorization

Before the chaining configuration can work, more changes first have to be made to the OpenLDAP provider server, kls1.example.com. What is required is something called SASL proxy authorization. With this mechanism it is possible to allow an authenticated user, such as the consumer server in this example, to assume the identity 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 needed to enable proxy authorization. First, the cn=kls2 LDAP object must be modified to include two authzTo attributes, which will allow it to act as an authorization proxy for certain users. Second, an olcAuthzPolicy directive must be added to the cn=config DIT.

Start by creating an LDIF file on kls1, called ~/kls2-mod.ldif, with the following contents:

dn: cn=kls2,ou=consumers,dc=example,dc=com
changetype: modify
add: authzTo
authzTo: dn.regex:^uid=[^,]+,ou=people,dc=example,dc=com$

The authzTo attribute is a source rules that determines which user identities a consumer server is allowed to assume. In this case its value is a regular expression that matches all uid objects in the ou=people,dc=example,dc=com container.

Run the following command on kls1 to apply this modification:

root@kls1:~# ldapmodify -Qf ~/kls2-mod.ldif
modifying entry "cn=kls2,ou=consumers,dc=example,dc=com"

root@kls1:~# _

The second change to make involves modifying the root object of the cn=config DIT on kls1. Here is its current state:

~# ldapsearch -LLLQY EXTERNAL -H ldapi:/// -b cn=config cn=config
dn: cn=config
objectClass: olcGlobal
cn: config
olcArgsFile: /var/run/slapd/slapd.args
olcAuthzRegexp: {0}uid=ldap/([^/\.]+).example.com,cn=example.com,cn=gssapi,cn=
 auth cn=$1,ou=consumers,dc=example,dc=com
olcAuthzRegexp: {1}uid=([^,]+),cn=example.com,cn=gssapi,cn=auth uid=$1,ou=peop
 le,dc=example,dc=com
olcLogLevel: stats
olcPidFile: /var/run/slapd/slapd.pid
olcSaslRealm: EXAMPLE.COM
olcToolThreads: 1

~# _

The only change that needs to be made here is to add an olcAuthzPolicy attribute. Create an LDIF file on kls1, called ~/olc-mod4.ldif, with the following contents:

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

This statement enables proxy authorization using rules associated with the authzTo attribute of the authentication DN (in this case cn=kls2). Without this, the authzTo attribute that was added to the cn=kls2 entry would be ignored.

Apply this change to slapd on kls1 with this command:

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

~# _

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


16. 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. This exercise will also be used as an excuse to create a new user account. Start by using kadmin to create an account for a user bbeamon with password longjump:

~# kadmin -p admin
Authenticating as principal admin with password.
Password for admin@EXAMPLE.COM: ammodytes
kadmin:  addprinc bbeamon
WARNING: no policy specified for bbeamon@EXAMPLE.COM; defaulting 
to no policy
Enter password for principal "bbeamon@EXAMPLE.COM": longjump
Re-enter password for principal "bbeamon@EXAMPLE.COM": longjump
Principal "bbeamon@EXAMPLE.COM" created.
kadmin: q
~# _

Having completed that, the object is now to test the proxy authentication configuration by creating a matching LDAP user account for bbeamon. If this 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 ~/bbeamon.ldif, with the following contents:

dn: cn=bbeamon,ou=groups,dc=example,dc=com
cn: bbeamon
gidNumber: 20002
objectClass: top
objectClass: posixGroup

dn: uid=bbeamon,ou=people,dc=example,dc=com
uid: bbeamon
uidNumber: 20002
gidNumber: 20002
cn: Bob
sn: Beamon
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
homeDirectory: /home/bbeamon
userPassword: {CRYPT}*

Then apply this change with the ldapadd command:

~# ldapadd -Qf ~/bbeamon.ldif
adding new entry "cn=bbeamon,ou=groups,dc=example,dc=com"

adding new entry "uid=bbeamon,ou=people,dc=example,dc=com"

~# _

Once the change has been made, examine /var/log/syslog on kls1. It should look similar to this:

conn=1009 fd=25 ACCEPT from IP=192.168.2.41:53181 (IP=0.0.0.0:389)
conn=1009 op=0 BIND dn="" method=163
conn=1009 op=0 RESULT tag=97 err=14 text=SASL(0): successful result: 
conn=1009 op=1 BIND dn="" method=163
conn=1009 op=1 RESULT tag=97 err=14 text=SASL(0): successful result: 
conn=1009 op=2 BIND dn="" method=163
conn=1009 op=2 BIND authcid="ldap/kls2.example.com@EXAMPLE.COM" authzid="ldap/kls2.example.com@EXAMPLE.COM"
conn=1009 op=2 BIND dn="cn=kls2,ou=consumers,dc=example,dc=com" mech=GSSAPI sasl_ssf=56 ssf=56
conn=1009 op=2 RESULT tag=97 err=0 text=
conn=1009 op=3 PROXYAUTHZ dn="uid=admin,ou=people,dc=example,dc=com"
conn=1009 op=3 ADD dn="cn=bbeamon,ou=groups,dc=example,dc=com"
conn=1009 op=3 RESULT tag=105 err=0 text=
conn=1010 fd=27 ACCEPT from IP=192.168.2.41:53182 (IP=0.0.0.0:389)
conn=1010 op=0 BIND dn="" method=163
conn=1010 op=0 RESULT tag=97 err=14 text=SASL(0): successful result: 
conn=1010 op=1 BIND dn="" method=163
conn=1010 op=1 RESULT tag=97 err=14 text=SASL(0): successful result: 
conn=1010 op=2 BIND dn="" method=163
conn=1010 op=2 BIND authcid="ldap/kls2.example.com@EXAMPLE.COM" authzid="ldap/kls2.example.com@EXAMPLE.COM"
conn=1010 op=2 BIND dn="cn=kls2,ou=consumers,dc=example,dc=com" mech=GSSAPI sasl_ssf=56 ssf=56
conn=1010 op=2 RESULT tag=97 err=0 text=
conn=1010 op=3 PROXYAUTHZ dn="uid=admin,ou=people,dc=example,dc=com"
conn=1010 op=3 ADD dn="uid=bbeamon,ou=people,dc=example,dc=com"
conn=1010 op=3 RESULT tag=105 err=0 text=

This confirms that kls2 is using its Kerberos ID, ldap/kls2.example.com@EXAMPLE.COM, which is then translated by the olcAuthzRegexp statement on kls1 to cn=kls2,ou=consumers,dc=example,dc=com, which is then authorized to act as a proxy for uid=admin,ou=people,dc=example,dc=com, which in turn is allowed to add the new cn=bbeamon,ou=people,dc=example,dc=com entry.

For another confirmation of success, a search for uid=bbeamon should show that this entry has indeed been added to the DIT:

~# ldapsearch -LLL uid=bbeamon
SASL/GSSAPI authentication started
SASL username: admin@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
dn: uid=bbeamon,ou=people,dc=example,dc=com
uid: bbeamon
uidNumber: 20002
gidNumber: 20002
cn: Bob
sn: Beamon
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
homeDirectory: /home/bbeamon

~# _

Note that the password is not visible. The admin user may be authorized to add new user objects, passwords included, from kls2, but has no special priviliges on that host to view all of their contents. If the admin account is used to execute the same command on kls1, then the password will be shown.


17. Bug warning

Unfortunately, there is another bug in the current version of slapd for which there is, as yet, no patch. It only affects proxy authorization when using SASL binds together with the GSSAPI mechanism − replication is unaffected. With version 2.4.23-7, it may be possible to install the provider and a consumer and complete the above test successfully, but this good behavior is likely to cease later on, such as after rebooting one or both systems.

The problem is that, when the consumer authenticates to the provider, it inexplicably does so with a SIMPLE bind (method=128), instead of with SASL-GSSAPI (method=163). Consequently, no new objects can be added to the DIT from the consumer and the client returns with an error:

~# ldapadd -Qf mmiller.ldif
adding new entry "cn=mmiller,ou=groups,dc=example,dc=com"
ldap_add: Strong(er) authentication required (8)

~# _

Hopefully, a fix will become available soon. When it does, the instructions for applying it will be included here.


18. See also
19. Further reading
  • Eastlake D, Panitz A. 1999. RFC2606 − Reserved Top Level DNS Names. The Internet Society. 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.
  • Kohl J, Neuman C. 1993. RFC1510 − The Kerberos Network Authentication Service (V5). HTML at the Internet FAQ Archives.
  • Linn J. 2000. RFC2743 − Generic Security Service Application Program Interface Version 2, Update 1. The Internet Society. HTML at the Internet FAQ Archives.
  • Myers J. 1997. RFC2222 − Simple Authentication and Security Layer (SASL). 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.
  • Wray J. 2000. RFC2744 − Generic Security Service API Version 2 : C-bindings. 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.

20. Sources
  • Carter G. 2003. LDAP System Administration. O'Reilly & Associates, Inc. ISBN 1-56592-491-6. 294 pp.
  • Massachusetts Institute of Technology. 1985-2010. Kerberos V5 System Administrator's Guide. HTML at the Massachusetts Institute of Technology (MIT). See section Configuring Kerberos with OpenLDAP back-end.
  • Milicchio F, Gehrke WA. 2007. Distributed Services with OpenAFS. Springer-Verlag. ISBN-13 978-3-540-36633-1. 395 pp.
  • OpenLDAP Project. 2009. OpenLDAP Software 2.4 Administrator's Guide. HTML at OpenLDAP.
  • Ubuntu documentation. Ubuntu 9.04. Ubuntu Server Guide, Network Authentication, Kerberos and LDAP. HTML at the Ubuntu 9.04 Server Guide.


Last modified: 2017-08-02, 17:50

©2003-2020 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.