OpenLDAP Setup

20 minute read

Note: I wrote this blog post before my actual website went up. I cannot account for the correctness and the use of proper english on tis post. Please read with a grain of salt. I will remove this warning when I have had a chance to read over it and make sure its complete.

Setting up a LDAP Server

On my goal of creating my home lab, I decided to add somthing similar to Windows Active Directory services so I could have one account that could access multiple services without tyoeing in different passwords. However, considering that I use linux for most of my day-to-day computing, I wanted to setup an OpenLDAP server on my Arch inux server.

LDAP

LDAP stands for Lightweight Directory Access Protocol. It is nothing more than a database. But it’s primary focus is to be quickly be accessable (read) with less emphasis on writing. The lightweight part of its name comes from the fact that it is a slimmed down version of the X.500 standard. Like X.500, LDAP is a directory service, it allows various information such as DHCP and DNS records to be stored in its database.

Server setup

Installing OpenLDAP on Arch Linux is pretty straight forward.

$ pacman -S openldap

Once the package manager installs the package, you can start editing the config file. However, after much research, I found out that after version 2.4.23, openldap moved to storeing its configuration inside of its ldap database rather than in a flat configuration. I decided that it would be best if I did minimal configuration using the flat configuration file, port it to the new OLC config format then add any other configuration that I needed to later on. In order to modify the flat config file, you can open this file using any sudo-permissive text editor.

$ nano /etc/openldap/slapd.conf

Below is the base configuration I had.

#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include         /etc/openldap/schema/core.schema
include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema
include         /etc/openldap/schema/misc.schema
include         /etc/openldap/schema/samba.schema


# Define global ACLs to disable default read access.

# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#referral       ldap://root.openldap.org

pidfile         /run/openldap/slapd.pid
argsfile        /run/openldap/slapd.args

# Load dynamic backend modules:
# modulepath    /usr/lib/openldap
# moduleload    back_mdb.la
# moduleload    back_ldap.la

# Sample security restrictions
#       Require integrity protection (prevent hijacking)
#       Require 112-bit (3DES or better) encryption for updates
#       Require 63-bit encryption for simple bind
# security ssf=1 update_ssf=112 simple_bind=64

# Sample access control policy:
#       Root DSE: allow anyone to read it
#       Subschema (sub)entry DSE: allow anyone to read it
#       Other DSEs:
#               Allow self write access
#               Allow authenticated users read access
#               Allow anonymous users to authenticate
#       Directives needed to implement policy:
access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
access to *
        by self write
        by users read
        by anonymous auth

# if no access controls are present, the default policy
# allows anyone and everyone to read anything but restricts
# updates to rootdn.  (e.g., "access to * by * read")
#
# rootdn can always read and write EVERYTHING!

#######################################################################
# MDB database definitions
#######################################################################

database        mdb
maxsize         1073741824
suffix          "dc=example,dc=com"
rootdn          "cn=Manager,dc=example,dc=com"
rootpw          your-password-here
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory       /var/lib/openldap/openldap-data
# Indices to maintain
index   objectClass     eq

index   uid             pres,eq
index   mail            pres,sub,eq
index   cn              pres,sub,eq
index   sn              pres,sub,eq
index   dc              eq

#######################################################################
# config database definitions
#######################################################################
# before the first database definition
database config
rootdn "cn=Manager,cn=config"
rootpw your-password-here

The main changes to the file (from the default Arch Linux config) are noted below. The include derivatives tells openldap various types of data that can be stored in the database and its structure. We imported some of the basic schemas, but more can be added later. The samba.schema is not included by default and must be copied from the examples like so: cp /usr/share/doc/samba/examples/LDAP/samba.schema /etc/openldap/schema.

include         /etc/openldap/schema/cosine.schema
include         /etc/openldap/schema/inetorgperson.schema
include         /etc/openldap/schema/nis.schema
include         /etc/openldap/schema/misc.schema
include         /etc/openldap/schema/samba.schema

The next modification simply allows the basic access to the LDAP server database. More information can be found from the comments.


access to dn.base="" by * read
access to dn.base="cn=Subschema" by * read
access to *
        by self write
        by users read
        by anonymous auth

Here you can change your suffix to your domain suffix. I cam currently using example.com, but change it whatever you want to call your domain. For rootpw you can either set the password as plain text as I did in the example (not recommended) or run slappasswd to get a hashed password like this: {SSHA}H23W7RmEQKcx98KA3UrM9N8ekKz3DTNB. More details about the salting and hasing can be found [here] (https://serverfault.com/a/675846).

suffix          "dc=example,dc=com"
rootdn          "cn=Manager,dc=example,dc=com"
rootpw          your-password-here

Next add the indexing properties for the database, these should be commonly used entries. The LDAP server will ‘cache’ these entries for faster access.

index   uid             pres,eq
index   mail            pres,sub,eq
index   cn              pres,sub,eq
index   sn              pres,sub,eq
index   dc              eq

The last edit I did was to allow access to change the configuration of the LDAP server. This is the new way to modify your server without any downtime or restart of the server, more details on this later. Similar to the main database, you must specify a rootdn or the ‘root’ account. The account must be under cn=config or you will not be able to login properly.

database config
rootdn "cn=Manager,cn=config"
rootpw your-password-here

Once I had my base configuration created, I created my base database by copying an example database.

$ cp /var/lib/openldap/openldap-data/DB_CONFIG.example /var/lib/openldap/openldap-data/DB_CONFIG

Before starting up the server, we must port the flat config file to the new OLC. First remove all the old files from the config folder. This must be done because LDAP will refuse to overwrite files if they already exist (I found out this the hard way). Then port the config file. Lastly, give permissions to the ldap user to read and write to that directory.

$ rm -rf /etc/openldap/slapd.d/*
$ slaptest -f /etc/openldap/slapd.conf -F /etc/openldap/slapd.d/
$ chown -R ldap:ldap /etc/openldap/slapd.d

These 3 commands MUST be run everytime you change the flat config file (/etc/openldap/slapd.conf). However, we can take advantage of the OLC feature to edit configs on the fly.

Finally you can start the database.

$ systemctl enable --now slapd.service

Server Configuration

In order to test that the configuration is valid, run this command. The command should print out the base configuration of the config database.

$ ldapsearch -W -x -D 'cn=Manager,cn=config' -b 'olcDatabase={0}config,cn=config'
Enter LDAP Password: 
# extended LDIF
#
# LDAPv3
# base <olcDatabase={0}config,cn=config> with scope subtree
# filter: (objectclass=*)
# requesting: ALL
#

# {0}config, config
dn: olcDatabase={0}config,cn=config
objectClass: olcDatabaseConfig
olcDatabase: {0}config
olcAccess: {0}to *  by * none
olcAddContentAcl: TRUE
olcLastMod: TRUE
olcMaxDerefDepth: 15
olcReadOnly: FALSE
olcRootDN: cn=Manager,cn=config
olcRootPW: your-root-password
olcSyncUseSubentry: FALSE
olcMonitoring: FALSE

# search result
search: 2
result: 0 Success

# numResponses: 2
# numEntries: 1

In order to add or change the configuration, I created a ldif (does not mean ldap diff file, but) file. I added this ldif file to allow any users to change their own name, password, etc

# Filename: access_ctrl.ldif

dn: olcDatabase={-1}frontend,cn=config
changetype: modify
delete: olcAccess
olcAccess: {0}
olcAccess: {1}
olcAccess: {2}

dn: olcDatabase={-1}frontend,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,givenName,sn,photo by self write by anonymous auth by * none
olcAccess: {1}to * by self read by * read

YOu can add this ldif file by runing this command.

$ ldapadd -D "cn=Manager,cn=config" -W -f access_ctrl.ldif

Now we want to populate the LDAP server with the base data. The ldif file is as shown below.

# example.org
dn: dc=example,dc=org
dc: example
o: Example Organization
objectClass: dcObject
objectClass: organization

# Manager, example.org
dn: cn=Manager,dc=example,dc=org
cn: Manager
description: LDAP administrator
objectClass: organizationalRole
objectClass: top
roleOccupant: dc=example,dc=org

# People, example.org
dn: ou=People,dc=example,dc=org
ou: People
objectClass: top
objectClass: organizationalUnit

# Groups, example.org
dn: ou=Group,dc=example,dc=org
ou: Group
objectClass: top
objectClass: organizationalUnit

Add the changes using ldapadd.

$ ldapadd -D "cn=Manager,dc=example,dc=org" -W -f base.ldif
Enter LDAP Password: 
adding new entry "dc=example,dc=com"

adding new entry "cn=Manager,dc=example,dc=com"

adding new entry "ou=People,dc=example,dc=com"

adding new entry "ou=Group,dc=example,dc=com"

Now that we have a basic tree for the LDAP database, we can start adding in the users. You can visit this webite to get migration tools that may help migrating users. In order order to migrate your account, you can download the source and run the script like this.

$ sudo perl -I . ./migrate_passwd.pl /etc/passwd users.ldif

Then exctract the user you want to from the ldif file and write it to another file. My final ldif file contained:

dn: uid=john,ou=People,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
cn: john
sn: Doe
givenName: John
title: Generic Person
telephoneNumber: +1 555 555 5555
postalAddress: Address Line 1$Address Line 2$Address Line 3
userPassword: your-password-here
shadowLastChange: 12345
shadowMin: 0
shadowMax: 99999
shadowWarning: 7
labeledURI: https://example.com/
loginShell: /bin/bash
uidNumber: 10000
gidNumber: 10000
homeDirectory: /home/john/
description: User account for John Doe

You can add the ldif file using ldapadd.

$ ldapadd -D "cn=Manager,dc=example,dc=com" -W -f user_john.ldif      
Enter LDAP Password: 
adding new entry "uid=john,ou=People,dc=example,dc=com"

»ldapadd -D "cn=Manager,dc=gempi,dc=re" -W
Enter LDAP Password: 
dn: cn=aryan,ou=Group,dc=gempi,dc=re
changetype: modify
replace: gidNumber
gidNumber: 7500

modifying entry "cn=aryan,ou=Group,dc=gempi,dc=re"