OpenLDAP : setup multiple instances on a server

Abstract : in some cases, it is interesting to have multiples instances of OpenLDAP running on the same machine. This could be used to separate data, test replication on the same server, or whatever you want.

This note will explain how to do this.

Main principles

In a standard GNU/Linux OpenLDAP install (Red Hat or Debian based), there are several files or directories used to set up OpenLDAP instance and data :

  • /etc/openldap/slapd.d : this directory stores the configuration files for the instance.
  • /var/lib/ldap : this directory contains the data for the instance
  • /etc/init.d/slapd : this file is the start / stop script for the instance
  • /etc/sysconfig/ldap : defines the default ports for LDAP, LDAPS (secured LDAP) and LDAPI (Interconnect = Unix Socket)

Whenever you start the instance, using :

/etc/init.d/slapd start

this will retrieve data from default setup (ie : /etc/sysconfig/ldap and /etc/init.d/slapd.d directory).

Then, you can see what is running with ps -ef command :

ps -ef
...
ldap     17233     1  0 18:13 ?        00:00:00 /usr/sbin/slapd -h  ldap:/// ldaps:/// ldapi:/// -u ldap
...

This is the default setup. If we look at the file /etc/sysconfig/ldap, we see that it defines several variables :

# Options of slapd (see man slapd)
#SLAPD_OPTIONS=

# At least one of SLAPD_LDAP, SLAPD_LDAPI and SLAPD_LDAPS must be set to 'yes'!
#
# Run slapd with -h "... ldap:/// ..."
#   yes/no, default: yes
SLAPD_LDAP=yes

# Run slapd with -h "... ldapi:/// ..."
#   yes/no, default: yes
SLAPD_LDAPI=yes

# Run slapd with -h "... ldaps:/// ..."
#   yes/no, default: no
SLAPD_LDAPS=yes

# Run slapd with -h "... $SLAPD_URLS ..."
# This option could be used instead of previous three ones, but:
# - it doesn't overwrite settings of $SLAPD_LDAP, $SLAPD_LDAPS and $SLAPD_LDAPI options
# - it isn't overwritten by settings of $SLAPD_LDAP, $SLAPD_LDAPS and $SLAPD_LDAPI options
# example: SLAPD_URLS="ldapi:///var/lib/ldap_root/ldapi ldapi:/// ldaps:///"
# default: empty
SLAPD_URLS=

 

Then we can use the SLAPD_URLS variable to set ports for ldap, ldaps and so on.
Note : if you use this variable, you must not use the other one (SLAPD_LDAP, SLAPD_LDAPS), because the start script uses the full URL and also separate variables.
For example, with such a configuration file :

#SLAPD_LDAP=yes
#SLAPD_LDAPI=yes
#SLAPD_LDAPS=yes

SLAPD_URLS="ldap://:1389/ ldapi:/// ldaps://:1636/"

If we start the slapd process with /etc/init.d/slapd start, the result is :

ps -ef
ldap     17176     1  0 18:11 ?        00:00:00 /usr/sbin/slapd -h ldap://:1389/ ldapi:/// ldaps://:1636/ -u ldap

We have been able to change the port. This gives a pretty good idea of what needs to be done to run multiple instances.

The man slapd command reveals also some interesting options :

slapd  [-4|-6]  [-T {acl|a[dd]|auth|c[at]|  d[n]|i[ndex]|p[asswd]|s[chema]|t[est]}] [-d debug-level] [-f slapd-
       config-file] [-F slapd-config-directory] [-h URLs] [-n service-name]  [-s syslog-level]  [-l syslog-local-user]
       [-o option[=value]] [-r directory] [-u user] [-g group] [-c cookie]
  • -d debug-level : run slapd with -d -1 to have a "dump" of all that happens when slapd tries to run. This can reveal issues with permissions, malformed ldif / schema files, etc
  • -F : slapd config directory, this means that you can use an alternative configuration. That is, separate instance !
  • -h URLS : this is what appears on the ps -ef command. Here we will be able to set the listening ports
  • -u / -g : user and group used to run slapd process. Interesting is you want to run separate instances with different users

 

How to implement multiple instances ?

If we want to have mutliple instances on the same server, we must define :

  • a configuration directory, which will include database configuration, schema definition, etc
  • data directory
  • logs directory (optional)
  • a startup script, which will define the ports and configuration directory
  • run files, used during startup (in /var/run or /run)

Test case

Let's imagine a scenario where we will have 3 separate instances on the same server, which can be used to test replication in a master/master + slave configuration.
We will name those instances master1, master2 and slave1

In this scenario, we use several partitions to dispatch data on the server :

  • /srv/data : will contain data for applications
  • /srv/conf : will contain all configuration files
  • /srv/logs : will contain transaction logs files
  • /srv/bin : will contain programs and scripts

 

Configuration directory

I think that the best option is to make a copy of the initial slapd.d directory.

So, once openldap is installed, we will copy the configuration. We will name each directory with a suffix '.d', just to mimic slapd.d configuration name

yum install openldap openldap-servers openldap-clients
# create the main configuration directory
mkdir /srv/conf/openldap
cp -R /etc/openldap/slapd.d /srv/conf/openldap/master1.d
cp -R /etc/openldap/slapd.d /srv/conf/openldap/master2.d
cp -R /etc/openldap/slapd.d /srv/conf/openldap/slave1.d

Let's check the content of /srv/conf/openldap/master1.d directory :

ls -R /srv/conf/openldap/master1.d
/srv/conf/openldap/master1.d:
cn=config  cn=config.ldif

