Table of Contents

Overview

{auth, auth1, auth2, … authN}.offbyone.lan, .lair.lan, and .dslab.lan are the authentication servers in use in the BITS universe.

hostname RAM disk swap OS Kernel
auth1.offbyone.lan 128MB 2GB (/) 128MB Debian 6.0 “Squeeze” (AMD64) 2.6.32-5-xen-amd64
auth2.offbyone.lan 128MB 2GB (/) 128MB Debian 6.0 “Squeeze” (AMD64) 2.6.32-5-xen-amd64
auth3.lair.lan 128MB 2GB (/) 128MB Debian 6.0 “Squeeze” (AMD64) 2.6.32-5-xen-amd64

News

TODO

Xen Config

The Xen config files for one of the auth-class VMs follows:

auth1

auth1.offbyone.lan was created by running:

halfadder:~# xen-create-image --hostname=auth1 --mac 00:16:3E:3C:83:50 --role=udev

Its Xen configuration file is as follows:

##########################################################################
# LAIR Xen VM configuration file (auth1.offbyone.lan)
##########################################################################

#################################################
#  Kernel + memory size
#
bootloader  = '/usr/lib/xen-default/bin/pygrub'
vcpus       = '1'
memory      = '128'

#################################################
#  Disk device(s).
#
root        = '/dev/xvda1 ro'
disk        = [ 'file:/xen/images/auth1.disk,xvda1,w',
                'file:/xen/images/auth1.swap,xvda2,w'  ]

#################################################
#  Hostname
#
name        = 'auth1'

#################################################
#  Networking
#
dhcp        = 'dhcp'
vif         = [ 'mac=00:16:3E:3C:83:50' ]

#################################################
#  Behaviour
#
on_poweroff = 'destroy'
on_reboot   = 'restart'
on_crash    = 'restart'

Network Configuration

Machine Interface IP Address MAC Address Other Names
auth.offbyone.lan eth0 10.80.2.8 N/A
auth.lair.lan eth0 10.80.1.8 N/A
auth1.offbyone.lan eth0 10.80.2.9 00:16:3E:3C:83:50 auth1.lair.lan
auth2.offbyone.lan eth0 10.80.2.10 00:16:3E:3C:83:51 auth2.lair.lan
auth3.lair.lan eth0 10.80.1.11 00:16:3E:42:EE:4A auth3.offbyone.lan

Configuring LDAP (slapd)

The method followed here is derived (and heavily so) from the OpenLDAP provider on Debian Squeeze tutorial at http://www.rjsystems.nl/en/2100-d6-openldap-provider.php … Information here is summarized from that document and adapted to fit the LAIR/BITS environment.

Overview

LDAP services are provided via slapd. This used to be configured in a file known as /etc/ldap/slapd.conf, but with Debian Squeeze, the version of OpenLDAP used (2.4.23-7), configuration information is now stored in an LDAP database, and manipulated via the various LDAP command-line tools (think registry).

Because we are also interested in configuring replication and having multiple LDAP servers, these instructions will by default include such instructions.

One immediate benefit of this new structure is that slapd can remain running… we no longer need to shut it down to perform various operations.

Prerequisite packages

To verify correct operation and validate various aspects of operational success, we will start off by installing the following (on all auth machines):

configure for LAIR packages

We'll want to install lair-std and lair-vm, and likely eventually lrrd-node, so do the following on both auth's:

all_auth:~# echo "deb http://mirror/lair squeeze main" >> /etc/apt/sources.list
all_auth:~# aptitude update
...
all_auth:~# swapon /dev/xvda2
all_auth:~# aptitude install lair-std lair-vm ntp
...

All auth-class systems should now be at a good initial state.

Working with the Debian scripts: Setting the FQDN

lair-std seems to have a bug that prevents proper domain name formatting in /etc/hosts… until this is fixed, be sure to manually check /etc/hosts to ensure that all domain names are set, and properly.

Additionally, to make Debian's slapd install scripts bootstrap with the desired “dc”, we're going to intentionally add an extra domain. As a result, the correct /etc/hosts files on auth1 and auth2 should be as follows:

