Blog

Easy LDAP Server Setup and Client Connection on CentOS 7: A Step-by-Step Guide

Nikolay Dzhenkov
Nikolay Dzhenkov
DevOps and Cloud Engineer
02.06.2023
Reading time: 19 mins.
Last Updated: 12.02.2024

Table of Contents

What is LDAP and what it’s used for?

LDAP (or Lightweight Directory Access Protocol) exists to store user account information in one central database server, which applications can then use to search different pieces of information within (like user ids, passwords, email addresses, etc.). It becomes really valuable in cases where an administrator needs to deal with a large number of users without having to do so on every single server within the environment separately.

As an example, we can use the following:

User Timmy is a developer and he has requested access to the Database server, the Redis server, and the web server. Depending on the environment, there may be more application servers to which the developer may need direct access, thus far, just for Timmy’s case, we already have his account in 3 different places, where it needs to be created, configured for permissions (maybe the user needs to use certain sudo commands), and if by chance Timmy forgets his password, it will need to be reset on several places. If load balancing is at play, there may be more than 1 of each discussed application servers in place, adding additional places where any single change will need to be made in order to keep the account up-to-date.

The above situation can become tedious for the user himself as well since he will need to update his password on all machines based on certain policies (maybe the passwords are set to expire every 3 months).

One can see how the usually easy and quick task of administrating a single user account can become a long and tiring process. LDAP solves all of the above-mentioned issues, as well as provides a very customizable set of rules, which can be set per server/per user and per the preference of the administrator.

Before we proceed, I would like to point out that while writing the below instructions, I assume the reader has at least sudo rights, as most commands will need root privileges to execute. Every time a line begins with the dollar symbol ($), that means that the line in question is a command. Having said that, let’s proceed.

So far we have an idea about the situations which would require LDAP, but how do we go about setting it up?

How to set up LDAP?

1. First we will need to install a few packets:

  • On the LDAP server, we will need the following packets installed:

openldap-clients, openldap, openldap-servers, openldap-devel, ldapvi

Or all of this in a single command:

$ yum install openldap-clients openldap openldap-servers openldap-devel ldapvi -y

  • On the LDAP client/s, we will be needing the following packets:

openldap, openldap-clients, nss-pam-ldapd, openssh-ldap, sssd

In a single command:

$ yum install openldap openldap-clients nss-pam-ldapd openssh-ldap sssd -y

2. Once the above has been done, we will need to open the LDAP/S ports within the firewall:

$ firewall-cmd --permanent --zone=public --add-port=636/tcp
$ firewall-cmd --permanent --zone=public --add-port=389/tcp
$ firewall-cmd --reload

Of course, if you do not want to add them to the public zone, you can always use another one like “trusted” etc.

3. Next we will need to create the certificates for encrypted communication with the server, we will start with creating the key and the CSR:

$ openssl req -new -newkey rsa:2048 -nodes -keyout /etc/openldap/certs/openldap.key -out /etc/openldap/certs/openldap.csr -subj '/C=EX/ST'=exampleST/L=ExampleLocation/O=exampleOrganization/OU=exampleOU/CN=example.com

Where the paths, as well as the example entries, can freely be changed as per your liking.

Afterward, we sign the key:

$ openssl x509 -req -days 365 -in /etc/openldap/certs/openldap.csr -signkey /etc/openldap/certs/openldap.key -out /etc/openldap/certs/openldap.crt

Note: Of course, if you have changed the CSR creation paths, the above ones will also need to be changed accordingly.

The above procedure will create 3 files:

/etc/openldap/certs/openldap.csr

/etc/openldap/certs/openldap.key

/etc/openldap/certs/openldap.crt

Which we will use later within the slapd (ldap daemon) config file.

We will also need to transfer the above files to the client machines (preferably to the same paths).

I recommend automating this procedure, as it can get tedious if the client systems are a considerable number, especially if the environment grows larger.

4. Create an example DB config file.

As a default, we can use the following example configuration:

Note: The following HereDoc can be selected and directly pasted within the terminal, as it will create the /var/lib/ldap/DB_CONFIG file and paste the contents within it. I will be using this sort of approach for all similar files as it is an easy way of following through the instructions.

