Starting point: an old convenience switch with too much trust
Kerberos delegation is not automatically bad in Active Directory. Many legitimate applications need a controlled double-hop: a web server accepts the user's authentication and then accesses a backend on behalf of that user, for example SQL, file services, or an internal API.
The risk starts when this is implemented with Unconstrained Delegation. The object is then not limited to specific destination services. Historically, that was convenient because old applications "just worked". In a modern AD hardening program, it is an overly broad trust decision.
Common patterns in real environments:
- old IIS, SharePoint, SQL, or middleware servers configured for delegation "to any service",
- service accounts with SPNs and unreviewed delegation settings,
- missing owners for legacy applications,
- privileged admin logons on servers that were never treated as Tier-0-relevant,
- exceptions that no one can justify anymore.
Domain controllers are a special case and need separate handling. The hardening focus is on member servers and service accounts that can broadly delegate without a clear need.
Target state: no broad delegation outside explicit exceptions
A useful target state is concrete:
- No Unconstrained Delegation on member servers or service accounts, unless there is a documented, time-bound exception.
- Application flows are understood: which frontend service must delegate to which backend service?
- Delegation is constrained: Kerberos Constrained Delegation or Resource-based Constrained Delegation only to defined destination services.
- Sensitive accounts cannot be delegated: privileged users, admin accounts, and break-glass accounts have "Account is sensitive and cannot be delegated" enabled; Protected Users is used where dependencies have been tested.
- Changes are measurable: inventory, owner, change window, monitoring, and rollback are part of the project.
The goal is not to ban delegation everywhere. The goal is to make delegation a deliberate and bounded trust path again.
Practical implementation: inventory first, targeted change second
1) Build a read-only inventory
Start with inventory only. No bulk change, no automatic cleanup.
Import-Module ActiveDirectory
Get-ADComputer -LDAPFilter '(&(objectCategory=computer)(userAccountControl:1.2.840.113556.1.4.803:=524288))' `
-Properties DNSHostName,OperatingSystem,ServicePrincipalName,DistinguishedName |
Select-Object Name,DNSHostName,OperatingSystem,DistinguishedName
Get-ADUser -LDAPFilter '(&(objectCategory=person)(objectClass=user)(userAccountControl:1.2.840.113556.1.4.803:=524288))' `
-Properties ServicePrincipalName,Enabled,DistinguishedName |
Select-Object SamAccountName,Enabled,DistinguishedName
These queries show objects with the delegation flag. Domain controllers should be marked separately in the report, not treated as ordinary findings. For member servers and service accounts, you then need owners, application context, SPNs, and the real authentication flow.
2) Classify each finding
Each finding gets a simple decision:
- remove: no business need or system is retired,
- replace: double-hop is needed, but only to defined services,
- temporarily accept: legacy dependency with owner, expiry date, and migration path,
- special case: domain controller or platform component that is not handled like a member server.
The most common clean target is not "no delegation", but constrained delegation to specific destination services. Where possible, service accounts should also move toward gMSA, clear SPN ownership, and separated operational roles.
3) Protect privileged accounts from delegation
Server cleanup must be paired with privileged-account hygiene. For admin accounts, "Account is sensitive and cannot be delegated" is an important minimum control.
Set-ADAccountControl -Identity "adm.example" -AccountNotDelegated $true
This does not replace tiering or admin workstation hygiene. It does prevent a sensitive account from being delegated if it accidentally touches a delegation-capable service. Before broad rollout, test whether admin workflows, services, or scheduled tasks break. Accounts used to run services should not be folded into this category casually; they need a separate migration decision.
4) Move service flows to constrained delegation
For applications that genuinely need double-hop, define the business path:
- frontend service account or computer object,
- destination service and SPN,
- involved domains,
- authentication type,
- owner and test case.
Then constrain delegation to those specific destination services. In modern environments, Resource-based Constrained Delegation is often easier to operate because the resource owner controls who may delegate to it. Classic Constrained Delegation still matters in many existing environments. Both models are better than "any service" when permissions and documentation are clean.
5) Remove Unconstrained Delegation deliberately
Only after owner, test case, and target state are clear should you remove broad delegation.
Set-ADAccountControl -Identity "APP01$" -TrustedForDelegation $false
Do this per application or in small waves, not as a domain-wide script run. After each wave, monitor sign-in paths, application behavior, and Kerberos failure patterns for a defined observation window.
Advantages
- Reduces blast radius for compromised member servers and service accounts.
- Indirectly protects Tier 0, because privileged logons should no longer touch broadly delegable systems.
- Forces ownership for old application flows, SPNs, and service accounts.
- Improves Kerberos hygiene as a base for AES-only, Protected Users, and clean admin tiers.
- Is measurable: number of findings, removed flags, and time-bound exceptions.
Disadvantages and limits
- Legacy applications can break when the real double-hop flow has not been understood.
- Constrained Delegation is not automatically safe: wrong SPNs, wrong destination objects, or broad RBCD ACLs create new risks.
- Domain controllers remain special cases and must not be compared blindly with member servers.
- The business value is not very visible, because successful hardening often means "nothing broke".
- It does not replace logon hygiene: admins still must not work from arbitrary application servers.
Typical pitfalls
- Treating every finding the same: DCs, member servers, and service accounts need separate evaluation.
- Bulk-disable without owners: it looks efficient and quickly turns into production incidents.
- Skipping SPN review: delegation is practically tied to service identities and SPNs.
- Setting RBCD too broadly: resource-based does not automatically mean safe; the ACL decides.
- Forgetting admin accounts: if sensitive accounts remain delegable, the security gain is incomplete.
- Exceptions without expiry: "temporary" otherwise becomes the new baseline.
Project checklist
- [ ] Inventory computers and users with Unconstrained Delegation in read-only mode.
- [ ] Mark domain controllers separately and exclude them from member-server cleanup.
- [ ] Document owner, application, SPNs, and real authentication flow for every finding.
- [ ] Check privileged users and break-glass accounts for
AccountNotDelegated. - [ ] Migrate double-hop applications to Constrained Delegation or Resource-based Constrained Delegation.
- [ ] Review service accounts for gMSA fit, SPN ownership, and minimal rights.
- [ ] Remove Unconstrained Delegation only in small waves.
- [ ] Monitor Kerberos errors, sign-in paths, and application functions after every wave.
- [ ] Track time-bound exceptions with owner, risk, target date, and next review.