###LAIRCONF###
127.0.0.1       localhost.localdomain   localhost
10.80.2.38      lab46.corning-cc.edu    lab46.offbyone.lan  lab46.lair.lan  lab46
10.80.2.3       nfs.offbyone.lan        nfs
10.80.2.9       auth1.lair.bits         auth1.offbyone.lan  auth1
10.80.2.10      auth2.lair.bits         auth2.offbyone.lan  auth2
10.80.1.11      auth3.lair.bits         auth3.lair.lan      auth3

Once slapd is installed and running, we can remove the auth[12].lair.bits phrases.

Reboot

At this point, to ensure everything is in order, give both systems a reboot.

Install LDAP bits (normal)

Since we are going to serve LDAP, we'll now do the following:

all_auth:~# aptitude install slapd ldap-utils
...

There will be a prompt for an administrator password.

Install LDAP bits (consumer)

As it turns out, there's currently a bug in the OpenLDAP code, as shipped by both Debian and still residing within the vanilla OpenLDAP releases, that causes errors (even affecting the ability for slapd to run) when enabling the chaining functionality, as is the case with LDAP consumers.

For this reason, the Debian packages were manually rebuilt, and a patch applied which resolves this issue. Until the fix is officially provided by the Debian packages, we'll have to rely on these packages instead.

Either rebuild the packages from source (follow the directions in the rjsystems.nl tutorial) or grab an existing copy from other prior efforts.

So instead of installing slapd and ldap-utils above, we'll instead want to do this:

auth_consumer:~# aptitude install libsasl2-2 libltdl7 libperl5.10 libslp1 unixodbc
...
auth_consumer:~# dpkg -i ldap-utils_2.4.23-7patched1_amd64.deb libldap-2.4-2_2.4.23-7patched1_amd64.deb slapd_2.4.23-7patched1_amd64.deb
...

Result of successful LDAP installation

Following the installation, we can check to make sure everything is in order. The intent is to use “dc=lair,dc=bits” for our LDAP database, so let's see if our hack to /etc/hosts has paid off:

all_auth:~# slapcat
hdb_db_open: database "dc=lair,dc=bits": unclean shutdown detected; attempting recovery.
hdb_db_open: database "dc=lair,dc=bits": recovery skipped in read-only mode. Run manual recovery if errors are encountered.
dn: dc=lair,dc=bits
objectClass: top
objectClass: dcObject
objectClass: organization
o: lair.bits
dc: lair
structuralObjectClass: organization
entryUUID: fadb154e-a654-102f-9d47-4b2dc132a5e2
creatorsName: cn=admin,dc=lair,dc=bits
createTimestamp: 20101227223249Z
entryCSN: 20101227223249.652609Z#000000#000#000000
modifiersName: cn=admin,dc=lair,dc=bits
modifyTimestamp: 20101227223249Z

dn: cn=admin,dc=lair,dc=bits
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword:: e1NTSEF9VG1LV2FDK1QxVkNTSk16MGlCWUQxTnVuOHFkeXdyTEU=
structuralObjectClass: organizationalRole
entryUUID: fadb71d8-a654-102f-9d48-4b2dc132a5e2
creatorsName: cn=admin,dc=lair,dc=bits
createTimestamp: 20101227223249Z
entryCSN: 20101227223249.654994Z#000000#000#000000
modifiersName: cn=admin,dc=lair,dc=bits
modifyTimestamp: 20101227223249Z

all_auth:~# 

If you see any “dc=nodomain” or things other than “dc=lair,dc=bits” (or the desired name), then you'll likely want to remove (purge), twiddle settings, and reinstall slapd until this becomes correct.

With further LDAP knowledge and experience, this could likely be fixed with a customized ldif file.

Configure /etc/ldap/ldap.conf

Hook up the rest of the system with our new LDAP service:

auth1

BASE    dc=lair,dc=bits
URI     ldap://auth1.offbyone.lan/

auth2

BASE    dc=lair,dc=bits
URI     ldap://auth2.offbyone.lan/

Remove auth[12].lair.bits from /etc/hosts

Before we go any further, we should remove the hack we put in place to facilitate (trick) the Debian installation scripts into giving us precisely what we want. It would of course been easier had we just used our default domain, but since the LAIR runs 3 different domains, and the long-term intent is to hook up the authentication domains at all BITS endpoints, I opted to adopt the .bits “domain” for authentication services.

So, go and edit /etc/hosts on BOTH auth's, and remove the reference to .lair.bits. The resulting file should look like this:

