OpenLdap with multiple domains

OpenLDAP or SLAPD, the heart of Zimbra authentication and Samba/AD. Not as easy as the click-er-die-click interface of Windows, but when set up correctly, just as powerful.

My headache came however when I wanted to host multiple domains or databases on the same server. One server that is the directory for and and maybe even, you get the drift.

Lesson one is to never to modify the /usr/share/slapd/slapd.conf file, configuration of OpenLdap is done through LDIF files and ldapadd.

Now the first thing we do is actually install OpenLdap and the Tools

apt-get install slapd ldap-utils
 mkdir /ldap
 chown -R openldap:openldap /ldap

Now if you already had OpenLdap/SlapD installed, purge and reinstall it like so

apt-get purge slapd ldap-utils --YES && wait
rm /var/lib/ldap/*
rm -rf /etc/ldap
rm -rf /ldap
apt-get install slapd ldap-utils
mkdir /ldap
chown -R openldap:openldap /ldap

The (re) installation will ask you for a password (from the dpkg-configure) I have not bothered to silence that yet.

You see the script made a folder /ldap and made openldap owner of that, since I don’t like to hide my databases somewhere in /var/lib

Next is to tell the AppArmor watchdog to leave our /LDAP folder alone

nano /etc/apparmor.d/usr.sbin.slapd 

and edit the section databases and logsto look like this

 # the databases and logs
 /var/lib/ldap/ r,
 /var/lib/ldap/** rwk,
 /ldap/ r,
 /ldap/** rwk,

And restart the Apparmor:

service apparmor restart

Now, the meat and potatoes, which I called all in one shell script file of course, but cut up a bit here to explain whats what.

PASS=$(slappasswd -s Supersecretpassword)
DATABASEID==$(ar=$(ls /etc/ldap/slapd.d/cn\=config/*{?}* | cut -d "{" -f2 | cut -d "}" -f1)&&nr=$(($(echo "${ar[*]}" | sort -nr | head -n1) + 1))&&echo $nr)

The variables, yes I know , clear text passwords, next time i’ll MD5 them. The database ID is the number of the DB. Get the currently used ones from  etc/ldap/slapd.d/cn\=config/*{?}* and a little bash magic adds one to the tally.

Now add the database folder and chown it to openldap, if it already exists the domain must already be created, so better stop there..

if [ ! -d /ldap/$DOMAINNAME-$DOMAINEXT ]; then
 chown -R openldap:openldap /ldap/$DOMAINNAME-$DOMAINEXT
 echo "Domain $DOMAINNAME.$DOMAINEXT exists, aborting"
 exit 1

Next up is construct the LDIF file with a simple cat << EOF >

cat << EOF > $TEMP/database.ldif
# Create directory database
dn: olcDatabase={$DATABASEID}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {$DATABASEID}hdb
olcDbDirectory: /ldap/$DOMAINNAME-$DOMAINEXT
olcRootDN: cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT
olcRootPW: $PASS
olcAccess: to attrs=userPassword 
 by dn="cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT" write 
 by anonymous auth 
 by self write 
 by * none
olcAccess: to attrs=shadowLastChange 
 by self write 
 by * read
olcAccess: to dn.base="" 
 by * read
olcAccess: to * 
 by dn="cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT" write 
 by * read
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: uid pres,eq
olcDbIndex: cn,sn,mail pres,eq,approx,sub
olcDbIndex: objectClass eq
# Modifications
dn: cn=config
changetype: modify
dn: olcDatabase={-1}frontend,cn=config
changetype: modify
delete: olcAccess
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootDN
olcRootDN: cn=admin,cn=config
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcRootPW
olcRootPW: $PASS
dn: olcDatabase={0}config,cn=config
changetype: modify
delete: olcAccess
Followed by the LDAPADD that imports the database 

ldapadd -Y EXTERNAL -H ldapi:/// -f $TEMP/database.ldif
rm $TEMP/database.ldif

Due to the unique way ldapadd reads config files, sometimes the olcAccess: class causes an ldap error 80. when this happens, make sure each line in the olcAccess class has a trailing space. 

Now it is time to fill the newly created database with a base structure. Same cat <<EOF there followed by another ldapadd

cat << EOF > $TEMP/dit.ldif
# Tree root
objectClass: dcObject
objectclass: organization
description: Tree root
# Populating
dn: cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
userPassword: $PASS
description: LDAP administrator
dn: ou=users,dc=$DOMAINNAME,dc=$DOMAINEXT
ou: users
objectClass: organizationalUnit
objectClass: top
dn: ou=groups,dc=$DOMAINNAME,dc=$DOMAINEXT
ou: groups
objectClass: organizationalUnit
objectClass: top
#Adding user
dn: uid=test,ou=users,dc=$DOMAINNAME,dc=$DOMAINEXT
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: test
sn: test
givenName: test
cn: test test
displayName: test test
uidNumber: 1002
gidNumber: 1000
userPassword: $PASS
gecos: test test
loginShell: /bin/bash
homeDirectory: /home/test
shadowExpire: -1
shadowFlag: 0
shadowWarning: 7
shadowMin: 8
shadowMax: 999999
shadowLastChange: 10877
postalCode: 31000
l: test
mobile: +852 12345678
homePhone: +852 12345678
title: test user
initials: tst
ldapadd -x -D cn=admin,dc=$DOMAINNAME,dc=$DOMAINEXT -W -f $TEMP/dit.ldif

Finally, for good measures  I normally add some certificates for the SSL authentication, I am assuming I do not need to explain how to create some SSL certs..

dn: cn=config
changetype: modify
add: olcTLSCipherSuite
olcTLSCipherSuite: NORMAL
add: olcTLSCRLCheck
olcTLSCRLCheck: none
add: olcTLSVerifyClient
olcTLSVerifyClient: never
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap-ca-cert.pem
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap-ca-key.pem

and apply with ldapadd

ldapadd -Y EXTERNAL -H ldapi:/// -f ssl.ldif

Now when all is quare and equal, you should have added a domain database. I use JXplorer to check if all is well, just connect into the cn=config for the full picture.

Next up is good old replication, but I’ll save that for another time..

Cest Ca.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s