Applies ToWindows Server 2008 Windows Server 2008 R2 Windows Server 2012 Windows Server 2012 R2 Windows Server 2016 Windows Server 2019, all editions

Summary

Forest trusts provide a way for resources in an Active Directory forest to trust identities from another forest. This trust can be configured in both directions. The trusted forest is the source of user identity. The trusting forest contains the resource to which users authenticate. The trusted forest can authenticate users to the trusting forest without allowing the reverse to occur.

Unconstrained Kerberos delegation is a mechanism in which a user sends its credentials to a service to enable the service to access resources on behalf of the user. To enable unconstrained Kerberos delegation, the service's account in Active Directory must be marked as trusted for delegation. This creates a problem if the user and service belong to different forests. The service forest is responsible for allowing delegation. The delegation includes the credentials of users from the user's forest.

Allowing one forest to make security decisions that affects another forest's accounts violates the security boundary between forests. An attacker that owns the trusting forest can request delegation of a TGT for an identity from the trusted forest, giving it access to resources in the trusted forest. This does not apply to Kerberos Constrained delegation (KCD).

Windows Server 2012 introduced Enforcement for Forest Boundary for Kerberos Full Delegation. This feature added a policy to the trusted domain to disable unconstrained delegation on a per-trust basis. The default setting for this feature allows unconstrained delegation and is unsafe.

Updates that provide security hardening exist for the following versions of Windows Server:

  • Windows Server 2019

  • Windows Server 2016

  • Windows Server 2012 R2

  • Windows Server 2012

This feature together with changes in security hardening were backported to the following versions:

  • Windows Server 2008 R2

  • Windows Server 2008

These security updates make the following changes:

  • Unconstrained Kerberos delegation is disabled by default on new forest and new external trusts after you install the May 14 update and later updates.

  • Unconstrained Kerberos delegation is disabled on forests (both new and existing) and external trusts after you install the July 9, 2019, update and later updates.

  • Administrators can enable unconstrained Kerberos delegation by using the May or later versions of NETDOM and AD PowerShell module.

The updates may cause compatibility conflicts for applications that currently require unconstrained delegation across forest or external trusts. This is especially true of external trust for which the quarantine flag (also known as SID filtering) is enabled by default. Specifically, authentication requests for services that use unconstrained delegation over the listed trust types will fail when you request new tickets.

For the release dates, see Updates timeline.

Workaround

To provide data and account security on a Windows Server version that has the Enforcement for Forest Boundary for Kerberos Full Delegation feature, you can block TGT delegation after you install the March 2019 updates across an incoming trust by setting the netdom flag EnableTGTDelegation to No, as follows:

netdom.exe trust fabrikam.com /domain:contoso.com /EnableTGTDelegation:No

TGT delegation is blocked on new and existing forest and external trusts after you install the May and July 2019 updates respectively.

To re-enable delegation across trusts and return to the original unsafe configuration until constrained or resource-based delegation can be enabled, set the EnableTGTDelegation flag to Yes.

The NETDOM command line to enable TGT delegation is as follows:

netdom trust <TrustedDomainName > /domain:<TrustingDomainName > /EnableTgtDelegation:Yes

You can conceptually think of the NETDOM syntax for enabling TGT delegation as follows:

netdom trust <domain that you are administering> /domain:<domain whose trust NETDOM is modifying> /EnableTgtDelegation:Yes

The NETDOM syntax to enable TGT delegation of fabrakam.com users on contoso.com servers is as follows:

netdom.exe trust fabrikam.com /domain:contoso.com /EnableTGTDelegation:Yes

Notes

  • The EnableTGTDelegation flag should be set in the trusted domain (fabrikam.com in this case) for each trusting domain (such as contoso.com). After the flag is set, the trusted domain will no longer allow TGTs to be delegated to the trusting domain.

  • The secure state for EnableTGTDelegation is No.

  • Any application or service that relies on unconstrained delegation across forests will fail when EnableTGTDelegation is manually or programmatically set to Yes. EnableTGTDelegation defaults to NO on new and existing trusts after you install the May 2019 and July 2019 updates. For more information about how to detect this failure, see Finding services that rely on unconstrained delegation. See Updates timeline for a timeline of changes that affect how this workaround can be applied.

  • For more information about NETDOM, see the Netdom.exe documentation.

  • If you must enable TGT delegation on a trust, it's recommended that you mitigate that risk by enabling Windows Defender Credential Guard on client computers. This prevents all unconstrained delegation from a computer that has Windows Defender Credential Guard enabled and running.

  • If you have a forest or external trust, and either are configured as quarantined, TGT delegation cannot be enabled because the two flags have opposite semantics. The quarantine bit strengthens the security boundary between participating domains. Enabling TGT delegation erases the security boundaries between domains by giving the trusting domain access to the credentials of users from the trusted domain. You cannot have it both ways.

    Add the quarantine:no flag to the NETDOM command line syntax if the quarantine flag is currently enabled.

  • If you changed EnableTGTDelegation to Yes, delete Kerberos tickets on originating and intermediate callers as required. The relevant ticket to delete is the client's referral TGT across the relevant trust. This could involve more than one device, depending on the number of delegation hops in a given environment.

