Cheap VPS & Xen Server


Residential Proxy Network - Hourly & Monthly Packages

Install Openldap From Source And Configure Multi-Master Replication


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:

  1. 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

  1. 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…

 

Comments

comments