Kerberos

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).

  1. Initial Login: The employee enters their username and password on their workstation.
  2. Authentication: Active Directory, acting as the Key Distribution Center (KDC), validates the credentials.
  3. TGT Issuance: The employee’s computer receives a Ticket Granting Ticket (TGT), which establishes a secure session.
  4. Resource Request: The employee tries to open a shared network folder hosted on a file server.
  5. Ticket Request: Behind the scenes, the computer uses the TGT to request a Service Ticket for the file server from the domain controller.
  6. 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.

  1. Initial Login: John logs into his corporate workstation in the morning using his username (john) and password (123456).
  2. Authentication (AS): The domain controller validates John’s credentials and issues his Ticket Granting Ticket (TGT).
  3. Accessing the Email Server (Allowed):
    1. John opens his corporate email client.
    2. Behind the scenes, his computer presents his TGT to the Ticket Granting Service (TGS) and requests a service ticket for the emailserver.
    3. Because John is authorized for the email server, the TGS issues the ticket, and the email server authenticates him successfully.
  4. Accessing the Web Server (Denied):
    1. Later, John tries to access a restricted internal webserver (such as an administrative dashboard or secure portal).
    2. His computer requests a service ticket for the web server from the TGS using his TGT.
    3. 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 tickets

class 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 TGTs

    def 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 client

    def 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 client

    def 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 data

    def 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 dictionary

class ServiceServer:
    def __init__(self, key):
        self.key = key # Store the secret key assigned to this service

    def 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 True

kdc = 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)