$ cat > /var/lib/ldap/DB_CONFIG <<EOF

# $OpenLDAP$
# Example DB_CONFIG file for use with slapd(8) BDB/HDB databases.
#
# See the Oracle Berkeley DB documentation
#   <http://www.oracle.com/technology/documentation/berkeley-db/db/ref/env/db_config.html>
# for detail description of DB_CONFIG syntax and semantics.
#
# Hints can also be found in the OpenLDAP Software FAQ
#	<http://www.openldap.org/faq/index.cgi?file=2>
# in particular:
#   <http://www.openldap.org/faq/index.cgi?file=1075>

# Note: most DB_CONFIG settings will take effect only upon rebuilding
# the DB environment.

# one 0.25 GB cache
set_cachesize 0 268435456 1

# Data Directory
#set_data_dir db

# Transaction Log settings
set_lg_regionmax 262144
set_lg_bsize 2097152
#set_lg_dir logs

# Note: special DB_CONFIG flags are no longer needed for "quick"
# slapadd(8) or slapindex(8) access (see their -q option). 
EOF

5. Once the above prerequisites have been completed, we can start configuring our new slapd (open-LDAP) server.

First, we will need to create the sysconfig file:

$ cat > /etc/sysconfig/slapd <<EOF
# OpenLDAP server configuration
# see 'man slapd' for additional information
# Where the server will run (-h option)
# - ldapi:/// is required for on-the-fly configuration using client tools
#   (use SASL with EXTERNAL mechanism for authentication)
# - default: ldapi:/// ldap:///
# - example: ldapi:/// ldap://127.0.0.1/ ldap://10.0.0.1:1389/ ldaps:///
SLAPD_URLS="ldapi:/// ldap:/// ldaps:///"

# Any custom options
SLAPD_OPTIONS="-s 256"

# Keytab location for GSSAPI Kerberos authentication
#KRB5_KTNAME="FILE:/etc/openldap/ldap.keytab"
EOF

Then, we need to start the service:

$ systemctl start slapd

We should also enable it, so it runs after reboot:

$ systemctl enable slapd

6. We’ll start by feeding the LDAP server with some schemas, which will be available in the “/etc/openldap/schema” directory. The command which we will be using to achieve that is the following:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif

In addition to the above, we will need to create an additional external ldif file with information related to the LDAP database (ldif is ldap’s syntax format). The file should look like the following:

$ cat > databases.ldif <<EOF
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
  read by dn.base="cn=manager,dc=example,dc=com" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=example,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=manager,dc=example,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: examplePassword

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by
  dn=cn=manager,dc=example,dc=com write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=manager,dc=example,dc=com" write by * read

dn: olcDatabase={0}config,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: examplePassword

dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: {0}( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DES
 C 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.
 1.1466.115.121.1.40 )
olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DESC
  'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MAY ( sshPublicKey $ 
 uid ) )

dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/openldap.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/openldap.key

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib64/openldap
olcModuleLoad: ppolicy.la


dn: olcOverlay=ppolicy,olcDatabase={2}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=passwordDefault,ou=Policies,dc=example,dc=com

dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcObjectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) )
EOF

Once the file is created, we can then feed it to the LDAP database using the following command:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f databases.ldif

If we don’t see any errors, all of the above configurations have been saved. We can confirm that by listing the LDAP database:

$ slapcat -n 0

That should display all entries that we have imported.

7. Once the first database has been imported, we need to import the LDAP skeleton as well:

Again, we will need to create a new file with the following contents (the domain components we will be using are dc=example and dc=com; however, they can be changed as per requirements, so long as they are changed everywhere they appear within this document):

$ cat > skeleton.ldif <<EOF
#Create the root DN:
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
o: example com
dc: example

#Create the Manager(LDAP administrator) DN
dn: cn=manager,dc=example,dc=com
objectClass: organizationalRole
cn: manager
description: Directory Manager

#Create the People DN (this is the dn under which we will populate the actual user accounts):
dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People

#Create the Group DN
dn: ou=Group,dc=example,dc=com
objectClass: organizationalUnit
ou: Group

