Category Archives: Authorization

Safely Storing Azure App Connection Secrets

Microsoft’s Azure AD surfaces a wide variety of capabilities that can be accessed programmatically via RESTful web APIs. The Azure Graph and its successor the Microsoft Graph are two of the more comprehensive APIs that enable the manipulation of most AAD objects. Using these APIs requires obtaining an OAuth access token to send with API requests. AAD uses two object types to provide the mechanism for obtaining OAuth tokens: Applications and Service Principals. An Application object can span multiple AAD tenants whereas the Service Principal is the tenant-specific representation of the application.

To obtain an OAuth access token, one must call the Microsoft authorization server endpoint to request it. This call must be authenticated by providing the Application’s client ID and client secret. These two values are the app’s credentials and must be protected as you would protect any other privileged credentials. This becomes a problem if you have automated tasks that need to connect to Azure. How can these credentials be safely stored?

The naive programmer would just embed these values into the task’s code. This is especially egregious if the code is checked into a source library because then the secrets will be in the change history even if they are later removed from the code. The first refinement is to put the secrets into a task configuration file. That’s fine as long as the configuration file is never checked into the source library or otherwise stored in an insecure fashion.

It turns out there is a much better solution. X509 certificates are designed to store secret keys and can be used for AAD OAuth token requests. The first step, after a suitable certificate is created1, is to add the certificate as an app access key2 using either the Azure Portal GUI4 or PowerShell. Then you need to install the cert, with private key, into the cert store of the server on which the task will run. Make certain to grant private key access to the service account being used to run the task. Refer to the article in the second footnote for an example of using this technique in C# code.

Using Certificate-based Authentication From PowerShell

The AzureAD PowerShell module wraps the functionality of the MS Graph. A connection to Azure must be made before any of the AzureAD commandlets can be called. The Connect-AzureAD3 commandlet is used to do this. In reality, what it is doing is obtaining and storing an OAuth access token in the PS session. I use the following bit of code to do this:

Import-Module AzureAD
# Check if there is a connection to AAD. If this call throws, then make the connection.
try {
    Get-AzureADCurrentSessionInfo | Out-Null
}
catch {
    # Use cert-based auth via the AAD app. Ensure that the
    # task context account has access to the cert private key.
    Write-Output "Connecting to AAD"
    $tenantId = ''
    $appId = ''
    $certThumbprint = ''
    Connect-AzureAD -TenantId $tenantId -ApplicationId $appId -CertificateThumbprint $certThumbprint
}

First this code tries to make an AAD call (Get-AzureADCurrentSessionInfo). That call will fail and throw an exception if there is no valid OAuth token. If that is the case, then the code in the catch block will make the connection and obtain the token using the certificate. Note that you will need to fill in the missing tenantId, appId, and certThumbprint values.

The try/catch setup allows you to run this code multiple times in the same PS session such that it will only attempt to make a connection if there isn’t a valid token.

Unfortunately there are still many functions related to Exchange Online and other Office 365 apps that are not currently manageable by the AzureAD module. For these operations one must revert to the older MSOnline PS module. It employs the Connect-MsolService commandlet to make the connection to Azure but it does not support using certificates to store an app secret.

Using a certificate as the Azure app secret store has many advantages. It provides multiple levels of security. The private key is stored only on the server running the tasks. The private key is protected by ACLs that only grant access to the accounts that are configured to have access. I recommend storing the certificate with the private key set as exportable but protected by a password. That way you can move the tasks and the cert to another server if needed. If you are truly paranoid you can skip this step since it is pretty easy to repeat the steps of creating a self-signed cert and adding it as a secret key to the Application object.

Footnotes

  1. A self-signed certificate is fine for this use. Creating a self-signed cert is pretty straightforward. This article explains one way to do this: https://blogs.msdn.microsoft.com/davidhardin/2013/08/27/azure-management-certificate-public-key-private-key/
  2. This article uses a sample daemon app to describes using a certificate for API access and goes into the details of every step: https://azure.microsoft.com/en-us/resources/samples/active-directory-dotnet-daemon-certificate-credential/
  3. The MS docs for the Connect-AzureAD commandlet also show how to do this from PowerShell although I wasn’t able to get every step of the sample to work as expected. https://docs.microsoft.com/en-us/powershell/module/azuread/connect-azuread?view=azureadps-2.0
  4. The Azure Portal GUI for setting a certificate as an Application secret Key:

    Note the “Upload Public Key” button that enables selecting a cert file that contains the public key.

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. 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).

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 must be set to enable constrained delegation. It is set automatically when you add delegation through the Delegation UI.

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 must ensure that the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit is set on userAccountControl.

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:

  • Microsoft’s overview of the new Server 2012 delegation features: https://technet.microsoft.com/en-us/library/jj553400(v=ws.11).aspx
  • A deep dive into the details of Kerberos: https://technet.microsoft.com/en-us/library/4a1daa3e-b45c-44ea-a0b6-fe8910f92f28

The above post updated on 2016/11/16 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.”

UW Group Sync Code Now On BitBucket

Yesterday I placed the UW Windows Infrastructure (UWWI) AD group synchronization source code into a publicly accessible repository on BitBucket.org. This code has been made available for perusal and reuse by the UW via an Apache 2.0 license. You can find it at https://bitbucket.org/uwitiam/group-sync.

The UW Groups Service places all change events on an Amazon SNS topic. The UWWI Group Sync agent reads an Amazon SQS queue that is attached to this topic. I gave a presentation on this event-driven architecture for distributing group changes at last year’s InCommon Identity Week conference. You can find that presentation here.

The UWWI Group Sync Agent updates the UWWI Active Directory based on these group change events. This is an extremely complex task that requires a detailed knowledge of AD. For example, making rapid successive changes to an AD object can be problematic if you don’t make all of the reads and writes to the same domain controller. AD uses a replication methodology known as “eventual consistency” which means that simultaneous reads from multiple DCs may not yield the same results. The solution to this issue is to use DC affinity; always bind to the same DC when making multiple reads and writes.

Another point of complexity is due to the changes that were made to the UWWI AD to give FERPA compliance. FERPA is a Federal statute that requires that student data be kept confidential. Active Directory was designed for a corporate environment where ease of access would grease the skids of commerce. IOW, any authenticated user can read a wide set of properties on any other object including group memberships. Unfortunately this design assumption leads to a violation of FERPA where the names, classes and other student details could be readable by any AD user. Brian Arkills, the UWWI Service Manager, designed a set of changes to AD to remove this default behavior. You can read about these changes here. Thus the Group Sync agent must ascertain the type of group, public or restricted, and set the appropriate ACLs.

UW Groups can be set to be Exchange-enabled. That is, they can act as both security groups to gate access to resource and they can be email distribution groups. The act of Exchange-enabling a group is a multi-step process. The first step is choosing to Exchange-enable a group in the UW Groups Service. One important part of this step is deciding on the email address for the group. The Groups Service validates that the chosen address is valid and unique. The Group Sync Agent then takes this info from the Groups Service change event message and creates or modifies the AD group, adding all of the attributes required for Exchange-enabling a group.

You can see more on the Group Sync Agent here.