###LAIRCONF###
127.0.0.1       localhost.localdomain   localhost
10.80.2.8       auth.offbyone.lan       auth.lair.lan       auth
10.80.2.38      lab46.corning-cc.edu    lab46.offbyone.lan  lab46.lair.lan  lab46
10.80.2.3       nfs.offbyone.lan        nfs
10.80.2.9       auth1.offbyone.lan      auth1
10.80.2.10      auth2.offbyone.lan      auth2

Configure LDAP provider (auth1)

Tweak settings in cn=config

To aid in debugging, the rjsystems.nl tutorial has us apply the following changes (I put in a file called olc1.ldif):

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

# 2.1.
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: uid eq
-
# 2.2.
add: olcDbIndex
olcDbIndex: cn eq
-
# 2.3.
add: olcDbIndex
olcDbIndex: ou eq
-
# 2.4.
add: olcDbIndex
olcDbIndex: dc eq

We then apply it as follows:

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

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

auth1:~# 

Because we're on the machine running the server, we can “get around” the need for authentication to make changes here to cn=config (which would make sense– why would we want to allow modifications to cn=config over the network?).

Push LDAP tree structure to LDAP database

We'll now push the initial structure we'd like to maintain in our LDAP tree.

Create structure

To do this, we need the information in an ldif file (see structure.ldif):

dn: ou=people,dc=lair,dc=bits
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=lair,dc=bits
objectClass: organizationalUnit
ou: groups

dn: ou=hosts,dc=lair,dc=bits
objectClass: organizationalUnit
ou: hosts

Add structure to database

With which we can use ldapadd to place it in our database:

auth1:~# ldapadd -xWD cn=admin,dc=lair,dc=bits -f structure.ldif
Enter LDAP Password: <LDAP admin password>
adding new entry "ou=people,dc=lair,dc=bits"

adding new entry "ou=groups,dc=lair,dc=bits"

adding new entry "ou=hosts,dc=lair,dc=bits"

auth1:~# 

Migrate LDAP user data

With the database in an amenable format to support our data, we will now transition our existing LDAP user data into the new one.

There are some mild format changes that need to take place, in addition to some additions and deletions of data.

Dump existing LDAP database into LDIF

Hopping onto auth (the current LDAP server), we will obtain a copy of the LDAP database as follows:

auth:~# ldapvi --out --discover -D "cn=admin,dc=lair,dc=lan" > ldapdb.ldif

--- Login
Type M-h for help on key bindings.

Filter or DN: cn=admin,dc=lair,dc=lan
    Password: <LDAP admin password>
auth:~# 

This will produce a file in the current directory called ldapdb.ldif.

Remove unnecessary entries

There are some entries in this LDIF that are not needed (due to the fact they already exist in the new LDAP database).

Specifically, we want to remove the following from the top of the file:

dn: dc=lair,dc=lan
objectClass: top
objectClass: dcObject
objectClass: organization
o: lair_lan
dc: lair
 
dn: cn=admin,dc=lair,dc=lan
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
userPassword: {SSHA}kjsdhfjksdf/sdlfkjsdf+223kKOA
 
dn: ou=People,dc=lair,dc=lan
ou: People
objectClass: organizationalUnit
 
dn: ou=Group,dc=lair,dc=lan
ou: Group
objectClass: organizationalUnit

Because we've already defined our distinguished name, admin is there, and we've just added our ou's for people and groups.

So just remove this data.

This will leave us starting with the lair group.

remove replica

We'll also want to remove the 'replica' object, which was used in the old LDAP replication. We'll be creating a new object to perform this functionality.

So search for and remove the following lines:

dn: cn=replica,dc=lair,dc=bits
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: replica
description: LDAP replicator
userPassword: {SSHA}sdjkfhWadsFSdg+hs/a4

Change spelling and dc data

