How to setup OpenLDAP Kerberos V with SASL GSSAPI authentication

How to setup OpenLDAP Kerberos V with SASL GSSAPI authentication

openldap_sasl_gssapi_auth

Here in this article we will try to configure our OpenLDAP server to use SASL based authentication using the Kerberos authentication mechanism.

Test Environment

Master KDC – ubreplica.stack.com
Master LDAP server – ubscratch.stack.com
LDAP and Kerberos client – ubscratch.stack.com

What is SASL

Simple Authentication and Security Layer is a framework for authentication and data security in Internet protocols.

It is a protocol developed by the Internet Engineering Task Force (IETF) for the purpose of providing an extensible and pluggable authentication framework, primarily for non-web related protocols.

It decouples authentication mechanisms from application protocols. Cyrus SASL is an implementation of SASL that makes it easy for application developers to integrate authentication mechanisms into their application in a generic way.

Applications use the SASL library to tell them how to accomplish the SASL protocol exchange, and what the results were.

What is GSSAPI

Generic Security Service Application Program Interface (GSSAPI) mechanism, defined in RFC 4752, defines a network oriented protocol for authenticating a client to a server, using Kerberos version 5, a trusted 3rd party ticket based system.

The GSSAPI mechanism should work with all clients and servers which implement support for it, regardless of the actual server protocol used (such as IMAP), given the protocol was designed for use with the SASL framework.

Kerberos Authentication Client Server Architecture with OpenLDAP server

If you are interested in watching the video. Here is the YouTube video on the same step by step procedure outlined below.

Procedure

Step1: Setup Kerberos V system

As a first step you need to ensure that you have a working Kerberos V authentication system in place with the client able to do a kerberos authentication with the KDC server. Please follow my previous blog “How to setup Kerberos authentication system on Ubuntu OS” for the same.

Step2: Create a service key with a principal for ldap service

Every entity contained within a Kerberos installation, including individual users, computers, and services running on servers, has a principal associated with it. So here we are going to use the “kadmin.local” fail-safe program to create an ldap service principal as shown below.

ubadmin@ubreplica:~/krb5-1.21.2/src$ sudo /usr/local/sbin/kadmin.local 
Authenticating as principal root/admin@STACK.COM with password.
kadmin.local:  addprinc ldap/ubscratch.stack.com@STACK.COM
No policy specified for ldap/ubscratch.stack.com@STACK.COM; defaulting to no policy
Enter password for principal "ldap/ubscratch.stack.com@STACK.COM": 
Re-enter password for principal "ldap/ubscratch.stack.com@STACK.COM": 
Principal "matt@STACK.COM" created.

Step3: Add ldap service entry to keytab file

ktadd command helps to add a principal or all principals matching principal regular experssion to a keytab file, randomizing each principal’s key in the process. So here we are adding ldap service principal and the assoicated key to the keytab file “/usr/local/var/krb5kdc/krb5.keytab”.

ubadmin@ubreplica:~/krb5-1.21.2/src$ sudo /usr/local/sbin/kadmin.local 
Authenticating as principal root/admin@STACK.COM with password.
kadmin.local:  ktadd -k /usr/local/var/krb5kdc/krb5.keytab ldap/ubscratch.stack.com@STACK.COM
Entry for principal ldap/ubscratch.stack.com@STACK.COM with kvno 3, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/usr/local/var/krb5kdc/krb5.keytab.
Entry for principal ldap/ubscratch.stack.com@STACK.COM with kvno 3, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/usr/local/var/krb5kdc/krb5.keytab.

Step4: Allow slapd service access to keytab file

We need to ensure that the ldap service has access to the following keytab file as a service cannot send a password for authentication. The keytab file needs to be copied onto the ldap server at “/etc/krb5.keytab”. In my case the ldap service is available on “ubscratch.stack.com”.

ubadmin@ubreplica:~/krb5-1.21.2/src$ sudo scp /usr/local/var/krb5kdc/krb5.keytab ubadmin@ubscratch.stack.com:/tmp/
ubadmin@ubscratch:~$ sudo cp /tmp/krb5.keytab /etc/krb5.keytab
ubadmin@ubscratch:~$ ls -ltr /etc/krb5.keytab 
-rw------- 1 root root 172 Jun  1 14:38 /etc/krb5.keytab

NOTE:

If you create /usr/lib/sasl2/slapd.conf (assuming that is the correct location on your system) with the following contents:

keytab: /etc/krb5.keytab-ldap
mech_list: GSSAPI