#Create the SUDOers DN
dn: ou=SUDOers,dc=example,dc=com
objectclass: organizationalunit
ou: SUDOers
description: LDAP SUDO Entry

#Create the default sudo LDAP sudo configuration
dn: cn=defaults,ou=SUDOers,dc=example,dc=com
objectClass: top
objectClass: sudoRole
cn: defaults
description: SUDO via LDAP
sudoOption: !authenticate
sudoOption: !visiblepw
sudoOption: always_set_home
sudoOption: match_group_by_gid
sudoOption: always_query_group_plugin
sudoOption: env_reset
sudoOption: env_keep =  "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
sudoOption: env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
sudoOption: env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
sudoOption: env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
sudoOption: env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
sudoOption: env_keep+=SSH_AUTH_SOCK
sudoOption: secure_path = /sbin:/bin:/usr/sbin:/usr/bin

#Create the SudoUsers group under the SUDOers OU:
dn: cn=SudoUsers,ou=SUDOers,dc=example,dc=com
objectClass: top
objectClass: sudoRole
cn: SudoUsers
sudoUser: %SudoUsers
sudoHost: ALL
sudoRunAs: ALL
sudoCommand: ALL

#Create the SudoUsers group itself:
dn: cn=SudoUsers,ou=Group,dc=example,dc=com
objectClass: top
objectClass: posixGroup
gidNumber: 4321

#Create the policies DN:
dn: ou=Policies,dc=example,dc=com
ou: Policies
objectClass: organizationalUnit

#Populate the policies DN (these will be the rules for the users’ passwords expirations etc.):
dn: cn=passwordDefault,ou=Policies,dc=example,dc=com
objectClass: pwdPolicy
objectClass: person
objectClass: top
cn: passwordDefault
sn: passwordDefault
pwdAttribute: userPassword
pwdCheckQuality: 2
pwdMinLength: 8
pwdMinAge: 0
pwdMaxAge: 0
pwdInHistory: 4
pwdMaxFailure: 6
pwdFailureCountInterval: 0
pwdLockout: TRUE
pwdLockoutDuration: 0
pwdAllowUserChange: TRUE
pwdExpireWarning: 0
pwdGraceAuthNLimit: 0
pwdMustChange: TRUE
pwdReset: TRUE
pwdSafeModify: FALSE
EOF

Feed the file to the server:

$ ldapadd -x -D 'cn=manager,dc=example,dc=com' -W -f skeleton.ldif

8. Okay! So far we have the LDAP skeleton ready, what we need now is to add a few users.

Depending on if we want to migrate the local users to LDAP or start completely anew, we can take one of two ways:

  • Migrate the current users from /etc/passwd:

Note: I will not be focusing on this part, as it will consume quite a lot of lines to this already fairly large document; however, if you need to migrate the users, the package is named “migrationtools”. There is a lot of documentation on the web on how it is used.

  • Add completely new users:

In this case, we will add the user Timmy. As always, we create a file named Timmy.ldif and insert the following contents into it:

Note: uidNumber and gidNumber will need to be tracked for future new user creations. As an example, Timmy will be using uidNumber 1337 as well as gidNumber 1337, if I am to add a new user, Alex, I will need to set Alex’s uidNumber and gidNumber to numbers different than the ones used by Timmy (for example 1338 for both for easier tracking).

Generate Timmy’s encrypted password:

$ slappasswd

Once we generate the encrypted password, then we will need to copy it and place it within the “userPassword:” field within the below text file.

$ cat > timmy.ldif <<EOF
dn: uid=timmy,ou=People,dc=example,dc=com
uid: timmy
cn: timmy
sn: timmy
mail: timmy@example.com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
userPassword: {SSHA}1n8RJajTNhx5W8FecLP002MFzg8RZmWO
pwdReset: TRUE
loginShell: /bin/bash
uidNumber: 1337
gidNumber: 1337
homeDirectory: /home/timmy
EOF

Feed it to the LDAP server:

$ ldapadd -x -D 'cn=manager,dc=example,dc=com' -W -f timmy.ldif

After the user information has been fed to the database, we will need to add his group as well:

$ cat > timmy_group.ldif <<EOF
dn: cn=timmy,ou=Group,dc=example,dc=com
objectClass: top
objectClass: posixGroup
gidNumber: 1337
cn: timmy
memberUid: timmy
EOF

Feed it to the LDAP server:

$ ldapadd -x -D 'cn=manager,dc=example,dc=com' -W -f timmy_group.ldif

9. Now, since Timmy is a very rounded-up developer, he will probably be needing ‘sudo’ rights. Earlier we created the sudo group “SudoUsers”, now all we need to do is add Timmy to it. As per usual, we create a new ldif file named sudo_timmy.ldif and fill it out with the following information:

$ cat > sudo_timmy.ldif <<EOF
dn: cn=SudoUsers,ou=Group,dc=example,dc=com
changetype: modify
add: memberuid
memberuid: timmy
EOF

Feed it to the LDAP server:

$ ldapadd -x -D 'cn=manager,dc=example,dc=com' -W -f sudo_timmy.ldif

And voila! So far we have set up the server’s rules and have populated the database with our very first user named Timmy, on top of that, we gave Timmy the rights to execute sudo commands. But how should Timmy connect to the environment using his new user?

10. Setting up the client machines.

As mentioned, we will be using SSSD to set-up the LDAP client>server connection, so we can add the following configuration within /etc/sssd/sssd.conf:

$ vi /etc/sssd/sssd.conf //Or editor of personal choice

[domain/default]

debug_level = 2
cache_credentials = True
id_provider = ldap
auth_provider = ldap
chpass_provider = ldap
sudo_provider = ldap

ldap_search_base = dc=example,dc=com
ldap_uri = ldaps://$your_ldap_server_ip_address:636
ldap_tls_cacertdir = /etc/openldap/cacerts
ldap_tls_reqcert = allow
ldap_sudo_search_base = ou=SUDOers,dc=example,dc=com

[sssd]
services = nss, sudo, pam, ssh
domains = default

Note: ldap_uri from the above lines will need to be changed to match the IP address of the machine on which the LDAP server is running.

Change the permissions:

$ chmod 600 /etc/sssd/sssd.conf

$ chown root:root /etc/sssd/sssd.conf

Afterward, start the sssd client so that the changes take effect:

$ systemctl start sssd

or

$ systemctl restart sssd

Next, we will configure the ldap client application by adding the following configuration into the /etc/openldap/ldap.conf file

$ cat > /etc/openldap/ldap.conf <<EOF
#
# LDAP Defaults
#

# See ldap.conf(5) for details
# This file should be world readable but not world writable.

#BASE	dc=example,dc=com
#URI	ldap://ldap.example.com ldap://ldap-master.example.com:666

#SIZELIMIT	12
#TIMELIMIT	15
#DEREF		never

tls_cacert /etc/openldap/certs/openldap.crt
TLS_CACERTDIR /etc/openldap/cacerts
TLS_REQCERT allow
# Turning this off breaks GSSAPI used with krb5 when rdns = false
#SASL_NOCANON	on
BASE dc=example,dc=com
sudoers_base ou=SUDOers,dc=example,dc=com
URI ldaps://$your_ldap_server_ip_address:636
EOF

Now we need to make some changes to the above file:

$ vi /etc/openldap/ldap.conf

And change the last line to:

ldaps://${THE_IP_OF_THE_YOUR_LDAP_SERVER}.

In addition, we will need to add the following line in our /etc/nsswitch.conf file:

sudoers:    files sss

Lastly, we will execute the following authconfig command:

$ authconfig --enableldap --enableldapauth --enableshadow --ldapserver=ldaps://$your_ldap_server_ip_address:636 --ldapbasedn=dc=example,dc=com --enablemkhomedir --update

If the command runs successfully, we should now have access to the LDAP server from the client machine. In order to test that, we can do a simple query to the database:

$ getent passwd timmy
timmy:*:1337:1337:timmy:/home/timmy:/bin/bash

$ su timmy
$ ls

11. Adding in a replication server

In order to add a replication server to the main openldap server, we will need to follow a lot of the steps from the main server. First, we will need to install the following packets:

openldap-clients,openldap, openldap-servers, openldap-devel, ldapvi

Or a single command:

$ yum install openldap-clients openldap openldap-servers openldap-devel ldapvi -y

Open the necessary ports:

$ firewall-cmd --permanent --zone=public --add-port=636/tcp
$ firewall-cmd --permanent --zone=public --add-port=389/tcp
$ firewall-cmd --reload

As well as copy the generated openldap certificates from the main server to the same paths on the replication server.

Once we have completed the above prerequisites, we can start the configuration. First, we will create the DB like we did in the main server:

$ cat > /var/lib/ldap/DB_CONFIG <<EOF

# $OpenLDAP$
# Example DB_CONFIG file for use with slapd(8) BDB/HDB databases.
#
# See the Oracle Berkeley DB documentation
#   <http://www.oracle.com/technology/documentation/berkeley-db/db/ref/env/db_config.html>
# for detail description of DB_CONFIG syntax and semantics.
#
# Hints can also be found in the OpenLDAP Software FAQ
#	<http://www.openldap.org/faq/index.cgi?file=2>
# in particular:
#   <http://www.openldap.org/faq/index.cgi?file=1075>

# Note: most DB_CONFIG settings will take effect only upon rebuilding
# the DB environment.

# one 0.25 GB cache
set_cachesize 0 268435456 1

# Data Directory
#set_data_dir db

# Transaction Log settings
set_lg_regionmax 262144
set_lg_bsize 2097152
#set_lg_dir logs

# Note: special DB_CONFIG flags are no longer needed for "quick"
# slapadd(8) or slapindex(8) access (see their -q option). 
EOF

Create the sysconfig file:

$ cat > /etc/sysconfig/slapd <<EOF
# OpenLDAP server configuration
# see 'man slapd' for additional information

# Where the server will run (-h option)
# - ldapi:/// is required for on-the-fly configuration using client tools
#   (use SASL with EXTERNAL mechanism for authentication)
# - default: ldapi:/// ldap:///
# - example: ldapi:/// ldap://127.0.0.1/ ldap://10.0.0.1:1389/ ldaps:///
SLAPD_URLS="ldapi:/// ldap:/// ldaps:///"

# Any custom options
SLAPD_OPTIONS="-s 256"

# Keytab location for GSSAPI Kerberos authentication
#KRB5_KTNAME="FILE:/etc/openldap/ldap.keytab"
EOF

Start the service:

$ systemctl start slapd

Enable it, so it runs after reboot:

$ systemctl enable slapd

We’ll start by feeding the LDAP server with some schemas, which will be available in the /etc/openldap/schema directory. The command which we will be using to achieve that is the following:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
$ ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/ppolicy.ldif

Additional structural entries for the internal slapd database (the oclRootPW: field is used to create the administrator password for the “manager” user, so be sure to change it as per your need):

$ cat > databases.ldif <<EOF
dn: olcDatabase={1}monitor,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to * by dn.base="gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth"
  read by dn.base="cn=manager,dc=example,dc=com" read by * none

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcSuffix
olcSuffix: dc=example,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootDN
olcRootDN: cn=manager,dc=example,dc=com

dn: olcDatabase={2}hdb,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: examplePassword

dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcAccess
olcAccess: {0}to attrs=userPassword,shadowLastChange by
  dn=cn=manager,dc=example,dc=com write by anonymous auth by self write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by dn="cn=manager,dc=example,dc=com" write by * read

dn: olcDatabase={0}config,cn=config
changetype: modify
replace: olcRootPW
olcRootPW: examplePassword

dn: cn=openssh-lpk,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: openssh-lpk
olcAttributeTypes: {0}( 1.3.6.1.4.1.24552.500.1.1.1.13 NAME 'sshPublicKey' DES
 C 'MANDATORY: OpenSSH Public key' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.
 1.1466.115.121.1.40 )
olcObjectClasses: {0}( 1.3.6.1.4.1.24552.500.1.1.2.0 NAME 'ldapPublicKey' DESC
  'MANDATORY: OpenSSH LPK objectclass' SUP top AUXILIARY MAY ( sshPublicKey $ 
 uid ) )

dn: cn=config
changetype: modify
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/openldap/certs/openldap.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/openldap/certs/openldap.key

dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulePath: /usr/lib64/openldap
olcModuleLoad: ppolicy.la


dn: olcOverlay=ppolicy,olcDatabase={2}hdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPPolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=passwordDefault,ou=Policies,dc=example,dc=com

dn: cn=sudo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: sudo
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.1 NAME 'sudoUser' DESC 'User(s) who may  run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.2 NAME 'sudoHost' DESC 'Host(s) who may run sudo' EQUALITY caseExactIA5Match SUBSTR caseExactIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.3 NAME 'sudoCommand' DESC 'Command(s) to be executed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.4 NAME 'sudoRunAs' DESC 'User(s) impersonated by sudo (deprecated)' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.5 NAME 'sudoOption' DESC 'Options(s) followed by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.6 NAME 'sudoRunAsUser' DESC 'User(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcAttributeTypes: ( 1.3.6.1.4.1.15953.9.1.7 NAME 'sudoRunAsGroup' DESC 'Group(s) impersonated by sudo' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )
olcObjectClasses: ( 1.3.6.1.4.1.15953.9.2.1 NAME 'sudoRole' SUP top STRUCTURAL DESC 'Sudoer Entries' MUST ( cn ) MAY ( sudoUser $ sudoHost $ sudoCommand $ sudoRunAs $ sudoRunAsUser $ sudoRunAsGroup $ sudoOption $ description ) )
EOF

Feed it to the server:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f databases.ldif

If we don’t see any errors, all of the above configurations have been saved. We can confirm that by listing the LDAP database:

$ slapcat -n 0

Once that is done, we will need to connect the replica to the main server:

In order to do so, we will need to add a few things to the MAIN server. First, we will add the replication user (the username for it will be “readonly” and the password we will be using is “ExamplePassword”):

$ cat > readonly.ldif << EOF
dn: uid=readonly,dc=example,dc=com
objectClass: simpleSecurityObject
objectclass: account
objectClass: shadowAccount
uid: readonly
description: Read only Replication  User
userPassword: {SSHA}vnocdPa1k3PZXAfWSe+Nru0ubuhKE3lj
EOF

Now, we feed the entry to the MAIN LDAP server:

$ ldapadd -x -D 'cn=manager,dc=example,dc=com' -W -f readonly.ldif

Next, again on the MAIN server, we will need to add the replication overlay:

$ cat > syncprov.ldif << EOF
dn: cn=module{0},cn=config
changetype: modify
add: olcModuleLoad
olcModuleLoad: syncprov.la

dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
olcSpNoPresent: TRUE
olcSpCheckpoint: 100 10
olcSpSessionlog: 100
EOF

And feed it:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f syncprov.ldif

Afterward, we go back to the Replication server and set up the connection to the main server:

$ cat > connection.ldif << EOF
dn: olcDatabase={2}hdb,cn=config
changetype: modify
add: olcSyncrepl
olcSyncrepl: 
  rid=001
  provider=ldaps://${main_server_ip_address}:636
  binddn="uid=readonly,dc=example,dc=com"
  tls_cert="/etc/openldap/certs/openldap.crt"
  tls_key="/etc/openldap/certs/openldap.key"
  tls_cacertdir=/etc/openldap/certs
  tls_reqcert=allow
  credentials=ExamplePassword
  searchbase="dc=example,dc=com"
  type=refreshAndPersist
  timeout=0
  network-timeout=0
  retry="60 +"
EOF

Feed the replica with the above file:

$ ldapadd -Y EXTERNAL -H ldapi:/// -f connection.ldif

And if all went through accordingly, we should be able to list the replica, the same way we list the main server:
$ slapcat | grep -i timmy

memberUid: timmy
dn: uid=timmy,ou=People,dc=example,dc=com
uid: timmy
cn: timmy
sn: timmy
mail: timmy@example.com
homeDirectory: /home/timmy
dn: cn=timmy,ou=Group,dc=example,dc=com
cn: timmy
memberUid: timmy

If we get the above output, it means that the replica server has successfully connected and copied the timmy entry, and will proceed to update itself with every entry we add to the main server.

12. All which is left now is to update the client systems with the newly added replica server, so if a main server issue is to arise, they fall to the replica server:

On the client machine, in the /etc/sssd/sssd.conf file, we will need to add the second entry right next to the first entry (comma separated):

$ vi /etc/sssd/sssd.conf

ldap_uri = ldaps://$main_server_ip_address:636,ldaps://$replica_server_ip_address:636

Restart sssd on the client machine so the above changes take effect:

$ systemctl restart sssd

13. At times, we will need to edit certain entries. Maybe Timmy forgot his password, so we need to reset it, or maybe we need to remove some sudo access or even add some. Whatever the case may be, the tool named “ldapvi” can help us a lot.

“ldapvi” is a package, which opens ldif entries via the “vi” editor.

As an example, we are going to change Timmy’s password, as well as remove him from the sudo privileged users’ list:

$ ldapvi -D "cn=manager,dc=example,dc=com" -b uid=timmy,ou=People,dc=example,dc=com

With this command, we authenticate to the LDAP server as the user “manager” (otherwise known as our administrative user) and we specify that we would like to edit Timmy’s ldif entries. That should open the following piece of information:

# -*- coding: utf-8 -*-
# http://www.lichteblau.com/ldapvi/manual#syntax

0 uid=timmy,ou=People,dc=example,dc=com
uid: timmy
cn: timmy
sn: timmy
mail: timmy@example.com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: top
userPassword: TimmysSuperSecretPassword!
loginShell: /bin/bash
uidNumber: 1337
gidNumber: 1337
homeDirectory: /home/timmy

From there, we can just edit any line which we need to make the changes required. For example, we’ve generated a new password for the user Timmy:

$ slappasswd -s TimmysSuperSecretPassword

{SSHA}BteytVTtuT7n4hIU8QyhDYAjlYwhMYf2

We copy the above string and place it in the userPassword field. Afterward, we save and close vi, as we would usually save a text document with vi. It’s going to give us a small summary of what will be done, as well as request us to confirm the changes. Once we get the input line, all we need to do is add a “y” to it and that’s it – next time Timmy logs into the server, he will need to use his new password.

Removing him from the administrative group can also be done just as easily with the command for that being:

$ ldapvi -D "cn=manager,dc=example,dc=com" -b cn=SudoUsers,ou=Group,dc=example,dc=com

In the above example, we open the group entry itself. That should give us the following text within the editor:

# -*- coding: utf-8 -*-
# http://www.lichteblau.com/ldapvi/manual#syntax

0 cn=SudoUsers,ou=Group,dc=example,dc=com
objectClass: top
objectClass: posixGroup
gidNumber: 4321
cn: SudoUsers
memberUid: timmy

If we would like to add or remove entries, we just edit the text like we would normally and add a new or remove the “memberUid:” entry. As an example, if we want to add the user “george” as a sudo user as well, we will just add a new line:

0 cn=SudoUsers,ou=Group,dc=example,dc=com
objectClass: top
objectClass: posixGroup
gidNumber: 4321
cn: SudoUsers
memberUid: timmy
memberUid: george

Again, save and exit, and the changes should take effect fairly quickly (keep in mind that it may take a few minutes for the changes to propagate due to caching).

To Wrap up:

Even though LDAP can seem intimidating at first, due to its many configurations, syntax, etc., it is a vital part of most IT environments and once we get used to the way it behaves, administration can get fairly easy, especially considering the large amount of information available on the web.

Have any questions?

I hope I was able to represent the basics in a comprehensive way and I wish this document’s readers a very pleasant LDAP administration journey.

Leave a Reply

Your email address will not be published. Required fields are marked *

More Posts

In the dynamic world of serverless computing, securing your AWS Lambda function is crucial. However, one often neglected area is the security of containerized applications in Amazon Elastic Container Registry...
Reading
Note: The following example demonstrates upgrading a Kubernetes cluster from version 1.23 to 1.24. Replace the version numbers according to your specific setup. To ensure a seamless upgrade, it’s crucial...
Reading
Get In Touch
ITGix provides you with expert consultancy and tailored DevOps services to accelerate your business growth.
Newsletter for
Tech Experts
Join 12,000+ business leaders and engineers who receive blogs, e-Books, and case studies on emerging technology.