Install Openldap From Source And Configure Multi-Master Replication

Author: Nitin Bhadauria
Version: 1.0

Going forward to my previous document on setting up a Qmail Server with Openldap, I am now sharing a doc on how we can set up an Openldap in multi-master replication mode. So If you want more than one ldap-server for redundancy here we go:

 

1 Preliminary Note

In this tutorial I will use two demo servers, just to make steps simple, But you can replicate the same setup on more then two servers.

server1.example.com: IP address 192.168.0.100
server2.example.com: IP address 192.168.0.101

Because we will run all the steps from this tutorial with root privileges, you can either pretend all commands in this tutorial with the string sudo, or we become root right now by typing:

sudo su

Two servers should be able to resolve the other systems' hostnames. If this cannot be done through DNS, you should edit the /etc/hosts file so that it looks as follows on all three systems:

vi /etc/hosts
127.0.0.1      localhost.localdomain   localhost
192.168.0.100  server1.example.com     server1
192.168.0.101  server2.example.com     server2
 

 

2 Prerequisites

a. Before compiling we will install some dependencies:

yum install libacl-devel libblkid-devel gnutls-devel readline-devel python-devel autoconf gcc-c++ gcc glibc-devel glibc-headers kernel-headers libgomp libstdc++-devel openssl-devel e2fsprogs-devel keyutils-libs-devel krb5-devel libselinux-devel libsepol-devel libtool-ltdl-devel

b. Before installing Openldap we need to install latest Oracle Berkeley DB.

