This post will show how to host a OpenLDAP service on the localhost step by step.
1. Prerequisites
docker-compose
installed.
2. Prepare LDAP data
We will create some data for LDAP service and populate it when the service runs up. Create a directory, for example openldap
, first, and create another sub-directory openldap/data
.
The structure of the LDAP data can be described by .ldif
file. So we can create below file openldap/data/bootstrap.ldif
as the LDAP boostrap data.
dn: cn=developer,dc=example,dc=org
changetype: add
objectclass: inetOrgPerson
cn: developer
givenname: developer
sn: Developer
displayname: Developer User
mail: developer@gmail.com
uid: developer
userpassword: developer_pass
dn: cn=maintainer,dc=example,dc=org
changetype: add
objectclass: inetOrgPerson
cn: maintainer
givenname: maintainer
sn: Maintainer
displayname: Maintainer User
mail: maintainer@gmail.com
uid: maintainer
userpassword: maintainer_pass
dn: cn=admin_gh,dc=example,dc=org
changetype: add
objectclass: inetOrgPerson
cn: admin_gh
givenname: admin_gh
sn: AdminGithub
displayname: Admin Github User
mail: admin_gh@gmail.com
userpassword: admin_gh_pass
dn: ou=Groups,dc=example,dc=org
changetype: add
objectclass: organizationalUnit
ou: Groups
dn: ou=Users,dc=example,dc=org
changetype: add
objectclass: organizationalUnit
ou: Users
dn: cn=Admins,ou=Groups,dc=example,dc=org
changetype: add
cn: Admins
objectclass: groupOfUniqueNames
uniqueMember: cn=admin_gh,dc=example,dc=org
dn: cn=Maintaners,ou=Groups,dc=example,dc=org
changetype: add
cn: Maintaners
objectclass: groupOfUniqueNames
uniqueMember: cn=maintainer,dc=example,dc=org
uniqueMember: cn=developer,dc=example,dc=org
The LDAP data structure looks like
So far, we only have one file bootstrap.ldif
under the directory /openldap
.
├── data
└── bootstrap.ldif
3. Prepare docker-compose file
Create /openldap/docker-compose.yaml
with the below content.
1version: '3.7'
2
3services:
4 ldap_server:
5 image: osixia/openldap:1.5.0
6 environment:
7 LDAP_ADMIN_PASSWORD: admin_pass
8 LDAP_BASE_DN: dc=example,dc=org
9 LDAP_DOMAIN: example.org
10 LDAP_ORGANISATION: "Example Inc."
11 hostname: ldap.example.org
12 command: --copy-service
13 ports:
14 - 389:389
15 volumes:
16 - ./data/bootstrap.ldif:/container/service/slapd/assets/config/bootstrap/ldif/50-bootstrap.ldif
17
18 ldap_server_admin:
19 image: osixia/phpldapadmin:0.7.2
20 ports:
21 - 8090:80
22 environment:
23 PHPLDAPADMIN_LDAP_HOSTS: ldap_server
24 PHPLDAPADMIN_HTTPS: 'false'
This docker-compose file is composed of two services: LDAP server
and LDAP admin panel
.
After running up the service with docker-compose up
and open the http://localhost:8090
from the web browser. We can see the below page.
We can test whether the bootstrap data is loaded or not by logging in the admin panel.
Note that the Login DN should be cn=admin,dc=example,dc=org
and Password is admin_pass
created by docker-compose environment.
Then you can see the LDAP data structure as below:
If you see the same result as above, it means the LDAP service is set up successfully.
If you prefer to use command line to test the LDAP server, you can run the below command without installing LDAP clent tool saperately.
docker exec openldap_ldap_server_1 ldapsearch -x -H ldap://localhost:389 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin_pass
The output should be like
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=org> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# example.org
dn: dc=example,dc=org
objectClass: top
objectClass: dcObject
objectClass: organization
o: Example Inc.
dc: example
# developer, example.org
dn: cn=developer,dc=example,dc=org
objectClass: inetOrgPerson
cn: developer
givenName: developer
sn: Developer
displayName: Developer User
mail: developer@gmail.com
uid: developer
userPassword:: ZGV2ZWxvcGVyX3Bhc3M=
# maintainer, example.org
dn: cn=maintainer,dc=example,dc=org
objectClass: inetOrgPerson
cn: maintainer
givenName: maintainer
sn: Maintainer
displayName: Maintainer User
mail: maintainer@gmail.com
uid: maintainer
userPassword:: bWFpbnRhaW5lcl9wYXNz
# admin_gh, example.org
dn: cn=admin_gh,dc=example,dc=org
objectClass: inetOrgPerson
cn: admin_gh
givenName: admin_gh
sn: AdminGithub
displayName: Admin Github User
mail: admin_gh@gmail.com
userPassword:: YWRtaW5fZ2hfcGFzcw==
# Groups, example.org
dn: ou=Groups,dc=example,dc=org
objectClass: organizationalUnit
ou: Groups
# Users, example.org
dn: ou=Users,dc=example,dc=org
objectClass: organizationalUnit
ou: Users
# Admins, Groups, example.org
dn: cn=Admins,ou=Groups,dc=example,dc=org
cn: Admins
objectClass: groupOfUniqueNames
uniqueMember: cn=admin_gh,dc=example,dc=org
# Maintainers, Groups, example.org
dn: cn=Maintainers,ou=Groups,dc=example,dc=org
cn: Maintainers
objectClass: groupOfUniqueNames
uniqueMember: cn=maintainer,dc=example,dc=org
uniqueMember: cn=developer,dc=example,dc=org
# search result
search: 2
result: 0 Success
# numResponses: 9
# numEntries: 8
Now, the directory structure of /openldap
is like:
├── data
│ └── bootstrap.ldif
└── docker-compose.yml
4. Host the service with custom TLS certificates
I will assume that you already had the custom TLS certificates before this step. You can put them under the directory /openldap/data/certs
.
If you don’t have, you can head to my another post How to generate custom TLS certificates with cfssl to generate a new one in 2 minutes.
After adding the custom TLS certificates, the file structure under /openldap
should look like
├── data
│ ├── bootstrap.ldif
│ └── certs
│ ├── ldap-ca.pem
│ ├── ldap-key.pem
│ └── ldap.pem
└── docker-compose.yml
Last step, we will need to update the docker-compose file for using our own TLS certificates.
1version: '3.7'
2
3services:
4 ldap_server:
5 image: osixia/openldap:1.5.0
6 environment:
7 LDAP_ADMIN_PASSWORD: admin_pass
8 LDAP_BASE_DN: dc=example,dc=org
9 LDAP_DOMAIN: example.org
10 LDAP_ORGANISATION: "Example Inc."
11 LDAP_TLS_CRT_FILENAME: ldap.pem
12 LDAP_TLS_KEY_FILENAME: ldap-key.pem
13 LDAP_TLS_CA_CRT_FILENAME: ldap-ca.pem
14 LDAP_TLS_VERIFY_CLIENT: try
15 hostname: ldap.example.org
16 command: --copy-service
17 ports:
18 - 389:389
19 - 636:636
20 volumes:
21 - ./data/bootstrap.ldif:/container/service/slapd/assets/config/bootstrap/ldif/50-bootstrap.ldif
22 - ./data/certs:/container/service/slapd/assets/certs
23
24 ldap_server_admin:
25 image: osixia/phpldapadmin:0.7.2
26 ports:
27 - 8090:80
28 environment:
29 PHPLDAPADMIN_LDAP_HOSTS: ldap_server
30 PHPLDAPADMIN_HTTPS: 'false'
It may take bit longer to run up the above docker-compose than the previous one. If the below logs are shown, it means it’s ready.
Now we can give a test. Unfortunately, we couldn’t take advantage of the image built-in ldapsearch tool docker exec openldap_ldap_server_1 ldapsearch
like before.
It’s because the certificate path is passed by the docker-compose environment variable, so we cannot really see the effect with custom TLS certificate.
In this case, I would suggest to install the ldapsearch
binary on your localhost or use the services that supports LDAP feature.
With the ldapsearch
binary, you may run the below command to test.
env LDAPTLS_CACERT=/path/to/cert ldapsearch -x -H ldaps://localhost:636 -b dc=example,dc=org -D "cn=admin,dc=example,dc=org" -w admin_pass
With other services that supports LDAP feature, I would suggest to try with Portainer even though it can do much much more than only testing LDAP service.
You can find the completed implementation from my github repository oscarzhou/openldap.
While I was learning the knowledge about ldap, I searched quite a lot of online sites, pages. Thanks to the authors of the below contents.
If this post helped you to solve a problem or provided you with new insights, please upvote it and share your experience in the comments below. Your comments can help others who may be facing similar challenges. Thank you!