Ubuntu 22.04 | Install and configure a Kerberos Server

0

Adventures in the LXD Lab | Authentication Services

As part of the lab and as a continuation of “Ubuntu 22.04 | Install and configure an OpenLDAP Server” I am going to use this time to configure a Kerberos server to compliment our LDAP implementation and further secure my authentication services. To facilitate this, I chose to deploy MIT Kerberos.

Here are the steps that I used to get the solution up and running.

# Launch a new Ubuntu image to be my Kerberos server
jason@lxd01:/$ lxc launch images:ubuntu/22.04 kdc

As with the previous post, I have some ‘pre-work’ to do to get our machine properly configured and setup to the standards of the build. Before you go complaining how this can be automated [particularly because I have an Ansible server], hear me out… 1). It is a learning exercise. 2). It is fun. 3). when building the first authentication stack in your environment, it is always good to go manual in lab, and automate in production after documenting/testing. Now – on with it!

# Gain initial access the instance console.
jason@apollo:/$ lxc exec kdc bash

# Set the desired hostname.
root@kdc:/# hostnamectl set-hostname kdc.linfra.loc

# Install all available updates.
root@kdc/: apt update; apt upgrade -y

# Add a standard user to the system for everyday operations. Grant sudo.
root@kdc:/# adduser jason
root@kdc:/# usermod -aG sudo jason

# Install the packages that I use regularly on all of my machines.
root@kdc:/# apt install nano net-tools landscape-client man mlocate openssh-server -y

# Configure my static IP's for the LAN and management interfaces.
root@kdc:/# nano /etc/netplan/10-lxc.yaml

network:
    version: 2
    ethernets:
        eth0:
            dhcp4: false
            addresses: [172.16.2.7/24]
            nameservers:
              addresses: [172.16.2.4]
        eth1:
            dhcp4: false
            addresses: [10.130.115.7/24]
            nameservers:
              addresses: [10.130.115.4]
            routes:
            - to: default
              via: 10.130.115.1

root@kdc:/# netplan apply

# Register the new machine with my Landscape server for management.
root@kdc:/# sudo landscape-config --computer-title "kdc.linfra.loc" --account-name standalone --url https://landscape.linfra.loc/message-system --ping-url http://landscape.linfra.loc/ping

# Test internet connectivity.
root@kdc:/# ping google.com
PING google.com (142.250.64.206) 56(84) bytes of data.
64 bytes from (142.250.64.206): icmp_seq=1 ttl=115 time=17.6 ms
64 bytes from (142.250.64.206): icmp_seq=2 ttl=115 time=17.0 ms

--- google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1006ms
rtt min/avg/max/mdev = 17.021/17.312/17.604/0.291 ms

Setting up DNS

As mentioned in previous articles,. I have already built and configured a Bind9 DNS server (ns1.linfra.loc | ns2.linfra.loc) to perform name resolution within the lab. While DNS is a ‘nice-to-have’ in the lab, proper name resolution is critical to Kerberos and LDAP working properly together. While this could be accomplished using host files, it is difficult to manage. Here I am going to add the necessary DNS records to my name server for my newly created Kerberos server.

# Connect to my DNS server
jason@apollo:/$ ssh [email protected]

# Edit my main DNS zone file and add records for my Kerberos server.
jason@ns:/$ sudo nano /etc/bind/zones/db.linfra.loc