wget http://download.oracle.com/berkeley-db/db-4.7.25.tar.gz
tar xvf db-4.7.25.tar.gz
cd db-4.7.25
cd build_unix
../dist/configure
make
make install
ls /usr/local/BerkeleyDB.4.7/
cp -p /usr/local/BerkeleyDB.4.7/bin/db_* /usr/bin/
cp -p /usr/local/BerkeleyDB.4.7/lib/* /usr/lib
cp -p /usr/local/BerkeleyDB.4.7/include/* /usr/include/
mv /usr/lib/libdb-4.7.so /usr/lib/libdb-4.7.so.0.0.0
ln -s /usr/lib/libdb-4.7.so.0.0.0 /usr/lib/libdb-4.7.so
ldconfig

 

3 Install Openldap

a. install the OpenLDAP server from source:

wget ftp://ftp.openldap.org/pub/OpenLDAP/openldap-release/openldap-2.4.26.tgz
tar xvf openldap-2.4.26.tgz
cd openldap-2.4.26
./configure --prefix=/usr/local/openldap --enable-overlays=mod --enable-modules --enable-bdb --enable-accesslog --enable-auditlog --enable-collect --enable-memberof --enable-syncprov
make depend
make
make install

Try to start the service and check it started without any error. To make sure we are good to go.

/usr/local/openldap/libexec/slapd -d 5

Note: Press "ctrl + c"  to exit.

Now we will follow the same steps to install the Openldap on other server.

 

4 Configure Multi-Master Replication

Now we will configure the replication although i will include most of the important configuration just to make sure that the configuration are in correct order (which is important because you can’t just put any line anywhere in file).

On server1 (192.168.0.100):

vi /usr/local/openldap/etc/openldap/slapd.conf
pidfile /usr/local/openldap/var/run/slapd.pid
argsfile /usr/local/openldap/var/run/slapd.args

# Load the required modules
moduleload syncprov.la
moduleload accesslog.la
moduleload back_bdb.la

#Define the server ID.
serverID 1

# Make sure you change below configuration as your need

database bdb
suffix " dc=example,dc=com "
rootdn "cn=ldadmin,dc=example,dc=com "
rootpw {SSHA}MxGntcb+QdYimYqbly7IOCY2ZJ0SxqCZ # Generate password using "slappasswd"
directory /usr/local/openldap/var/openldap-data

# These are basic performances configuration required
checkpoint 10240 720 # check point whenever 10M data bytes written or 24Hr has elapsed whichever occurs first
cachesize 50000 # LDAP maintains 50,000 entries in memory

# These configurations are to set the default database parameters
dbconfig set_cachesize 0 524288000 1 # Set the database in memory cache size to 500 MB, Tuning this value can greatly effect your database performance.
dbconfig set_lk_max_locks 3000
dbconfig set_lk_max_objects 1500
dbconfig set_lk_max_lockers 1500
dbconfig set_lg_regionmax 262144
dbconfig set_lg_bsize 2097152

# Replication configuration, only things you may have to change here are provider, binddn, credentials and searchbase.
syncrepl rid=001
    provider=ldap://server2.example.com:389
    binddn="cn=ldadmin,dc=example,dc=com "
    bindmethod=simple
    credentials=secret
    searchbase=" dc=example,dc=com "
    type=refreshAndPersis
    interval=00:00:00:10
    retry="5 5 300 5"
    timeout=1

index objectClass eq

#Rest replication configuration goes to end of the file.
mirrormode TRUE
overlay syncprov
syncprov-nopresent TRUE
syncprov-reloadhint TRUE
syncprov-checkpoint 1000 60 

Now configure server2 (192.168.0.101):

vi /usr/local/openldap/etc/openldap/slapd.conf
pidfile /usr/local/openldap/var/run/slapd.pid
argsfile /usr/local/openldap/var/run/slapd.args
moduleload syncprov.la
moduleload accesslog.la
moduleload back_bdb.la
serverID 1

database bdb
suffix " dc=example,dc=com "
rootdn "cn=ldadmin,dc=example,dc=com "
rootpw {SSHA}MxGntcb+QdYimYqbly7IOCY2ZJ0SxqCZ # Generate password using “slappasswd”
directory /usr/local/openldap/var/openldap-data

checkpoint 10240 720
cachesize 50000
dbconfig set_cachesize 0 524288000 1
dbconfig set_lk_max_locks 3000
dbconfig set_lk_max_objects 1500
dbconfig set_lk_max_lockers 1500
dbconfig set_lg_regionmax 262144
dbconfig set_lg_bsize 2097152

syncrepl rid=002
    provider=ldap://server1.example.com:389
    binddn="cn=ldadmin,dc=example,dc=com "
    bindmethod=simple
    credentials=secret
    searchbase="dc=example,dc=com "
    type=refreshAndPersist
    interval=00:00:00:10
    retry="5 5 300 5"
    timeout=1

index objectClass eq

mirrormode TRUE
overlay syncprov
syncprov-nopresent TRUE
syncprov-reloadhint TRUE
syncprov-checkpoint 1000 60 

 

5 Configure Startup Script File

First create an account to run ldap service:

groupadd ldap
useradd -g ldap -d /usr/local/openldap/var/openldap-data/ -s /bin/false -p'*' ldap

As openldap didn't include any scripts in package we will create one:


vi /etc/init.d/ldap
#!/bin/bash
#
# ldap This shell script takes care of starting and stopping
# ldap servers (slapd and slurpd).
#
# chkconfig: - 27 73
# description: LDAP stands for Lightweight Directory Access Protocol, used \
# for implementing the industry standard directory services.
# processname: slapd
# config: /usr/local/openldap/etc/openldap/slapd.conf
# pidfile: /usr/local/openldap/var/run/slapd.pid

# Source function library.
. /etc/init.d/functions

# Source networking configuration and check that networking is up.
if [ -r /etc/sysconfig/network ] ; then
. /etc/sysconfig/network
[ ${NETWORKING} = "no" ] && exit 1
fi

# Source an auxiliary options file if we have one, and pick up OPTIONS,
# SLAPD_OPTIONS, SLURPD_OPTIONS, SLAPD_LDAPS, SLAPD_LDAPI, and maybe
# KRB5_KTNAME and SLURPD_KRB5CCNAME.
if [ -r /etc/sysconfig/ldap ] ; then
. /etc/sysconfig/ldap
fi

#slapd=/usr/sbin/slapd
slapd=/usr/local/openldap/libexec/slapd
slurpd=/usr/sbin/slurpd
slaptest=/usr/local/openldap/sbin/slaptest
[ -x ${slapd} ] || exit 1
[ -x ${slurpd} ] || exit 1

RETVAL=0

#
# Pass commands given in $2 and later to "test" run as user given in $1.
#
function testasuser() {
local user= cmd=
user="$1"
shift
cmd="$@"
if test x"$user" != x ; then
if test x"$cmd" != x ; then
/sbin/runuser -f -m -s /bin/sh -c "test $cmd" -- "$user"
else
false
fi
else
false
fi
}

#
# Check for read-access errors for the user given in $1 for a service named $2.
# If $3 is specified, the command is run if "klist" can't be found.
#
function checkkeytab() {
local user= service= klist= default=
user="$1"
service="$2"
default="${3:-false}"
if test -x /usr/kerberos/bin/klist ; then
klist=/usr/kerberos/bin/klist
elif test -x /usr/bin/klist ; then
klist=/usr/bin/klist
fi
KRB5_KTNAME="${KRB5_KTNAME:-/etc/krb5.keytab}"
export KRB5_KTNAME
if test -s "$KRB5_KTNAME" ; then
if test x"$klist" != x ; then
if LANG=C $klist -k "$KRB5_KTNAME" | tail -n 4 | awk '{print $2}' | grep -q ^"$service"/ ; then
if ! testasuser "$user" -r ${KRB5_KTNAME:-/etc/krb5.keytab} ; then
true
else
false
fi
else
false
fi
else
$default
fi
else
false
fi
}

function configtest() {
local user= ldapuid= dbdir= file=
# Check for simple-but-common errors.
user=ldap
prog=`basename ${slapd}`
ldapuid=`id -u $user`
# Unaccessible database files.
for dbdir in `LANG=C egrep '^directory[[:space:]]+[[:print:]]+$' /usr/local/openldap/etc/openldap/slapd.conf | sed s,^directory,,` ; do
for file in `find ${dbdir}/ -not -uid $ldapuid -and \( -name "*.dbb" -or -name "*.gdbm" -or -name "*.bdb" -or -name "__db.*" \)` ; do
echo -n $"$file is not owned by \"$user\"" ; warning ; echo
done
done
# Unaccessible keytab with an "ldap" key.
if checkkeytab $user ldap ; then
file=${KRB5_KTNAME:-/etc/krb5.keytab}
echo -n $"$file is not readable by \"$user\"" ; warning ; echo
fi
# Unaccessible TLS configuration files.
tlsconfigs=`LANG=C egrep '^(TLS_CACERT|TLSCACertificateFile|TLSCertificateFile|TLSCertificateKeyFile)[[:space:]]' /usr/local/openldap/etc/openldap/slapd.conf /usr/local/openldap/etc/openldap/ldap.conf | awk '{print $2}'`
for file in $tlsconfigs ; do
if ! testasuser $user -r $file ; then
echo -n $"$file is not readable by \"$user\"" ; warning ; echo
fi
done
# Check the configuration file.
slaptestout=`/sbin/runuser -m -s "$slaptest" -- "$user" "-u" 2>&1`
slaptestexit=$?
if test $slaptestexit == 0 ; then
if echo "$slaptestout" | grep -v "config file testing succeeded" >/dev/null ; then
echo -n $"Checking configuration files for $prog: " ; warning ; echo
echo "$slaptestout"
fi
else
echo -n $"Checking configuration files for $prog: " ; failure ; echo
echo "$slaptestout"
if /sbin/runuser -m -s "$slaptest" -- "$user" "-u" &>/dev/null ; then
for directory in `LANG=C egrep '^directory[[:space:]]+[[:print:]]+$' /usr/local/openldap/etc/openldap/slapd.conf | sed s,^directory,,` ; do
if test -r $directory/__db.001 ; then
echo -n $"stale lock files may be present in $directory" ; warning ; echo
fi
done
fi
exit 1
fi
}

function start() {
configtest
# Define a couple of local variables which we'll need. Maybe.
user=ldap
prog=`basename ${slapd}`
if test x$SLAPD_LDAP = xyes ; then
harg="ldap:///"
fi
if grep -q ^TLS /usr/local/openldap/etc/openldap/slapd.conf || test x$SLAPD_LDAPS = xyes ; then
harg="$harg ldaps:///"
fi
if test x$SLAPD_LDAPI = xyes ; then
harg="$harg ldapi:///"
fi
# Start daemons.
echo -n $"Starting $prog: "
ulimit $ULIMIT_SETTINGS > /dev/null 2>&1
daemon --check=$prog ${slapd} -h \"$harg\" -u ${user} $OPTIONS $SLAPD_OPTIONS
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
if grep -q "^replogfile" /usr/local/openldap/etc/openldap/slapd.conf; then
prog=`basename ${slurpd}`
echo -n $"Starting $prog: "
if [ -n "$SLURPD_KRB5CCNAME" ]; then
export KRB5CCNAME="$SLURPD_KRB5CCNAME";
fi
daemon ${slurpd} $OPTIONS $SLURPD_OPTIONS
RETVAL=$?
echo
fi
fi
[ $RETVAL -eq 0 ] && touch /usr/local/openldap/var/lock/subsys/ldap
return $RETVAL
}

function stop() {
# Stop daemons.
prog=`basename ${slapd}`
echo -n $"Stopping $prog: "
killproc -d $STOP_DELAY ${slapd}
RETVAL=$?
echo
if [ $RETVAL -eq 0 ]; then
if grep -q "^replogfile" /usr/local/openldap/etc/openldap/slapd.conf; then
prog=`basename ${slurpd}`
echo -n $"Stopping $prog: "
killproc ${slurpd}
RETVAL=$?
echo
fi
fi
[ $RETVAL -eq 0 ] && rm -f /usr/local/openldap/var/lock/subsys/ldap /usr/local/openldap/var/run/slapd.args
return $RETVAL
}

# See how we were called.
case "$1" in
configtest)
configtest
;;
start)
start
RETVAL=$?
;;
stop)
stop
RETVAL=$?
;;
status)
status ${slapd}
RETVAL=$?
if grep -q "^replogfile" /usr/local/openldap/etc/openldap/slapd.conf ; then
status ${slurpd}
RET=$?
if [ $RET -ne 0 ] ; then
RETVAL=$RET;
fi
fi
;;
restart)
stop
start
;;
condrestart)
if [ -f /usr/local/openldap/var/lock/subsys/ldap ] ; then
stop
start
RETVAL=$?
fi
;;
*)
echo $"Usage: $0 {start|stop|restart|status|condrestart}"
RETVAL=1
esac

exit $RETVAL

You may have to make some aditional directory required:

mkdir -p /usr/local/openldap/var/{run,lock/subsys}
chown ldap: -R /usr/local/openldap

Now, make this script executable and change its default permissions:

chmod 700  /etc/init.d/ldap
chkconfig --add ldap
chkconfig --level 345 ldap on

Start your OpenLDAP Server manually with the following command:

/etc/init.d/ldap start

 

6 Migration

Only follow these steps if you are setting replication on already running Openldap server:

a. First copy all the schema used in your running setup, I would suggest sync the whole directory.

rsync -av /usr/local/openldap/etc/openldap/schema root@server2:/usr/local/openldap/etc/openldap/schema

Now remember to include the these schema in your configuration:

vi /usr/local/openldap/etc/openldap/slapd.conf
include         /usr/local/openldap/etc/openldap/schema/core.schema
include         /usr/local/openldap/etc/openldap/schema/cosine.schema
include         /usr/local/openldap/etc/openldap/schema/inetorgperson.schema
include         /usr/local/openldap/etc/openldap/schema/nis.schema
include         /usr/local/openldap/etc/openldap/schema/qmail.schema

b. Now import all the data from server1 to server2.

on server1:

ldapsearch -x -b 'dc=example,dc=com' > master.ldif
scp master.ldif root@server2:

on server2:

ldapmodify -cvx -D'cn=ldadmin,dc=example,dc=com' -W -f /root/master.ldif

Enter LDAP Password:

Now restart Ldap service simultaneously on both servers:

/etc/init.d/ldap restart

 

7 Configure Qmail And IMAP To Use Both servers

Now we will edit a qmail control file to define multiple ldap servers:  

vi /var/qmail/control/ldapserver
server1.example.com:389
server2.example.com:389

And courier-auth configuration to make imap use both the servers:

vi /etc/courier/authldaprc
LDAP_URI    ldap://server1.example.com, ldap://server2.example.com

Now just restart the services and all should be good :)

I will be publishing a doc to configure replication over SSL very soon...

Share this page:

9 Comment(s)