Constrained delegation and RBCD done safely in AD
Configure KCD and RBCD without new attack paths: protocol transition, SPN scoping, and auditing who can write msDS-AllowedToActOnBehalfOfOtherIdentity.
Once unconstrained delegation is gone, the delegation that remains is the scoped kind: Kerberos constrained delegation (KCD) and resource-based constrained delegation (RBCD). Both are legitimate and often necessary. Both also turn into impersonation primitives when they are configured loosely or when the wrong people can modify them. Attackers use tools such as Rubeus and Impacket to request S4U tickets; this guide focuses on the defensive side, meaning the configuration choices and audits that decide whether those requests get anything useful.
It assumes you already know the three models from the Delegation pillar guide. Here we go into the Kerberos extensions behind them, the settings that make each one risky, and a repeatable audit of who can write RBCD on your computer objects.
How S4U makes delegation work
Both scoped models rely on two Kerberos extensions, collectively called Service for User (S4U):
- S4U2Self lets a service request a ticket to itself on behalf of any user, without that user's credentials. It exists so a service can learn a user's group memberships.
- S4U2Proxy lets a service take a ticket it holds for a user (the "evidence" ticket) and exchange it for a ticket to a different service, still as that user.
The KDC checks S4U2Proxy against delegation configuration: msDS-AllowedToDelegateTo on the front end for KCD, or msDS-AllowedToActOnBehalfOfOtherIdentity on the back end for RBCD. Two details decide how dangerous a given configuration is.
Protocol transition
With "Kerberos only" KCD, S4U2Proxy only succeeds if the evidence ticket is forwardable, which in practice means the user really authenticated to the front end with Kerberos. With "Use any authentication protocol" (the TRUSTED_TO_AUTH_FOR_DELEGATION flag, 0x1000000), the front end can obtain a forwardable ticket for any user through S4U2Self alone. The user never has to show up.
That means anyone who controls a front-end account with protocol transition can impersonate any non-protected user, including Domain Admins, to every SPN in its allow list, at any time. Protocol transition is needed for forms authentication, certificate or smart card logon handled by the application, and some SSO gateways. It is not needed for an intranet site using Windows Integrated Authentication.
RBCD and forwardable tickets
For RBCD, the KDC accepts a non-forwardable evidence ticket as long as the back end trusts the front end. So an attacker who controls any account with an SPN (a computer account they created is enough) and can write RBCD on a target computer can impersonate users to that target. That is why RBCD hygiene is mostly about write permissions, and why ms-DS-MachineAccountQuota matters so much here.
Service name substitution
The SPN in a service ticket is not protected by the ticket's encryption. A ticket issued for cifs/fs01 is equally valid for host/fs01, http/fs01 or ldap/fs01 if those services run under the same account, and on a computer account they all do. Scope accordingly: an entry pointing at any service on a domain controller is effectively delegation to the whole DC.
Measure: inventory the scoped delegation
Collect both models across every domain, including the protocol transition flag.
Import-Module ActiveDirectory
# KCD: front-end accounts with msDS-AllowedToDelegateTo
Get-ADObject -LDAPFilter '(msDS-AllowedToDelegateTo=*)' `
-Properties samAccountName, objectClass, msDS-AllowedToDelegateTo, userAccountControl |
Select-Object samAccountName, objectClass,
@{n='ProtocolTransition';e={[bool]($_.userAccountControl -band 0x1000000)}},
@{n='Targets';e={$_.'msDS-AllowedToDelegateTo' -join '; '}}
# RBCD: back-end resources and who may delegate to them
Get-ADComputer -LDAPFilter '(msDS-AllowedToActOnBehalfOfOtherIdentity=*)' `
-Properties PrincipalsAllowedToDelegateToAccount |
Select-Object Name,
@{n='AllowedFrom';e={$_.PrincipalsAllowedToDelegateToAccount -join '; '}}PrincipalsAllowedToDelegateToAccount is the ActiveDirectory module's friendly view of the msDS-AllowedToActOnBehalfOfOtherIdentity security descriptor, so you do not have to parse it by hand. RBCD can also be set on user and service accounts; if you want full coverage, run the same filter with Get-ADObject.
Flag these as critical:
- Any KCD target or RBCD resource that is a domain controller, AD CS server or other Tier 0 asset.
- Any front end with protocol transition that is not documented as needing it.
- Any RBCD entry pointing at a computer account created by a regular user (check
mS-DS-CreatorSIDon the front end). - Any delegation configured on a user account with a static password.
Audit: who can write RBCD
An RBCD entry you know about is only half the picture. The other half is who could add one tomorrow. Look for these rights on computer objects, especially servers and Tier 0 machines:
GenericAll,GenericWrite,WriteDaclorWriteOwneron the object, or ownership of it.WritePropertyfor all properties, or for the attributemsDS-AllowedToActOnBehalfOfOtherIdentity(schemaIDGUID3f78c3e5-f79a-46bd-a0b8-9d18116ddc79).WritePropertyon the Account Restrictions property set (4c164200-20c0-11d0-a768-00aa006e0529), which is commonly granted to the account that joined a machine and includes this attribute.
$rbcdAttr = [guid]'3f78c3e5-f79a-46bd-a0b8-9d18116ddc79'
$acctRestr = [guid]'4c164200-20c0-11d0-a768-00aa006e0529'
$expected = 'NT AUTHORITY\\SYSTEM|\\Domain Admins$|\\Enterprise Admins$|BUILTIN\\Administrators|\\Key Admins$|\\Enterprise Key Admins$|NT AUTHORITY\\SELF'
Get-ADComputer -Filter * -SearchBase 'OU=Servers,DC=corp,DC=example,DC=com' |
ForEach-Object {
$dn = $_.DistinguishedName
$acl = Get-Acl -Path "AD:\$dn"
$acl.Access | Where-Object {
$_.AccessControlType -eq 'Allow' -and
$_.IdentityReference -notmatch $expected -and (
$_.ActiveDirectoryRights -match 'GenericAll|GenericWrite|WriteDacl|WriteOwner' -or
($_.ActiveDirectoryRights -match 'WriteProperty' -and
$_.ObjectType -in @([guid]::Empty, $rbcdAttr, $acctRestr))
)
} | Select-Object @{n='Computer';e={$dn}}, IdentityReference, ActiveDirectoryRights, ObjectType, IsInherited
} | Export-Csv .\rbcd-writers.csv -NoTypeInformationAlso review $acl.Owner for each object: an owner can always rewrite the DACL. Inherited ACEs point to OU-level delegation that is too broad; fix those at the OU rather than object by object. For a graph view across the whole domain, the attack path management guide shows how to query the same relationships in BloodHound.
Note the SELF exclusion above. A computer account can write RBCD on its own object in default configurations, which is harmless on its own but is exactly what relay chains such as KrbRelayUp exploit: they relay the machine's authentication to LDAP and write RBCD as the machine. The fix is not an ACL change, it is LDAP signing and channel binding on every DC.
Enforce: configure scoped delegation safely
Kerberos-only KCD
When users reach the front end with Kerberos, use KCD without protocol transition, with the smallest list of SPNs that works.
Set-ADComputer -Identity WEB01 -Replace @{
'msDS-AllowedToDelegateTo' = @('MSSQLSvc/sql01.corp.example.com:1433','MSSQLSvc/sql01.corp.example.com')
}
Set-ADAccountControl -Identity (Get-ADComputer WEB01) -TrustedToAuthForDelegation $falseIf protocol transition is genuinely required, run the front end under a gMSA, keep it in a dedicated tier, restrict local admin on its hosts, and make sure the SPN list contains no DC, AD CS or management server.
RBCD
Set RBCD with the dedicated parameter so the security descriptor is well formed, and prefer a group when several front ends need access so changes happen in membership, not in the descriptor.
$front = Get-ADGroup 'GG-SQL01-Delegation-Frontends'
Set-ADComputer -Identity SQL01 -PrincipalsAllowedToDelegateToAccount $frontClear stale entries with Set-ADComputer -Identity <name> -PrincipalsAllowedToDelegateToAccount $null.
Protect the identities that must never be impersonated
Every Tier 0 account should be in Protected Users or flagged "Account is sensitive and cannot be delegated". Both cause the KDC to refuse S4U tickets for those users, which neutralises most delegation abuse even when a front end is compromised. Set the NOT_DELEGATED flag as well, including on the built-in Administrator and on break-glass accounts that may not be in Protected Users: it is enforced by the KDC regardless of group membership and survives an accidental group cleanup. Keep DCs patched for CVE-2020-17049 (the Bronze Bit issue), which let a compromised front end bypass both protections by tampering with the forwardable flag.
Verify
-
Re-run the inventory. Every KCD and RBCD entry maps to a change record and an owner; no entry targets a Tier 0 host.
-
Re-run the writer audit on server and Tier 0 OUs. The only non-default writers are documented provisioning groups.
-
Confirm privileged accounts carry
NOT_DELEGATEDor Protected Users membership. This should return nothing:PowerShell# Protected Users is RID 525; nested members count too $protected = (Get-ADGroupMember -Identity "$((Get-ADDomain).DomainSID)-525" -Recursive).SID.Value Get-ADUser -Filter 'AccountNotDelegated -eq $false' -SearchBase '<admin OU>' | Where-Object { $_.SID.Value -notin $protected } -
Enable a SACL for writes to
msDS-AllowedToActOnBehalfOfOtherIdentityandmsDS-AllowedToDelegateToon the domain root (Directory Service Changes auditing) and alert on event 5136 for either attribute. -
On DCs, event 4769 includes a
Transited Servicesfield that is populated for S4U2Proxy requests. Baseline which front ends appear there; a new one is worth investigating. The event ID reference lists the other fields worth collecting.
What it breaks
- Removing protocol transition breaks applications that authenticate users with forms, client certificates handled in the app, or claims from an external IdP and then call a Kerberos back end. They fail at the second hop with anonymous or access denied errors.
- Trimming SPN lists breaks access through aliases: if users hit
sql01by short name and only the FQDN SPN is listed, delegation fails. Include both forms where clients use both. - Adding admins to Protected Users or
NOT_DELEGATEDmeans those admins can no longer use delegating applications as themselves, such as web consoles that query back ends with the user's identity. They should use a standard account for those tools. - Tightening OU delegation removes the ability of helpdesk or deployment accounts to modify computer attributes they used to touch, which can break reimaging scripts that reset or rewrite computer objects.
Related reading: the Delegation topic, the resource-based constrained delegation glossary entry, and auditing Active Directory ACLs for the broader permission review this audit is part of.
Frequently asked questions
Is constrained delegation to one SPN really limited to that one service?
Not entirely. The service name in a Kerberos service ticket sits outside the encrypted part, so a ticket obtained for cifs/server can be rewritten to another service class on the same host that runs under the same account, such as host, http or ldap. Treat a delegation entry as granting access to every service that runs as the target account on that host, not just the SPN you listed.
Why can a normal user sometimes configure RBCD on a computer?
RBCD is governed by an ordinary write permission on the target computer object, not by SeEnableDelegationPrivilege. Anyone holding GenericWrite, GenericAll, WriteDacl, ownership or a write on msDS-AllowedToActOnBehalfOfOtherIdentity can set it. On many domains that includes the account that joined the computer, helpdesk groups with broad OU delegation and, through NTLM relay to LDAP, the computer account itself.
Should I prefer KCD or RBCD for a new application?
Prefer RBCD when the back-end owner should decide who delegates to it, or when the front end and back end live in different domains. Prefer Kerberos-only KCD when Domain Admins must approve every change, because it requires SeEnableDelegationPrivilege. In both cases avoid protocol transition unless users truly cannot authenticate with Kerberos, and never point either model at domain controller services.
Constrained delegation and RBCD done safely in AD