Преглед изворни кода

Merge branch 'hotfix-0.10.2' into stable

ofreax пре 10 година
родитељ
комит
2f7ea270bf
37 измењених фајлова са 486 додато и 131 уклоњено
  1. 28 6
      CHANGELOG.md
  2. 1 2
      Makefile
  3. 90 34
      README.md
  4. 9 12
      image/Dockerfile
  5. 17 2
      image/env.yml
  6. 0 1
      image/service/slapd/assets/config/README.md
  7. 1 0
      image/service/slapd/assets/config/bootstrap/README.md
  8. 7 0
      image/service/slapd/assets/config/bootstrap/ldif/config-password.ldif
  9. 6 0
      image/service/slapd/assets/config/bootstrap/ldif/index.ldif
  10. 1 1
      image/service/slapd/assets/config/bootstrap/ldif/logging.ldif
  11. 0 0
      image/service/slapd/assets/config/bootstrap/ldif/security.ldif
  12. 1 0
      image/service/slapd/assets/config/bootstrap/schema/README.md
  13. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/README.md
  14. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/dhcp.schema
  15. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/dnszone.schema
  16. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/mail.schema
  17. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/mmc.schema
  18. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/openssh-lpk.schema
  19. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/quota.schema
  20. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/radius.schema
  21. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/samba.schema
  22. 0 0
      image/service/slapd/assets/config/bootstrap/schema/mmc/zarafa.schema
  23. 26 0
      image/service/slapd/assets/config/replication/replication-disable.ldif
  24. 43 0
      image/service/slapd/assets/config/replication/replication-enable-template.ldif
  25. 13 0
      image/service/slapd/assets/config/tls/tls-disable.ldif
  26. 5 5
      image/service/slapd/assets/config/tls/tls-enable.ldif
  27. 1 1
      image/service/slapd/assets/ssl/README.md
  28. 166 59
      image/service/slapd/container-start.sh
  29. 1 1
      image/service/slapd/daemon.sh
  30. 2 0
      image/service/test/add-host.sh
  31. 14 0
      image/service/test/new-user.ldif
  32. BIN
      test/database/__db.001
  33. BIN
      test/database/__db.002
  34. BIN
      test/database/__db.003
  35. BIN
      test/database/alock
  36. BIN
      test/database/log.0000000001
  37. 54 7
      test/test.bats

+ 28 - 6
CHANGELOG.md

@@ -1,8 +1,30 @@
-## 0.10.1 (release date: 2015-05-17)
-  - Add ldapi
-  - Add custom ldap schema
-  - Auto convert .schema to .ldif
-  - Fixes issues #2 #3
+# Changelog
 