Now on to some substitutions (doesn't have to be done on old auth… we can copy our file somewhere and perform the changes):

auth:~# cat ldapdb.ldif | sed 's/dc=lan/dc=bits/g' \
> | sed 's/ou=Group/ou=groups/g' | sed 's/ou=People/ou=people/g' \                  # correct our ou's
> | sed 's/^objectClass: account/objectClass: top\nobjectClass: person/g' \         # fix objectClasses
> | sed 's/^cn: \([a-zA-z]*\) \([a-zA-Z]*\)$/cn: \1\nsn: \2/g' \                    # cn/sn fix 1 (first/last)
> | sed 's/^cn: \([a-zA-z]*\) \([a-zA-Z]\.\) \([a-zA-Z]*\)$/cn: \1 \2\nsn: \3/g' \  # cn/sn fix 2 (initials)
> | sed 's/^cn: \([a-zA-z]*\) \([a-zA-Z]*\) \([a-zA-Z]*\)$/cn: \1\nsn: \2 \3/g' \   # cn/sn fix 3 (3 words)
> | sed 's/^objectClass: posixGroup/objectClass: top\nobjectClass: posixGroup/g' \  # fix group objectClasses
> | sed '/^shadowLastChange/d' | sed '/^host: /d' > ldapdbnew.ldif                  # remove unneeded things
auth:~# 

A few accounts will be pruned by hand (since there are so few of these exceptions that don't warrant a regex).

When done with pruning, be sure the resultant file is copied over to auth1.

Commit LDAP user data to new LDAP database

Time to add the data to our new database:

auth1:~# ldapadd -cxWD cn=admin,dc=lair,dc=bits -f ~/ldapdbnew.ldif
Enter LDAP Password: <LDAP admin password>
adding new entry "cn=lair,ou=groups,dc=lair,dc=bits"

adding new entry "uid=wedge,ou=people,dc=lair,dc=bits"

adding new entry "uid=ian,ou=people,dc=lair,dc=bits"

adding new entry "uid=squirrel,ou=people,dc=lair,dc=bits"
...
auth:~# 

Any errors in the entry, and that account would not be added. Luckily, we can just scan the output of the ldapadd to look for errors, make the appropriate corrections, and run the command again (we'll then get a bunch of “ldap_add: Already exists (68)” messages, but these are harmless) to add the corrected entries.

Test/Verify data

Once the data is added, we can do some quick checks to ensure it is there and works.

Does 'wedge' exist?

auth1:~# ldapsearch -xLLL uid=wedge
dn: uid=wedge,ou=people,dc=lair,dc=bits
uid: wedge
cn: Matthew
sn: Haas
objectClass: top
objectClass: person
objectClass: posixAccount
objectClass: shadowAccount
loginShell: /bin/bash
uidNumber: 1020
gidNumber: 1000
homeDirectory: /home/wedge
gecos: Matthew Haas

auth1:~# 

Check.

User Authentication

Can 'wedge' authenticate and verify its identity?

auth:~# ldapwhoami -xD uid=wedge,ou=people,dc=lair,dc=bits -W
Enter LDAP Password: <wedge LDAP password>
dn:uid=wedge,ou=people,dc=lair,dc=bits
auth1:~# 

Also good.

Initial LDAP install complete

At this point, LDAP (via slapd) should be installed and running.

LDAP Consumers (auth2 and auth3)

The method followed here is derived (and heavily so) from the OpenLDAP consumer on Debian Squeeze tutorial at http://www.rjsystems.nl/en/2100-d6-openldap-consumer.php … Information here is summarized from that document and adapted to fit the LAIR/BITS environment.

With a basic slapd database on auth2 and auth3, and a fully functional LDAP server on auth1, we will be moving to configure auth2 and auth3 as an LDAP consumers (slave servers), so we'll have some level of redundancy/availability of LDAP services in the LAIR.

Create replicator object

As in our past replicating instantiations, we need an LDAP object to bind as to perform the synchronization activities.

The aim is to have an LDAP consumer in both the offbyone.lan and lair.lan domains, so we'll end up with an auth2 and auth3 VM. For our purposes we'll create objects called auth2repl and auth3repl, which need to be added to the existing LDAP database on auth1.

Its LDIF is as follows:

dn: cn=auth2repl,dc=lair,dc=bits
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: authrepl
description: LDAP auth2 replicator
userPassword: chosen_password
-
dn: cn=auth3repl,dc=lair,dc=bits
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: authrepl
description: LDAP auth3 replicator
userPassword: chosen_password

And then to add it to the database (note we're on auth1):

auth1:~# ldapadd -cxWD cn=admin,dc=lair,dc=bits -f ~/authrepl.ldif 
Enter LDAP Password: <LDAP admin password>
adding new entry "cn=auth2repl,dc=lair,dc=bits"

adding new entry "cn=auth3repl,dc=lair,dc=bits"

auth1:~# 

Configure syncrepl on auth1

Also as in prior LDAP synchronization attempts, we'll be making use of the syncrepl functionality. The LDIF to provide this functionality is as follows (I put in a file called syncrepl.ldif:

# Remove olcAccess ACL (since it only allows admin to write)
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=lair,dc=bits" write
  by * none
-
# Add it back in, only also add in the ability for the authrepl object to read data
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by self write
  by dn="cn=admin,dc=lair,dc=bits" write
  by dn="cn=auth2repl,dc=lair,dc=bits" read
  by dn="cn=auth3repl,dc=lair,dc=bits" read
  by anonymous auth
  by * none
-
# add new indexing option
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# avoid verbose logs later through optimization
add: olcDbIndex
olcDbIndex: uid,uidNumber,gidNumber,memberUid,uniqueMember,objectClass,cn eq
-
# add another indexing option
add: olcDbIndex
olcDbIndex: entryCSN eq

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

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

And then adding it (on auth1):

auth1:~# ldapmodify -QY EXTERNAL -H ldapi:/// -f ~/syncrepl.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"

auth1:~# 

Configure syncrepl on auth2

Now that auth1 has been configured to be a provider, we now turn to configuring auth2 to act as an LDAP consumer.

We'll need to apply some information to the LDAP database on auth2, the LDIF (replconsume.ldif):

# for debugging purposes, crank up logging on auth2
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: stats

# remove the current olcAccess {0} ACL
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=lair,dc=bits" write
  by * none
-
# set the olcAccess {0} ACL
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange
  by anonymous auth
  by * none
-
# remove the {2} olcAccess ACL
delete: olcAccess
olcAccess: {2}to *
  by self write
  by dn="cn=admin,dc=lair,dc=bits" write
  by * read
-
# alter the olcAccess ACL
add: olcAccess
olcAccess: {2}to *
  by * read
-
# replace olcRootDN
replace: olcRootDN
olcRootDN: cn=manager
-
# remove olcRootPW
delete: olcRootPW
-
# indexing option (by entryCSN)
add: olcDbIndex
olcDbIndex: entryCSN eq
-
# indexing option (by entryUUID)
add: olcDbIndex
olcDbIndex: entryUUID eq
-
# indexing option (by uid)
add: olcDbIndex
olcDbIndex: uid eq
-
# indexing option (by cn)
add: olcDbIndex
olcDbIndex: cn eq
-
# indexing option (by ou)
add: olcDbIndex
olcDbIndex: ou eq
-
# indexing option (by dc)
add: olcDbIndex
olcDbIndex: dc eq
-
# syncrepl definition (who are we synchronizing with)
add: olcSyncrepl
olcSyncrepl: rid=102
  provider="ldap://auth1.offbyone.lan:389/"
  type=refreshAndPersist
  retry="60 30 300 +"
  searchbase="dc=lair,dc=bits"
  bindmethod=simple
  binddn="cn=auth2repl,dc=lair,dc=bits"
  credentials=chosen_password

And add it to the LDAP database on auth2:

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

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

auth2:~# 

prep auth2 for synchronization

Because there is default data residing in the LDAP database on auth2, we'll want to clear it out before engaging in full replication activities.

Shut down slapd on auth2, remove the LDAP database, and restart:

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

potential problem

After resuming slapd operations, I noticed the following appear in the logs:

Dec 30 18:20:31 auth2 slapd[1232]: do_syncrep2: rid=123 LDAP_RES_SEARCH_RESULT (4) Size limit exceeded 
Dec 30 18:20:31 auth2 slapd[1232]: do_syncrep2: rid=123 (4) Size limit exceeded 
Dec 30 18:20:31 auth2 slapd[1232]: do_syncrepl: rid=123 rc -2 retrying (29 retries left)

As it turns out, because we're not binding as an admin user, there are limits applied, and with the full size of the LAIR LDAP database, we easily exceed those default limits.

So what we'll need to do is disable those limits.

The following LDIF file (size.ldif) applied to the LDAP database on auth1 should do the trick:

# fix "Size limit exceeded" message in logs
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcLimits
olcLimits: dn.exact="cn=auth2repl,dc=lair,dc=bits" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
-
add: olcLimits
olcLimits: dn.exact="cn=auth3repl,dc=lair,dc=bits" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
auth1:~# ldapmodify -Y external -H ldapi:/// -f ~/size.ldif 
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={1}hdb,cn=config"

auth1:~# 

This appears to have resolved the problem.

Relocating LDAP database

Getting a sense of success with the recent LDAP efforts, certain actions should be taken to prepare the way for replication with other BITS peers.

The one big thing that will need to happen is the relocation of LDAP data to a specific directory– /var/lib/ldap/lair for LAIR LDAP, /var/lib/ldap/dslab for DSLAB LDAP, etc.

We'll handle this change on auth2 since it is more expendable in the case of a problem.

First up, the LDIF that will change the location of the LDAP database (dbdir.ldif):

# change where the LDAP database is located
dn: olcDatabase={1}hdb,cn=config
changetype: modify
delete: olcDbDirectory
-
add: olcDbDirectory
olcDbDirectory: /var/lib/ldap/lair

And then, prepping auth2 and actually performing the change:

auth2:~# mkdir /var/lib/ldap/lair /var/lib/ldap/dslab
auth2:~# chown openldap:openldap /var/lib/ldap/lair
auth2:~# chown openldap:openldap /var/lib/ldap/dslab
auth2:~# ldapmodify -Y external -H ldapi:/// -f ~/dbdir.ldif 
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "olcDatabase={1}hdb,cn=config"

auth2:~# /etc/init.d/slapd stop
Stopping OpenLDAP: slapd.
auth2:~# rm -f /var/lib/ldap/*
rm: cannot remove `dslab': Is a directory
rm: cannot remove `lair': Is a directory
auth2:~# /etc/init.d/slapd start
Starting OpenLDAP: slapd.
auth2:~# 

If we now check, /var/lib/ldap/ should be free of LDAP database files, whereas /var/lib/ldap/lair should now be populated with the files (in fact it will have transferred all the data fresh from auth1).

Success!

Referrals

Right now, replication has established a provider and consumer… they both contain complete replicas of the LAIR LDAP database. But as it is, the provider (auth1) is the only resource that can commit writes, although both can read.

So when the various LAIR LDAP clients are configured, they'll have free selection over either auth1 or auth2, but if they reach auth2 and need to perform a write, we'll need to rig up some functionality so this will succeed.

What we want to rig up are LDAP referrals. Basically, what that will do is forward the write request from auth2 to auth1, enabling the action to go through despite auth2's inability to write.

The beauty is, the end client should notice no difference whether they are communicating with auth2 or auth1… it should just work.

Here is the LDIF (referral.ldif):

# set referral host
dn: olcDatabase={1}hdb,cn=config
changetype: modify
add: olcUpdateref
olcUpdateref: "ldap://auth1.offbyone.lan:389/"

# load module for referring/chaining
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: {1}back_ldap

# configuring chaining, which will force chasing of referrals
dn: olcOverlay=chain,olcDatabase={-1}frontend,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcChainConfig
olcOverlay: {0}chain
olcChainReturnError: TRUE

# more chaining configuration (to enable proxy-like behavior)
dn: olcDatabase=ldap,olcOverlay={0}chain,olcDatabase={-1}frontend,
 cn=config
changetype: add
objectClass: olcLDAPConfig
objectClass: olcChainDatabase
olcDatabase: {0}ldap
olcDbURI: "ldap://auth1.offbyone.lan:389/"
olcDbRebindAsUser: TRUE
olcDbIDAssertBind: bindmethod=simple
  binddn="cn=auth2repl,dc=lair,dc=bits"
  credentials=chosen_password
  mode=self

and adding it (we're on auth2):

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

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

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

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

auth2:~# 

Referral/Proxy authorization

The last step that needs to take place is to establish the proper authorization on auth1 so that it knows to trust these incoming connections from auth2 (since it'll be using the auth2repl/auth3repl objects).

So, we'll start on auth1… first file up is authorize.ldif:

# Enable ability for authrepl to proxy
dn: cn=auth2repl,dc=lair,dc=bits
changetype: modify
add: authzTo
authzTo: {0}dn.regex:^uid=[^,]+,ou=people,dc=lair,dc=bits$
authzTo: {1}dn.exact:cn=admin,dc=lair,dc=bits

And to add it:

auth1:~# ldapmodify -xWD "cn=admin,dc=lair,dc=bits" -f ~/authorize.ldif 
Enter LDAP Password: 
modifying entry "cn=auth2repl,dc=lair,dc=bits"

auth1:~# 

Finally, in a file called policy.ldif, we have the following, which enables acceptance of proxy requests:

# Enable proxy access
dn: cn=config
changetype: modify
add: olcAuthzPolicy
olcAuthzPolicy: to

Then to add it:

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

auth1:~# 

At this point, proxy access should be working! A write to auth2 should be properly forwarded and processed by auth1.

LDAP client connectivity

Due to the various structure changes to the LDAP database, there are some changes required to accomplish client LDAP access in the LAIR.

To facilitate matters, I have updated the lair-ldap package.. doing an “aptitude update” then upgrade or direct install of lair-ldap will bring it in… it is tested and known working with etch, lenny, and squeeze systems.

Here will be a breakdown of the various files and their settings needed to establish proper LDAP client access.

/etc/ldap/ldap.conf

###LAIRCONF###                                                                            
#
# $OpenLDAP: pkg/ldap/libraries/libldap/ldap.conf,v 1.9 2000/09/04 19:57:01 kurt Exp $
#
# LDAP Defaults
#

BASE    dc=lair,dc=bits
URI     ldap://auth1 ldap://auth2 ldap://auth3

/etc/pam_ldap.conf

###LAIRCONF###                                                                            
#
# @(#)$Id: ldap.conf,v 1.36 2005/03/23 08:29:59 lukeh Exp $
#
# This is the configuration file for the LDAP nameservice
# switch library and the LDAP PAM module.
#

base                dc=lair,dc=bits
uri                 ldap://auth1 ldap://auth2 ldap://auth3
ldap_version        3

pam_password exop

nss_base_passwd     ou=people,dc=lair,dc=bits?one
#nss_base_passwd        ou=People,dc=dslab,dc=lan?one
#nss_base_passwd        ou=People,dc=sunyit,dc=lan?one

nss_base_shadow     ou=people,dc=lair,dc=bits?one
#nss_base_shadow        ou=People,dc=dslab,dc=lan?one
#nss_base_shadow        ou=People,dc=sunyit,dc=lan?one

nss_base_group      ou=groups,dc=lair,dc=bits?one
#nss_base_group     ou=Group,dc=dslab,dc=lan?one
#nss_base_group     ou=Group,dc=sunyit,dc=lan?one

/etc/libnss_ldap.conf

###LAIRCONF###                                                                            
#
# @(#)$Id: ldap.conf,v 2.47 2006/05/15 08:13:44 lukeh Exp $
#
# This is the configuration file for the LDAP nameservice
# switch library and the LDAP PAM module.
#

base                dc=lair,dc=bits
ldap_version        3
uri                 ldap://auth1 ldap://auth2 ldap://auth3

bind_policy         soft

nss_base_passwd     ou=people,dc=lair,dc=bits?one
#nss_base_passwd        ou=People,dc=dslab,dc=lan?one
#nss_base_passwd        ou=People,dc=sunyit,dc=lan?one

nss_base_shadow     ou=people,dc=lair,dc=bits?one
#nss_base_shadow        ou=People,dc=dslab,dc=lan?one
#nss_base_shadow        ou=People,dc=sunyit,dc=lan?one

nss_base_group      ou=groups,dc=lair,dc=bits?one
#nss_base_group     ou=Group,dc=dslab,dc=lan?one
#nss_base_group     ou=Group,dc=sunyit,dc=lan?one

/etc/nsswitch.conf

###LAIRCONF###                                                                            
#
# /etc/nsswitch.conf
#
passwd:         files [SUCCESS=return] ldap
group:          files [SUCCESS=return] ldap
shadow:         files [SUCCESS=return] ldap

hosts:          files dns 
networks:       files

protocols:      files
services:       files
ethers:         files
rpc:            files

netgroup:       files

/etc/pam.d/common-account

###LAIRCONF###                                                                            
#
# /etc/pam.d/common-account - authorization settings common to all services
#

# try password file first, then ldap
account [success=2 new_authtok_reqd=done default=ignore]    pam_unix.so
account [success=1 default=ignore]                          pam_ldap.so
account requisite                                           pam_deny.so
account required                                            pam_permit.so

/etc/pam.d/common-auth

###LAIRCONF###                                                                            
#
# /etc/pam.d/common-auth - authentication settings common to all services
#

# try password file first, then ldap
auth    [success=2 default=ignore]  pam_unix.so nullok_secure   try_first_pass
auth    [success=1 default=ignore]  pam_ldap.so use_first_pass
auth    requisite                   pam_deny.so
auth    required                    pam_permit.so

/etc/pam.d/common-password

###LAIRCONF###                                                                            
#
# /etc/pam.d/common-password - password-related modules common to all services
#

# try password files first, then ldap. enforce use of very strong passwords.
password    [success=2 default=ignore]                  pam_unix.so obscure sha512
password    [success=1 user_unknown=ignore default=die] pam_ldap.so try_first_pass
password    requisite                                   pam_deny.so
password    required                                    pam_permit.so

NOTE: if the option use_authtok is present, especially on the line for pam_ldap.so, users will be able to log in, but a failure will take place when a write action to LDAP records occurs, such as in changing passwords. Removal of use_authtok will resolve this problem.

/etc/pam.d/common-session

###LAIRCONF###                                                                            
#
# /etc/pam.d/common-session - session-related modules common to all services
#
session [default=1] pam_permit.so
session requisite   pam_deny.so
session required    pam_permit.so
session required    pam_unix.so
session optional    pam_ldap.so

LDAP client access

Prior to this LDAP update, we accomplished access to machines via the host: attribute stored in each user's LDAP entry. This functionality wasn't enabled this time around, so we're resorting to another method.

To control access to the systems, /etc/pam.d/sshd and /etc/security/access.conf are configured:

/etc/pam.d/sshd

The default file has everything we need, just uncomment the following line:

account    required    pam_access.so

/etc/security/access.conf

Depending on the level of access, we'll want to add a line like the following to this file:

-:ALL EXCEPT root lair:ALL EXCEPT LOCAL

What this line does is exclude access to anyone not root or in the lair group (we can add additional usernames or groups to this list to enable access.

slapd cn=config tweaks

Change slapd log level

To alter the level or type of information that slapd reports, we adjust the olcLogLevel attribute in the cn=config tree.

This can be done as follows:

auth1:~# ldapmodify -Y external -H ldapi:/// <<EOF
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: sync none
EOF

Where olcLogLevel's old value is replaced with the new (in this case, sync and none).

We actually have a logical OR going on here to report this. The possible logging levels available are:

int hex and symbol description
0 (0x0) logging is disabled
1 (0x1 trace) trace function calls
2 (0x2 packets) debug packet handling
4 (0x4 args) heavy trace debugging (function args)
8 (0x8 conns) connection management
16 (0x10 BER) print out packets sent and received
32 (0x20 filter) search filter processing
64 (0x40 config) configuration file processing
128 (0x80 ACL) access control list processing
256 (0x100 stats) stats log connections/operations/results
512 (0x200 stats2) stats log entries sent
1024 (0x400 shell) print communication with shell backends
2048 (0x800 parse) entry parsing
16384 (0x4000 sync) LDAPSync replication
32768 (0x8000 none) only messages that get logged whatever log level is set

Source of Information

(uniqueMember) not indexed

auth1 was spewing into the logs the following quite often:

Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed 
Dec 29 09:22:30 auth1 slapd[1236]: <= bdb_equality_candidates: (uidNumber) not indexed

I resolved it by doing the following:

auth1:~# ldapmodify -Y external -H ldapi:/// <<EOF
dn: olcDatabase={1}hdb,cn=config
changetype: modify
replace: olcDbIndex 
olcDbIndex: uid,uidNumber,gidNumber,memberUid,uniqueMember,objectClass,cn eq
EOF

This appeared to immediately resolve the problem.

Source of Information

Viewing slapd settings

It will likely be desired to view the settings in place on slapd, especially if we wish to change them, we need to know how to identify what we wish to change.

The following will perform a dump (to STDOUT) of the cn=config database:

auth1:~# slapcat -b cn=config | less

We can then do a search for what it is we are interested in “dn: cn=config”, “dn: olcDatabase={1}hdb,cn=config”, “dn: olcOverlay={0}syncprov,olcDatabase={1}hdb,cn=config”, etc.

Packages

At the end of the configuration process, the following packages have been installed on auth{1,2}:

References

Most Influential

Kerberos and LDAP (Debian Lenny)

LDAP documentation

PAM configuration

Debian-specific information

Setting up LDAP

Configuring cn=config

Replication