For more information about this procedure, see the following Windows IT Pro Center article:

Protect derived domain credentials with Windows Defender Credential Guard

Updates timeline

March 12, 2019

The enforcement for forest boundary for Kerberos full delegation will be available as an update to enable this feature on all supported versions of Windows Server that are listed in the Applies to section at the top of this article. We recommend that you set the feature on incoming forest trusts.

The update will add the Enforcement for Forest Boundary for Kerberos Full Delegation feature to the following systems:

  • Windows Server 2008 R2

  • Windows Server 2008

May 14, 2019

An update was released adding a new safe default configuration to new forest and external trusts. If you require delegation across trusts, the EnableTGTDelegation flag should be set to Yes before the July 9, 2019 update is installed. If you do not require delegation across trusts, you should not set the EnableTGTDelegation flag. The EnableTGTDelegation flag will be ignored until the July 9, 2019 update is installed to give administrators time to re-enable unconstrained Kerberos delegation when it is required.

As a part of this update, the EnableTGTDelegation flag will be set to No by default for any newly created trusts. This is the opposite of the previous behavior. We recommend that administrators instead reconfigure the affected services to use resource-based constrained delegation.

For more information about how to detect compatibility issues, see Finding services that rely on unconstrained delegation.

July 9, 2019

An update was released that enforces the new default behavior on the inbound side of forest and external trusts. Authentication requests for services that use unconstrained delegation over the listed trust types will be authenticated but without delegation. The service will fail when it tries to run delegated operations.

For mitigation, see the "Workaround" section.

Finding services that rely on unconstrained delegation

To scan for forests that have incoming trusts that allow TGT delegation, and to find any security principals that allow unconstrained delegation, run the following PowerShell scripts in a script file (for example, Get-RiskyServiceAccountsByTrust.ps1 -Collect):

Note: You can also pass the -ScanAll flag to search across trusts that do not allow TGT delegation.


[CmdletBinding()]  
Param  
(  
    [switch]$Collect, 
    [switch]$ScanAll 
) 
 
if ($Debug) {  
    $DebugPreference = 'Continue'  
} 
else { 
    $DebugPreference = 'SilentlyContinue'  
} 

function Get-AdTrustsAtRisk 
{ 
    [CmdletBinding()]  
    Param  
    (  
        [string]$Direction = "Inbound", 
        [switch]$ScanAll 
    ) 
 
    if ($ScanAll) { 
        return get-adtrust -filter {Direction -eq $Direction} 
    } 
    else { 
        return get-adtrust -filter {Direction -eq $Direction -and TGTDelegation -eq $false} 
    } 
} 
 
function Get-ServiceAccountsAtRisk 
{ 
    [CmdletBinding()]  
    Param  
    (  
        [string]$DN = (Get-ADDomain).DistinguishedName, 
        [string]$Server = (Get-ADDomain).Name 
    ) 
 
    Write-Debug "Searching $DN via $Server" 
 
    $SERVER_TRUST_ACCOUNT = 0x2000  
    $TRUSTED_FOR_DELEGATION = 0x80000  
    $TRUSTED_TO_AUTH_FOR_DELEGATION= 0x1000000  
    $PARTIAL_SECRETS_ACCOUNT = 0x4000000    
 
    $bitmask = $TRUSTED_FOR_DELEGATION -bor $TRUSTED_TO_AUTH_FOR_DELEGATION -bor $PARTIAL_SECRETS_ACCOUNT  
  
$filter = @"  
(& 
  (servicePrincipalname=*) 
  (| 
    (msDS-AllowedToActOnBehalfOfOtherIdentity=*) 
    (msDS-AllowedToDelegateTo=*) 
    (UserAccountControl:1.2.840.113556.1.4.804:=$bitmask) 
  ) 
  (| 
    (objectcategory=computer) 
    (objectcategory=person) 
    (objectcategory=msDS-GroupManagedServiceAccount) 
    (objectcategory=msDS-ManagedServiceAccount) 
  ) 
) 
"@ -replace "[\s\n]", ''  
  
    $propertylist = @(  
        "servicePrincipalname",   
        "useraccountcontrol",   
        "samaccountname",   
        "msDS-AllowedToDelegateTo",   
        "msDS-AllowedToActOnBehalfOfOtherIdentity"  
    )  
 
    $riskyAccounts = @() 
 
    try { 
        $accounts = Get-ADObject -LDAPFilter $filter -SearchBase $DN -SearchScope Subtree -Properties $propertylist -Server $Server 
    } 
    catch { 
        Write-Warning "Failed to query $Server. Consider investigating seperately. $($_.Exception.Message)" 
    } 
              
    foreach ($account in $accounts) {  
        $isDC = ($account.useraccountcontrol -band $SERVER_TRUST_ACCOUNT) -ne 0  
        $fullDelegation = ($account.useraccountcontrol -band $TRUSTED_FOR_DELEGATION) -ne 0  
        $constrainedDelegation = ($account.'msDS-AllowedToDelegateTo').count -gt 0  
        $isRODC = ($account.useraccountcontrol -band $PARTIAL_SECRETS_ACCOUNT) -ne 0  
        $resourceDelegation = $account.'msDS-AllowedToActOnBehalfOfOtherIdentity' -ne $null  
      
        $acct = [PSCustomobject] @{  
            domain = $Server 
            sAMAccountName = $account.samaccountname  
            objectClass = $account.objectclass          
            isDC = $isDC  
            isRODC = $isRODC  
            fullDelegation = $fullDelegation  
            constrainedDelegation = $constrainedDelegation  
            resourceDelegation = $resourceDelegation  
        }  
 
        if ($fullDelegation) {  
            $riskyAccounts += $acct    
        } 
    }  
 
    return $riskyAccounts 
} 
 
