Kerberos Delegation in Active Directory

The topic of Active Directory Kerberos delegation seems rather retro given that it is as old as AD itself. However, this is a very confusing and complex subject which has resulted in much misinformation out on the Internet. I am hoping that my explanation will be useful to a broad audience.

What is Kerberos Authentication?

Kerberos is an authentication protocol. It facilitates users proving their identity to services via the exchange of “tickets” mediated by the AD domain controllers. It is also a mutual authentication mechanism that allows services to prove their identities to users. Much has been written about Kerberos so suffice it to say that it is one of the most secure authentication protocols in wide use. The protocol is defined in https://tools.ietf.org/html/rfc4120.

What is Kerberos Delegation?

Kerberos delegation is used in multi-tier application/service situations. A common scenario would be a web server application making calls to a database running on another server. The first tier is the user who browses to the web site’s URL. The second tier is the web site. The third or data tier would be the database. Delegation allows the database to know who is actually accessing its data.

One way to set this up is to run the web site using a domain service account. Let’s call this service account WebServerAcct. The database is running on a different server under its own service account. In many cases the database is run by a separate team from the web application so that the web application team must request database access for their WebServerAcct service account. The database admins would need to grant sufficient access to the WebServerAcct account for all possible actions of the web application. This means that the web application developers and/or admins determine who can access the application and by extension the data in the back end. This situation may be unacceptable to the database admins as they cannot control who ultimately has access to the data. The solution is to use Kerberos delegation.

Kerberos delegation would be configured on the WebServerAcct service account which grants it permission to delegate to the database service account. What does this actually mean? When a user accesses the web site they authenticate with Windows Integrated Authentication. This results in the WebServerAcct application receiving a request from the user that is accompanied by the user’s Kerberos ticket (I’m glossing over lots of details here in order to keep the scenario relatively simple). The user’s ticket contains a list of the user’s AD group memberships. The WebServerAcct application can examine the user’s group memberships and only allow access if the user is in a specific group. With delegation configured, the WebServerAcct service can request a Kerberos ticket to the database as the user rather than as itself. IOW, the database would receive a Kerberos ticket from the user rather than from the WebServerAcct application. This allows the database to examine the user’s groups to see if there is a membership in a group that is permitted access to the database. Without delegation the database would have no idea what user is actually accessing the data since it would have to give blanket access to the WebServerAcct account.

A concrete example of the above scenario is running SQL Server Reporting Services (SSRS) on a computer that is separate from the SQL Server database that provides the report data. The SSRS developer/admin can limit access to reports to specific users or groups. However, this does not actually grant those users/groups access to the data in the database. With delegation the database admins can control which users or groups can actually access the data rather than giving unlimited access to the SSRS service account.

Constrained Versus Unconstrained Delegation

Unconstrained delegation (a.k.a. basic delegation) was introduced with Active Directory in Windows 2000. It has the rather severe shortcoming in that it allows a user/service to request delegated tickets to any other service. This capability can be abused as an elevation-of-privilege attack vector. It was, however, the only reliable way to do delegation across a domain-trust boundary until Server 2012. Constrained delegation imposes limits as to which service accounts a delegating account can delegate to. This vastly reduces the potential for abuse of the delegating service account’s privileges.

There are actually two flavors of constrained delegation.

Original Constrained Delegation

This initial form of constrained delegation was introduced in Server 2003. With this type of delegation you explicitly list the services that the first tier account is allowed to delegate to. Using the above example, you would set constrained delegation on the WebServerAcct account. The Active Directory Users and Computers (ADUC) user property sheet has a page for configuring delegation. This form of constrained delegation may not be used across a domain/forest trust unless all of the DCs are at least Server 2012. With pre-2012 domains both the middle tier and back end tier services must be in the same domain.1 There are two other caveats around this form of constrained delegation. 1) the delegation tab will only appear on user and computer objects that have Service Principal Names (SPNs) set. If you expect a delegation tab and it isn’t there, that means that SPNs are not configured. 2) the delegation tab has some shortcomings in supporting service accounts that are user accounts; it will only list services running as a computer’s local account (Network Service, etc.). Thus to delegate to a user object service account one must directly edit the msDS-AllowedToDelegateTo (A2D2) attribute.

SPNs are discussed in many places on the web, so I won’t dwell on them here.

Resource-Based Delegation

The new form of delegation was introduced in Server 2012. It is designed to overcome several limitations of A2D2 delegation. First, it allows for delegation across a trust. Second, it changes how delegation is controlled. Rather than configuring the middle tier account to enable delegation, you configure the data-tier (resource) account to specify who can delegate to it. Additionally it does not require domain-administrator privilege to configure. The admin who has the ability to manage the resource service account can make the delegation changes. This change introduced the msDS-AllowedToActOnBehalfOfOtherIdentity attribute which would be configured on the resource service account.

This article is a good in-depth explanation of the Kerberos S4U2Proxy extension that enables constrained delegation and the changes introduced with Server 2012: http://windowsitpro.com/security/how-windows-server-2012-eases-pain-kerberos-constrained-delegation-part-1 (with more technical details in the second part). Unfortunately it appears that this site is gone. Here is the official article: https://docs.microsoft.com/en-us/windows-server/security/kerberos/kerberos-constrained-delegation-overview

I don’t believe the proffered advantages are as compelling in a real world situation. First, the domain is not a security boundary (see Security Bulletin MS02-001). I understand that there are a lot of legacy setups in the wild, but if you aren’t thinking about domain consolidation you really ought to be. Second, the data custodians/DBAs still need to control access to the databases by limiting access to specific groups. Do you really gain much by giving DBAs the additional ability to limit access to specific apps/services through this second delegation option? Regardless, there are certainly scenarios where these features will be useful.

Sensitive to Delegation?

This may be the most confusing part of Kerberos delegation. What exactly does the user account option “Account is sensitive and cannot be delegated” do? Does it control whether an account can request delegated tickets to another account? NO! It has no bearing on whether an account can do delegation! Rather, it means that a service account cannot request a delegated ticket for an account with this setting.

I think an example is in order. First, what would be a sensitive account? That means an account with elevated privilege in AD. An obvious example is Domain Admins. You would not want a service to request a delegated token for a domain admin. That would elevate the service’s privilege to that of domain admin. It is a best practice to set AD ACLs to limit the access of ordinary user accounts (e.g. ordinary users should not be able to log into and configure servers). Service accounts and systems admin accounts often need additional privileges to do what they do. Thus you should also stamp these accounts with the “Account is sensitive” setting.

A note on AD security: do not grant ordinary user accounts elevated privileges! Create clearly named separate accounts for those administrative tasks. Never use highly privileged domain or enterprise admin accounts for tasks that do not require that level of privilege! If you do server administration, browse the web, or read email with an account with EA/DA privs, the hackers will own you. ‘Nuff said.

Technical Details

All AD security principals contain the attribute userAccountControl. This attribute is a bit set, meaning that each binary digit is assigned a specific meaning. These bit values are defined in the Windows SDK in lmaccess.h. We are interested in three of these “flag” values:

#define UF_TRUSTED_FOR_DELEGATION                     0x80000
#define UF_NOT_DELEGATED                             0x100000
#define UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION   0x1000000

The UF_NOT_DELEGATED bit is set when you select the “Account is sensitive and cannot be delegated” checkbox.

The UF_TRUSTED_FOR_DELEGATION bit specifies unconstrained delegation. It is set when you select “Trust this user/computer for delegation to any service (Kerberos only)” in the Delegation tab. The only accounts that should have this bit set are the domain controller computer accounts. We have to trust our DCs; we’d rather not extend this level of trust to anyone else!

The UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit, if set, enables protocol transition for constrained delegation. It is set when you check the “Use any authentication protocol” radio button on the Delegation UI. When set, if a user authenticates with NTLM the server can request a Kerberos ticket for that user. If not set, a user authenticating with NTLM can not be delegated.

As I mentioned earlier, the msDS-AllowedToDelegateTo attribute enables constrained delegation to the named servers/services. The entries in this attribute must match the SPN(s) set on the corresponding server or service account. If you manually modify this attribute, then you should ensure that the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit is set on userAccountControl if you want protocol transition.

The msDS-AllowedToActOnBehalfOfOtherIdentity attribute controls the newer form of constrained delegation. It is set on the back-end data tier service account and names those middle-tier accounts that are allowed to request delegated tickets to the back-end service.

LDAP and PowerShell Techniques for Managing Delegation

It is a good policy to periodically scan your AD accounts to see which have delegation enabled. To make this an effective tool though you’d need a table of those accounts that have been granted permission to delegate. This enables spotting accounts whose delegation authorization has expired or who were never actually given administrative authorization. Similarly it is a good idea to scan privileged and service accounts to ensure that they have the “Account is sensitive” bit set.

Searching AD for accounts with one of these bits set in userAccountControl is straightforward but certainly not obvious. The first challenge is understanding LDAP query filter structure which is based on prefix notation. This means that the logical operators that combine query clauses are placed before the clauses. LDAP query clauses are enclosed in parenthesis. If you have clause A and clause B and you wanted both to be true to satisfy the query, it would be structured as (&(A)(B)) rather than the more conventional programming infix notation of (A & B).