-## 0.10.0 (release date: 2015-03-03)
+## 0.10.2
+
+  - New features:
+    - Bootstrap config, only on non existing slapd config
+    - Limit max open file descriptors to fix slapd memory usage (#9)
+    - Don't disable network access from outside (#8)
+    - Make log level configurable via environment variable (#7)
+    - Support for ldaps (#10)
+
+
+  - Fixes:
+    - Unable to start container with the following invocation. (#6)
+
+## 0.10.1
+
+  - New features:
+    - Add ldapi
+    - Add ldapi
+    - Add custom ldap schema
+    - Auto convert .schema to .ldif
+
+
+  - Fixes :
+    - Docker VOLUME is not needed to be able to stop a container without losing data (#2)
+    - starting from old data (#3)
+
+## 0.10.0
   - New version initial release

+ 1 - 2
Makefile

@@ -1,5 +1,5 @@
 NAME = osixia/openldap
-VERSION = 0.10.1
+VERSION = 0.10.2
 
 .PHONY: all build test tag_latest release
 
@@ -19,4 +19,3 @@ release: build test tag_latest
 	@if ! head -n 1 CHANGELOG.md | grep -q 'release date'; then echo 'Please note the release date in Changelog.md.' && false; fi
 	docker push $(NAME)
 	@echo "*** Don't forget to run 'twgit release/hotfix finish' :)"
-

+ 90 - 34
README.md

@@ -6,29 +6,27 @@ A docker image to run OpenLDAP.
 Fork of Nick Stenning docker-slapd :
 https://github.com/nickstenning/docker-slapd
 
-Add support of tls. Use docker 1.5.0
+Add support of TLS and multi master replication.
 
 ## Quick start
 Run OpenLDAP docker image :
 
-	docker run -d osixia/openldap
-  
+	docker run -h ldap.example.org -d osixia/openldap
+
 This start a new container with a OpenLDAP server running inside.
 The odd string printed by this command is the `CONTAINER_ID`.
 We are going to use this `CONTAINER_ID` to execute some commands inside the container.
 
-Wait 1 or 2 minutes the container startup to be completed.
-
 Then run a terminal on this container,
 make sure to replace `CONTAINER_ID` by your container id :
 
 	docker exec -it CONTAINER_ID bash
 
-You should now be in the container terminal, 
+You should now be in the container terminal,
 and we can search on the ldap server :
-	
-	ldapsearch -x -h 127.0.0.1 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
-	
+
+	ldapsearch -x -h ldap.example.org -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
+
 This should output :
 
 	# extended LDIF
@@ -38,17 +36,17 @@ This should output :
 	# filter: (objectclass=*)
 	# requesting: ALL
 	#
-	
+
 	[...]
 
 	# numResponses: 3
 	# numEntries: 2
-	
+
 if you have the following error, OpenLDAP is not started yet, wait some time.
 
 		ldap_sasl_bind(SIMPLE): Can't contact LDAP server (-1)
-	
-	
+
+
 ## Examples
 
 ### Create new ldap server
@@ -58,7 +56,7 @@ It will create an empty ldap for the compagny **Example Inc.** and the domain **
 
 By default the admin has the password **admin**. All those default settings can be changed at the docker command line, for example :
 
-	docker run -e LDAP_ORGANISATION="My Compagny" -e LDAP_DOMAIN="my-compagny.com" \
+	docker run -h ldap.example.org -e LDAP_ORGANISATION="My Compagny" -e LDAP_DOMAIN="my-compagny.com" \
 	-e LDAP_ADMIN_PASSWORD="JonSn0w" -d osixia/openldap
 
 #### Data persitance
@@ -71,15 +69,15 @@ For more information about docker data volume, please refer to :
 
 > [https://docs.docker.com/userguide/dockervolumes/](https://docs.docker.com/userguide/dockervolumes/)
 
-	
+
 ### Use an existing ldap database
 
-This can be achieved by mounting host directories as volume. 
+This can be achieved by mounting host directories as volume.
 Assuming you have a LDAP database on your docker host in the directory `/data/slapd/database`
 and the corresponding LDAP config files on your docker host in the directory `/data/slapd/config`
 simply mount this directories as a volume to `/var/lib/ldap` and `/etc/ldap/slapd.d`:
 
-	docker run -v /data/slapd/database:/var/lib/ldap \
+	docker run -h ldap.example.org -v /data/slapd/database:/var/lib/ldap \
 	-v /data/slapd/config:/etc/ldap/slapd.d
 	-d osixia/openldap
 
@@ -89,26 +87,73 @@ You can also use data volume containers. Please refer to :
 ### Using TLS
 
 #### Use autogenerated certificate
-By default TLS is enable, a certificate is created for the CN (common name) ldap.example.org. To work properly on your server adjust SERVER_NAME environment variable to match the ldap server CN.
+By default TLS is enable, a certificate is created with the container hostname (set by -h option eg: ldap.example.org).
 
-	docker run -e SERVER_NAME=ldap.my-compagny.com -d osixia/openldap
+	docker run -h ldap.example.org -e SERVER_NAME=ldap.my-compagny.com -d osixia/openldap
 
 #### Use your own certificate
 
 Add your custom certificate, private key and CA certificate in the directory **image/service/slapd/assets/ssl** adjust filename in **image/env.yml** and rebuild the image ([see manual build](#manual-build)).
 
-Or you can set your custom certificate at run time, by mouting your a directory containing thoses files to **/osixia/slapd/ssl** and adjust there name with the following environment variables :
+Or you can set your custom certificate at run time, by mouting a directory containing thoses files to **/osixia/slapd/assets/ssl** and adjust there name with the following environment variables :
 
-	docker run -v /path/to/certifates:/osixia/slapd/ssl \
+	docker run -h ldap.example.org -v /path/to/certifates:/osixia/slapd/assets/ssl \
 	-e SSL_CRT_FILENAME=my-ldap.crt \
 	-e SSL_KEY_FILENAME=my-ldap.key \
 	-e SSL_CA_CRT_FILENAME=the-ca.crt \
 	-d osixia/openldap
-	
+
 #### Disable TLS
 Add -e USE_TLS=false to the run command :
 
-	docker run -e USE_TLS=false -d osixia/openldap
+	docker run -h ldap.example.org  -e USE_TLS=false -d osixia/openldap
+
+### Multi master replication
+Quick example, with the default config.
+
+Create the first ldap server, save the container id in LDAP_CID and get its IP:
+
+	LDAP_CID=$(docker run -h ldap.example.org -e USE_REPLICATION=true -d osixia/openldap)
+	LDAP_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP_CID)
+
+Create the second ldap server, save the container id in LDAP2_CID and get its IP:
+
+	LDAP2_CID=$(docker run -h ldap2.example.org -e USE_REPLICATION=true -d osixia/openldap)
+	LDAP2_IP=$(docker inspect -f "{{ .NetworkSettings.IPAddress }}" $LDAP2_CID)
+
+Add the pair "ip hostname" to /etc/hosts on each containers,
+beacause ldap.example.org and ldap2.example.org are fake hostnames
+
+	docker exec $LDAP_CID /osixia/test/add-host.sh $LDAP2_IP ldap2.example.org
+	docker exec $LDAP2_CID /osixia/test/add-host.sh $LDAP_IP ldap.example.org
+
+We reload slapd to let him take into consideration /etc/hosts changes
+
+	docker exec $LDAP_CID pkill slapd
+	docker exec $LDAP2_CID pkill slapd
+
+That's it ! But a litle test to be sure :
+
+Add a new user "billy" on the first ldap server
+
+	docker exec $LDAP_CID ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /osixia/test/new-user.ldif -h ldap.example.org -ZZ
+
+Search on the second ldap server, and billy should show up !
+
+	docker exec $LDAP2_CID ldapsearch -x -h ldap2.example.org -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin -ZZ
+
+	[...]
+
+	# billy, example.org
+	dn: uid=billy,dc=example,dc=org
+	uid: billy
+	cn: billy
+	sn: 3
+	objectClass: top
+	objectClass: posixAccount
+	objectClass: inetOrgPerson
+	[...]
+
 
 ## Administrate your ldap server
 If you are looking for a simple solution to administrate your ldap server you can take a look at our phpLDAPadmin docker image :
@@ -116,9 +161,12 @@ If you are looking for a simple solution to administrate your ldap server you ca
 
 ## Environment Variables
 
-Environement variables defaults are set in **image/env.yml**. You can modify environment variable values directly in this file and rebuild the image ([see manual build](#manual-build)) or you can override those values at run time with -e argument. See example below.
+Environement variables defaults are set in **image/env.yml**. You can modify environment variable values directly in this file and rebuild the image ([see manual build](#manual-build)). You can also override those values at run time with -e argument or by setting your own env.yml file as a docker volume to `/etc/env.yml`. See examples below.
+
+General container configuration :
+- **LDAP_LOG_LEVEL**: Slap log level. defaults to  `-1`. See table 5.1 in http://www.openldap.org/doc/admin24/slapdconf2.html for the available log levels.
 
-Required for new ldap server :
+Required and used for new ldap server only :
 - **LDAP_ORGANISATION**: Organisation name. Defaults to `Example Inc.`
 - **LDAP_DOMAIN**: Ldap domain. Defaults to `example.org`
 - **LDAP_ADMIN_PASSWORD** Admin password. Defaults to `admin`
@@ -128,15 +176,25 @@ TLS options :
 - **SSL_CRT_FILENAME**: Ldap ssl certificate filename. Defaults to `ldap.crt`
 - **SSL_KEY_FILENAME**: Ldap ssl certificate private key filename. Defaults to `ldap.key`
 - **SSL_CA_CRT_FILENAME**: Ldap ssl CA certificate  filename. Defaults to `ca.crt`
-- **SERVER_NAME**: Use by autogenerated certificate: Server CN. Defaults to `ldap.example.org`
+
+Replication options :
+- **USE_REPLICATION**: Add openldap replication capabilities. Defaults to `false`
+- **REPLICATION_CONFIG_SYNCPROV**: olcSyncRepl options used for the config database. Without **rid** and **provider** which are automaticaly added based on REPLICATION_HOSTS.  Defaults to `binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical`
+- **REPLICATION_HDB_SYNCPROV**: olcSyncRepl options used for the HDB database. Without **rid** and **provider** which are automaticaly added based on REPLICATION_HOSTS.  Defaults to `binddn="cn=admin,$BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="5 5 300 5" timeout=1  starttls=critical`
+- **REPLICATION_HOSTS**: list of replication hosts, must contains the current container hostname set by -h on docker run command. Defaults to `['ldap://ldap.example.org', 'ldap://ldap2.example.org']`
 
 ### Set environment variables at run time :
 
 Environment variable can be set directly by adding the -e argument in the command line, for example :
-	
-	docker run -e LDAP_ORGANISATION="My Compagny" -e LDAP_DOMAIN="my-compagny.com" \
+
+	docker run -h ldap.example.org -e LDAP_ORGANISATION="My Compagny" -e LDAP_DOMAIN="my-compagny.com" \
 	-e LDAP_ADMIN_PASSWORD="JonSn0w" -d osixia/openldap
 
+Or by setting your own `env.yml` file as a docker volume to `/etc/env.yml`
+
+	docker run -h ldap.example.org -v /data/my-ldap-env.yml:/etc/env.yml \
+	-d osixia/openldap
+
 ## Manual build
 
 Clone this project :
@@ -148,18 +206,18 @@ Adapt Makefile, set your image NAME and VERSION, for example :
 
 	NAME = osixia/openldap
 	VERSION = 0.10.0
-	
+
 	becomes :
 	NAME = billy-the-king/openldap
 	VERSION = 0.1.0
 
 Build your image :
-	
+
 	make build
-	
+
 Run your image :
 
-	docker run -d billy-the-king/openldap:0.1.0
+	docker run -h ldap.example.org -d billy-the-king/openldap:0.1.0
 
 ## Tests
 
@@ -170,5 +228,3 @@ We use **Bats** (Bash Automated Testing System) to test this image:
 Install Bats, and in this project directory run :
 
 	make test
-
-	

+ 9 - 12
image/Dockerfile

@@ -1,4 +1,4 @@
-FROM osixia/baseimage:0.10.4
+FROM osixia/baseimage:0.10.5
 MAINTAINER Bertrand Gouny <[email protected]>
 
 # Use baseimage-docker's init system.
@@ -7,24 +7,21 @@ CMD ["/sbin/my_init"]
 # Add openldap user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added
 RUN groupadd -r openldap && useradd -r -g openldap openldap
 
-# Install OpenLDAP and ldap-utils (and ssl-kit from baseimage), remove default ldap db
+# Install OpenLDAP, ldap-utils and ssl-kit from baseimage, remove default ldap db
 RUN apt-get -y update && /sbin/enable-service ssl-kit \
-	&& LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes --no-install-recommends slapd ldap-utils \
-	&& rm -rf /var/lib/ldap
+	&& LC_ALL=C DEBIAN_FRONTEND=noninteractive apt-get install -y --force-yes --no-install-recommends \
+	slapd ldap-utils ntp \
+	&& rm -rf /var/lib/ldap /etc/ldap/slapd.d
 
-# Add OpenLDAP assets
-ADD service/slapd/assets /osixia/slapd
+# Add service directory to /osixia
+ADD service /osixia
 
-# Clean all
-RUN apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
+# Use baseimage service auto-install script and clean all
+RUN ./sbin/auto-install && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
 
 # Add default env variables
 ADD env.yml /etc/env.yml
 
-# Add OpenLDAP container start config & daemon
-ADD service/slapd/container-start.sh /etc/my_init.d/slapd
-ADD service/slapd/daemon.sh /etc/service/slapd/run
-
 # Set OpenLDAP data and config directories in a data volume
 VOLUME ["/var/lib/ldap", "/etc/ldap/slapd.d"]
 

+ 17 - 2
image/env.yml

@@ -1,11 +1,26 @@
 LDAP_ORGANISATION: Example Inc.
 LDAP_DOMAIN: example.org
 LDAP_ADMIN_PASSWORD: admin
-LDAP_LOG_LEVEL: -1
+LDAP_CONFIG_PASSWORD: config
 
-SERVER_NAME: ldap.example.org
+#See table 5.1 in http://www.openldap.org/doc/admin24/slapdconf2.html for the available log levels.
+LDAP_LOG_LEVEL: -1
 
 USE_TLS: true
 SSL_CRT_FILENAME: ldap.crt
 SSL_KEY_FILENAME: ldap.key
 SSL_CA_CRT_FILENAME: ca.crt
+
+
+USE_REPLICATION: false
+# variables $BASE_DN, $LDAP_ADMIN_PASSWORD, $LDAP_CONFIG_PASSWORD and $SSL_*
+# are automaticaly replaced at run time
+
+# if you want to add replication to an existing ldap
+# adapt REPLICATION_CONFIG_SYNCPROV and REPLICATION_HDB_SYNCPROV to your configuration
+# avoid using $BASE_DN, $LDAP_ADMIN_PASSWORD and $LDAP_CONFIG_PASSWORD variables
+REPLICATION_CONFIG_SYNCPROV: binddn="cn=admin,cn=config" bindmethod=simple credentials=$LDAP_CONFIG_PASSWORD searchbase="cn=config" type=refreshAndPersist retry="5 5 300 5" timeout=1 starttls=critical
+REPLICATION_HDB_SYNCPROV: binddn="cn=admin,$BASE_DN" bindmethod=simple credentials=$LDAP_ADMIN_PASSWORD searchbase="$BASE_DN" type=refreshAndPersist interval=00:00:00:10 retry="5 5 300 5" timeout=1  starttls=critical
+REPLICATION_HOSTS:
+  - ldap://ldap.example.org # The order must be the same on all ldap servers
+  - ldap://ldap2.example.org

+ 0 - 1
image/service/slapd/assets/config/README.md

@@ -1 +0,0 @@
-Add your ldif config file here

+ 1 - 0
image/service/slapd/assets/config/bootstrap/README.md

@@ -0,0 +1 @@
+Bootstrap config, for a container started without an existing ldap config.

+ 7 - 0
image/service/slapd/assets/config/bootstrap/ldif/config-password.ldif

@@ -0,0 +1,7 @@
+# Set config password
+dn: cn=config
+changeType: modify
+
+dn: olcDatabase={0}config,cn=config
+add: olcRootPW
+olcRootPW: {{ CONFIG_PASSWORD_ENCRYPTED }}

+ 6 - 0
image/service/slapd/assets/config/bootstrap/ldif/index.ldif

@@ -0,0 +1,6 @@
+# Add indexes
+dn: olcDatabase={1}hdb,cn=config
+changetype:  modify
+replace: olcDbIndex
+olcDbIndex: entryCSN eq
+olcDbIndex: entryUUID eq

+ 1 - 1
image/service/slapd/assets/config/logging.ldif → image/service/slapd/assets/config/bootstrap/ldif/logging.ldif

@@ -1,4 +1,4 @@
 dn: cn=config
 changetype: modify
 replace: olcLogLevel
-olcLogLevel: stats
+olcLogLevel: stats

+ 0 - 0
image/service/slapd/assets/security.ldif → image/service/slapd/assets/config/bootstrap/ldif/security.ldif


+ 1 - 0
image/service/slapd/assets/config/bootstrap/schema/README.md

@@ -0,0 +1 @@
+Bootstrap schemas, for a container started without an existing ldap config.

+ 0 - 0
image/service/slapd/assets/schema/mmc/README.md → image/service/slapd/assets/config/bootstrap/schema/mmc/README.md


+ 0 - 0
image/service/slapd/assets/schema/mmc/dhcp.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/dhcp.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/dnszone.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/dnszone.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/mail.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/mail.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/mmc.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/mmc.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/openssh-lpk.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/openssh-lpk.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/quota.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/quota.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/radius.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/radius.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/samba.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/samba.schema


+ 0 - 0
image/service/slapd/assets/schema/mmc/zarafa.schema → image/service/slapd/assets/config/bootstrap/schema/mmc/zarafa.schema


+ 26 - 0
image/service/slapd/assets/config/replication/replication-disable.ldif

@@ -0,0 +1,26 @@
+# Delete sync replication on hdb
+dn: olcDatabase={1}hdb,cn=config
+changetype: modify
+delete: olcSyncRepl
+-
+delete: olcMirrorMode
+
+# Delete syncprov on hdb
+dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
+changetype: delete
+
+# Delete sync replication on config
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+delete: olcSyncRepl
+-
+delete: olcMirrorMode
+
+# Delete syncprov on config
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: delete
+
+# Delete server ID
+dn: cn=config
+changeType: modify
+delete: olcServerID

+ 43 - 0
image/service/slapd/assets/config/replication/replication-enable-template.ldif

@@ -0,0 +1,43 @@
+# Load syncprov module
+dn: cn=module{0},cn=config
+changetype: modify
+add: olcModuleLoad
+olcModuleLoad: syncprov
+
+# Set server ID
+dn: cn=config
+changeType: modify
+add: olcServerID
+{{ REPLICATION_HOSTS }}
+
+# Add syncprov on config
+dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+# Add sync replication on config
+dn: olcDatabase={0}config,cn=config
+changetype: modify
+add: olcSyncRepl
+{{ REPLICATION_HOSTS_CONFIG_SYNC_REPL }}
+-
+add: olcMirrorMode
+olcMirrorMode: TRUE
+
+# Add syncprov on hdb
+dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
+changetype: add
+objectClass: olcOverlayConfig
+objectClass: olcSyncProvConfig
+olcOverlay: syncprov
+
+# Add sync replication on hdb
+dn: olcDatabase={1}hdb,cn=config
+changetype: modify
+add: olcSyncRepl
+{{ REPLICATION_HOSTS_HDB_SYNC_REPL }}
+-
+add: olcMirrorMode
+olcMirrorMode: TRUE

+ 13 - 0
image/service/slapd/assets/config/tls/tls-disable.ldif

@@ -0,0 +1,13 @@
+dn: cn=config
+changetype: modify
+delete: olcTLSCipherSuite
+-
+delete: olcTLSCACertificateFile
+-
+delete: olcTLSCertificateFile
+-
+delete: olcTLSCertificateKeyFile
+-
+delete: olcTLSDHParamFile
+-
+delete: olcTLSVerifyClient

+ 5 - 5
image/service/slapd/assets/tls.ldif → image/service/slapd/assets/config/tls/tls-enable.ldif

@@ -4,16 +4,16 @@ replace: olcTLSCipherSuite
 olcTLSCipherSuite: SECURE256:-VERS-SSL3.0
 -
 replace: olcTLSCACertificateFile
-olcTLSCACertificateFile: /osixia/slapd/ssl/ca.crt
+olcTLSCACertificateFile: /osixia/slapd/assets/ssl/ca.crt
 -
 replace: olcTLSCertificateFile
-olcTLSCertificateFile: /osixia/slapd/ssl/ldap.crt
+olcTLSCertificateFile: /osixia/slapd/assets/ssl/ldap.crt
 -
 replace: olcTLSCertificateKeyFile
-olcTLSCertificateKeyFile: /osixia/slapd/ssl/ldap.key
+olcTLSCertificateKeyFile: /osixia/slapd/assets/ssl/ldap.key
 -
 replace: olcTLSDHParamFile
-olcTLSDHParamFile: /osixia/slapd/ssl/dhparam.pem
+olcTLSDHParamFile: /osixia/slapd/assets/ssl/dhparam.pem
 -
 replace: olcTLSVerifyClient
-olcTLSVerifyClient: never
+olcTLSVerifyClient: demand

+ 1 - 1
image/service/slapd/assets/ssl/README.md

@@ -1,2 +1,2 @@
 Add your ssl crt, key and ca crt here
-or during docker run mount a data volume with thoses files to /osixia/slapd/ssl
+or during docker run mount a data volume with thoses files to /osixia/slapd/assets/ssl

+ 166 - 59
image/service/slapd/container-start.sh

@@ -1,6 +1,8 @@
 #!/bin/bash -e
 
 FIRST_START_DONE="/etc/docker-openldap-first-start-done"
+WAS_STARTED_WITH_TLS="/etc/ldap/slapd.d/docker-openldap-was-started-with-tls"
+WAS_STARTED_WITH_REPLICATION="/etc/ldap/slapd.d/docker-openldap-was-started-with-replication"
 
 # Reduce maximum number of number of open file descriptors to 1024
 # otherwise slapd consumes two orders of magnitude more of RAM
@@ -8,13 +10,16 @@ FIRST_START_DONE="/etc/docker-openldap-first-start-done"
 ulimit -n 1024
 
 #fix file permissions
-chown -R openldap:openldap /var/lib/ldap 
+chown -R openldap:openldap /var/lib/ldap
 chown -R openldap:openldap /etc/ldap
+chown -R openldap:openldap /osixia/slapd
+
+/etc/init.d/ntp restart
 
 # container first start
 if [ ! -e "$FIRST_START_DONE" ]; then
 
-  function get_base_dn(){
+  function get_base_dn() {
     BASE_DN=""
     IFS='.' read -ra BASE_DN_TABLE <<< "$LDAP_DOMAIN"
     for i in "${BASE_DN_TABLE[@]}"; do
@@ -25,7 +30,7 @@ if [ ! -e "$FIRST_START_DONE" ]; then
     BASE_DN=${BASE_DN::-1}
   }
 
-  function is_new_schema(){
+  function is_new_schema() {
     local COUNT=$(ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config cn | grep -c $1)
     if [ "$COUNT" -eq 0 ]; then
       echo 1
@@ -34,8 +39,31 @@ if [ ! -e "$FIRST_START_DONE" ]; then
     fi
   }
 
-  # database is uninitialized
-  if [ -z "$(ls -A /var/lib/ldap)" ]; then
+  function check_tls_files() {
+
+    local CA_CRT=$1
+    local LDAP_CRT=$2
+    local LDAP_KEY=$3
+
+    # check certificat and key or create it
+    /sbin/ssl-kit "/osixia/slapd/assets/ssl/$LDAP_CRT" "/osixia/slapd/assets/ssl/$LDAP_KEY" --ca-crt=/osixia/slapd/assets/ssl/$CA_CRT --gnutls
+
+    # create DHParamFile if not found
+    [ -f /osixia/slapd/assets/ssl/dhparam.pem ] || openssl dhparam -out /osixia/slapd/assets/ssl/dhparam.pem 2048
+
+    # fix file permissions
+    chown -R openldap:openldap /osixia/slapd
+  }
+
+
+  BOOTSTRAP=false
+
+  # database and config directory are empty -> set bootstrap config
+  if [ -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
+
+    BOOTSTRAP=true
+    echo "database and config directory are empty"
+    echo "-> set bootstrap config"
 
     cat <<EOF | debconf-set-selections
 slapd slapd/internal/generated_adminpw password ${LDAP_ADMIN_PASSWORD}
@@ -55,78 +83,160 @@ EOF
 
     dpkg-reconfigure -f noninteractive slapd
 
-    # start OpenLDAP
-    slapd -h "ldapi:///" -u openldap -g openldap
-
-    get_base_dn 
-    sed -i "s|dc=example,dc=org|$BASE_DN|g" /osixia/slapd/security.ldif
-
-    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/security.ldif
+  elif [ -z "$(ls -A /var/lib/ldap)" ] && [ ! -z "$(ls -A /etc/ldap/slapd.d)" ]; then
+    echo "Error: the database directory (/var/lib/ldap) is empty but not the config directory (/etc/ldap/slapd.d)"
+    exit 1
+  elif [ ! -z "$(ls -A /var/lib/ldap)" ] && [ -z "$(ls -A /etc/ldap/slapd.d)" ]; then
+    echo "the config directory (/etc/ldap/slapd.d) is empty but not the database directory (/var/lib/ldap)"
+    exit 1
 
   else
+    # there is an existing database and config
 
-    # start OpenLDAP
-    slapd -h "ldapi:///" -u openldap -g openldap
+    # if the config was bootstraped with TLS
+    # to avoid error (#6) we check tls files
+    if [ -e "$WAS_STARTED_WITH_TLS" ]; then
 
+      . $WAS_STARTED_WITH_TLS
+
+      check_tls_files $PREVIOUS_SSL_CA_CRT_FILENAME $PREVIOUS_SSL_CRT_FILENAME $PREVIOUS_SSL_KEY_FILENAME
+    fi
   fi
 
+  # start OpenLDAP
+  echo "Starting openldap..."
+  slapd -h "ldapi:///" -u openldap -g openldap
+  echo "ok"
+
+  # set bootstrap config part 2
+  if $BOOTSTRAP; then
+
+    # add ppolicy schema if not already exists
+    ADD_PPOLICY=$(is_new_schema ppolicy)
+    if [ "$ADD_PPOLICY" -eq 1 ]; then
+      ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif
+    fi
+
+    # convert schemas to ldif
+    SCHEMAS=""
+    for f in $(find /osixia/slapd/assets/config/bootstrap/schema -name \*.schema -type f); do
+      SCHEMAS="$SCHEMAS ${f}"
+    done
+    /osixia/slapd/assets/schema-to-ldif.sh "$SCHEMAS"
+
+    # add schemas
+    for f in $(find /osixia/slapd/assets/config/bootstrap/schema -name \*.ldif -type f); do
+      echo "Processing file ${f}"
+      # add schema if not already exists
+      SCHEMA=$(basename "${f}" .ldif)
+      ADD_SCHEMA=$(is_new_schema $SCHEMA)
+      if [ "$ADD_SCHEMA" -eq 1 ]; then
+        echo "add schema ${SCHEMA}"
+        ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f
+      else
+        echo "schema ${f} already exists"
+      fi
+    done
+
+    # set config password
+    CONFIG_PASSWORD_ENCRYPTED=$(slappasswd -s $LDAP_CONFIG_PASSWORD)
+    sed -i "s|{{ CONFIG_PASSWORD_ENCRYPTED }}|$CONFIG_PASSWORD_ENCRYPTED|g" /osixia/slapd/assets/config/bootstrap/ldif/config-password.ldif
+
+    # adapt security config file
+    get_base_dn
+    sed -i "s|dc=example,dc=org|$BASE_DN|g" /osixia/slapd/assets/config/bootstrap/ldif/security.ldif
+
+    # process config files
+    for f in $(find /osixia/slapd/assets/config/bootstrap/ldif  -name \*.ldif -type f); do
+      echo "Processing file ${f}"
+      ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $f
+    done
+
+  fi
 
   # TLS config
   if [ "${USE_TLS,,}" == "true" ]; then
 
-    # check certificat and key or create it
-    /sbin/ssl-kit "/osixia/slapd/ssl/$SSL_CRT_FILENAME" "/osixia/slapd/ssl/$SSL_KEY_FILENAME" --ca-crt=/osixia/slapd/ssl/$SSL_CA_CRT_FILENAME --gnutls
+    echo "Use TLS"
 
-    # create DHParamFile if not found
-    [ -f /osixia/slapd/ssl/dhparam.pem ] || openssl dhparam -out /osixia/slapd/ssl/dhparam.pem 2048
+    check_tls_files $SSL_CA_CRT_FILENAME $SSL_CRT_FILENAME $SSL_KEY_FILENAME
 
     # adapt tls ldif
-    sed -i "s,/osixia/slapd/ssl/ca.crt,/osixia/slapd/ssl/${SSL_CA_CRT_FILENAME},g" /osixia/slapd/tls.ldif
-    sed -i "s,/osixia/slapd/ssl/ldap.crt,/osixia/slapd/ssl/${SSL_CRT_FILENAME},g" /osixia/slapd/tls.ldif
-    sed -i "s,/osixia/slapd/ssl/ldap.key,/osixia/slapd/ssl/${SSL_KEY_FILENAME},g" /osixia/slapd/tls.ldif
+    sed -i "s,/osixia/slapd/assets/ssl/ca.crt,/osixia/slapd/assets/ssl/${SSL_CA_CRT_FILENAME},g" /osixia/slapd/assets/config/tls/tls-enable.ldif
+    sed -i "s,/osixia/slapd/assets/ssl/ldap.crt,/osixia/slapd/assets/ssl/${SSL_CRT_FILENAME},g" /osixia/slapd/assets/config/tls/tls-enable.ldif
+    sed -i "s,/osixia/slapd/assets/ssl/ldap.key,/osixia/slapd/assets/ssl/${SSL_KEY_FILENAME},g" /osixia/slapd/assets/config/tls/tls-enable.ldif
 
-    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/tls.ldif
+    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/assets/config/tls/tls-enable.ldif
 
-    # add localhost route to certificate cn (need docker 1.5.0)
-    cn=$(openssl x509 -in /osixia/slapd/ssl/$SSL_CRT_FILENAME -subject -noout | sed -n 's/.*CN=\(.*\)\/*\(.*\)/\1/p')
-    echo "127.0.0.1 $cn" >> /etc/hosts
+    [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
+    touch $WAS_STARTED_WITH_TLS
+    echo "export PREVIOUS_SSL_CA_CRT_FILENAME=${SSL_CA_CRT_FILENAME}" >> $WAS_STARTED_WITH_TLS
+    echo "export PREVIOUS_SSL_CRT_FILENAME=${SSL_CRT_FILENAME}" >> $WAS_STARTED_WITH_TLS
+    echo "export PREVIOUS_SSL_KEY_FILENAME=${SSL_KEY_FILENAME}" >> $WAS_STARTED_WITH_TLS
+    chmod +x $WAS_STARTED_WITH_TLS
 
-    # local ldap tls client config
-    sed -i "s,TLS_CACERT.*,TLS_CACERT /osixia/slapd/ssl/${SSL_CA_CRT_FILENAME},g" /etc/ldap/ldap.conf
-  fi
+    # ldap client config
+    sed -i "s,TLS_CACERT.*,TLS_CACERT /osixia/slapd/assets/ssl/${SSL_CA_CRT_FILENAME},g" /etc/ldap/ldap.conf
+    echo "TLS_REQCERT demand" >> /etc/ldap/ldap.conf
+
+    [[ -f "$HOME/.ldaprc" ]] && rm -f $HOME/.ldaprc
+    touch $HOME/.ldaprc
+    echo "TLS_CERT /osixia/slapd/assets/ssl/${SSL_CRT_FILENAME}" >> $HOME/.ldaprc
+    echo "TLS_KEY /osixia/slapd/assets/ssl/${SSL_KEY_FILENAME}" >> $HOME/.ldaprc
+
+  else
+
+    echo "Don't use TLS"
+
+    [[ -f "$WAS_STARTED_WITH_TLS" ]] && rm -f "$WAS_STARTED_WITH_TLS"
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/assets/config/tls/tls-disable.ldif || true
 
-  # add ppolicy schema if not already exists
-  ADD_PPOLICY=$(is_new_schema ppolicy)
-  if [ "$ADD_PPOLICY" -eq 1 ]; then
-    ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif
   fi
 
-  # convert  schemas to ldif
-  SCHEMAS=""
-  for f in $(find /osixia/slapd/schema -name \*.schema -type f); do
-    SCHEMAS="$SCHEMAS ${f}"
-  done
-  /osixia/slapd/schema-to-ldif.sh "$SCHEMAS"
-
-  for f in $(find /osixia/slapd/schema -name \*.ldif -type f); do
-    echo "Processing file ${f}"
-    # add schema if not already exists
-    SCHEMA=$(basename "${f}" .ldif)
-    ADD_SCHEMA=$(is_new_schema $SCHEMA)
-    if [ "$ADD_SCHEMA" -eq 1 ]; then
-      echo "add schema ${SCHEMA}"
-      ldapadd -c -Y EXTERNAL -Q -H ldapi:/// -f $f
-    else
-      echo "schema ${f} already exists"
-    fi
 
-  done
+  # replication config
+  if [ "${USE_REPLICATION,,}" == "true" ]; then
+
+    echo "Use replication"
+
+    # copy template file
+    cp /osixia/slapd/assets/config/replication/replication-enable-template.ldif /osixia/slapd/assets/config/replication/replication-enable.ldif
+
+    REPLICATION_HOSTS=($REPLICATION_HOSTS)
+    i=1
+    for host in "${REPLICATION_HOSTS[@]}"
+    do
+
+      #host var contain a variable name, we access to the variable value and cast it to a table
+      host=${!host}
+
+      sed -i "s|{{ REPLICATION_HOSTS }}|olcServerID: $i ${host}\n{{ REPLICATION_HOSTS }}|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "s|{{ REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|olcSyncRepl: rid=00$i provider=${host} ${REPLICATION_CONFIG_SYNCPROV}\n{{ REPLICATION_HOSTS_CONFIG_SYNC_REPL }}|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+      sed -i "s|{{ REPLICATION_HOSTS_HDB_SYNC_REPL }}|olcSyncRepl: rid=10$i provider=${host} ${REPLICATION_HDB_SYNCPROV}\n{{ REPLICATION_HOSTS_HDB_SYNC_REPL }}|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+
+      ((i++))
+    done
+
+    get_base_dn
+    sed -i "s|\$BASE_DN|$BASE_DN|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+    sed -i "s|\$LDAP_ADMIN_PASSWORD|$LDAP_ADMIN_PASSWORD|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+    sed -i "s|\$LDAP_CONFIG_PASSWORD|$LDAP_CONFIG_PASSWORD|g" /osixia/slapd/assets/config/replication/replication-enable.ldif
+
+    sed -i "/{{ REPLICATION_HOSTS }}/d" /osixia/slapd/assets/config/replication/replication-enable.ldif
+    sed -i "/{{ REPLICATION_HOSTS_CONFIG_SYNC_REPL }}/d" /osixia/slapd/assets/config/replication/replication-enable.ldif
+    sed -i "/{{ REPLICATION_HOSTS_HDB_SYNC_REPL }}/d" /osixia/slapd/assets/config/replication/replication-enable.ldif
+
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/assets/config/replication/replication-enable.ldif
+    touch $WAS_STARTED_WITH_REPLICATION
+
+  else
+
+    echo "Don't use replication"
+    [[ -f "$WAS_STARTED_WITH_REPLICATION" ]] && rm -f "$WAS_STARTED_WITH_REPLICATION"
+    ldapmodify -c -Y EXTERNAL -Q -H ldapi:/// -f /osixia/slapd/assets/config/replication/replication-disable.ldif || true
+
+  fi
 
-  # OpenLDAP config 
-  for f in $(find /osixia/slapd/config -name \*.ldif -type f); do
-    echo "Processing file ${f}"
-    ldapmodify -Y EXTERNAL -Q -H ldapi:/// -f $f
-  done
 
   # stop OpenLDAP
   kill -INT `cat /run/slapd/slapd.pid`
@@ -134,7 +244,4 @@ EOF
   touch $FIRST_START_DONE
 fi
 
-# fix file permissions
-chown openldap:openldap -R /osixia/slapd
-
 exit 0

+ 1 - 1
image/service/slapd/daemon.sh

@@ -5,4 +5,4 @@
 # see https://github.com/docker/docker/issues/8231
 ulimit -n 1024
 
-exec /usr/sbin/slapd -h "ldap:/// ldaps:/// ldapi:///" -u openldap -g openldap -d "$LDAP_LOG_LEVEL"
+exec /usr/sbin/slapd -h "ldap://$HOSTNAME ldaps://$HOSTNAME ldapi:///" -u openldap -g openldap -d "$LDAP_LOG_LEVEL"

+ 2 - 0
image/service/test/add-host.sh

@@ -0,0 +1,2 @@
+#!/bin/bash -e
+echo $@ >> /etc/hosts

+ 14 - 0
image/service/test/new-user.ldif

@@ -0,0 +1,14 @@
+dn: uid=billy,dc=example,dc=org
+uid: billy
+cn: billy
+sn: 3
+objectClass: top
+objectClass: posixAccount
+objectClass: inetOrgPerson
+loginShell: /bin/bash
+homeDirectory: /home/billy
+uidNumber: 14583102
+gidNumber: 14564100
+userPassword: {SSHA}j3lBh1Seqe4rqF1+NuWmjhvtAni1JC5A
+mail: [email protected]
+gecos: Billy User

BIN
test/database/__db.001


BIN
test/database/__db.002


BIN
test/database/__db.003


BIN
test/database/alock


BIN
test/database/log.0000000001


+ 54 - 7
test/test.bats

@@ -10,9 +10,9 @@ load test_helper
 
 @test "ldapsearch new database" {
 
-  run_image -e USE_TLS=false
+  run_image -h ldap.example.org -e USE_TLS=false
   wait_service slapd
-  run docker exec $CONTAINER_ID ldapsearch -x -h 127.0.0.1 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
+  run docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin
   clear_container
 
   [ "$status" -eq 0 ]
@@ -21,7 +21,7 @@ load test_helper
 
 @test "ldapsearch new database with strict TLS" {
 
-  run_image
+  run_image -h ldap.example.org
   wait_service slapd
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=example,dc=org -ZZ -D "cn=admin,dc=example,dc=org" -w admin
   clear_container
@@ -32,7 +32,7 @@ load test_helper
 
 @test "ldapsearch new database with strict TLS and custom ca/crt" {
 
-  run_image -v $BATS_TEST_DIRNAME/ssl:/osixia/slapd/ssl -e SSL_CRT_FILENAME=ldap-test.crt -e SSL_KEY_FILENAME=ldap-test.key -e SSL_CA_CRT_FILENAME=ca-test.crt
+  run_image -h ldap.osixia.net -v $BATS_TEST_DIRNAME/ssl:/osixia/slapd/assets/ssl -e SSL_CRT_FILENAME=ldap-test.crt -e SSL_KEY_FILENAME=ldap-test.key -e SSL_CA_CRT_FILENAME=ca-test.crt
   wait_service slapd
   run docker exec $CONTAINER_ID ldapsearch -x -h ldap.osixia.net -b dc=example,dc=org -ZZ -D "cn=admin,dc=example,dc=org" -w admin
   clear_container
@@ -45,13 +45,60 @@ load test_helper
 
 @test "ldapsearch existing database and config" {
 
-  run_image -e USE_TLS=false -v $BATS_TEST_DIRNAME/database:/var/lib/ldap -v $BATS_TEST_DIRNAME/config:/etc/ldap/slapd.d
+  run_image -h ldap.example.org -e USE_TLS=false -v $BATS_TEST_DIRNAME/database:/var/lib/ldap -v $BATS_TEST_DIRNAME/config:/etc/ldap/slapd.d
   wait_service slapd
-  run docker exec $CONTAINER_ID ldapsearch -x -h 127.0.0.1 -b dc=osixia,dc=net -D "cn=admin,dc=osixia,dc=net" -w admin
+  run docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=osixia,dc=net -D "cn=admin,dc=osixia,dc=net" -w admin
   clear_container
 
   chown -R $UNAME:$UNAME $BATS_TEST_DIRNAME || true
 
   [ "$status" -eq 0 ]
 
-}
+}
+
+
+@test "replication with new databases and strict TLS" {
+
+  tmp_file="$BATS_TMPDIR/docker-test"
+
+  # replication ldap server
+  LDAP_REPL_CID=$(docker run -h ldap2.example.org -e USE_REPLICATION=true -d $IMAGE_NAME)
+  LDAP_REPL_IP=$(get_container_ip_by_cid $LDAP_REPL_CID)
+
+  # ldap server
+  run_image -h ldap.example.org -e USE_REPLICATION=true
+
+  # add route to hosts
+  docker exec $LDAP_REPL_CID /osixia/test/add-host.sh $CONTAINER_IP ldap.example.org
+  docker exec $CONTAINER_ID /osixia/test/add-host.sh $LDAP_REPL_IP ldap2.example.org
+
+  # wait services on both servers
+  wait_service slapd
+  wait_service_by_cid $LDAP_REPL_CID slapd
+
+  # restart slapd
+  docker exec $LDAP_REPL_CID pkill slapd
+  docker exec $CONTAINER_ID pkill slapd
+
+  # wait services on both servers
+  wait_service slapd
+  wait_service_by_cid $LDAP_REPL_CID slapd
+
+  # add user on ldap2.example.org
+  docker exec $LDAP_REPL_CID ldapadd -x -D "cn=admin,dc=example,dc=org" -w admin -f /osixia/test/new-user.ldif -h ldap2.example.org -ZZ
+
+  sleep 5
+
+  # search user on ldap.example.org
+  docker exec $CONTAINER_ID ldapsearch -x -h ldap.example.org -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin -ZZ >> $tmp_file
+  run grep -c "billy" $tmp_file
+
+  rm $tmp_file
+  clear_container
+
+  clear_containers_by_cid $LDAP_REPL_CID
+
+  [ "$status" -eq 0 ]
+  [ "$output" = "6" ]
+
+}