LDAP as a Kerberos store
© 2014 Dennis Leeuw dleeuw at made-it dot com
License: GPLv2 or later
MIT kerberos needs a stand alone update process from the master to the slave servers and that process needs to be run from cron. An easier solution is to add the Kerberos database to LDAP. Since we already have OpenLDAP running and the database is already replicated to slave servers and we intent to run Kerberos on the same servers as the LDAP servers, we might as well use LDAP as the backend for Kerberos.
This document will describe how to setup both OpenLDAP and MIT Kerberos to support this configuration.
Add to ou=dso,dc=example,dc=com two security objects that are needed for the maintenance of the kerberos database. The first object is krb5-kdc. This the account needed for the KDC servers to contact the LDAP database. The next account is krb5-adm, which is needed by the master KDC that also has the kadmind daemon running.
A simple LDIF for the accounts might look like this (use slappasswd to create the password hashes):
dn: uid=krb5-kdc,ou=dso,dc=example,dc=com objectClass: top objectClass: account objectClass: simpleSecurityObject uid: krb5-kdc userPassword: {SSHA}COFFEE123456789BAD description: LDAP account for the Kerberos KDC seeAlso: slapd ACL section dn: uid=krb5-adm,ou=dso,dc=example,dc=com objectClass: top objectClass: account objectClass: simpleSecurityObject uid: krb5-kdc userPassword: {SSHA}BAD1234567CAFEBABE description: LDAP account for the Kerberos kadmind seeAlso: slapd ACL section
To tell kdc and kadmind what their passwords are by creating a stash-file that contains the same passwords as used in the LDIF entry:
mkdir /etc/secrets chmod 755 /etc/secrets kdb5_ldap_util stashsrvpw -f /etc/secrets/krb5-ldap.pass uid=krb5-kdc,ou=dso,dc=example,dc=com kdb5_ldap_util stashsrvpw -f /etc/secrets/krb5-ldap.pass uid=krb5-adm,ou=dso,dc=example,dc=com chown root:root /etc/secrets/krb5-ldap.pass chmod 0750 /etc/secrets/krb5-ldap.passOf course on slave Kerberos servers you only need the krb5-kdc account.
To give the accounts enough access to our LDAP tree, we need to add the following ACLs:
# Access to realm container access to dn.subtree="cn=EXAMPLE.COM,cn=mit-krb5,ou=apps,dc=example,dc=com" by dn.exact="cn=krb5-kdc,ou=dso,dc=example,dc=com" read by dn.exact="cn=krb5-adm,ou=dso,dc=example,dc=com" write by * none # Access to the user principals access to dn.subtree="ou=people,dc=example,dc=com by dn.exact="cn=krb5-kdc,ou=dso,dc=example,dc=com" read by dn.exact="cn=krb5-adm,ou=dso,dc=example,dc=com" write by * none # Access to the computer principals access to dn.subtree="ou=devices,dc=example,dc=com by dn.exact="cn=krb5-kdc,ou=dso,dc=example,dc=com" read by dn.exact="cn=krb5-adm,ou=dso,dc=example,dc=com" write by * none
The last part is to add krbPrincipalKey to the line that limits access to the userPassword.
To be able to add Kerberos attributes to the LDAP database we need to include the kerberos.schema file. This file can be found on a Red Hat based system in /usr/share/doc/krb5-server-ldap-x.y.z/kerberos.schema and on a Debian based system it is present as /usr/share/doc/krb5-kdc-ldap/kerberos.schema.gz. Copy this file to your OpenLDAP schema directory and add to your slapd.conf the following line:
For Red Hat based systems:
include /etc/openldap/schema/kerberos.schemaFor Debian based systems:
include /etc/ldap/schema/kerberos.schema
We are going to build a network with a hidden master and readonly slaves so we do not want the slave to update the succesful login date field in our database, that why you will find the disable_last_success entry. We assume slapd and kdc run on the same machine. If your LDAP server does not run on the same machine as the KDC change the ldap_servers line to point to your master LDAP server.
[kdcdefaults] kdc_ports = 88 v4_mode = none [logging] kdc = SYSLOG:INFO:DAEMON admin_server = SYSLOG:INFO:DAEMON [realms] EXAMPLE.COM = { database_module = EXAMPLE.COM key_stash_file = /etc/secrets/krb5-kdc.stash } [dbmodules] EXAMPLE.COM = { db_library = kldap } [dbdefaults] ldap_servers = ldapi:/// ldap_kerberos_container_dn = "cn=mit-krb5,ou=apps,dc=examle,dc=com" ldap_kdc_dn = "uid=krb5-kdc,ou=dso,dc=examle,dc=com" ldap_kadmind_dn = "uid=krb5-adm,ou=dso,dc=examle,dc=com" ldap_service_password_file = /etc/secrets/krb5-ldap.pass ldap_conns_per_server = 5 disable_last_success = true
On our master server we want tools to talk to our own system and not a remote LDAP server, nor a remote KDC. To accomplish this we create a /etc/krb5.conf file with the following content:
[libdefaults] dns_lookup_realm = false dns_lookup_kdc = false default_realm = EXAMPLE.COM [realms] EXAMPLE.COM = { kdc = localhost } [domain_realm] .example.com = EXAMPLE.COM example.com = EXAMPLE.COMWe do not do DNS lookups, we use our own KDC (if you have an older version of MIT Kerberos you might want to use the FQDN, use netstat to figure out if "localhost" works).
Now that these files are in place we can create the initial database in LDAP:
kdb5_ldap_util -D "cn=manager,dc=example,dc=com" create -s -sf /etc/secrets/krb5-kdc.stashYou are first asked to provide the password for the account (cn=manager) that is able to make the changes in the LDAP tree and second you should provide a KDC database master key. This key should be stored in a safe somewhere, it is like the root password for the KDC.
Add to the slapd.conf file the following line:
index krbPrincipalName eqand create the index database by stopping slapd and running:
slapindex -b "dc=example,dc=com"After the command is finished, make sure the access rights on the newly created index file in /var/lib/ldap are set correctly. On the slave servers do the same and also start slapd again, and finaly start slapd on the master.
service krb5kdc start
kadmin.local
kadmin.local: listprincs K/M@EXAMPLE.COM krbtgt/EXAMPLE.COM@EXAMPLE.COM kadmin/admin@EXAMPLE.COM kadmin/changepw@EXAMPLE.COM kadmin/history@EXAMPLE.COM kadmin/your.host.name@EXAMPLE.COM
A Kerberos slave is nothing more then just the KDC without the administration server. Since we use LDAP for replicating the database, there is not much we need to do to create a slave.
on the slave we need: