Once your realm has a KDC, the next job is pointing machines at it. A Kerberos client needs four things: an accurate clock, a /etc/krb5.conf that knows where the KDCs are, a host keytab so other systems can trust it, and (if you want logins to use Kerberos passwords) SSSD wired into PAM. With those in place, users can run kinit, get a ticket at login, and SSH between hosts without typing a password again.
This guide configures an AlmaLinux 10 client (10.2 at the time of writing, krb5 1.21) against the realm built in Set Up an MIT Kerberos KDC on AlmaLinux 10 and made highly available in Set Up a Kerberos Primary and Replica KDC on AlmaLinux 10. The same steps work on AlmaLinux 9.x, Rocky Linux, Oracle Linux and RHEL, with one difference noted in the SSSD section.
Lab layout used in this guide
- Realm:
EXAMPLE.COM - Primary KDC and admin server:
kdc1.example.comat192.168.1.10 - Replica KDC:
kdc2.example.comat192.168.1.11 - Kerberized SSH server from the keytab post:
web1.example.comat192.168.1.20 - New client:
client1.example.comat192.168.1.30, AlmaLinux 10.2 minimal, SELinux enforcing - Admin principal
admin/admin@EXAMPLE.COMand test useralice@EXAMPLE.COM
Replace these names with your own everywhere they appear.
Prerequisites
- A working KDC. If you do not have one yet, follow Set Up an MIT Kerberos KDC on AlmaLinux 10 first.
- Forward and reverse DNS for every host, or matching
/etc/hostsentries. Kerberos service principals are tied to fully qualified hostnames. - Time synchronized with chrony on the client and the KDCs. By default Kerberos rejects requests when clocks differ by more than 5 minutes.
- Root or
sudoaccess on the client, and theadmin/adminpassword. - Outbound access from the client to the KDCs on TCP and UDP port 88, TCP port 749 for
kadminand TCP and UDP port 464 for password changes. No inbound firewall changes are needed on the client except SSH, which AlmaLinux allows by default.
Step 1: Set the hostname and name resolution
sudo hostnamectl set-hostname client1.example.com
hostname -f
If you do not have DNS for the lab, add the hosts to /etc/hosts on the client:
192.168.1.10 kdc1.example.com kdc1
192.168.1.11 kdc2.example.com kdc2
192.168.1.20 web1.example.com web1
192.168.1.30 client1.example.com client1
Add the client1 line to /etc/hosts on the KDCs and on web1 as well, so they can resolve the new client.
Step 2: Make sure time is synchronized
sudo dnf install -y chrony
sudo systemctl enable --now chronyd
chronyc tracking
timedatectl
timedatectl should report System clock synchronized: yes. If the offset in chronyc tracking is large, fix it before going further, because every later step depends on it.
Step 3: Install the client packages
sudo dnf install -y krb5-workstation sssd sssd-krb5 sssd-proxy sssd-tools openssh-clients
krb5-workstation provides kinit, klist, kvno, kpasswd and kadmin. The SSSD packages are only needed if you want Kerberos password logins (Step 7). If you only want users to run kinit and use SSH with tickets, krb5-workstation is enough.
Step 4: Configure /etc/krb5.conf
The simplest way to get a correct client configuration is to copy it from a KDC, since it already lists both KDCs:
sudo scp root@kdc1.example.com:/etc/krb5.conf /etc/krb5.conf
sudo restorecon -v /etc/krb5.conf
If you prefer to write it by hand, this is the full file. Keep the includedir line at the top: on AlmaLinux it pulls in the system crypto policy for Kerberos.
includedir /etc/krb5.conf.d/
[logging]
default = FILE:/var/log/krb5libs.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
kdc = kdc2.example.com
admin_server = kdc1.example.com
primary_kdc = kdc1.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
The client tries the kdc entries in order and fails over to kdc2 if kdc1 does not answer. primary_kdc tells the client to retry a failed password check against the primary, which matters right after a password change that has not propagated to the replica yet. admin_server must always point at the primary, because only it runs kadmind.
If you published the DNS SRV records described in the KDC post, you can set dns_lookup_kdc = true instead and drop the kdc lines, which saves editing every client when a KDC changes.
Step 5: Test kinit as a user
kinit alice
klist
kdestroy
klist should show a krbtgt/EXAMPLE.COM@EXAMPLE.COM ticket with the 24-hour lifetime set in the configuration. If it does, the client can reach a KDC and the realm configuration is correct.
Step 6: Create the host principal and keytab
A host keytab lets the client act as an SSH server for Kerberos logins and lets SSSD verify that tickets really came from your KDC. Run these on the client; kadmin asks for the admin/admin password:
sudo kadmin -p admin/admin -q "addprinc -randkey host/client1.example.com"
sudo kadmin -p admin/admin -q "ktadd host/client1.example.com"
sudo klist -ke /etc/krb5.keytab
sudo chmod 600 /etc/krb5.keytab
sudo restorecon -v /etc/krb5.keytab
Confirm the keytab works by getting a ticket with it instead of a password:
sudo kinit -k host/client1.example.com
sudo klist
sudo kdestroy
Remember that ktadd randomizes the key each time it runs. See Create and Manage Kerberos Keytabs on AlmaLinux 10 for extracting keytabs on the KDC, rotation and the other details.
Step 7: Use Kerberos passwords for logins with SSSD
This step makes a normal password login (console, SSH or su) check the password against the KDC and leave the user with a ticket, so they never have to run kinit by hand. Here user accounts stay local in /etc/passwd and only the password lives in Kerberos. If you have a directory such as LDAP, FreeIPA or Active Directory, use its SSSD provider instead; Join CentOS/RedHat to Active Directory Domain covers the Active Directory case.
AlmaLinux 10 removed the old SSSD files provider and now uses the local authselect profile by default. The supported way to combine local accounts with Kerberos authentication is the SSSD proxy identity provider with the krb5 authentication provider. That is why sssd-proxy was installed in Step 3.
Create the local account without a local password, so the only password that works is the Kerberos one:
sudo useradd alice
sudo passwd -S alice
passwd -S should report the password as locked or not set. Next create /etc/sssd/sssd.conf:
[sssd]
services = nss, pam
domains = EXAMPLE.COM
[domain/EXAMPLE.COM]
id_provider = proxy
proxy_lib_name = files
auth_provider = krb5
chpass_provider = krb5
krb5_realm = EXAMPLE.COM
krb5_server = kdc1.example.com, kdc2.example.com
krb5_kpasswd = kdc1.example.com
krb5_validate = true
krb5_renewable_lifetime = 7d
krb5_renew_interval = 1h
cache_credentials = true
krb5_store_password_if_offline = true
krb5_server lists both KDCs for failover, and krb5_kpasswd sends password changes to the primary. krb5_validate = true makes SSSD check each new ticket against the host keytab from Step 6, which stops an attacker from logging in with a fake KDC. The last two lines let users log in with their cached password when no KDC is reachable.
SSSD refuses to start unless the file is owned by root with mode 600. Set that, switch the system to the sssd authselect profile and start the service:
sudo chown root:root /etc/sssd/sssd.conf
sudo chmod 600 /etc/sssd/sssd.conf
sudo restorecon -v /etc/sssd/sssd.conf
sudo authselect select sssd
sudo authselect current
sudo systemctl enable --now sssd
The sssd profile puts pam_sss into the PAM stack and sss into /etc/nsswitch.conf. Check that passwd and group list sss:
grep -E '^(passwd|group|shadow):' /etc/nsswitch.conf
On AlmaLinux 9 you can still use this exact configuration. The older id_provider = files setting also works there, but it is deprecated and will not survive an upgrade to 10.
Step 8: Enable Kerberos (GSSAPI) logins for SSH
AlmaLinux already enables GSSAPI authentication in the default OpenSSH configuration (in /etc/ssh/sshd_config.d/50-redhat.conf and /etc/ssh/ssh_config.d/50-redhat.conf). Confirm it on the client:
sudo sshd -T | grep -i gssapi
ssh -G web1.example.com | grep -i gssapi
You want gssapiauthentication yes in both outputs. If not, create /etc/ssh/sshd_config.d/60-kerberos.conf:
GSSAPIAuthentication yes
GSSAPICleanupCredentials yes
sudo sshd -t && sudo systemctl reload sshd
Every SSH server that should accept tickets needs its own host/ principal in /etc/krb5.keytab, and the user needs a local account with the same name as the principal. MIT Kerberos maps alice@EXAMPLE.COM to the local user alice because EXAMPLE.COM is the default realm. To let a different principal into an account, list it in that account’s ~/.k5login file, one principal per line. Once a .k5login exists, only the principals in it are allowed.
Forwarding the ticket to the remote host is off by default. Turn it on only for hosts you trust, for example in ~/.ssh/config:
Host *.example.com
GSSAPIAuthentication yes
GSSAPIDelegateCredentials yes
Verify the client
Name lookups and SSSD status
getent passwd alice
id alice
sudo sssctl user-checks alice
getent and id should return the local account, and sssctl user-checks should show that SSSD can look up alice and that PAM account checks pass.
Log in with the Kerberos password
From another machine, or from the client itself, log in as alice with password authentication and check that a ticket was created:
ssh -o PreferredAuthentications=keyboard-interactive,password alice@client1.example.com
klist
klist should show a krbtgt/EXAMPLE.COM ticket for alice@EXAMPLE.COM with a KEYRING:persistent cache, without you having run kinit.
SSH with a ticket instead of a password
With that ticket still active, SSH to web1, which already has a host keytab and needs a local alice account (sudo useradd alice):
ssh -v alice@web1.example.com hostname 2>&1 | grep -i 'authenticated'
klist
The verbose output should include Authenticated to web1.example.com using "gssapi-with-mic", and klist on the client now also lists a host/web1.example.com@EXAMPLE.COM service ticket. Always connect with the fully qualified hostname so the client requests the right service principal.
Change a password
kpasswd
kpasswd talks to kadmind on the primary through port 464. Users who log in through SSSD can also use the normal passwd command, which SSSD forwards to Kerberos because of chpass_provider = krb5.
Failover
Stop krb5kdc on kdc1 for a moment and run kinit alice on the client again. It should still succeed, served by kdc2. Start krb5kdc on kdc1 again afterwards.
Troubleshooting
For any kinit problem, start by running it with tracing turned on. The trace shows which KDCs the client tried, which encryption types it used and the exact error:
KRB5_TRACE=/dev/stderr kinit alice
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 of /etc/krb5.conf, that the realm name is uppercase and matches exactly, and that the KDC hostnames resolve. If you use dns_lookup_kdc = true, confirm the SRV records with dig _kerberos._udp.example.com SRV.
kinit: Cannot contact any KDC for realm ‘EXAMPLE.COM’ while getting initial credentials
The client found the KDC but cannot reach it. Test port 88 with nc -vz kdc1.example.com 88, and check that kerberos is allowed in firewalld on the KDCs (sudo firewall-cmd --list-services).
Clock skew too great
The client and KDC clocks differ by more than the allowed skew. Fix chrony on both sides (chronyc sources -v) rather than raising clockskew.
SSH still asks for a password
Run ssh -vvv and look for the GSSAPI lines. Common causes are a missing host/ principal in the server’s keytab (sudo klist -k on the server), connecting by IP address or short name instead of the FQDN, no valid ticket on the client (klist), a missing local account on the server, or a ~/.k5login on the server that does not list the principal. On the server, sudo journalctl -u sshd usually names the reason.
SSSD will not start, or the password login fails
Check sudo journalctl -u sssd and sudo sssctl config-check. Wrong permissions on sssd.conf and typos in option names are the usual causes. If authentication fails only with krb5_validate = true, the host keytab is missing or out of date, so re-run Step 6. For more detail, set debug_level = 6 in the domain section, restart SSSD and read /var/log/sssd/krb5_child.log and /var/log/sssd/sssd_EXAMPLE.COM.log.
klist shows no ticket after logging in
Make sure authselect current reports the sssd profile and that the login went through password authentication, not an SSH key. A login with an SSH public key never sends a password, so there is nothing to get a ticket with. Also check which cache is in use: if sssd-kcm is installed, its file in /etc/krb5.conf.d/ switches the default cache to KCM:, which is fine but changes what klist prints.
Next steps
Your AlmaLinux clients now get tickets at login and use them for passwordless SSH. Repeat Steps 1 to 8 on each new machine, or put them in an Ansible role or kickstart file. From here you can Kerberize other services on the same hosts, such as NFS with sec=krb5p or Apache with an HTTP/ keytab as shown in Create and Manage Kerberos Keytabs on AlmaLinux 10. If you have many users, move their accounts into LDAP or FreeIPA so SSSD can look them up centrally instead of creating local accounts on every host.
References: MIT Kerberos: krb5.conf, MIT Kerberos: Installing and configuring UNIX client machines, SSSD: Files provider removal and Red Hat: Configuring authentication and authorization in RHEL 10.
