configurable container running LDAP
Go to file
2025-09-28 14:20:42 -04:00
dockerfile Update dockerfile 2025-09-16 14:56:18 -04:00
README.md Update README.md 2025-09-28 14:20:42 -04:00

ldapdock

a configurable container running openLDAP

Step by step approach on how to setup and run the openLDAP server on a classic systemd-less Docker image container

note about the dockerfile and running the generated image container on FG (foreground) or BG (background): by default the dockerfile generates an image to be run in FG, it expects to be run into it and launch slapd (openLDAP server) manually; to run the image container in BG and start slapd automatically without any user intervention, uncomment the line number 31 of the dockerfile.

Creating the ldapdock image container

build ldapdock

> docker build -t ldapdock /path/to/dockerfile

after build, check the docker image has been created properly with the given REPOSITORY name

> docker images
REPOSITORY    TAG       IMAGE ID       CREATED       SIZE
ldapdock      latest    0e4a1521b346   6 hours ago   138MB

If you just want to jump in the container and right now don't care saving the configuration or directories, you can run it with this command:

> docker run -h example.com -i -t ldapdock /bin/bash

If you wish (and it is recommended in development) to save the configuration and LDAP directory structure (also called LDAP database) outside of the container, run this command instead:

> docker run -h example.com -i -t -v ldap_data:/var/lib/ldap -v ldap_config:/etc/ldap/slapd.d ldapdock /bin/bash

Parameters explanation:with -h we are specifying the name of the host, we are using example.com, this is very important. -i tells docker to run in an interactive way instead of running the container in the background. -t goes in hand with -i, and allocates a tty (terminal) so we can run commands. -v mounts a volume to save information (we use one to save the data and another one to save the configuration).

Explaining DN, parentDN, CN, and DC as parameters

One of the key configuration of LDAP is our "DC" or "parent DN" and other terms, which to explain it in a pure pragmatic way, we will use some examples: we use per defect example.com as our domain, so the DC (Distinguished Name) that we would use it is "dc=example,dc=com", instead, if our domain would be for example "ideas.lab.com", the parent DN would be "dc=ideas,dc=lab,dc=com". This configuration it's very often passed with the CN (Common Name) in concatenation with the DN (Distinguished Name), and the result it's very simple, in the case of the domain example.com, it is DN: "cn=config,dn=example,dn=com", or for ideas.lab.com DN: "cn=config,dn=ideas,dn=lab,dn=com".

Inside the ldapdock image container

Use the following command to start openLDAP

root@example:/# slapd -h "ldap:/// ldapi:///" -g openldap -u openldap -F /etc/ldap/slapd.d

It's always a good idea to test connectivity to slapd the first times

root@example:/# ldapsearch -x -H ldap://localhost -b "dc=example,dc=com" -s base "(objectclass=*)"
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope baseObject
...

Create an Administrator account

In order to create users with different attributes and permits, we need to create a new admin account besides the root one that comes with slapd by default.
We will refer to the LDAP Administrator account as admin or administrative account, and to the root account simply the one sat by default. When running any Administrative task that requires the usage of either the admin or root account, like creating an Organizational Unit (ou) or a new user, both accounts will have set the same privileges, meaning both will work, but it is strongly recommended to use the admin or administrative one created here. An easy way to differentiate them it's setting different passwords for each one, as we will see...

Generate a password hash for our administrator user, 1234 here being the password

root@example:/# slappasswd -s 1234  # Change 1234 to your desired password
{SSHA}yxIgYTzcuRRdlesjfWkIN6K97/8jOrZF

Create the .ldif file that will create the admin user, editing the userPassword attribute with our password hash

root@example:/# vim create_admin.ldif
dn: cn=admin,dc=example,dc=com
changetype: add
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: admin
userPassword: {SSHA}yxIgYTzcuRRdlesjfWkIN6K97/8jOrZF  # Replace with the hash of your password
description: LDAP administrator

Execute create_admin.ldif using as password, the root password admin which is the default one

root@example:/etc/ldap# ldapadd -x -H ldap:/// -D "cn=admin,dc=example,dc=com" -w admin -f create_admin.ldif
adding new entry "cn=admin,dc=example,dc=com"

Check the attributes of our new administrator user of our domain (parentDN)

