Grant Cohoe

Cloud plumber, bit wrangler, solution engineer, hockey nut.

Secure OpenLDAP Server With Kerberos Authentication

Host Configuration

There are some things we need to set up prior to installing and configuring OpenLDAP.

Kerberos

You will need a working KDC somewhere in your domain. You also need to have the server configured as a Kerberos client (/etc/krb5.conf) and be able to kinit without issue.

There are two principals that you will need in your /etc/krb5.keytab:

  • host/server.example.com@EXAMPLE.COM
  • ldap/server.example.com@EXAMPLE.COM

saslauthd

If you do not already have this working, see my guide on how to set it up.

Packages

You need the following for our setup:

  • krb5-server-ldap (for the Kerberos schema)
  • openldap
  • openldap-clients
  • openldap-servers
  • cyrus-sasl-gssapi
  • cyrus-sasl-ldap

SSL Certificates

You will need SSL certificates matching the hostname you intend your LDAP server to listen on (ldap.example.com is different than server.example.com). Procure these from your PKI administrator. I place mine in the default directories as shown:

  • Server Public Key - /etc/pki/tls/certs/slapd.pem
  • Server Private Key - /etc/pki/tls/private/slapd.pem
  • CA Certificate - /etc/pki/tls/cert.pem

ACLs

The LDAP user needs to be able to read the private key and keytab you configured earlier. Ensure that it can.

1
2
[root@localhost ~]# setfacl -m u:ldap:r /etc/krb5.keytab
[root@localhost ~]# setfacl -m u:ldap:r /etc/pki/tls/private/slapd.pem

OpenLDAP Configuration

Directory Cleanup

By default there are some extra files in the configuration directory. Since we are not using the cn=config method of configuring the server, we are simply going to remove the things we don’t want.

1
2
[root@localhost ~]# cd /etc/openldap/
[root@localhost ~]# rm -rf slapd.d ldap.conf cacerts

We will be re-creating ldap.conf later on with the settings that we want.

Kerberos Schema

