MIT Kerberos gives your Linux servers single sign-on: users get a ticket once with kinit and then authenticate to SSH, NFS, LDAP and web services without sending passwords over the network. This guide walks through building a standalone MIT Kerberos Key Distribution Center (KDC) on AlmaLinux 10 (10.2 at the time of writing, with krb5 1.21). The same steps work on AlmaLinux 9.x.
By the end you will have a working realm with the krb5kdc and kadmin services running, an admin principal, a test user, and a host principal, all verified with kinit and klist.
Lab layout used in this guide
- Realm:
EXAMPLE.COM(realm names are conventionally your DNS domain in UPPERCASE) - DNS domain:
example.com - KDC hostname:
kdc1.example.comat192.168.1.10 - OS: AlmaLinux 10.2 minimal install, SELinux enforcing, firewalld running
Replace these values with your own everywhere they appear.
Prerequisites
- An AlmaLinux 10 (or 9.x) server with root or sudo access.
- A static IP address and a fully qualified hostname that resolves forward and reverse. Kerberos is very sensitive to name resolution. If you need an internal DNS server first, see Configure Internal DNS Server CentOS/RedHat Linux.
- Accurate time on every machine in the realm. By default Kerberos rejects requests when clocks differ by more than 5 minutes. AlmaLinux uses chrony; the older Setting up NTP on CentOS 6 post explains the concepts if you are new to time sync.
- Ports 88/tcp+udp (Kerberos), 464/tcp+udp (kpasswd) and 749/tcp (kadmin) reachable from clients.
Step 1: Set the hostname and name resolution
Set the hostname to the FQDN and make sure it resolves. If you do not have DNS yet, an /etc/hosts entry works for a lab, but every client will need the same entry.
sudo hostnamectl set-hostname kdc1.example.com
echo "192.168.1.10 kdc1.example.com kdc1" | sudo tee -a /etc/hosts
# Verify forward and reverse lookups
hostname -f
getent hosts kdc1.example.com
getent hosts 192.168.1.10
Step 2: Make sure time is synchronized
chrony is installed and enabled on a standard AlmaLinux install. Confirm it is running and synchronized:
sudo dnf install -y chrony
sudo systemctl enable --now chronyd
chronyc tracking
timedatectl
timedatectl should report System clock synchronized: yes.
Step 3: Install the Kerberos server packages
The KDC, admin server and client tools all ship in the AlmaLinux BaseOS repository:
sudo dnf install -y krb5-server krb5-workstation krb5-libs
krb5-server provides krb5kdc, kadmind, kdb5_util and kadmin.local. krb5-workstation provides kinit, klist, kadmin and ktutil.
Step 4: Configure /etc/krb5.conf
/etc/krb5.conf tells the Kerberos libraries (on the KDC and on every client) which realm to use and where its KDC lives. Edit it so it looks like this. Keep the includedir line at the top, because AlmaLinux uses it to apply the system-wide crypto policy from /etc/krb5.conf.d/crypto-policies.
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.log
kdc = FILE:/var/log/krb5kdc.log
admin_server = FILE:/var/log/kadmind.log
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
spake_preauth_groups = edwards25519
dns_canonicalize_hostname = fallback
qualify_shortname = ""
default_ccache_name = KEYRING:persistent:%{uid}
[realms]
EXAMPLE.COM = {
kdc = kdc1.example.com
admin_server = kdc1.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
The main changes from the packaged file are uncommenting default_realm and filling in the [realms] and [domain_realm] sections.
Step 5: Configure the KDC (kdc.conf)
The KDC-specific settings live in /var/kerberos/krb5kdc/kdc.conf. The file shipped with AlmaLinux 10 already uses the EXAMPLE.COM realm and modern defaults. If your realm has a different name, rename the realm block. It is also a good idea to drop the legacy RC4 and Camellia types from supported_enctypes so new keys are only generated with AES:
[kdcdefaults]
kdc_ports = 88
kdc_tcp_ports = 88
spake_preauth_kdc_challenge = edwards25519
[realms]
EXAMPLE.COM = {
master_key_type = aes256-cts-hmac-sha384-192
acl_file = /var/kerberos/krb5kdc/kadm5.acl
dict_file = /usr/share/dict/words
default_principal_flags = +preauth
max_life = 24h
max_renewable_life = 7d
supported_enctypes = aes256-cts-hmac-sha384-192:normal aes128-cts-hmac-sha256-128:normal aes256-cts-hmac-sha1-96:normal aes128-cts-hmac-sha1-96:normal
}
default_principal_flags = +preauth requires pre-authentication for every new principal, which blocks offline password-guessing against tickets the KDC hands out. If the system is in FIPS mode, limit supported_enctypes to the two SHA-2 AES types, as the comment in the stock file suggests.
Step 6: Set up the admin ACL
kadmind decides who may administer the database using /var/kerberos/krb5kdc/kadm5.acl. The default entry grants full rights to any principal with an /admin instance in the realm. Make sure the realm matches yours:
sudo cat /var/kerberos/krb5kdc/kadm5.acl
*/admin@EXAMPLE.COM *
Step 7: Create the Kerberos database
Create the realm database and a stash file for the master key. You will be prompted for the database master password. Use a long, unique password and store it somewhere safe: you need it to restore or migrate the database.
sudo kdb5_util create -s -r EXAMPLE.COM
The -s option writes the master key to a stash file (/var/kerberos/krb5kdc/.k5.EXAMPLE.COM) so the KDC can start without anyone typing the master password. The database files are created in /var/kerberos/krb5kdc/.
sudo ls -la /var/kerberos/krb5kdc/
Step 8: Create the admin and user principals
Use kadmin.local, which works directly on the database as root and does not need kadmind running yet. Each addprinc prompts for that principal’s password.
# Administrative principal (matches */admin in kadm5.acl)
sudo kadmin.local -q "addprinc admin/admin"
# Regular user principal for testing
sudo kadmin.local -q "addprinc alice"
# Host principal for the KDC itself (random key, used later in a keytab)
sudo kadmin.local -q "addprinc -randkey host/kdc1.example.com"
# List everything in the realm
sudo kadmin.local -q "listprincs"
listprincs should show your new principals plus the built-in ones such as krbtgt/EXAMPLE.COM@EXAMPLE.COM and kadmin/admin@EXAMPLE.COM.
Step 9: Start and enable the KDC services
sudo systemctl enable --now krb5kdc kadmin
sudo systemctl status krb5kdc kadmin --no-pager
Both services should be active (running). Confirm they are listening:
sudo ss -tulpn | grep -E ':(88|464|749)\b'
Step 10: Open the firewall
firewalld ships predefined services for all three Kerberos ports:
sudo firewall-cmd --permanent --add-service={kerberos,kpasswd,kadmin}
sudo firewall-cmd --reload
sudo firewall-cmd --list-services
Optional: Publish DNS SRV records
If you run your own DNS, SRV records let clients find the KDC automatically (with dns_lookup_kdc = true), which is handy once you add a replica KDC. In a BIND zone file for example.com:
_kerberos._udp.example.com. IN SRV 0 0 88 kdc1.example.com.
_kerberos._tcp.example.com. IN SRV 0 0 88 kdc1.example.com.
_kerberos-master._udp.example.com. IN SRV 0 0 88 kdc1.example.com.
_kerberos-adm._tcp.example.com. IN SRV 0 0 749 kdc1.example.com.
_kpasswd._udp.example.com. IN SRV 0 0 464 kdc1.example.com.
_kerberos.example.com. IN TXT "EXAMPLE.COM"
Verify the KDC
Get a ticket
kinit alice
klist
klist should show a ticket-granting ticket for krbtgt/EXAMPLE.COM@EXAMPLE.COM with the default principal alice@EXAMPLE.COM. Destroy it with kdestroy when you are done.
Test remote administration through kadmind
Unlike kadmin.local, the kadmin client authenticates over the network to kadmind, so this proves the admin service, ACL and firewall rules all work:
kadmin -p admin/admin -q "listprincs"
kadmin -p admin/admin -q "getprinc alice"
Request a service ticket
kinit alice
kvno host/kdc1.example.com
klist
kvno asks the KDC for a service ticket and prints the key version number. A second ticket for host/kdc1.example.com@EXAMPLE.COM should now appear in klist.
Check the logs
sudo tail -n 20 /var/log/krb5kdc.log
sudo journalctl -u krb5kdc -u kadmin --since "10 min ago"
Successful requests show up as AS_REQ (initial tickets) and TGS_REQ (service tickets) lines with ISSUE.
Troubleshooting
kinit: Cannot find KDC for realm “EXAMPLE.COM” while getting initial credentials
The client does not know where the KDC is. Check the [realms] section in /etc/krb5.conf (realm names are case-sensitive), or enable dns_lookup_kdc = true and verify your SRV records with dig +short SRV _kerberos._udp.example.com.
Clock skew too great
The client and KDC clocks differ by more than 5 minutes. Fix time sync with chronyc sources -v and chronyc makestep on whichever machine is off.
Client not found in Kerberos database
The principal does not exist or you typed the realm in lowercase. Run sudo kadmin.local -q "listprincs" to confirm the exact name.
kadmin: Missing parameters in krb5.conf required for kadmin client
The admin_server line is missing from the realm block in /etc/krb5.conf.
kadmin: Operation requires “list” privilege while retrieving list
The principal you authenticated as is not covered by kadm5.acl. Check the realm in the ACL matches, then restart with sudo systemctl restart kadmin.
Cannot contact any KDC for realm
The KDC is unreachable. Check systemctl status krb5kdc, ss -tulpn | grep :88 on the KDC, and firewall-cmd --list-services. From a client, nc -vz kdc1.example.com 88 tests TCP reachability.
Services fail to start after restoring or copying the database
Restored files can carry the wrong SELinux labels. Reset them with sudo restorecon -Rv /var/kerberos and check sudo ausearch -m avc -ts recent for denials.
Next steps
You now have a working MIT Kerberos KDC on AlmaLinux. From here you can export keytabs for services and hosts, add a replica KDC for redundancy with kprop, and configure AlmaLinux clients to authenticate against the realm. Keep regular backups of the database with kdb5_util dump and store the master key password separately from the backups.
Reference: MIT Kerberos: Installing KDCs.