function Get-RiskyServiceAccountsByTrust  
{ 
    [CmdletBinding()]  
    Param  
    ( 
        [switch]$ScanAll 
    ) 
     
    $riskyAccounts = @() 
 
    $trustTypes = $("Inbound", "Bidirectional") 
 
    foreach ($type in $trustTypes) { 
 
        $riskyTrusts = Get-AdTrustsAtRisk -Direction $type -ScanAll:$ScanAll 
 
        foreach ($trust in $riskyTrusts) { 
            $domain = $null 
     
            try { 
                $domain = Get-AdDomain $trust.Name -ErrorVariable eatError -ErrorAction Ignore 
            } catch { 
                write-debug $_.Exception.Message 
            } 
 
            if($eatError -ne $null) { 
                Write-Warning "Couldn't find domain: $($trust.Name)" 
            } 
 
            if ($domain -ne $null) { 
                $accts = Get-ServiceAccountsAtRisk -DN $domain.DistinguishedName -Server $domain.DNSRoot 
 
                foreach ($acct in $accts) { 
                    Write-Debug "Risky: $($acct.sAMAccountName) in $($acct.domain)" 
                }             
 
                $risky = [PSCustomobject] @{  
                    Domain = $trust.Name 
                    Accounts = $accts 
                } 
 
                $riskyAccounts += $risky 
            } 
        } 
    } 
 
    return $riskyAccounts 
} 
 
if ($Collect) { 
   Get-RiskyServiceAccountsByTrust -ScanAll:$ScanAll | Select-Object -expandProperty Accounts | format-table 
}

The output of the PowerShell scripts list Active Directory security principals in domains that are configured for an incoming trust from the executing domain that has unconstrained delegation configured. The output will resemble the following example.

domain

sAMAccountName

objectClass

partner.fabrikam.com

dangerous

user

partner.fabrikam.com

labsrv$

computer

Detecting unconstrained delegation through Windows events

When a Kerberos ticket is issued, an Active Directory domain controller logs the following security events. The events contain information about the target domain. You can use the events to determine whether unconstrained delegation is being used across incoming trusts.

Note: Check for events that contain a TargetDomainName value that matches the trusted domain name.

Event log

Event source

Event ID

Details

Security

Microsoft-Windows-Security-Auditing

4768

A Kerberos TGT was issued.

Security

Microsoft-Windows-Security-Auditing

4769

A Kerberos Service Ticket was issued.

Security

Microsoft-Windows-Security-Auditing

4770

A Kerberos Service Ticket was renewed.

Troubleshooting authentication failures

When unconstrained delegation is disabled, applications may have compatibility issues with these changes if the applications rely on unconstrained delegation. These applications should be configured to use constrained delegation or constrained delegation that is resource-based. For more information, see Kerberos Constrained Delegation Overview.

Applications that rely on round-trip authentication across trusts are not supported by using constrained delegation. For example, a delegation fails if a user in Forest A authenticates to an application in Forest B and the application in Forest B is trying to delegate a ticket back to Forest A.

További segítségre van szüksége?

További lehetőségeket szeretne?

Explore subscription benefits, browse training courses, learn how to secure your device, and more.

Communities help you ask and answer questions, give feedback, and hear from experts with rich knowledge.