root@example:/# ldapsearch -x -H ldap:/// -D "cn=admin,dc=example,dc=com" -w 1234 -b "cn=admin,dc=example,dc=com" "(objectclass=*)"
# extended LDIF
#
# LDAPv3
# base <cn=admin,dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#
# admin, example.com
dn: cn=admin,dc=example,dc=com
objectClass: organizationalRole
objectClass: simpleSecurityObject
cn: admin
userPassword:: e1NTSEF9eXhJZ1lUemN1UlJkbGVzamZXa0lONks5Ny84ak9yWkY=
description: LDAP administrator
...

That's all, our administrator user was properly done.

First administrative tasks

Create our first Organizational Unit (ou) with a new user

Prepare a new LDAP directory (ou) called Supergirls with the following data

root@example:/# vim add_ou.ldif
dn: ou=Supergirls,dc=example,dc=com
objectClass: organizationalUnit
ou: Supergirls

Execute the .ldif file to create it in the LDAP server, and when asked for the root password, remember in the dockerfile by default is admin

root@example:/# ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f add_ou.ldif
Enter LDAP Password:
adding new entry "ou=Supergirls,dc=example,dc=com"

verify the entry in the LDAP server

root@example:/# ldapsearch -x -LLL -b "dc=example,dc=com" "(ou=Supergirls)" dn
dn: ou=Supergirls,dc=example,dc=com

create a new LDAP password to manage our new directory, annotate both the entered plain password and the result hashed password

root@example:/# slappasswd
New password:
Re-enter new password:
{SSHA}hashedpasswd

create a .ldif file with the necessary attributes to insert in our Supergirls directory

root@example:/# vim add_user_supergirls.ldif
dn: uid=marisa,ou=Supergirls,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
cn: Marisa
sn: Kirisame
givenName: Marisa
displayName: Marisa Kirisame
uid: marisa
uidNumber: 1001
gidNumber: 5000
homeDirectory: /home/marisa
loginShell: /bin/bash
userPassword: {SSHA}hashedpasswd
mail: marisa@example.com

insert the new user (marisa) in our Supergirls directory (LDAP OU), still using the root password admin

root@example:/# ldapadd -x -D "cn=admin,dc=example,dc=com" -W -f add_user_supergirls.ldif
Enter LDAP Password:
adding new entry "uid=marisa,ou=Supergirls,dc=example,dc=com"

verify the user (marisa) has been added to the Supergirls OU

root@example:/# ldapsearch -x -LLL -b "dc=example,dc=com" "(uid=marisa)" dn
dn: uid=marisa,ou=Supergirls,dc=example,dc=com

Modify users attributes

create a new .ldif file with the attributes we want to change
in this case we want to modify the mail marisa@example.com of the user (uid) marisa from the group (ou) Supergirls

root@example:/home# vim modify_user.ldif
dn: uid=marisa,ou=Supergirls,dc=example,dc=com
changetype: modify
replace: mail
mail: marisa.kirisame@example.com

run the modify file, when asked for the root password, remember in the dockerfile by default is admin

root@example:/home# ldapmodify -x -D "cn=admin,dc=example,dc=com" -W -f modify_user.ldif
Enter LDAP Password:
modifying entry "uid=marisa,ou=Supergirls,dc=example,dc=com"

verify the mail attribute of the user marisa has been changed to marisa.kirisame@example.com

root@example:/home# ldapsearch -x -LLL -b "dc=example,dc=com" "(uid=marisa)" mail
dn: uid=marisa,ou=Engineering,dc=example,dc=com
mail: marisa.kirisame@example.com

Modify user password

In this examples, we are changing the special attribute password of the user marisa from ou Supergirls, using the old password.

In order to change the password interactively (writing in the prompt when asked), we can run this command:

root@example:/etc/ldap# ldappasswd -H ldap:/// -x -D "uid=marisa,ou=Supergirls,dc=example,dc=com" -W -S "uid=marisa,ou=Supergirls,dc=example,dc=com"
New password: newpasswd
Re-enter new password: newpasswd
Enter LDAP Password: oldpasswd

newpasswd being the new password we want to use, and oldpasswd, the last password we were using for the user uid marisa.

To change the password in an non interactive (sending the password directly via the command), we can run this:

root@example:/etc/ldap# ldappasswd -H ldap:/// -x -D "uid=marisa,ou=Supergirls,dc=example,dc=com" -w newpasswd "uid=marisa,ou=Supergirls,dc=example,dc=com"
New password: 6vUj/2lE

newpasswd being the new password we want to use. We can also notice the hashed output of our new password is not a typical LDAP SSHA hash, this is due to security implementations.

Reset user password

In the likely common event that we forgot the old password of an specific user, we need to reset it.
In this example we forgot the password of the user uid marisa, we can reset it with this command:

root@example:/etc/ldap# ldappasswd -H ldap:/// -x -D "cn=admin,dc=example,dc=com" -W -S "uid=marisa,ou=Supergirls,dc=example,dc=com"
New password: newpasswd
Re-enter new password: newpasswd
Enter LDAP Password: admin

Note we need to use the root password (admin by default) in the last query ("Enter LDAP Password") to reset an user's password.

Query as an specific user

we already created the user (uid) marisa, and established the user's own password using slappasswd
now we are gonna query our LDAP server using the user (uid) marisa credentials, and the password we entered during slappasswd, called plain password (plainpasswd)

root@example:/etc/ldap# ldapsearch -D uid=marisa,ou=Supergirls,dc=example,dc=com -b "dc=example,dc=com" -w plainpasswd
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# example.com
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: nodomain
dc: example

# Supergirls, example.com
dn: ou=Supergirls,dc=example,dc=com
...

we can narrow this search to get only specific attributes of the user marisa, remember we are using the plainpasswd when asked

root@example:/etc/ldap# ldapsearch -D uid=marisa,ou=Supergirls,dc=example,dc=com -b "dc=example,dc=com" -w plainpasswd givenName uidNumber gidNumber homeDirectory
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> with scope subtree
# filter: (objectclass=*)
# requesting: givenName uidNumber gidNumber homeDirectory
#

# example.com
dn: dc=example,dc=com

# Supergirls, example.com
dn: ou=Supergirls,dc=example,dc=com

# marisa, Supergirls, example.com
dn: uid=marisa,ou=Supergirls,dc=example,dc=com
givenName: Marisa
uidNumber: 1001
gidNumber: 5000
homeDirectory: /home/marisa

Reset root password

Build line by line, the .ldif file we will need to reset root password, starting with the following command:

root@example:/# ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config '(olcSuffix=dc=example,dc=com)' dn > rootpw.ldif

which writes to the rootpw.ldif file, the current rootDN (Distinguised Name): dn: olcDatabase={1}mdb,cn=config
The next command will add the 'changetype' (modify, add, etc.) and what object are we working with:

root@example:/# echo -e 'changetype: modify\nreplace: olcRootPW: ' >> rootpw.ldif
root@example:/etc/ldap# cat rootpw.ldif
dn: olcDatabase={1}mdb,cn=config

changetype: modify
replace: olcRootPW

We run a simple sed command to delete blank lines

root@example:/# sed '/^$/d' rootpw.ldif > chrootpw.ldif
root@example:/# cat chrootpw.ldif
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcRootPW

It's time to write our new password (newpasswd):

root@example:/# slappasswd -s 1234
{SSHA}2xbd33S4ZumAZW4Oks0GJidBFJYEVBPz

The last line it's our password 1234 hashed in SSHA cryptography. We will need to copy and paste it in the following command:

root@example:/# echo "olcRootPW: {SSHA}2xbd33S4ZumAZW4Oks0GJidBFJYEVBPz" >> chrootpw.ldif

The file that describes the variables needed to change our root password, chrootpw.ldif should be ready, we finally run:

root@example:/etc/ldap# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f chrootpw.ldif
modifying entry "olcDatabase={1}mdb,cn=config"

If successful, the output will show the modified entry.

Password schemas

Since no policy overlay exists (more on this later), we need to create our own.

Try adding one of the core schemas that comes with LDAP.

root@example:/# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/corba.ldif
adding new entry "cn=corba,cn=schema,cn=config"

Notice we are using the -Q and -Y EXTERNAL parameters instead of our usual -x, meaning SASL EXTERNAL authentication over the ldapi:/// socket, which we usually use binding as the root account. We need to make use of a real administrative account to continue, like the one we created in the first part. If we get a result different from the showed up here, we won't be able to implement any schemas or ACLs, and we should check the dockerfile first, and second the commands we used to run the container as well that we started slapd with the specified parameters before.
Check our administrative account was well created, so it has it's own directory so we can add special configurations, such schemas

root@example:/# ldapsearch -Q -Y EXTERNAL -H ldapi:/// -D "cn=admin,dc=example,dc=com" -b cn=config "(objectclass=olcModuleList)"
# extended LDIF
#
# LDAPv3
# base <cn=config> with scope subtree
# filter: (objectclass=olcModuleList)
# requesting: ALL
#
# module{0}, config
dn: cn=module{0},cn=config
objectClass: olcModuleList
cn: module{0}
olcModulePath: /usr/lib/ldap
olcModuleLoad: {0}back_mdb
...