/srv/conf/openldap/master1.d/cn=config:
cn=schema  cn=schema.ldif  olcDatabase={0}config.ldif  olcDatabase={-1}frontend.ldif  olcDatabase={1}monitor.ldif  olcDatabase={2}bdb.ldif

/srv/conf/openldap/master1.d/cn=config/cn=schema:
cn={0}corba.ldif     cn={11}collective.ldif  cn={2}cosine.ldif   cn={4}dyngroup.ldif       cn={6}java.ldif  cn={8}nis.ldif
cn={10}ppolicy.ldif  cn={1}core.ldif         cn={3}duaconf.ldif  cn={5}inetorgperson.ldif  cn={7}misc.ldif  cn={9}openldap.ldif

Note : in fact it will be more interesting to setup the first master configuration, which declares the root suffix, data and so on, and the duplicate this first directory.

Setup for each instance

Some configuration files include elements of structure. Therefore, these files must be updated to reflect the new setup.

cn=config.ldif

The file LDAP.D/cn=config.ldif contains several references to directories.
These attributes should be changed accordingly (in this example, we update data for master1 instance):

  • olcConfigDir: /etc/openldap/slapd.d => change to /srv/conf/openldap/master1.d
  • olcArgsFile: /var/run/openldap/slapd.args => change to /var/run/openldap/master1.args
  • olcPidFile: /var/run/openldap/slapd.pid => change to /var/run/openldap/master1.pid

olcDatabase

In your database definition file olcDatabase={2}bdb.ldif, change the data directory (olcDbDirectory attribute).

  • olcDbDirectory: /var/lib/ldap => change to /srv/data/master1

Data directory

Here again, we will create one sub-directory for each instance.

mkdir -p /srv/data/openldap
mkdir /srv/data/master1
mkdir /srv/data/master2
mkdir /srv/data/slave1

Logs directory

These directories contains the transaction log files, which are used by OpenLDAP.

In recent versions, OpenLDAP "technical" logging is using syslog mechanism.

Startup script

Then, you must create a startup script for each instance, which will start with the correct parameters.
A very simple script could use the configuration in code :

#!/bin/bash
# 
# Startup script for master1
#  
SLAPD_URLS="ldap://:2389/ ldapi://var%2Frun%2Fopenldap%2Fldap-master1 ldaps://:2636/" 
SLAPD_CONFDIR=/srv/conf/openldap/master1.d
SLAPD_NAME=master1
SLAPD_USER=ldap
SLAPD_GROUP=ldap
#
echo "Starting ${SLAPD_NAME} instance..."
/usr/sbin/slapd -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${SLAPD_CONFDIR} -n ${SLAPD_NAME}

Note : the URL for ldapi should be encoded as an URL, with '/' replaced by '%2F', as specified in the "man slapd" command.

In order to keep everything quite simple, we can add a file in the configuration directory, that will "emulate" the default /etc/sysconfig/ldap file.

For example, let's create a file /srv/conf/openldap/master1.d/config.ldap which contains :

SLAPD_URLS="ldap://:2389/ ldapi://var%2Frun%2Fopenldap%2Fldap-master1 ldaps://:2636/" 
SLAPD_SHUTDOWN_TIMEOUT=3
SLAPD_NAME=master1
SLAPD_USER=ldap
SLAPD_GROUP=ldap

 

Then, our start script could be located in /srv/bin/openldap/slapd. It will be run with these options :

/srv/bin/openldap/slapd [start|stop|status] <INSTANCE_NAME>

For example, to start the instance master1, we should run :

/srv/bin/openldap/slapd start master1

Our startup script should then test if the configuration file exists, and then source this file to define the parameters.
Then, this will run the command :

CONF_BASE=/srv/conf/openldap
source ${CONF_BASE}/${INSTANCE}.d/config.ldap
pidfile=/var/run/slapd.${INSTANCE}

/usr/sbin/slapd -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${CONF_BASE}/${INSTANCE}.d -n ${INSTANCE

Our complete startup script would be this one :

#!/bin/bash
#
# ---------------------------------------------------------------------
SLAPD=/usr/sbin/slapd

CONF_BASE=/srv/conf/openldap

if [ -z "$2" ] ; then
  echo -n "LDAP Instance : "
  read INSTANCE
else
  INSTANCE=$2
fi

if [ -f ${CONF_BASE}/${INSTANCE}.d/config.ldap ] ; then
  source ${CONF_BASE}/${INSTANCE}.d/config.ldap
else
  echo "Configuration file ${CONF_BASE}/${INSTANCE}.d/config.ldap not found"
  echo "Exiting..."
  exit 1
fi

pidfile=/var/run/slapd.${INSTANCE}

start_ldap() {
  echo "Starting LDAP Instance ${INSTANCE}"
  ${SLAPD} -h "${SLAPD_URLS}" -g ${SLAPD_GROUP} -u ${SLAPD_USER} -F ${CONF_BASE}/${INSTANCE}.d -n ${INSTANCE}

}

# Stop slapd daemon
stop_ldap() {
  echo "Stop LDAP instance ${INSTANCE}"
  SLAPPID=$(ps -fe|grep ${INSTANCE}.d|grep -v grep|awk '{print $2}' )
  kill $SLAPPID
}

case "$1" in
  start)
        start_ldap ;;
  stop)
        stop_ldap ;;
  restart|force-reload)
        stop_ldap
        start_ldap
        ;;
  *)
        echo "Usage: $0 {start|stop|restart|force-reload}"
        exit 1
        ;;
esac

Catégorie