Then the server will search within /etc/krb5.keytab-ldap when initializing the GSSAPI plugin. The server will only offer the mechanisms listed in mech_list. If mech_list is not specified, the server will offer all the mechanisms available, and that it can initialize.

Step5: Add ldap user principal

For an LDAP user to be authentication using the SASL with GSSAPI authentication mechanism, let us create a principal for the ldap user “matt” in the kerberos realm. We are going to use the same program “kadmin.local” to add the ldap user principal.

ubadmin@ubreplica:~/krb5-1.21.2/src$ sudo /usr/local/sbin/kadmin.local 
Authenticating as principal root/admin@STACK.COM with password.
kadmin.local:  addprinc matt@STACK.COM
No policy specified for matt@STACK.COM; defaulting to no policy
Enter password for principal "matt@STACK.COM": 
Re-enter password for principal "matt@STACK.COM": 
Principal "matt@STACK.COM" created.
kadmin.local:

kadmin.local:  listprincs
K/M@STACK.COM
kadmin/admin@STACK.COM
kadmin/changepw@STACK.COM
krbtgt/STACK.COM@STACK.COM
ldap/ubscratch.stack.com@STACK.COM
matt@STACK.COM
ubadmin/admin@STACK.COM
ubtest@STACK.COM

Step6: Obtain kerberos ticket for ldap user to authentice

To use the GSSAPI mechanism to authenticate to the directory, the user obtains a Ticket Granting Ticket (TGT) prior to running the LDAP client.

ubadmin@ubscratch:~$ kinit matt
Password for matt@STACK.COM: 
ubadmin@ubscratch:~$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: matt@STACK.COM

Valid starting     Expires            Service principal
02/06/24 11:40:37  03/06/24 11:40:37  krbtgt/STACK.COM@STACK.COM

Step7: Configure and Start slapd with SASL authentication

Here in this step we will need ensure that we have the cyrus-sasl authentication framework enabled when we install the openldap package.

Let us install the sasl library packages as shown below.

ubadmin@ubscratch:~/openldap-2.6.7$ sudo apt-get install libsasl2-dev libsasl2-2 sasl2-bin

Now download, extract and configure the openldap package with “–with-cyrus-sasl” along with “–with-tls=openssl” for TLS support and install the openldap package. Follow my blog “How to secure communication between OpenLDAP server and client using TLS” for more details on TLS setup.

ubadmin@ubscratch:~/openldap-2.6.7$ ./configure --with-tls=openssl --with-cyrus-sasl
ubadmin@ubscratch:~/openldap-2.6.7$ make depend
ubadmin@ubscratch:~/openldap-2.6.7$ make
ubadmin@ubscratch:~/openldap-2.6.7$ sudo make install

Here we are going to load the slapd configuration database file “slapd.ldif”. The important part in this configuration file is related to “olcAuthzRegexp” directive.

olcAuthzRegexp Used by the authentication framework to convert simple user names, such as provided by SASL subsystem, to an LDAP DN used for authorization purposes.

ubadmin@ubscratch:~$ cat /home/ubadmin/testldapconfig/slapd.ldif
#
# See slapd-config(5) for details on configuration options.
# This file should NOT be world readable.
#
dn: cn=config
objectClass: olcGlobal
cn: config
#
#
# Define global ACLs to disable default read access.
#
olcArgsFile: /usr/local/var/run/slapd.args
olcPidFile: /usr/local/var/run/slapd.pid
#
# Do not enable referrals until AFTER you have a working directory
# service AND an understanding of referrals.
#olcReferral:	ldap://root.openldap.org
#
# Sample security restrictions
#	Require integrity protection (prevent hijacking)
#	Require 112-bit (3DES or better) encryption for updates
#	Require 64-bit encryption for simple bind
#olcSecurity: ssf=1 update_ssf=112 simple_bind=64
#######################################################################
# TLS
#######################################################################
olcTLSCACertificateFile: /usr/local/etc/openldap/tls/ca.pem
olcTLSCertificateFile: /usr/local/etc/openldap/tls/server-crt.pem
olcTLSCertificateKeyFile: /usr/local/etc/openldap/tls/server-key.pem
#######################################################################
# SASL configuration
#######################################################################
#olcSaslRealm: stack.com
#olcAuthzRegexp: "^uid=([^,]+).*,cn=auth$" "uid=$1,ou=Users,dc=stack,dc=com"
olcAuthzRegexp: "^uid=([^,]+).*,cn=auth$" "ldap:///dc=stack,dc=com??sub?(uid=$1)"

