Introduction to Kerberos Constrained Delegation
Kerberos delegation allows a service to authenticate to another service on behalf of a user. This is a fundamental requirement for multi-tier applications — for example, a web front-end authenticating to a backend SQL Server using the end user’s identity, or SharePoint accessing a remote file share as the logged-in user. Without delegation, the service could only present its own service account identity to downstream services. Kerberos Constrained Delegation (KCD) limits which specific services a given service account or computer account is allowed to delegate to, preventing unconstrained delegation which is a significant security risk. Windows Server 2022 supports both the classic KCD model and the modern Resource-Based Kerberos Constrained Delegation (RBKCD) introduced in Windows Server 2012.
Classic KCD vs Resource-Based KCD
The two KCD models differ primarily in where the delegation trust is configured and who has authority to manage it.
Classic KCD: The delegation configuration lives on the front-end service account or computer account in Active Directory. A Domain Admin (or account with write access to the msDS-AllowedToDelegateTo attribute) must configure which backend services the front-end can delegate to. This requires knowledge of all target services at configuration time and does not work well in dynamic or cross-domain scenarios.
Resource-Based KCD (RBKCD): The delegation configuration lives on the back-end resource (the service being delegated TO). The resource owner controls which front-end services are allowed to present delegated credentials. This is configured via the msDS-AllowedToActOnBehalfOfOtherIdentity attribute on the back-end computer or service account. RBKCD works across forest trusts and can be delegated to local administrators of a resource, making it more flexible for distributed environments.
Classic KCD:
- Attribute: msDS-AllowedToDelegateTo on the FRONT-END account
- Who configures: Domain Admin
- Trust direction: Front-end specifies where it can delegate
- Cross-domain: Limited
RBKCD:
- Attribute: msDS-AllowedToActOnBehalfOfOtherIdentity on the BACK-END account
- Who configures: Resource owner (local admin on back-end)
- Trust direction: Back-end specifies who can delegate to it
- Cross-domain: Supported across forest trusts
Configuring Classic KCD
For classic KCD, use the Active Directory Users and Computers console or PowerShell. The front-end service account must be configured with the target service SPNs it is allowed to delegate to.
Using the GUI: open Active Directory Users and Computers, navigate to the front-end computer or service account, open Properties, go to the Delegation tab, and select “Trust this computer for delegation to specified services only.” Then add the specific service/SPN entries.
Using PowerShell (preferred for scripting and automation):
# Import the ActiveDirectory module
Import-Module ActiveDirectory
# Scenario: IIS web server (webfront01) needs to delegate to SQL server (sqlback01)
# The SQL Server service is running under a service account (sqlsvc)
# First, verify the SQL SPN exists
setspn -L sqlsvc
# Should show: MSSQLSvc/sqlback01.domain.com:1433
# Configure classic KCD on the front-end computer account
Set-ADComputer -Identity "webfront01" -Add @{
"msDS-AllowedToDelegateTo" = @(
"MSSQLSvc/sqlback01.domain.com:1433",
"MSSQLSvc/sqlback01.domain.com"
)
}
# Verify the configuration
Get-ADComputer "webfront01" -Properties msDS-AllowedToDelegateTo |
Select-Object Name, msDS-AllowedToDelegateTo
To configure KCD on a service account (not a computer account), use Set-ADUser instead:
# Service account scenario: iissvc account running the web application pool
Set-ADUser -Identity "iissvc" -Add @{
"msDS-AllowedToDelegateTo" = @(
"HTTP/sharepoint.domain.com",
"HTTP/sharepoint"
)
}
# Allow the service account to delegate with protocol transition
# (required when front-end uses forms-based or certificate auth, not Kerberos)
Set-ADUser -Identity "iissvc" -TrustedToAuthForDelegation $true
# TrustedToAuthForDelegation sets the TRUSTED_TO_AUTH_FOR_DELEGATION flag
# This enables S4U2Self (see below)
Protocol Transition and the S4U2Self Protocol
Protocol Transition is needed when the front-end service authenticates users via a mechanism other than Kerberos — such as NTLM, forms-based authentication, certificate authentication, or a custom auth method. Without protocol transition, the front-end cannot obtain a Kerberos service ticket on behalf of the user because it never received a Kerberos ticket from the user in the first place.
When Protocol Transition is enabled (“Trust this computer for delegation to specified services only — Use any authentication protocol” in the GUI), the front-end service can call S4U2Self (Service-for-User-to-Self) to obtain a Kerberos ticket for any user, presenting only the username. The KDC issues a ticket as if the user had authenticated via Kerberos. This ticket can then be used with S4U2Proxy to request a service ticket for the back-end.
Enabling Protocol Transition via PowerShell:
# Enable Protocol Transition on a computer account
# This sets both the delegation list AND the S4U2Self flag
$acct = Get-ADComputer "webfront01"
$acct | Set-ADComputer -TrustedToAuthForDelegation $true
# For service accounts:
Set-ADUser -Identity "iissvc" -TrustedToAuthForDelegation $true
# Verify the UserAccountControl flag
Get-ADUser "iissvc" -Properties UserAccountControl | Select-Object UserAccountControl
# TRUSTED_TO_AUTH_FOR_DELEGATION = 0x1000000 (16777216)
# Add this value to the standard UAC value (e.g., 512 = NORMAL_ACCOUNT)
# Total UAC for a normal account with protocol transition: 16777728
Configuring Resource-Based KCD (RBKCD)
RBKCD is configured on the back-end resource. The msDS-AllowedToActOnBehalfOfOtherIdentity attribute holds a security descriptor (not a list of SPNs), so it is set using a different PowerShell pattern. The key advantage is that a local administrator of the back-end resource can configure this without needing Domain Admin rights.
# Scenario: Allow webfront01 to delegate to sqlback01 using RBKCD
# Step 1: Get the SID of the front-end computer account
$frontend = Get-ADComputer "webfront01"
$frontendSID = $frontend.SID
# Step 2: Build the security descriptor
# Create a raw security descriptor granting the front-end account
# the right to impersonate
$rawSD = New-Object Security.AccessControl.RawSecurityDescriptor(
"O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;" + $frontendSID + ")"
)
# Convert to byte array
$sdBytes = New-Object byte[] $rawSD.BinaryLength
$rawSD.GetBinaryForm($sdBytes, 0)
# Step 3: Set the attribute on the back-end resource
Set-ADComputer "sqlback01" -Replace @{
msDS-AllowedToActOnBehalfOfOtherIdentity = $sdBytes
}
# Verify
$backend = Get-ADComputer "sqlback01" -Properties msDS-AllowedToActOnBehalfOfOtherIdentity
$sd = New-Object Security.AccessControl.RawSecurityDescriptor(
$backend.'msDS-AllowedToActOnBehalfOfOtherIdentity', 0
)
$sd.DiscretionaryAcl | ForEach-Object { Write-Host "Trustee SID: $($_.SecurityIdentifier)" }
To clear RBKCD configuration from a computer account:
Set-ADComputer "sqlback01" -Clear msDS-AllowedToActOnBehalfOfOtherIdentity
The S4U2Proxy Protocol
S4U2Proxy (Service-for-User-to-Proxy) is the Kerberos extension that allows a front-end service to request a service ticket for a back-end service on behalf of a user. It requires that the front-end has either a forwardable Kerberos ticket from the user (classic KCD) or is trusted via RBKCD. The KDC validates the delegation permission before issuing the ticket.
KCD delegation flow:
1. User authenticates to front-end (Kerberos or via Protocol Transition/S4U2Self)
2. Front-end calls S4U2Proxy:
- Presents: its own TGT + user's service ticket (or S4U2Self result)
- Requests: ticket for back-end SPN
3. KDC checks:
- Classic KCD: Is back-end SPN in msDS-AllowedToDelegateTo on front-end?
- RBKCD: Is front-end SID in msDS-AllowedToActOnBehalfOfOtherIdentity on back-end?
4. KDC issues a service ticket for the back-end, impersonating the user
5. Front-end connects to back-end presenting this ticket
6. Back-end sees the connection as coming from the original user
Testing Kerberos Delegation with klist
The klist command shows the Kerberos ticket cache and is the primary tool for verifying that delegation is working correctly. Run it on the front-end server in the context of the service account to observe ticket acquisition:
# View current Kerberos tickets for the logged-in session
klist
# View tickets for a specific logon session (use klist sessions first)
klist sessions
klist -li 0x3e7 # 0x3e7 is the SYSTEM logon session
# Purge the Kerberos ticket cache (force fresh ticket acquisition)
klist purge
# After testing a delegation scenario, look for:
# - A TGT for the service account
# - A service ticket for the back-end SPN (e.g., MSSQLSvc/sqlback01.domain.com:1433)
# - The KerbTicket Encryption Type should be AES256 (not RC4/DES)
# - The flags on delegated tickets will show FORWARDABLE or FORWARDED
To test the full delegation chain manually, run a test application or script that triggers the delegation. For SQL Server delegation testing:
# Test SQL connection with delegation from the web front-end server
# Run this as the application pool service account
$conn = New-Object System.Data.SqlClient.SqlConnection
$conn.ConnectionString = "Server=sqlback01.domain.com;Database=TestDB;Integrated Security=True"
$conn.Open()
$cmd = $conn.CreateCommand()
$cmd.CommandText = "SELECT SYSTEM_USER, AUTH_SCHEME FROM sys.dm_exec_requests WHERE session_id = @@SPID"
$reader = $cmd.ExecuteReader()
while ($reader.Read()) {
Write-Host "SQL User: $($reader[0]), Auth Scheme: $($reader[1])"
}
$conn.Close()
# Expected output: SQL User: domainoriginaluser, Auth Scheme: KERBEROS
Practical Delegation Scenarios
IIS to SQL Server delegation: The IIS application pool account must have an SPN registered for the web URL, and the SQL service account must have SPNs registered for the SQL instance. Configure classic KCD or RBKCD as shown above. Ensure the IIS application pool uses a domain service account, not NETWORK SERVICE or LOCAL SYSTEM.
# Register SPNs for IIS service account
setspn -S HTTP/webfront01.domain.com iissvc
setspn -S HTTP/webfront01 iissvc
# Register SPNs for SQL service account
setspn -S MSSQLSvc/sqlback01.domain.com:1433 sqlsvc
setspn -S MSSQLSvc/sqlback01.domain.com sqlsvc
# Verify no duplicate SPNs
setspn -X # searches for duplicates across entire domain
SharePoint to remote content source: SharePoint uses delegation extensively. Each web application’s application pool account must be configured for KCD to the content databases and any remote data sources (file shares, external databases). The UPA (User Profile Application) service account also typically requires delegation to domain controllers for profile synchronization.
Cross-domain delegation: Classic KCD does not support cross-domain delegation in most configurations. RBKCD works across forest trusts. When configuring cross-domain RBKCD, the front-end in domain A and back-end in domain B must both have their respective attributes set. The forest trust must be configured with selective authentication or full trust, and SPNs must be resolvable across the trust.
Troubleshooting Kerberos Delegation
Common delegation failures and their causes:
Error: The attempted logon is invalid (Kerberos 0xC000015B)
Cause: msDS-AllowedToDelegateTo does not include the target SPN
Fix: Add the correct SPN to the delegation list
Error: The security database does not have a computer account (0xC0000064)
Cause: SPN not registered or registered on wrong account
Fix: Use setspn -L on the service account to verify SPN registration
Error: No Kerberos credentials available (NTLM used instead)
Cause: SPN mismatch - the URL/hostname used doesn't match a registered SPN
Fix: Ensure the SPN exactly matches the connection string used
# Enable Kerberos logging on Windows Server for deep troubleshooting:
reg add "HKLMSYSTEMCurrentControlSetControlLsaKerberosParameters" /v LogLevel /t REG_DWORD /d 1 /f
# Events appear in System log under source Kerberos
# Capture Kerberos traffic with netsh for network-level analysis
netsh trace start capture=yes tracefile=C:kerberos.etl provider="Microsoft-Windows-Kerberos-Key-Distribution-Center"
# Reproduce the issue, then:
netsh trace stop
Kerberos Constrained Delegation, whether classic or resource-based, provides a secure and auditable mechanism for multi-tier service authentication. The shift toward RBKCD in modern environments is recommended because it distributes delegation management authority, works across forest boundaries, and aligns better with the principle of least privilege by placing configuration responsibility with the resource owner rather than requiring Domain Admin intervention for every new service deployment.