Copy /usr/share/doc/krb5-server-ldap-1.9/kerberos.schema into your schema directory (default: /etc/openldap/schema. This contains all of the definitions for Kerberos-related attributes.

Data Directory

Decide where you want your data directory to be. By default this is /var/lib/ldap Copy over the standard DB_CONFIG file to that directory from /usr/share/openldap-servers/DB_CONFIG.example. This contains optimization information about the structure of the database.

Enable LDAPS

Some systems require you to explicitly enable LDAPS listening. On Red Hat Enterprise Linux-based distributions, this is done by changing SLAPD_LDAPS to YES in /etc/sysconfig/ldap.

slapd.conf

Create a /etc/openldap/slapd.conf to configure your server. You can grab a copy of my basic configuration file here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# Include base schema files provided by the openldap-servers package.
include /etc/openldap/schema/corba.schema
include /etc/openldap/schema/core.schema
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/duaconf.schema
include /etc/openldap/schema/dyngroup.schema
include /etc/openldap/schema/inetorgperson.schema
include /etc/openldap/schema/java.schema
include /etc/openldap/schema/misc.schema
include /etc/openldap/schema/nis.schema
include /etc/openldap/schema/openldap.schema
include /etc/openldap/schema/pmi.schema
include /etc/openldap/schema/ppolicy.schema

# Site-specific schema and ACL includes. These are either third-party or custom.
include /etc/openldap/schema/kerberos.schema

# Daemon files needed for the running of the daemon
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args

# Limit SASL options to only GSSAPI and not other client-favorites. Apparently there is an issue where
# clients will default to non-working SASL mechanisms and will make you angry.
sasl-secprops noanonymous,noplain,noactive

# SASL connection information. The realm should be your Kerberos realm as configured for the system. The
# host should be the LEGITIMATE hostname of this server
sasl-realm EXAMPLE.COM
sasl-host ldap.example.com

# SSL certificate file paths
TLSCertificateFile /etc/pki/tls/certs/slapd.pem
TLSCertificateKeyFile /etc/pki/tls/private/slapd.pem
TLSCACertificateFile /etc/pki/tls/cert.pem

# Rewrite certain SASL bind DNs to more readable ones. Otherwise you bind as some crazy default
# that ends up in a different base than your actual one. This uses regex to rewrite that weird
# DN and make it become one that you can put within your suffix.
authz-policy from
authz-regexp "^uid=[^,/]+/admin,cn=example\.com,cn=gssapi,cn=auth" "cn=ldaproot,dc=example,dc=com"
authz-regexp "^uid=host/([^,]+)\.example\.com,cn=example\.com,cn=gssapi,cn=auth" "cn=$1,ou=hosts,dc=example,dc=com"
authz-regexp "^uid=([^,]+),cn=example\.com,cn=gssapi,cn=auth" "uid=$1,ou=users,dc=example,dc=com"

# Logging
#loglevel 16384
loglevel 256

# Actual LDAP database for things you want
database bdb
suffix "dc=example,dc=com"
rootdn "cn=ldaproot,dc=example,dc=com"
rootpw {MD5}X03MO1qnZdYdgyfeuILPmQ==
directory /var/lib/ldap

# Indicies for the database. These are used to improve performance of the database
index entryCSN eq
index entryUUID eq
index objectClass eq,pres
index ou,cn,mail eq,pres,sub,approx
index uidNumber,gidNumber,loginShell eq,pres

# Configuration database
database config
rootdn "cn=ldaproot,dc=example,dc=com"

# Monitoring database
database monitor
rootdn "cn=ldaproot,dc=example,dc=com"

To generate a password for your directory and hash it, you can use the slappasswd utility. See my guide on LDAP utilities for details. After that you should be all set. Start the slapd service, but dont query it yet.

Client Configuration

The /etc/openldap/ldap.conf file is the system-wide default LDAP connection settings. This way you do not have to specify the host and protocol each time you want to run a command. Make it now.

1
2
3
4
5
# OpenLDAP client configuration file. Used for host default settings
BASE            dc=example,dc=com
URI             ldaps://ldap.example.com
TLS_CACERT      /etc/pki/tls/cert.pem
TLS_REQCERT     demand

Population

Right now you should have a running server, but with no data in it. I created a simple example setup file to get a basic tree set up. At this point you need to architect how you want your directory to be organized. You may chose to follow this or chose your own.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
miranda ldap # cat setup.ldif
dn: dc=example,dc=com
dc: example
o: Example Corporation
objectclass: top
objectclass: dcObject
objectclass: organization

dn: ou=hosts,dc=example,dc=com
ou: hosts
objectclass: top
objectclass: organizationalUnit

dn: ou=users,dc=example,dc=com
ou: users
objectclass: top
objectclass: organizationalUnit

dn: cn=ldap1,ou=hosts,dc=example,dc=com
cn: ldap1
sn: ldap1
objectclass: top
objectclass: person

dn: cn=ldap2,ou=hosts,dc=example,dc=com
cn: ldap2
sn: ldap2
objectclass: top
objectclass: person

dn: uid=user,ou=users,dc=example,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: posixAccount
objectclass: inetOrgPerson
ou: Users
uid: user
uidNumber: 10000
gidNumber: 150
givenName: Firstname
sn: Lastname
cn: Firstname Lastname
gecos: Firstname Lastname
Description: Firstname Lastname
homeDirectory: /users/user
loginShell: /bin/bash
mail: firstname.lastname@example.com
displayname: Firstname Lastname (user)
userPassword: {SASL}user@EXAMPLE.COM

dn: uid=admin,ou=users,dc=example,dc=com
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: posixAccount
objectclass: inetOrgPerson
ou: Users
uid: admin
uidNumber: 10001
gidNumber: 151
givenName: Firstname
sn: Lastname
cn: Firstname Lastname
gecos: Firstname Lastname
Description: Firstname Lastname
homeDirectory: /users/admin
loginShell: /bin/bash
mail: firstname.lastname@example.com
displayname: Firstname Lastname (admin)

You can add the contents of this file to your directory using ldapadd.

1
ldapadd -x -D cn=ldaproot,dc=example,dc=com -W -f setup.ldif

Testing

You should now be able to query your server and figure out who it thinks you are based on your Kerberos principal.

1
2
3
4
5
6
7
8
9
[root@ldap ~]# kinit user
Password for user@EXAMPLE.COM:
[root@ldap ~]# ldapwhoami
SASL/GSSAPI authentication started
SASL username: user@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
dn:uid=user,ou=users,dc=example,dc=com
[root@ldap ~]#

Here you can see that it thinks that I am uid=user,ou=users,dc=example,dc=com given my principal of user@EXAMPLE.COM.

Now try searching:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
[root@ldap ~]# ldapsearch uid=user
SASL/GSSAPI authentication started
SASL username: user@EXAMPLE.COM
SASL SSF: 56
SASL data security layer installed.
# extended LDIF
#
# LDAPv3
# base <dc=example,dc=com> (default) with scope subtree
# filter: uid=user
# requesting: ALL
#

# user, users, example.com
dn: uid=user,ou=users,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: posixAccount
objectClass: inetOrgPerson
ou: Users
uid: user
uidNumber: 10000
gidNumber: 150
givenName: Firstname
sn: Lastname
cn: Firstname Lastname
gecos: Firstname Lastname
description: Firstname Lastname
homeDirectory: /users/user
loginShell: /bin/bash
mail: firstname.lastname@example.com
displayName: Firstname Lastname (user)

# search result
search: 5
result: 0 Success

# numResponses: 2
# numEntries: 1
[root@ldap ~]#