#
# Load dynamic backend modules:
#
dn: cn=module,cn=config
objectClass: olcModuleList
cn: module
olcModulepath:	/usr/local/libexec/openldap
olcModuleload:	back_mdb.la
#olcModuleload:	back_ldap.la
#olcModuleload:	back_passwd.la

dn: cn=schema,cn=config
objectClass: olcSchemaConfig
cn: schema

include: file:///usr/local/etc/openldap/schema/core.ldif
include: file:///usr/local/etc/openldap/schema/cosine.ldif
include: file:///usr/local/etc/openldap/schema/inetorgperson.ldif

# Frontend settings
#
dn: olcDatabase=frontend,cn=config
objectClass: olcDatabaseConfig
objectClass: olcFrontendConfig
olcDatabase: frontend
#
# Sample global 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
#
#olcAccess: to dn.base="" by * read
#olcAccess: to dn.base="cn=Subschema" by * read
#olcAccess: 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!
#

#######################################################################
# LMDB database definitions
#######################################################################
#
dn: olcDatabase=mdb,cn=config
objectClass: olcDatabaseConfig
objectClass: olcMdbConfig
olcDatabase: mdb
olcDbMaxSize: 1073741824
olcSuffix: dc=stack,dc=com
olcRootDN: cn=Manager,dc=stack,dc=com
# Cleartext passwords, especially for the rootdn, should
# be avoided.  See slappasswd(8) and slapd-config(5) for details.
# Use of strong authentication encouraged.
olcRootPW: secret
# The database directory MUST exist prior to running slapd AND 
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
olcDbDirectory:	/usr/local/var/openldap-data
# Indices to maintain
olcDbIndex: objectClass eq
olcDbIndex: uid pres,eq
olcDbIndex: cn,sn pres,eq,approx,sub
olcAccess: to attrs=uid
  by anonymous read
  by users read
olcAccess: to attrs=userPassword
  by self write
  by anonymous auth
  by dn.base="cn=Admin,dc=stack,dc=com" write
  by * none
olcAccess: to *
  by self write
  by dn.base="cn=Admin,dc=stack,dc=com" write
  by * read

dn: olcDatabase=monitor,cn=config
objectClass: olcDatabaseConfig
olcDatabase: monitor
olcRootDN: cn=config
olcMonitoring: FALSE

We can now load the slapd configuration database and start the openldap service. We can start the ldap service in trace to get more details on how the SASL authentication and mapping of the SASL username to LDAP DN is happening.

ubadmin@ubscratch:~/openldap-2.6.7$ sudo /usr/local/sbin/slapadd -n 0 -F /usr/local/etc/slapd.d -l /home/ubadmin/testldapconfig/slapd.ldif
Closing DB...
ubadmin@ubscratch:~/openldap-2.6.7$ sudo /usr/local/libexec/slapd -F /usr/local/etc/slapd.d -d trace

Let us now load the ldap DIT in the following file “stack.com.dns_naming.ldif”. Here are the details.

ubadmin@ubscratch:~$ cat ~/testldapconfig/stack.com.dns_naming.ldif 
# This is the root of the directory tree
dn: dc=stack,dc=com
description: stack.com, your trusted non-existent corporation.
dc: stack
o: stack.com
objectClass: top
objectClass: dcObject
objectClass: organization

# Subtree for users
dn: ou=Users,dc=stack,dc=com
ou: Users
description: stack.com Users
objectClass: organizationalUnit

# Subtree for groups
dn: ou=Groups,dc=stack,dc=com
ou: Groups
description: stack.com Groups
objectClass: organizationalUnit

# Subtree for system accounts
dn: ou=System,dc=stack,dc=com
ou: System
description: Special accounts used by software applications
objectClass: organizationalUnit

# Barbara Jensen
dn: uid=barbara,ou=Users,dc=stack,dc=com
ou: Users
uid: Barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@stack.com
userPassword: barbara@1234
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

# Matt Butcher
dn: uid=matt,ou=Users,dc=stack,dc=com
ou: Users
# Name info:
uid: Matt
cn: Matt Butcher
sn: Butcher
givenName: Matt
givenName: Matthew
displayName: Matt Butcher
# Work Info:
title: Systems Integrator
description: Systems Integration and IT for Example.Com
employeeType: Employee
departmentNumber: 001
employeeNumber: 001-08-98
mail: mbutcher@stack.com
mail: matt@stack.com
roomNumber: 301
telephoneNumber: +1 555 555 4321
mobile: +1 555 555 6789
st: Illinois
l: Chicago
street: 1234 Cicero Ave.
# Home Info:
homePhone: +1 555 555 9876
homePostalAddress: 1234 home street $ Chicago, IL $ 60699-1234
# Misc:
userPassword: matt@1234
preferredLanguage: en-us,en-gb
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

