Kerberos

Index

    1. How does kerberos work
    2. Add accounts to maintain the Kerbersos database
    3. Creating the Kerberos Database
    4. Adding Kerberos to existing entries

How does kerberos work

When you have maintained an LDAP directory you know how nice it is to have a single store for everything. The only downside of LDAP is that if you store passwords in the database your passwords are sent over the wire and there is a possibilty that those passwords are eavesdropped by someone. To overcome this security hurdle there is a solution called Kerberos which maintains a database of passwords, but authentication is done without sending passwords (encrypted or not) over the wire. Kerberos is also a centralized database and can even use LDAP as its store for the user passwords. To prevent the passwords from once again traveling over the wire, we advise that the LDAP server and Kerberos server are placed on the same machine and use sockets to interconnect, all following examples are based on this.

To give you an idea how Kerberos does the authentication without sending passwords over the wire, here is a little schema:
Client   KDC   Service
A client tells the login service its username and password  
The login service converts the username into a principal name and sends it to the KDC requesting a Ticket Granting Ticket (TGT). AS_REQ ->    
  <- AS_REP The KDC generates a session key (TGT), and encrypts a copy with the principal password stored in its database and sends it back to the login service.  
The login service uses the password from the client to decrypt the received message. If it succeeds it knows the TGT and it knows the principal has provided the correct password.  
Now that the client has a Ticket Granting Ticket it can request access to a service. TGS_REQ ->  
  <- TGS_REP The KDC generates a new session key. One copy of the Service Ticket is encrypted with the principals TGT and another is encrypted with the password of the requested service. Both (Service Ticket) are send back.  
The client decrypts part one with its TGT and now knows the service session key. It encrypts a timestamp with the session key (Authenticator). The client then sends the still encrypted second part of the received message plus the Authenticator to the service provider. AP_REQ ->  
    The service provider uses its password from the keytab-file to decrypt part two of the Service Ticket. If this succeeds it knows the received message was encrypted by the KDC holding its password. Assuming the KDC is secure, the received session key is authentic.
    With the session key it can decrypt the timestamp. If the timestamp is within the agreed limits it knows the received information is current and not some play back. But it also knows that the requesting party is who they say they are, otherwise it would not have known the session key.
  <- AP_REP If requested by the client the service provider can send an reply to prove to the client that the provider is who it is by encrypting the reply with the session key, since that is the piece of information that is encrypted with the secret (password) from the KDC and known to the client. But this is optional.

Kerberos also makes sure no passwords are transmitted over the wire which makes it inherently more safe then any other product in the world. By using trusts between the different systems a user logging in to e.g. Active Directory can use services on the GNU/Linux network without the need of logging in again. The user is "trusted". Next to these security and interoperability benefits there is also the gain of Single-Sign-On.

Add accounts to maintain the Kerbersos database

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

dn: uid=krb5-adm,ou=dso,dc=example,dc=com
objectClass: top
objectClass: account
objectClass: simpleSecurityObject
uid: krb5-kdc
userPassword: {SSHA}BAD1234567CAFEBABE

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.pass
Of 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:

# Providing access to realm container
access to dn.subtree= cn=EXAMPLE.COM,cn=krb5,ou=services,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

# Providing 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

# Providing 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

Creating the Kerberos Database

To be able to add Kerberos attributes to the LDAP database we need to include the kerberos.schema file. Add to your slapd.conf the following line:

include /etc/openldap/schema/kerberos.schema
If you are on the Red Hat based system or do:
include /etc/ldap/schema/kerberos.schema
If you are on a Debian based system.

Create a /etc/krb5.conf file with the following content:

[libdefaults]
    dns_lookup_realm = true
    dns_lookup_kdc   = true
    default_realm    = EXAMPLE.COM

[realms]
    EXAMPLE.COM = {
        database_module = EXAMPLE.COM
	key_stash_file  = /etc/secrets/krb5-kdc.stash
    }

[logging]
    kdc          = SYSLOG:INFO:DAEMON
    admin_server = SYSLOG:INFO:DAEMON

[dbdefaults]
    ldap_kerberos_container_dn = "cn=krb5,ou=services,dc=example,dc=com"

[dbmodules]
    EXAMPLE.COM = {
        db_library                 = kldap
        disable_last_success       = true
        ldap_kdc_dn                = "cn=krb5-kdc,ou=dso,dc=example,dc=com"
        ldap_kadmind_dn            = "cn=krb5-adm,ou=dso,dc=example,dc=com"
        ldap_service_password_file = /etc/secrets/krb5-ldap.pass
        ldap_servers               = ldapi:///
        ldap_conns_per_server      = 5
    }
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.

For our KDCs we need a kdc.conf that contains more or less the same as the /etc/krb5.conf file. On Red Hat based systems symlink the /var/kerberos/krb5kdc/kdc.conf to /etc/krb5.conf and on Debian based systems do the same for /etc/krb5kdc/kdc.conf.

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.stash
You 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.

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

Adding Kerberos to existing entries

To make an LDAP entry a Kerberos principal add the krbPrincipalAux object class to the entry, using a simple LDIF:

dn: cn=dleeuw,ou=people,dc=example,dc=com
changetype: modify
add: objectClass
objectClass: krbPrincipalAux
-
add: krbPrincipalName
krbPrincipalName: dleeuw@EXAMPLE.COM
With the cpw command of kadmin.local you can now change the key for the user. The above process has to be done for all user and computer accounts within you network.