Configuring N-Way Multimaster replication on RHEL6 using OpenLDAP
Issue
Configuring N-Way Multimaster replication on RHEL6 using OpenLDAP
Environment
- Red Hat Enterprise Linux 6.2
- Two Servers are called Master-1/m1 and Master-2/m2
- Hostname: ldap1.example.org (Master-1)
- Hostname: ldap2.example.org (Master-2)
- Suffix: dc=example,dc=org
- Version of OpenLDAP:
- openldap-devel-2.4.23-20.el6.x86_64
- openldap-2.4.23-20.el6.x86_64
- openldap-clients-2.4.23-20.el6.x86_64
- openldap-servers-2.4.23-20.el6.x86_64
Resolution
-
The below steps enumerate the procedure to configure N-Way Multimaster replication on RHEL6.2 using OpenLDAP . The steps are explained assuming the above
Environment -
Master-1(m1) Server
-
Install Openldap-server package
# yum install openldap-servers
-
Installation of Openldap-servers gives a template slapd.conf with an example bdb configured, In this example, We modify the slapd.conf to convert
it to cn=config format. cn=config is a new feature of OpenLDAP 2.4 which enables dynamic changes to configuration without requiring to restart. Below is an minimal slapd.conf required to get us started with using cn=config.include /etc/openldap/schema/corba.schema include /etc/openldap/schema/core.schema include /etc/openldap/schema/cosine.schema include /etc/openldap/schema/duaconf.schema include /etc/openldap/schema/dyngroup.schema include /etc/openldap/schema/inetorgperson.schema include /etc/openldap/schema/java.schema include /etc/openldap/schema/misc.schema include /etc/openldap/schema/nis.schema include /etc/openldap/schema/openldap.schema include /etc/openldap/schema/ppolicy.schema include /etc/openldap/schema/collective.schema allow bind_v2 pidfile /var/run/openldap/slapd.pid argsfile /var/run/openldap/slapd.args #### Encrypting Connections TLSCACertificateFile /etc/pki/tls/certs/cacert.crt TLSCertificateFile /etc/pki/tls/certs/ldap.crt TLSCertificateKeyFile /etc/pki/tls/certs/ldap.key ### Database Config### database config rootdn "cn=admin,cn=config" rootpw config access to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth manage by * break ### Enable Monitoring database monitor # allow only rootdn to read the monitor access to * by dn.exact="cn=admin,cn=config" read by * none
-
Brief Explanation of above configuration:
-
The above configuration includes default schema files required, One could add only the required schema files removing the others
-
The above configuration uses certificates signed using Self-sign CA created using OpenSSL. One could comment out the TLS* Lines to avoid encryption or use "make slapd.pem" under /etc/pki/tls/certs/ directory to create a self signed Certs. You could refer to below article on how to create a CA using Openssl and signing certificates.
How do i configure CA and sign certificates using OpenSSL using Red Hat Enterprise Linux
-
We have defined cn=config database, The rootdn of this database is managed by "cn=admin,cn=config" , and the password of this DN is "config"
- cn=monitor is defined to monitor the Openldap Databases, connections, requests. Again managed by "cn=admin,cn=config".
-
-
Convert slapd.conf to cn=config format
-
Create slapd.d directory to store cn=config format
# mkdir /etc/openldap/slapd.d/
-
Using slaptest convert slapd.conf to cn=config
# slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d
-
Allow "ldap" user to read and write to slapd.d directory
# chown ldap.ldap /etc/openldap/slapd.d # chown ldap.ldap /etc/openldap/slapd.d/* -R # chmod 700 /etc/openldap/slapd.d
-
Make sure that if certificates are used, the certs are readable by user ldap
# chown ldap.ldap /etc/pki/tls/certs/cacert.crt # chown ldap.ldap /etc/pki/tls/certs/ldap.crt # chown ldap.ldap /etc/pki/tls/certs/ldap.key
-
-
Set the selinux to permissive mode temporarily till we configure N-Way MMR. Reason being when cn=config database is modified dynamically using ldapadd/modify/delete , It's better if those changes are saved back in /etc/openldap/slapd.d. Currently selinux would not allow the "slapd" process to write to slapd.d directory unless selinux is set to Permissive or create a selinux policy to allow the write operation
-
We need to define a suffix that we want to host in our ldap server and which database to be used for suffix, In this case we are going with
berkely DB. Below is bdb definitation for our Environment1. dn: olcDatabase=bdb,cn=config 2. objectClass: olcDatabaseConfig 3. objectClass: olcBdbConfig 4. olcDatabase: {1}bdb 5. olcSuffix: dc=example,dc=org 6. olcDbDirectory: /var/lib/ldap 7. olcRootDN: cn=Manager,dc=example,dc=org 8. olcRootPW: redhat 9. olcDbCacheSize: 1000 10. olcDbCheckpoint: 1024 10 11. olcDbIDLcacheSize: 3000 12 olcDbConfig: set_cachesize 0 10485760 0 13. olcDbConfig: set_lg_bsize 2097152 14. olcDbConfig: set_lg_dir /var/tmp/bdb-log 15. olcDbConfig: set_flags DB_LOG_AUTOREMOVE 16. olcLimits: dn.exact="cn=Manager,dc=example,dc=org" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited 17. olcDbIndex: uid pres,eq 18. olcDbIndex: cn,sn,displayName pres,eq,approx,sub 19. olcDbIndex: uidNumber,gidNumber eq 20. olcDbIndex: memberUid eq 21. olcDbIndex: objectClass eq 22. olcDbIndex: entryUUID pres,eq 23. olcDbIndex: entryCSN pres,eq 24. olcAccess: to attrs=userPassword by self write by anonymous auth by dn.children="ou=admins,dc=example,dc=org" write by * none 25. olcAccess: to * by self write by dn.children="ou=admins,dc=example,dc=org" write by * read
Brief Explanation of the above bdb definition:
- Lines 1-5 specify that we want to use berkely database(bdb) as our backend for DIT and our suffix is "dc=example,dc=org"
- Line 6 specifies the location where bdb files are stored
- Lines 7-8 Specifies the rootdn (Administrator) and password for the suffix "dc=example,dc=org"
-
Lines 9-11 specifies the db cachesize,checkpoint and IDLcachesize that we wanted to have for our suffix. More information on
these attributes can be obtained from OpenLDAP Admin Guide -
Line 12-15 specifies the Berkely DB Environment variables that are require for better management of bdb. In this example we have set
bdb cachesize to 10Mb, Transaction log size to 2MB, Transaction logs are stored in /var/tmp/bdb-log and Logs are autoremoved
when un-necessary, This would prevent from disk getting filled with Transaction logs -
Line 16 specifies the Limist for roodn, In this example we have set unlimited limits for rootdn.
- Lines 17-21 defines Indexes required for better performances.
-
Lines 22-23 define indexes required for Replication
-
Line 24 the Access Control lists for our suffix, The above example uses basic ACL's where in userPassword attribute can be
modified by self , anonymous have to authenticated and entries created under ou=admins,dc=example,dc=org can modify -
Line 25 gives permissions to entries created under "ou=admins,dc=example,dc=com" to modify/delete/create all the entries and
attributes under "dc=example,dc=org".
-
Before we go and add the above bdb definition under cn=config, Create the above transaction log directory and check is directory mentioned under "olcdbDirectory"exists and is empty. By default when openldap-servers package is installed it creates a DB_CONFIG file in /var/lib/ldap. This needs to be removed as we are defining berkely db environment variables under cn=config
# mkdir /var/tmp/bdb-log # chown ldap.ldap /var/tmp/bdb-log # chmod 700 /var/tmp/bdb-log # rm -rf /var/lib/ldap/* # chown ldap.ldap /var/lib/ldap
-
Start the slapd service
[root@ldap1 ldap]# service slapd start Starting slapd: [ OK ]
-
Run ldapsearch to check if you could query the cn=config database , The output would be as below
[root@ldap1 ~]# ldapsearch -x -b "cn=config" -D "cn=admin,cn=config" -w config -h localhost dn -LLL | grep -v ^$ dn: cn=config dn: cn=schema,cn=config dn: cn={0}corba,cn=schema,cn=config dn: cn={1}core,cn=schema,cn=config dn: cn={2}cosine,cn=schema,cn=config dn: cn={3}duaconf,cn=schema,cn=config dn: cn={4}dyngroup,cn=schema,cn=config dn: cn={5}inetorgperson,cn=schema,cn=config dn: cn={6}java,cn=schema,cn=config dn: cn={7}misc,cn=schema,cn=config dn: cn={8}nis,cn=schema,cn=config dn: cn={9}openldap,cn=schema,cn=config dn: cn={10}ppolicy,cn=schema,cn=config dn: cn={11}collective,cn=schema,cn=config dn: cn={12}samba,cn=schema,cn=config dn: olcDatabase={-1}frontend,cn=config dn: olcDatabase={0}config,cn=config dn: olcDatabase={1}monitor,cn=config
-
Store the above bdb definition (Step-6) in an ldif file bdb.ldif and add it to cn=config database
[root@ldap1 kcs]# ldapadd -x -D "cn=admin,cn=config" -w config -f bdb.ldif -h localhost adding new entry "olcDatabase=bdb,cn=config"
- After executing the above command , you should have a bdb files created in /var/lib/ldap and also a DB_CONFIG file with bdb environment variables as defined in step-9
-
Run ldapsearch to check if you are able to query the cn=config database and bdb definitions are visible as we have defined.
[root@ldap1 kcs]# ldapsearch -x -b "cn=config" -D "cn=admin,cn=config" -w config -h localhost dn -LLL | grep -v ^$ dn: cn=config dn: cn=schema,cn=config dn: cn={0}corba,cn=schema,cn=config dn: cn={1}core,cn=schema,cn=config dn: cn={2}cosine,cn=schema,cn=config dn: cn={3}duaconf,cn=schema,cn=config dn: cn={4}dyngroup,cn=schema,cn=config dn: cn={5}inetorgperson,cn=schema,cn=config dn: cn={6}java,cn=schema,cn=config dn: cn={7}misc,cn=schema,cn=config dn: cn={8}nis,cn=schema,cn=config dn: cn={9}openldap,cn=schema,cn=config dn: cn={10}ppolicy,cn=schema,cn=config dn: cn={11}collective,cn=schema,cn=config dn: cn={12}samba,cn=schema,cn=config dn: olcDatabase={-1}frontend,cn=config dn: olcDatabase={0}config,cn=config dn: olcDatabase={1}monitor,cn=config dn: olcDatabase={2}bdb,cn=config [root@ldap1 kcs]# ldapsearch -x -b "cn=config" -D "cn=admin,cn=config" -w config -h localhost objectClass=olcBdbConfig -LLL dn: olcDatabase={2}bdb,cn=config objectClass: olcDatabaseConfig objectClass: olcBdbConfig olcDatabase: {2}bdb olcDbDirectory: /var/lib/ldap olcSuffix: dc=example,dc=org olcAccess: {0}to attrs=userPassword by self write by anonymous auth by dn.chil dren="ou=admins,dc=example,dc=com" write by * none olcAccess: {1}to * by self write by dn.children="ou=admins,dc=example,dc=com" write by * read olcLimits: {0}dn.exact="cn=Manager,dc=example,dc=org" time.soft=unlimited time .hard=unlimited size.soft=unlimited size.hard=unlimited olcRootDN: cn=Manager,dc=example,dc=org olcRootPW: redhat olcDbCacheSize: 1000 olcDbCheckpoint: 1024 10 olcDbConfig: {0}set_cachesize 0 10485760 0 olcDbConfig: {1}set_lg_bsize 2097152 olcDbConfig: {2}set_lg_dir /var/tmp/bdb-log olcDbConfig: {3}set_flags DB_LOG_AUTOREMOVE olcDbIDLcacheSize: 3000 olcDbIndex: uid pres,eq olcDbIndex: cn,sn,displayName pres,eq,approx,sub olcDbIndex: uidNumber,gidNumber eq olcDbIndex: memberUid eq olcDbIndex: objectClass eq olcDbIndex: entryUUID pres,eq olcDbIndex: entryCSN pres,eq
-
Check the /var/lib/ldap directory to see the files are created with appropriate ldap user permissions
[root@ldap1 kcs]# ls -l /var/lib/ldap/ total 1580 -rw-r--r--. 1 ldap ldap 2048 Mar 24 10:03 alock -rw-------. 1 ldap ldap 24576 Mar 24 10:03 __db.001 -rw-------. 1 ldap ldap 737280 Mar 24 10:03 __db.002 -rw-------. 1 ldap ldap 13115392 Mar 24 10:03 __db.003 -rw-------. 1 ldap ldap 2162688 Mar 24 10:03 __db.004 -rw-------. 1 ldap ldap 753664 Mar 24 10:03 __db.005 -rw-------. 1 ldap ldap 32768 Mar 24 10:03 __db.006 -rw-r--r--. 1 ldap ldap 104 Mar 24 10:03 DB_CONFIG -rw-------. 1 ldap ldap 8192 Mar 24 10:03 dn2id.bdb -rw-------. 1 ldap ldap 32768 Mar 24 10:03 id2entry.bdb
-
Create a basic DIT for suffix dc=example,dc=org. Below is an example ldif data
dn: dc=example,dc=org objectClass: top objectClass: dcObject objectclass: organization o: Example Organization dc: Example description: LDAP Example dn: ou=People,dc=example,dc=org objectClass: organizationalUnit ou: People dn: ou=Groups,dc=example,dc=org objectClass: organizationalUnit ou: Groups dn: ou=Admins,dc=example,dc=org objectClass: organizationalUnit ou: Admins dn: uid=student1,ou=People,dc=example,dc=org uid: student1 cn: student1 sn: 1 objectClass: top objectClass: posixAccount objectClass: inetOrgPerson loginShell: /bin/bash homeDirectory: /home/student1 uidNumber: 14583100 gidNumber: 14564100 userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A mail: student1@example.org gecos: Student1 User dn: uid=student2,ou=People,dc=example,dc=org uid: student2 cn: student2 sn: 2 objectClass: top objectClass: posixAccount objectClass: inetOrgPerson loginShell: /bin/bash homeDirectory: /home/student2 uidNumber: 14583101 gidNumber: 14564100 userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A mail: student2@example.org gecos: Student2 User dn: cn=students,ou=Groups,dc=example,dc=org objectClass: posixGroup objectClass: top cn: ldapusers userPassword: {crypt}x gidNumber: 14564100 memberuid: uid=student1 memberuid: uid=student2 dn: cn=replicator,ou=Admins,dc=example,dc=org cn: replicator sn: user objectClass: person userPassword: Secret123
-
Save the above data in ldif file and add the data using ldapadd command while binding as user "cn=Manager,dc=example,dc=com" who's the rootdn of "dc=example,dc=org" suffix
[root@ldap1 kcs]# ldapadd -x -D "cn=Manager,dc=example,dc=org" -w redhat -h localhost -f data1.ldif adding new entry "dc=example,dc=org" adding new entry "ou=People,dc=example,dc=org" adding new entry "ou=Groups,dc=example,dc=org" adding new entry "ou=Admins,dc=example,dc=org" adding new entry "uid=student1,ou=People,dc=example,dc=org" adding new entry "uid=student2,ou=People,dc=example,dc=org" adding new entry "cn=students,ou=Groups,dc=example,dc=org" adding new entry "cn=replicator,ou=Admins,dc=example,dc=org"
-
Step-1 to Step-13 should be performed on Master-2(m2) System. Do not proceed further unless all the above steps gets executed successfully.
-
Configuring Replication
-
In the Below steps we will enable Replication on both Masters using syncrepl. The steps we would broadly follow are:
* Load the syncprov module on both masters
* Configure syncrepl for cn=config database
* Configure syncrepl for berkely database i.e (dn: olcDatabase={2}bdb,cn=config)-
Before Replication is configured, It's required that all the server's clock must be tightly synchronized using NTP
-
Enabling Syncprov module for both masters . In cn=config format, all the modules are specified in "cn=modules,cn=config" and the attribute
to load the module is "olcModuleLoad" . Save the below content in ldif file and add in both the mastersdn: cn=module,cn=config objectClass: olcModuleList cn: module olcModuleLoad: syncprov.la [root@ldap1 mmr]# ldapadd -x -D "cn=admin,cn=config" -w config -f sync.ldif -h master1 adding new entry "cn=module,cn=config" [root@ldap1 mmr]# ldapadd -x -D "cn=admin,cn=config" -w config -f sync.ldif -h master2 adding new entry "cn=module,cn=config"
-
Configuring syncrepl for "cn=config" database.
[root@ldap1 kcs]# cat config-repl.ldif #Specify ServerID for both the masters dn: cn=config changetype: modify add: olcServerID olcServerID: 101 ldap://ldap1.example.org olcServerID: 201 ldap://ldap2.example.org #Enable Syncprov Overlay for config database dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config changetype: add objectclass: olcOverlayConfig objectclass: olcSyncProvConfig olcOverlay: syncprov #Configure SyncRepl for config database dn: olcDatabase={0}config,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 provider=ldap://ldap1.example.org binddn="cn=admin,cn=config" bindmethod=simple credentials=config searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 olcSyncRepl: rid=002 provider=ldap://ldap2.example.org binddn="cn=admin,cn=config" bindmethod=simple credentials=config searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 - add: olcMirrorMode olcMirrorMode: TRUE
Brief Description of the above data
- In the above ldif file, We give each master to have unique ServerID and also the provider(master) URI
- Enable the syncprov overlay for cn=config
- unique rid for each replication agreement.
Run the above on cn=config on Master-1
[root@ldap1 kcs]# ldapmodify -x -D "cn=admin,cn=config" -w config -f config-repl.ldif -h ldap1.example.org modifying entry "cn=config" adding new entry "olcOverlay=syncprov,olcDatabase={0}config,cn=config" modifying entry "olcDatabase={0}config,cn=config
Next on cn=config on Master-2
[root@ldap1 kcs]# ldapmodify -x -D "cn=admin,cn=config" -w config -f config-repl.ldif -h ldap2.example.org modifying entry "cn=config" adding new entry "olcOverlay=syncprov,olcDatabase={0}config,cn=config" modifying entry "olcDatabase={0}config,cn=config"
-
URLs specified in olcSyncRepl directives(step-2) are the URLs of the servers from which to replicate.
These must exactly match the URLs slapd listens on (-h in Command-Line Options). Otherwise slapd may attempt to replicate from itself, causing a loop.-
Edit /etc/sysconfig/ldap Master-1 (ldap1.example.org) to run slapd with -h and specifying the URL ldap1.example.org.
SLAPD_LDAP=no SLAPD_LDAPI=no SLAPD_LDAPS=no SLAPD_URLS="ldap://ldap1.example.org:389 ldaps://ldap1.example.org ldapi:///"
-
Restart the slapd service and check if slapd process
[root@ldap1 ~]# service slapd restart Stopping slapd: [ OK ] Starting slapd: [ OK ] [root@ldap1 ~]# ps aux | grep slapd ldap 3350 0.3 0.2 327928 5844 ? Ssl 10:20 0:00 /usr/sbin/slapd -h ldap://ldap1.example.org:389 ldaps://ldap1.example.org ldapi:/// -u ldap root 3358 0.0 0.0 103228 808 pts/1 S+ 10:21 0:00 grep slapd
-
Modify /etc/sysconfig/ldap on Master-2 (ldap2.example.org) to run slapd with -h and specifying the URL ldap2.example.org
[root@ldap2 ~]# cat /etc/sysconfig/ldap | grep -v ^$ | grep -v ^# SLAPD_LDAP=no SLAPD_LDAPI=no SLAPD_LDAPS=no SLAPD_URLS="ldap://ldap2.example.org:389 ldaps://ldap2.example.org ldapi:///" [root@ldap2 ~]# service slapd restart Stopping slapd: [ OK ] Starting slapd: [ OK ] [root@ldap2 ~]# ps aux | grep slapd ldap 2348 0.0 0.3 302176 6804 ? Ssl 10:27 0:00 /usr/sbin/slapd -h ldap://ldap2.example.org:389 ldaps://ldap2.example.org ldapi:/// -u ldap root 2356 0.0 0.0 103228 812 pts/1 S+ 10:27 0:00 grep slapd
-
-
Configuring syncrepl for berkely batabase that hosts the suffix "dc=example,dc=org".
[root@ldap1 kcs]# cat bdb-repl.ldif dn: olcDatabase={2}bdb,cn=config changetype: modify add: olcSyncRepl olcSyncRepl: rid=003 provider=ldap://ldap1.example.org binddn="cn=replicator,ou=Admins,dc=example,dc=org" bindmethod=simple credentials=Secret123 searchbase="dc=example,dc=org" type=refreshAndPersist retry="5 5 5 +" timeout=3 olcSyncRepl: rid=004 provider=ldap://ldap2.example.org binddn="cn=replicator,ou=Admins,dc=example,dc=org" bindmethod=simple credentials=Secret123 searchbase="dc=example,dc=org" type=refreshAndPersist retry="5 5 5 +" timeout=3 - add: olcMirrorMode olcMirrorMode: TRUE dn: olcOverlay=syncprov,olcDatabase={2}bdb,cn=config changetype: add objectClass: olcOverlayConfig objectClass: olcSyncProvConfig olcOverlay: syncprov
Brief Description of the above data
* We create syncrepl agreement specifying the rid for each agreement. * binddn used for the replication should have appropriate rights to add/modify/delete the entries
-
Run the above on olcDatabase={2}bdb,cn=config on Master-1
[root@ldap1 kcs]# ldapmodify -x -D "cn=admin,cn=config" -w config -f bdb-repl.ldif -h ldap1.example.org modifying entry "olcDatabase={2}bdb,cn=config" adding new qentry "olcOverlay=syncprov,olcDatabase={2}bdb,cn=config"
-
Since we have created syncrepl for cn=config, the above should replicated to Master-2 (ldap2.example.org)
-
-
Create a sample User informatio to be added in Master-1 to check if it gets replicated to Master-2
[root@ldap1 kcs]# cat newuser.ldif dn: uid=student3,ou=People,dc=example,dc=org uid: student3 cn: student3 sn: 3 objectClass: top objectClass: posixAccount objectClass: inetOrgPerson loginShell: /bin/bash homeDirectory: /home/student3 uidNumber: 14583102 gidNumber: 14564100 userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A mail: student3@example.org gecos: Student3 User
Add the User on Master-1 (ldap1.example.org)
[root@ldap1 kcs]# ldapadd -x -D "cn=replicator,ou=admins,dc=example,dc=org" -w Secret123 -f newuser.ldif -h ldap1.example.org adding new entry "uid=student3,ou=People,dc=example,dc=org"
Users student3 should be replicated to both Masters
[root@ldap1 kcs]# ldapsearch -LLL -x -b "ou=People,dc=example,dc=org" -D "cn=replicator,ou=admins,dc=example,dc=org" -w Secret123 uid=student3 -h ldap2.exampl e.org dn: uid=student3,ou=People,dc=example,dc=org uid: student3 cn: student3 sn: 3 objectClass: top objectClass: posixAccount objectClass: inetOrgPerson loginShell: /bin/bash homeDirectory: /home/student3 uidNumber: 14583102 gidNumber: 14564100 userPassword:: e1NTSEF9ajNsQmgxU2VxZTRycUYxK051V21qaHZ0QW5pMUpDNUE= mail: student3@example.org gecos: Student3 User
-
References
Subscriber exclusive content
A Red Hat subscription provides unlimited access to our knowledgebase, tools, and much more.