# LDAP Admin Group:
dn: cn=LDAP Admins,ou=Groups,dc=stack,dc=com
cn: LDAP Admins
ou: Groups
description: Users who are LDAP administrators
uniqueMember: uid=barbara,dc=stack,dc=com
uniqueMember: uid=matt,dc=stack,dc=com
objectClass: groupOfUniqueNames

# Special Account for Authentication:
dn: uid=authenticate,ou=System,dc=stack,dc=com
uid: authenticate
ou: System
description: Special account for authenticating users
userPassword: secret
objectClass: account
objectClass: simpleSecurityObject
ubadmin@ubscratch:~/openldap-2.6.7$ sudo ldapadd -x -D "cn=Manager,dc=stack,dc=com" -W -f ~/testldapconfig/stack.com.dns_naming.ldif 

Step8: Search LDAP directory with GSSAPI Auth

Now we are ready to do a ldapsearch using the GSSAPI authentication mechanism supported by the SASL framework. At this point we already have Ticket granting ticket after we did the authentication using “matt” in step5.

Here the ldapsearch client tool will be using the ticket granting ticket to send a ticket granting service request to ticket granting server. The ticket granting server response contains the ldap service principal ticket which is valid for 24 hours.

NOTE: For detailed information on the kerberos protocol message exchange flow refer to book “Kerberos – The Definitive Guide by Jason Garman”

Now the ldapsearch client can use the ldap service until the kerberos ldap service ticket is valid.

ubadmin@ubscratch:~$ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: matt@STACK.COM

Valid starting     Expires            Service principal
02/06/24 11:46:31  03/06/24 11:46:31  krbtgt/STACK.COM@STACK.COM
02/06/24 11:47:09  03/06/24 11:46:31  ldap/ubscratch.stack.com@STACK.COM

Here we are trying to search for uid=matt. The following SASL authentiction DN “uid=matt,cn=GSSAPI,cn=auth” is requested which based slapd authorization regular expression gets converted to “ldap:///dc=stack,dc=com??sub?(uid=matt)'”. The following ldap query try to find an entry with “uid=matt”.

As there is an entry with the following attribute “uid=matt” in our ldap directory tree we get a response back. Also note the userPassword that is fetched for the same uid.

ubadmin@ubscratch:~$ ldapsearch -LLL -b 'dc=stack,dc=com' -Y GSSAPI '(uid=matt)'
SASL/GSSAPI authentication started
SASL username: matt@STACK.COM
SASL SSF: 256
SASL data security layer installed.
dn: uid=matt,ou=Users,dc=stack,dc=com
ou: Users
uid: Matt
cn: Matt Butcher
sn: Butcher
givenName: Matt
givenName: Matthew
displayName: Matt Butcher
title: Systems Integrator
description: Systems Integration and IT for Example.Com
employeeType: Employee
departmentNumber: 001
employeeNumber: 001-08-98
mail: mbutcher@stack.com
mail: matt@stack.com
roomNumber: 301
telephoneNumber: +1 555 555 4321
mobile: +1 555 555 6789
st: Illinois
l: Chicago
street: 1234 Cicero Ave.
homePhone: +1 555 555 9876
homePostalAddress: 1234 home street $ Chicago, IL $ 60699-1234
userPassword:: bWF0dEAxMjM0
preferredLanguage: en-us,en-gb
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

If we try to get an entry for “uid=barbara” we will be able to get the entry details expect for the “userPassword” attribute is protected using acl.

ubadmin@ubscratch:~$ ldapsearch -LLL -b 'dc=stack,dc=com' -Y GSSAPI '(uid=barbara)'
SASL/GSSAPI authentication started
SASL username: matt@STACK.COM
SASL SSF: 256
SASL data security layer installed.
dn: uid=barbara,ou=Users,dc=stack,dc=com
ou: Users
uid: Barbara
sn: Jensen
cn: Barbara Jensen
givenName: Barbara
displayName: Barbara Jensen
mail: barbara@stack.com
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson

Hope you enjoyed reading this article. Thank you..