Setting up the Kerberos client side: client package installation, the anatomy of the /etc/krb5.conf file, first authentication with kinit, klist, and kdestroy, credential cache management, and system login integration with pam_krb5 and SSSD.

In episode 5 you successfully built a MIT Kerberos KDC: the principal database was created, the master key was stashed, and the krb5kdc service is running. Now it's time to flip positions — you move to the client side. This episode covers client configuration in full: package installation, the anatomy of /etc/krb5.conf as the "roadmap" to the realm, first authentication with kinit, reading the cache with klist, managing the credential cache, and system login integration through pam_krb5 and sssd.
Why is this episode important? Most Kerberos failures in the field — Cannot contact any KDC, No credentials cache found, Clock skew too great — are rooted in wrong client configuration, not server-side issues. Understand one thing from the start: /etc/krb5.conf stores no secrets whatsoever. It only contains addresses and preferences. All secrets remain on the KDC and in the ticket cache on your side.
The package name differs between distributions. On the Red Hat family it's krb5-workstation; on Debian and Ubuntu it's krb5-user.
# RHEL / Rocky / AlmaLinux
sudo dnf install krb5-workstation
# Debian / Ubuntu
sudo apt install krb5-userThis package brings three core tools that become your daily "access cards":
kinit — requests a ticket from the KDC (login).klist — views the tickets stored in the cache.kdestroy — removes tickets from the cache (logout).The /etc/krb5.conf configuration file is read by all Kerberos tools, both client and KDC. There are four sections clients most often touch:
| Section | Function |
|---|---|
[libdefaults] | Global defaults: realm, lifetime, enctype, ticket flags |
[realms] | KDC and admin server addresses per realm |
[domain_realm] | DNS domain to realm mapping |
[logging] | Where Kerberos logs are written |
A minimal example for one realm:
[libdefaults]
default_realm = EXAMPLE.COM
dns_lookup_kdc = true
dns_lookup_realm = true
ticket_lifetime = 24h
renew_lifetime = 7d
forwardable = true
rdns = false
[realms]
EXAMPLE.COM = {
kdc = kdc1.example.com
admin_server = kdc1.example.com
}
[domain_realm]
.example.com = EXAMPLE.COM
example.com = EXAMPLE.COM
[logging]
default = FILE:/var/log/krb5libs.logPoints to examine carefully:
default_realm is the realm used when you run kinit budi without specifying a realm — your default "home address".dns_lookup_kdc asks the client to find the KDC via the _kerberos._udp SRV records we built in episode 4. If DNS is wrong, the client will never find the KDC.kdc and admin_server are the explicit safety net; admin_server is used by kadmin and password change commands.[domain_realm] maps DNS domains (e.g. web1.example.com) to realms — useful when the realm doesn't follow the DNS pattern.Before you can kinit, the user principal must exist in the KDC database. From a client machine with admin access, you can add it via remote kadmin. From the KDC itself, use kadmin.local, which needs no authentication:
$ sudo kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM with password.
kadmin.local: addprinc budi
Enter password for principal "budi@EXAMPLE.COM":
Re-enter password for principal "budi@EXAMPLE.COM":
Principal "budi@EXAMPLE.COM" created.
kadmin.local: quitNote that kadmin.local talks directly to the KDC database, so it may only be run on the KDC machine by root. For remote management, you must kinit admin/admin first, then run kadmin. The details of these privileges are covered more deeply in episode 8.
Once the principal is created, the first authentication is just three commands:
kinit budi
klist
kdestroykinit budi prompts for a password, then sends it as encrypted preauthentication to the KDC (not as a plain password). klist displays the newly obtained TGT along with its expiration time. kdestroy clears the cache — mandatory when you leave a shared machine.
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: budi@EXAMPLE.COM
Valid starting Expires Service principal
08/03/2026 09:00:00 08/03/2026 10:00:00 krbtgt/EXAMPLE.COM@EXAMPLE.COMTickets aren't stored on the KDC — they're carried home by the client and placed in the credential cache. The choice of location can affect both security and convenience:
| Cache type | Location | Advantage |
|---|---|---|
FILE | /tmp/krb5cc_UID | Simple, portable across hosts |
KEYRING | Linux kernel keyring | Isolated per session, not on disk |
DIR | Directory holding many cache files | Can store many credentials |
KCM | KCM daemon | Shared cache between applications |
The FILE type is the classic default: /tmp/krb5cc_1000 means a cache owned by the user with UID 1000. The cache location is controlled by the KRB5CCNAME environment variable. You can point it at your own file or keyring:
export KRB5CCNAME=FILE:/tmp/mycache
kinit budi
klist -c /tmp/mycacheOn modern desktops, KEYRING:persistent:UID is the favorite choice because credentials live in the kernel keyring — harder for other processes to read, and automatically cleaned up when the session ends.
For full Single Sign-On — one password, log into the system and get tickets at the same time — you need to link Kerberos to PAM. Two common approaches:
krb5 provider for authentication and ldap for user data.Example SSSD domain using Kerberos as the authentication provider:
[sssd]
services = nss, pam
domains = example.com
[domain/example.com]
id_provider = ldap
auth_provider = krb5
chpass_provider = krb5
krb5_realm = EXAMPLE.COM
krb5_server = kdc1.example.comWith correct krb5_realm and krb5_server, users can log into the system with their Kerberos password, and their tickets become automatically available to applications. This is the foundation of SSO on Linux.
In [libdefaults] above there are two flags you'll meet often: forwardable and renewable.
forwardable{:ini} = true allows a ticket to be forwarded to another host — the basis for SSH delegation (covered in episode 13).renewable allows a ticket to be renewed without entering the password again — crucial for batch jobs running for days (details in episode 9).Tip
Don't enable every flag indiscriminately. forwardable enabled everywhere means a ticket can be carried anywhere if the cache is stolen. Enable flags only as needed — the principle of least privilege applies to tickets too.
When authentication fails, recognize the pattern from the error message:
| Symptom | Likely cause | Fix |
|---|---|---|
Cannot contact any KDC | DNS or SRV wrong, port 88 blocked | Check dig SRV _kerberos._udp.example.com and the firewall |
Clock skew too great | Client and KDC clocks unsynchronized | Make sure NTP or chrony is running |
No credentials cache found | No kinit yet or wrong KRB5CCNAME | Run kinit, check the cache location |
Preauthentication failed | Wrong password or mismatched enctype | Retry kinit, check the enctype |
Cannot find KDC for requested realm | Wrong default_realm or [domain_realm] | Correct /etc/krb5.conf |
To see what the client is actually sending, enable tracing:
KRB5_TRACE=/dev/stdout kinit budiThe trace shows every step — looking up the realm, contacting the KDC, choosing an enctype, receiving the ticket — so you can see exactly at which step authentication fails.
In this episode 6, you prepared the client-side foundation: the krb5-workstation package, /etc/krb5.conf as the realm map, the kinit-klist-kdestroy cycle, credential cache management with KRB5CCNAME, login integration through pam_krb5 and SSSD, and the skill of reading error messages.
Key takeaways:
/etc/krb5.conf stores no secrets — it's only addresses and preferences.kinit, klist, kdestroy are the client-side ticket lifecycle.FILE, KEYRING, DIR, or KCM — choose according to your security needs.In the next episode, episode 7, we flip the focus to services: how to give passwordless identity to services (SSH, web, NFS) through service principals and keytabs. Make sure you're comfortable with kinit first, because everything in episode 7 builds on this Kerberos identity concept.