The second hurdle is searching for specific bits in a bit set. This requires the specification of a “custom” query operator that is identified using an OID (an Object ID). OIDs are a bit like GUIDs except that they have a hierarchical namespace (digit space?) and are regulated by a standards body. At any rate the OID for doing a bit-match query clause in LDAP is “1.2.840.113556.1.4.803”. Another thing to keep in mind is that this LDAP bit-match query expects a decimal (base-10) number rather than the hexadecimal (base-16) number used in lmaccess.h.

  • Unconstrained delegation (UF_TRUSTED_FOR_DELEGATION 0x80000) = 524288 decimal
  • Sensitive to delegation (UF_NOT_DELEGATED 0x100000) = 1048576 decimal

To search for all accounts that are enabled for unconstrained delegation use the LDAP query filter of:

(userAccountControl:1.2.840.113556.1.4.803:=524288)

To search for accounts that should have “Sensitive to delegation” but don’t:

(&(name=$userPrefix)(!userAccountControl:1.2.840.113556.1.4.803:=1048576))

Note the exclamation point in front of userAccountControl. That means to find all accounts that don’t have that bit set. The $userPrefix is a placeholder for a user filter expression that would apply to your AD. We create all of our admin and service accounts with specific prefixes to make them easy to identify. Thus you could have (name=a_*) to search for all accounts that start with a_.

You can use these query filters with a tool like LDAPDE. I’ll show how to make these queries from PowerShell. The first example searches for user accounts starting with a specific prefix that don’t have UF_NOT_DELEGATED set.

# Find all user accounts matching the prefix that don't have "Sensitive to delegation" set
param([string]$userPrefix="a_*")
Import-Module ActiveDirectory
$filter = "(&(name=$userPrefix)(!userAccountControl:1.2.840.113556.1.4.803:=1048576))"
$users = Get-ADUser -LDAPFilter $filter -Properties userAccountControl
Write-Host "$($users.Count) accounts found without UF_NOT_DELEGATED set"
foreach ($user in $users) {
    # do something for each user or simply log the results
}

This script searches for all accounts (user, computer, gMSA, etc.) that have unconstrained delegation (UF_TRUSTED_FOR_DELEGATION) set.

# Find all accounts that are enabled for unconstrained delegation
$filter = "(userAccountControl:1.2.840.113556.1.4.803:=524288)"
$objects = Get-ADObject -LDAPFilter $filter
$objects | select Name

To search for objects with constrained delegation, you look for non-empty msDS-AllowedToDelegateTo attributes with this query filter:

$filter = "(msDS-AllowedToDelegateTo=*)"

If you want to change the userAccountControl value of accounts that are out of compliance, there is a PowerShell commandlet for doing this.

Set-ADAccountControl

This commandlet does not require bit-set manipulation. You list the settings you want as separate command parameters. See https://technet.microsoft.com/en-us/library/ee617249.aspx. There does not appear to be a corresponding Get-ADAccountControl which I find a little strange.

Conclusion

Wow, this ended up being much longer than I expected. I hope that this information is useful and leads to less confusion over the topic of Kerberos delegation.

Addenda

Additional resources:

The above post updated on 2016/11/16 and 2019/07/10 to clarify several points.

  1. I’ve seen references to doing constrained delegation across a domain trust using versions of Windows Server prior to 2012. However, I’ve not found a definitive explanation of how this would work. At the very least it would require an up-level trust that supports Kerberos and all of the related configuration to enable Kerberos referrals to work properly. The second addendum-linked article, which is for pre-Server 2012, says “Constrained delegation is the only delegation mode supported with protocol transition and only works in the boundary of a domain.” Jorge de Almeida Pinto has an excellent blog post with visualizations of the different permutations of KCD and domain topologies: https://jorgequestforknowledge.wordpress.com/2015/11/08/kerberos-constrained-delegation-kcd-visualized-the-easy-way/

3 thoughts on “Kerberos Delegation in Active Directory

  1. SDL

    Great article that condenses a lot of useful information. One important correction though:

    The UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION flag in the userAccountControl attribute does *not* enable constrained delegation as the article indicates. Only a populated msDS-AllowedToDelegateTo attribute is required for that. What that flag does is enable protocol transition, so that a front-end service which was authenticated to by a user account using NTLM can in turn request a Kerberos ticket for that user account to perform delegation to a back-end service as listed in msDS-AllowedToDelegateTo. If not enabled (the default) then constrained delegation only works when the users authenticating to the front-end service do so with Kerberos authentication.

    In the ADUC UI on the delegation tab this is the difference between setting:
    – Use Kerberos only (flag not set)
    – Use any authentication protocol (flag set)

    Reply
    1. Eric Post author

      Thanks Samuel, this is really good info and makes sense. I was wondering what those two radio buttons did. I wrote this article because the documentation on Kerberos delegation is so spotty and I appreciate the help in getting it right.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.