# DONT FORGET to increment your serial number!
;
; BIND data file for local loopback interface
;
$TTL	604800
@	IN	SOA	linfra.loc. admin.linfra.loc. (
			     11		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL

; ## LOCAL LAN CONFIGURATION ##

; Nameserver records
	IN	NS	ns.linfra.loc.

; 172.16.2.0/24 - A Records
apollo.linfra.loc.	IN	A	10.130.115.1
ns.linfra.loc.		IN	A	172.16.2.4
ns.linfra.loc.		IN	A	10.130.115.4
splunk.linfra.loc.	IN	A	172.16.2.3
splunk.linfra.loc.	IN	A	10.130.115.3
kdc.linfra.loc.		IN	A	172.16.2.7
kdc.linfra.loc.		IN	A	10.130.115.7
access.linfra.loc.	IN	A	172.16.2.8
access.linfra.loc.	IN	A	10.130.115.245
ansible.linfra.loc.	IN	A	172.16.2.9
ansible.linfra.loc.	IN	A	10.130.115.9
ldap.linfra.loc.	IN	A	172.16.2.10
ldap.linfra.loc.	IN	A	10.130.115.10
landscape.linfra.loc.	IN	A	172.16.2.109
landscape.linfra.loc.	IN	A	10.130.115.242

# Edit my PTR zone files and add records for my Kerberos server.
jason@ns:/$ sudo nano /etc/bind/zones/db.2.16.172

# DONT FORGET to increment your serial number!
;
; BIND reverse data file for local loopback interface
;
$TTL	604800
@	IN	SOA	linfra.loc. admin.linfra.loc. (
			      9		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL
;
; ### NAME SERVER CONFIGURATION ###

; NS records
	IN	NS	ns.linfra.loc.

; PTR records
4	IN	PTR	ns.linfra.loc.		;172.16.2.4
7	IN	PTR	kdc.linfra.loc.		;172.16.2.7
3	IN	PTR	splunk.linfra.loc.	;172.16.2.3
8	IN	PTR	access.linfra.loc.	;172.16.2.8
9	IN	PTR	ansible.linfra.loc.	;172.16.2.9
10	IN	PTR	ldap.linfra.loc.	;172.16.2.10
109	IN	PTR	landscape.linfra.loc.	;172.16.2.109

# Edit my PTR zone files and add records for my Kerberos server.
jason@ns:/$ sudo nano /etc/bind/zones/db.115.130.10

# DONT FORGET to increment your serial number!
;
; BIND reverse data file for local loopback interface
;
$TTL	604800
@	IN	SOA	linfra.loc. admin.linfra.loc. (
			      8		; Serial
			 604800		; Refresh
			  86400		; Retry
			2419200		; Expire
			 604800 )	; Negative Cache TTL
;
; ### NAME SERVER CONFIGURATION ###

; NS records
	IN	NS	ns.linfra.loc.

; PTR records
2	IN	PTR	apollo.linfra.loc.	;10.130.115.1
3       IN      PTR     splunk.linfra.loc.      ;10.130.115.3
4	IN	PTR	ns.linfra.loc.		;10.130.115.4
7	IN	PTR	kdc.linfra.loc.		;10.130.115.7
9	IN	PTR	ansible.linfra.loc.	;10.130.115.9
10	IN	PTR	ldap.linfra.loc.	;10.130.115.10
242	IN	PTR	landscape.linfra.loc.	;10.130.115.242
245     IN      PTR     access.linfra.loc.      ;10.130.115.245

Install Kerberos on the KDC server

Up to this point, I have done all of the necessary prep work to get the server ready to be a Kerberos server and integrate with my OpenLDAP server, perform any initial configuration tasks and test to ensure it is functioning as expected.

# Install Kerberos and Kerberos utilities
jason@kdc:~$ sudo apt install krb5-kdc-ldap krb5-admin-server

# Copy the Kerberos LDAP schema files to home directory and extract them
jason@kdc:~$ mkdir ldap-schema && cd ldap-schema
jason@kdc:~$ sudo cp /usr/share/doc/krb5-kdc-ldap/kerberos.schema.gz .
jason@kdc:~$ gunzip kerberos.schema.gz

# Copy the extracted Kerberos schema to the LDAP server.
jason@kdc:~$ scp kerberos.schema [email protected]:/home/jason

Configure the LDAP server

At this point, I have the Kerberos server up and running (kdc.linfra.loc) but not yet configured. To get all of this working properly, there is also some work that must be done on the LDAP server. Throughout this article, it will be necessary to swicth between the LDAP server and the Kerberos server to perform various configuration tasks.

# Connect to the LDAP server
jason@kdc:~$ ssh [email protected]

# Install the necessary Kerberos schema-to-ldif tool(s)
jason@ldap:~$ sudo apt install schema2ldif

# Move copied schema file to LDAP schema directory
jason@ldap:~$ sudo mv kerberos.schema /etc/ldap/schema/

# Import the Kerberos schema into the LDAP cn=config
jason@ldap:~$ sudo ldap-schema-manager -i kerberos.schema

Now that I have imported the Kerberos schema into my LDAP cn=config database, I can begin configuring the LDAP server further, starting with creating common indexes as well as administrative entities.

# Create the LDIF file containing what to index (common)
jason@ldap:~$ sudo nano /etc/ldap/krb_slapd_index01.ldif

dn: olcDatabase={1}mdb,cn=config
add: olcDbIndex
olcDbIndex: krbPrincipalName eq,pres,sub

# Import the index LDIF file created above
jason@ldap:~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/krb_slapd_index01.ldif

# Create the LDIF file containing the administrative entities
jason@ldap:~$ sudo nano /etc/ldap/krb_slapd_admin_entites.ldif

dn: uid=kdc-service,dc=linfra,dc=loc
uid: kdc-service
objectClass: account
objectClass: simpleSecurityObject
userPassword: {CRYPT}x
description: Account used for the Kerberos KDC

dn: uid=kadmin-service,dc=linfra,dc=loc
uid: kadmin-service
objectClass: account
objectClass: simpleSecurityObject
userPassword: {CRYPT}x
description: Account used for the Kerberos Admin server

# Add the kadmin-service and kdc-service user to the LDAP database (from LDIF created above)
jason@ldap:~$ sudo ldapadd -x -D cn=admin,dc=linfra,dc=loc -W -f /etc/ldap/krb_slapd_admin_entities.ldif

# Set the passwords for kadmin-service and kdc-service users
# kdc-service user:
jason@ldap:~$ ldappasswd -x -D cn=admin,dc=linfra,dc=loc -W -S uid=kdc-service,dc=linfra,dc=loc

# kadmin-service user:
jason@ldap:~$ ldappasswd -x -D cn=admin,dc=linfra,dc=loc -W -S uid=kadmin-service,dc=linfra,dc=loc

# Test that authentication is working as expected
# kdc-service user:
jason@ldap:~$ ldapwhoami -x -D uid=kdc-service,dc=linfra,dc=loc -W

# kadmin-service user:
jason@ldap:~$ ldapwhoami -x -D uid=kadmin-service,dc=linfra,dc=loc -W

Once the above steps are complete, I have a functioning LDAP configuration ready for Kerberos integration. In the next step, I need to update the default ACL to allow the Kerberos server to modify LDAP entries and add Kerberos attributes etc.

# Create the LDIF file containing the desired ACL's
jason@ldap:~$ sudo nano /etc/ldap/krb_slapd_acl_config.ldif

dn: olcDatabase={1}mdb,cn=config
add: olcAccess
olcAccess: {2}to attrs=krbPrincipalKey
  by anonymous auth
  by dn.exact="uid=kdc-service,dc=linfra,dc=loc" read
  by dn.exact="uid=kadmin-service,dc=linfra,dc=loc" write
  by self write
  by * none
-
add: olcAccess
olcAccess: {3}to dn.subtree="cn=krbContainer,dc=linfra,dc=loc"
  by dn.exact="uid=kdc-service,dc=linfra,dc=loc" read
  by dn.exact="uid=kadmin-service,dc=linfra,dc=loc" write
  by * none

# Update the LDAP config database with this newly created ACL
jason@ldap:~$ sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/krb_slapd_acl_config.ldif

Configure the KDC server to use the LDAP server

Now that the LDAP server is configured and ready to act as the backend database for Kerberos, it is time to move back to the Kerberos server and configure it to properly communicate with the LDAP server.

# Edit /etc/kdc.conf to specify database module and other values
jason@kdc:~$ nano /etc/krb5kdc/kdc.conf

[kdcdefaults]
    kdc_ports = 750,88

[realms]
    LINFRA.LOC = {
        database_name = /var/lib/krb5kdc/principal
        admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
        acl_file = /etc/krb5kdc/kadm5.acl
        key_stash_file = /etc/krb5kdc/stash
        kdc_ports = 750,88
        max_life = 10h 0m 0s
        max_renewable_life = 7d 0h 0m 0s
        master_key_type = des3-hmac-sha1
        #supported_enctypes = aes256-cts:normal aes128-cts:normal
        default_principal_flags = +preauth
        database_module = openldap_ldapconf
    }

[dbdefaults]
        ldap_kerberos_container_dn = cn=krbContainer,dc=linfra,dc=loc

[dbmodules]
        openldap_ldapconf = {
                db_library = kldap

                # if either of these is false, the ldap_kdc_dn needs to
                # have write access
                disable_last_success = true
                disable_lockout  = true

                # this object needs to have read rights on
                # the realm container, principal container realm sub-trees
                ldap_kdc_dn = "uid=kdc-service,dc=linfra,dc=loc"

                # this object needs to have read and write rights on
                # the realm container, principal container realm sub-trees
                ldap_kadmind_dn = "uid=kadmin-service,dc=linfra,dc=loc"

                ldap_service_password_file = /etc/krb5kdc/service.keyfile
                ldap_conns_per_server = 5
                ldap_servers = ldaps://ldap.linfra.loc
        }

Because the LDAP server in this environment uses a self-signed certificate, it must be installed on the KDC for the next steps to function properly, otherwise the Kerberos server will not trust the LDAP server and will not connect. Here I will copy that certificate from the LDAP server and update the certificate database on the Kerberos server to trust the LDAP server certificate.

# Copy the self-signed certificate from the LDAP server
jason@kdc:~$ scp [email protected]:/usr/local/share/ca-certificates/linfra-self-signed.crt .

# Move the certificate to the certificate store location
jason@kdc:~$ sudo mv linfra-self-signed.crt /usr/local/share/ca-certificates/

# Update the certificate store with the LDAP certificate
jason@kdc:~$ sudo update-ca-certificates

Once I have the certificate installed and the LDAP server is trusted, it is time to initialize the database and create the realm defined in the configuration(s) above. I will also create a stash of the password used to bind to the LDAP server. You will be prompted for the admin credential that were set on the LDAP server during initial configuration.

# Initialize database
jason@kdc:~$ sudo kdb5_ldap_util -D cn=admin,dc=linfra,dc=loc create -subtrees dc=linfra,dc=loc -r LINFRA.LOC -s -H ldaps://ldap.linfra.loc

# Stash credentials for binding to the LDAP server
jason@kdc:~$ sudo kdb5_ldap_util -D cn=admin,dc=linfra,dc=loc stashsrvpw -f /etc/krb5kdc/service.keyfile uid=kdc-service,dc=linfra,dc=loc

jason@kdc:~$ sudo kdb5_ldap_util -D cn=admin,dc=linfra,dc=loc stashsrvpw -f /etc/krb5kdc/service.keyfile uid=kadmin-service,dc=linfra,dc=loc

# Create the ACL file for the admin server
jason@kdc:~$ sudo nano /etc/krb5kdc/kadm5.acl

*/[email protected]        *

# Start (or restart) Kerberos KDC and Admin daemons
jason@kdc:~$ sudo systemctl start krb5-kdc.service krb5-admin-server.service

If all went well with the above procedures, I should now have a functioning Kerberos server along side my LDAP server to provide robust and secure authentication to users and machines in my environment.

Leave a Reply