Kerberos is a network authentication protocol that offers strong authentication for client/server applications using secret-key (symmetric) cryptography. It enables users, computers, and network services to securely verify each other’s identities over untrusted networks without the need to repeatedly transmit passwords.
Developed at the Massachusetts Institute of Technology (MIT) as part of Project Athena, Kerberos is named after Cerberus, the three-headed dog from Greek mythology that guards the entrance to Hades. The name reflects its purpose of protecting access to network resources.
Kerberos employs a trusted third party known as the Key Distribution Center (KDC) to manage authentication and issue encrypted tickets. Instead of sending user credentials every time someone accesses a network resource, Kerberos uses a ticket-based authentication mechanism to establish trust between clients and services.
Kerberos Core Characteristics
- Strong Authentication: This mechanism allows both clients and servers to securely verify each other’s identities using cryptographic methods, thereby preventing unauthorized access and impersonation.
- Secret-Key Cryptography: This approach primarily uses symmetric encryption (secret-key cryptography) to secure authentication messages and tickets. Keys are typically derived from user passwords or securely managed for network services.
- Ticket-Based System: After initial authentication, the user receives a Ticket Granting Ticket (TGT). This ticket enables the user to request service tickets for specific resources without the need to repeatedly transmit user credentials across the network.
- Centralized Authentication: This system relies on a trusted central authority, known as the Key Distribution Center (KDC), which manages user identities, issues authentication tickets, and distributes session keys.
- Time Synchronization: It is essential for client and server system clocks to be synchronized within an acceptable tolerance (usually a maximum difference of 5 minutes) to prevent replay attacks that exploit old timestamps.
- Pre-authentication: Clients must provide cryptographic proof of their identity—such as a timestamp encrypted with their password hash—before the KDC issues a TGT. This step mitigates the risk of offline password-guessing dictionary attacks.
- Mutual Authentication: This process allows both the client and the target server to verify each other’s identities, ensuring that the client is communicating with a legitimate service and not an imposter.
Kerberos Components
- Key Distribution Center (KDC): The central trust authority consisting of two logical sub-services:
- Authentication Server (AS): Validates initial user credentials and issues Ticket Granting Tickets (TGTs).
- Ticket Granting Service (TGS): Issues service tickets to clients presenting a valid TGT.
- Client: The principal (user, workstation, or application) requesting access to a network service.
- Server: The resource provider hosting the target service (e.g., file server, database, web application).
- Ticket Granting Ticket (TGT): Issued by the AS after successful initial authentication. The KDC encrypts it with its internal master key for the TGS (historically known as the krbtgt account key). It proves the user’s authenticated identity to the TGS.
- Service Ticket: Issued by the TGS and encrypted using the unique secret key shared exclusively between the KDC and the target service server. Presented by the client to access that specific service.
- Session Key: Temporary cryptographic key used for secure communication
Kerberos Workflow
- Client Authentication (AS-REQ / AS-REP):
- The client sends an initial authentication request to the Authentication Server (AS) containing its username (principal name) and pre-authentication data.
- If valid, the AS responds with a TGT (encrypted with the TGS master key) and a client-TGS session key, with this response payload encrypted using a key derived from the user’s password.
- Service Request (TGS-REQ):
- When the client wants to access a service, it sends the TGT to the Ticket Granting Service (TGS) along with the target service’s principal name and an authenticator (a timestamp encrypted with the client-TGS session key to prove freshness).
- Service Ticket Issuance (TGS-REP):
- The TGS decrypts and validates the TGT and the authenticator.
- If valid and the user is authorized, the TGS issues a Service Ticket (encrypted using the target service’s secret key) along with a new client-service session key.
- Service Access & Mutual Authentication (AP-REQ / AP-REP):
- The client presents the Service Ticket and a fresh authenticator to the destination application server.
- The server decrypts the ticket using its own secret key, validates the authenticator, and grants access based on its access control policies.
- Optionally, the server returns a reply to complete mutual authentication, proving to the client that it is the legitimate service.
Real-world examples
When an employee logs into a Windows domain computer, Active Directory authenticates the user and issues a Ticket Granting Ticket (TGT). Once the employee has the TGT, their computer can automatically use it to request a Service Ticket whenever they access network resources, such as a file share. This process enables secure, password-free Single Sign-On (SSO).
- Initial Login: The employee enters their username and password on their workstation.
- Authentication: Active Directory, acting as the Key Distribution Center (KDC), validates the credentials.
- TGT Issuance: The employee’s computer receives a Ticket Granting Ticket (TGT), which establishes a secure session.
- Resource Request: The employee tries to open a shared network folder hosted on a file server.
- Ticket Request: Behind the scenes, the computer uses the TGT to request a Service Ticket for the file server from the domain controller.
- Authorization: The file server decrypts and validates the ticket, granting access based on the employee’s permissions.
John logs into his corporate workstation with his username and password, which the domain controller (Authentication Server) validates and uses to issue a Ticket Granting Ticket (TGT). When John tries to access the corporate email server, his computer presents the TGT to the Ticket Granting Service (TGS), which verifies his permissions and issues a service ticket, allowing him to access his email. Later, John attempts to access a restricted internal web server, but the TGS determines that he is not authorized to access that service and denies the request.
- Initial Login: John logs into his corporate workstation in the morning using his username (john) and password (123456).
- Authentication (AS): The domain controller validates John’s credentials and issues his Ticket Granting Ticket (TGT).
- Accessing the Email Server (Allowed):
- John opens his corporate email client.
- Behind the scenes, his computer presents his TGT to the Ticket Granting Service (TGS) and requests a service ticket for the emailserver.
- Because John is authorized for the email server, the TGS issues the ticket, and the email server authenticates him successfully.
- Accessing the Web Server (Denied):
- Later, John tries to access a restricted internal webserver (such as an administrative dashboard or secure portal).
- His computer requests a service ticket for the web server from the TGS using his TGT.
- The TGS checks John’s access control list, realizes he is not authorized for the web server, and denies the request ([Ticket Granting Service] Access Denied: User john is not authorized for webserver).
import json # Used to serialize Python dictionaries into JSON and deserialize JSON back into dictionaries
import secrets # Used to generate cryptographically secure random session keys
import time # Used to manage ticket expiration timestamps
from cryptography.fernet import Fernet # Provides symmetric encryption and decryption for Kerberos ticketsclass KerberosKDC:
def __init__(self):
self.users = {“john”: {“password”: “123456”}} # Simulated user database
self.service_keys = {“emailserver”: Fernet.generate_key()} # Generate encryption key for the email server
self.kdc_key = Fernet.generate_key() # Secret key used by the KDC to encrypt and decrypt TGTsdef authenticate_user(self, username, password):
if username not in self.users or self.users[username][“password”] != password: # Verify the user’s username and password
print(“[Authentication Server] Invalid username or password”)
return None
session_key = secrets.token_hex(16) # Generate a random session key for the user
tgt = {“username”: username, “session_key”: session_key, “expires”: time.time() + 3600} # Create a TGT containing user information, session key, and expiration time
encrypted_tgt = self.encrypt_ticket(tgt, self.kdc_key) # Encrypt the TGT using the KDC secret key
print(f”[Authentication Server] Issued TGT for {username}”)
return encrypted_tgt # Return the encrypted TGT to the clientdef request_service_ticket(self, tgt, service):
if tgt is None: # Check whether a TGT was provided
return None
tgt_data = self.decrypt_ticket(tgt, self.kdc_key) # Decrypt the TGT using the KDC secret key
if tgt_data[“expires”] < time.time(): # Check whether the TGT has expired
print(“[Ticket Granting Service] Ticket Granting Ticket (TGT) expired”)
return None
if service not in self.service_keys: # Verify that the requested service exists
print(“[Ticket Granting Service] Service not found”)
return None
service_session_key = secrets.token_hex(16) # Generate a session key for communication with the requested service
ticket = {“username”: tgt_data[“username”], “service”: service, “session_key”: service_session_key, “expires”: time.time() + 3600} # Create a service ticket with user information, session key, and expiration time
encrypted_ticket = self.encrypt_ticket(ticket, self.service_keys[service]) # Encrypt the service ticket using the requested service’s secret key)
print(f”[Ticket Granting Service] Issued service ticket for {service}”)
return encrypted_ticket # Return the encrypted service ticket to the clientdef encrypt_ticket(self, data, key):
cipher = Fernet(key) # Initialize Fernet encryption using the provided key
serialized = json.dumps(data).encode(“utf-8”) # Convert the ticket dictionary into JSON and encode it as bytes
return cipher.encrypt(serialized) # Encrypt the ticket and return the encrypted datadef decrypt_ticket(self, ticket, key):
cipher = Fernet(key) # Initialize Fernet decryption using the provided key
decrypted = cipher.decrypt(ticket) # Decrypt the encrypted ticket
return json.loads(decrypted.decode(“utf-8”)) # Decode the data and convert the JSON back into a Python dictionaryclass ServiceServer:
def __init__(self, key):
self.key = key # Store the secret key assigned to this servicedef authenticate(self, ticket):
if ticket is None: # Check whether a service ticket was provided
return False
cipher = Fernet(self.key) # Initialize Fernet using the service’s secret key
data = cipher.decrypt(ticket) # Decrypt the service ticket
ticket_data = json.loads(data.decode(“utf-8”)) # Convert the decrypted JSON data into a Python dictionary
if ticket_data[“expires”] < time.time(): # Verify that the service ticket has not expired
print(“Service ticket expired”)
return False
print(f”Authenticated user: {ticket_data[‘username’]} for {ticket_data[‘service’]}”) # Display the authenticated username and requested service
return Truekdc = KerberosKDC() # Initialize the Key Distribution Center (KDC)
print(“Accessing emailserver..”)
tgt_john = kdc.authenticate_user(“john”, “123456”) # Authenticate John and obtain a Ticket Granting Ticket (TGT)
ticket_john = kdc.request_service_ticket(tgt_john, “emailserver”) # Use the TGT to request a service ticket for the email server
if ticket_john:
email_server = ServiceServer(kdc.service_keys[“emailserver”]) # Initialize the email server with its secret key
email_server.authenticate(ticket_john) # Validate the service ticket and authenticate John
import json
import secrets
import time
from cryptography.fernet import Fernet
class KerberosKDC:
def __init__(self):
self.users = {"john": {"password": "123456"}}
self.service_keys = {"emailserver": Fernet.generate_key()}
self.kdc_key = Fernet.generate_key()
def authenticate_user(self, username, password):
if username not in self.users or self.users[username]["password"] != password:
print("[Authentication Server] Invalid username or password")
return None
session_key = secrets.token_hex(16)
tgt = {"username": username, "session_key": session_key, "expires": time.time() + 3600}
encrypted_tgt = self.encrypt_ticket(tgt, self.kdc_key)
print(f"[Authentication Server] Issued TGT for {username}")
return encrypted_tgt
def request_service_ticket(self, tgt, service):
if tgt is None:
return None
tgt_data = self.decrypt_ticket(tgt, self.kdc_key)
if tgt_data["expires"] < time.time():
print("[Ticket Granting Service] Ticket Granting Ticket (TGT) expired")
return None
if service not in self.service_keys:
print("[Ticket Granting Service] Service not found")
return None
service_session_key = secrets.token_hex(16)
ticket = {"username": tgt_data["username"], "service": service, "session_key": service_session_key, "expires": time.time() + 3600}
encrypted_ticket = self.encrypt_ticket(ticket, self.service_keys[service])
print(f"[Ticket Granting Service] Issued service ticket for {service}")
return encrypted_ticket
def encrypt_ticket(self, data, key):
cipher = Fernet(key)
serialized = json.dumps(data).encode("utf-8")
return cipher.encrypt(serialized)
def decrypt_ticket(self, ticket, key):
cipher = Fernet(key)
decrypted = cipher.decrypt(ticket)
return json.loads(decrypted.decode("utf-8"))
class ServiceServer:
def __init__(self, key):
self.key = key
def authenticate(self, ticket):
if ticket is None:
return False
cipher = Fernet(self.key)
data = cipher.decrypt(ticket)
ticket_data = json.loads(data.decode("utf-8"))
if ticket_data["expires"] < time.time():
print("Service ticket expired")
return False
print(f"Authenticated user: {ticket_data['username']} for {ticket_data['service']}")
return True
kdc = KerberosKDC()
print("Accessing emailserver..")
tgt_john = kdc.authenticate_user("john", "123456")
ticket_john = kdc.request_service_ticket(tgt_john, "emailserver")
if ticket_john:
email_server = ServiceServer(kdc.service_keys["emailserver"])
email_server.authenticate(ticket_john)