Exercise 4: build an LDAP server

This is by far the hardest part of the operation, due to the cryptic way OpenLDAP 2.4 now stores its configs within LDAP instead of in a config file. See man slapd-config

We are going to build an LDAP server with Base DN "dc=realm1,dc=ws,dc=nsrc,dc=org". Change this to match your own realm.

Install the slapd server and ensure everything else needed is present:

# apt-get install slapd ldap-utils libsasl2-modules-gssapi-mit

Set up the service principal with keytab readable by slapd:

# mkdir /etc/ldap/krb5
# kadmin -p student/admin
addprinc -randkey ldap/pc1.ws.nsrc.org
ktadd -k /etc/ldap/krb5/krb5.keytab ldap/pc1.ws.nsrc.org
^D
# chown -R openldap:openldap /etc/ldap/krb5
# chmod 550 /etc/ldap/krb5
# chmod 440 /etc/ldap/krb5/krb5.keytab
# editor /etc/default/slapd
...
export KRB5_KTNAME=/etc/ldap/krb5/krb5.keytab

# service slapd restart

Install the schemas we need:

# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/misc.ldif

NOTE: For a real production LDAP server, read the files in /usr/share/doc/slapd carefully, especially README.Debian.gz and README.DB_CONFIG.gz

Now we need to run some scripts - either paste directly to a root shell, or create in temporary files and then run them.

BEWARE: in LDIF files, superfluous spaces at the end of lines may cause attributes to be rejected as invalid!

First is create_database.sh

ldapadd -Y EXTERNAL -H ldapi:/// <<EOS
# Load hdb backend module
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module
olcModulepath: /usr/lib/ldap
olcModuleload: {0}back_hdb
EOS

ldapadd -Y EXTERNAL -H ldapi:/// <<EOS
# Create the hdb database and place the files under /var/lib/ldap
dn: olcDatabase={1}hdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcHdbConfig
olcDatabase: {1}hdb
olcDbDirectory: /var/lib/ldap
olcSuffix: dc=realm1,dc=ws,dc=nsrc,dc=org
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
olcLastMod: TRUE
olcDbCheckpoint: 512 30
olcDbIndex: uid pres,eq
olcDbIndex: cn,sn,mail pres,eq,approx,sub
olcDbIndex: objectClass eq
EOS

(Note: we have no olcRootDN or olcRootPW. This is a pure Kerberos config)

Next is init_database.sh

ldapadd -Y EXTERNAL -H ldapi:/// <<EOS
dn: dc=realm1,dc=ws,dc=nsrc,dc=org
objectClass: dcObject
objectclass: organization
o: ws.nsrc.org
dc: ws
description: LDAP root

dn: ou=People,dc=realm1,dc=ws,dc=nsrc,dc=org 
objectClass: top
objectClass: organizationalUnit
ou: People 

dn: ou=Groups,dc=realm1,dc=ws,dc=nsrc,dc=org
objectClass: top
objectClass: organizationalUnit
ou: Groups
EOS

And finally config.sh

# Because these are 'replace' operations it's safe to modify this script
# and re-run it
ldapmodify -Y EXTERNAL -H ldapi:/// <<EOS
dn: cn=config
replace: olcSaslSecProps
olcSaslSecProps: noanonymous,noplain,minssf=56

dn: olcDatabase={1}hdb,cn=config
replace: olcAccess
olcAccess: {0}to * by dn.regex="^uid=([^@,]+)/admin,cn=gssapi,cn=auth$" manage by users read
-
replace: olcRequires
olcRequires: SASL
EOS

The simple ACL says that full access is permitted to */admin principals in our realm, and otherwise read access is granted to any valid user (i.e. anyone with a kerberos ticket that we recognize). See OpenLDAP ITS#6757 for a note on the format of the auth DN.

We also require SASL, which disables anonymous and simple binds.

Note: minssf enforces encryption. GSSAPI always returns 56 for ssf, regardless of the strength of the actual crypto mechanism in use. See http://lists.andrew.cmu.edu/pipermail/cyrus-sasl/2006-September/000628.html

The following tweak disables unused sasl mechanisms, and means that -Y GSSAPI can be omitted form the ldapsearch command line.

# editor /etc/ldap/sasl2/slapd.conf
mech_list: gssapi external

Test LDAP

Update /etc/ldap/ldap.conf to point to your own LDAP server and base DN. Use ldapsearch to check that you can query it.

$ kinit testuser
$ ldapsearch [-Y GSSAPI] [-b "dc=realm1,dc=realm1,dc=ws,dc=nsrc,dc=org"]

This should dump back the (mostly empty) LDAP database, as long as you have a Kerberos ticket

Create user

We are going to create a user called "newuser"

Firstly in Kerberos:

$ kadmin -p student/admin
addprinc newuser
... choose a password
^D

And now in LDAP:

$ kinit student/admin
$ ldapadd <<EOS
dn: uid=newuser,ou=People,dc=ws,dc=nsrc,dc=org
objectClass: account
objectClass: posixAccount
cn: newuser
uid: newuser
uidNumber: 10000
gidNumber: 100
homeDirectory: /home/newuser
loginShell: /bin/bash
gecos: newuser
description: User account
EOS
$ kdestroy

Test NSS

Now update your LDAP nscd/nsswitch configuration (part 2 of exercise 2). You will need to edit /etc/ldap.conf with your own PC as LDAP server and your own Base DN. Restart nscd after doing this.

To verify all is working:

$ id newuser

You should see a result with the uid and gid. Repeated operations should be quick as nscd will be caching them.

Troubleshooting:

ldapscripts

There is a package called ldapscripts with simple tools for adding and managing LDAP users. Unfortunately it doesn't know about GSSAPI authentication, so you need to patch it. See ldapscripts-sasl.diff

Then configure it:

# editor /etc/ldapscripts/ldapscripts.conf
SASLAUTH="GSSAPI"
...
SERVER="ldap://pc1.ws.nsrc.org"
...
SUFFIX="dc=realm1,dc=ws,dc=nsrc,dc=org"

Then adding a new user in LDAP is as simple as:

$ kinit student/admin
$ ldapadduser someuser users
$ kdestroy

Adding groups and users into groups:

$ ldapaddgroup noc
$ ldapaddusertogroup someuser noc

You may need to restart nscd before 'id' shows this information.

Configure backup LDAP

OpenLDAP replication is left as an exercise to the reader.