Ubuntu 22.04 | Install and configure a Kerberos Server
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.