I’ve decided to do this blog post after finding several accounts configured with Unconstrained Delegation in Active Directory. If you want to find accounts in your environment, I can recommend using PingCastle. Microsoft have also done a PowerShell script (TechNet Gallery) which will give you a list of your accounts to target. This post won’t go in to detail about how Kerberos works (it’s a topic in itself that I might cover at a later date).
There are lots of posts saying ‘remove Unconstrained Delegation’, but what if your environment has been up and running since Windows 2000 days? You weren’t there at the start so didn’t do it right. The people who set everything up are long gone. You want to remove delegation but don’t know if it’s being used. So, I set about trying to establish if the accounts configured for unconstrained delegation are actually using Kerberos delegation so that I can constrain them, or remove the delegation permission.
What is Kerberos Delegation?
Kerberos Delegation is a feature that allows an application to impersonate a user. For example, you have a Web Application that connects to a SQL database. Kerberos Delegation can be configured on the application to connect to the database as the accessing user.
What is Unconstrained Delegation?
Unconstrained Delegation (introduced with Server 2000) means that the Web Application can impersonate a user against ANY service within the domain. This could include the domain controllers as domain admins.
What is Constrained Delegation
Constrained Delegation (introduced with Server 2003) means that the Web Application can only impersonate a user against SPECIFIC services within the domain (i.e. only the MSSQL database).
What is Resource-based Constrained Delegation
Resource-based Constrained Delegation (introduced with Server 2012) would be set on the SQL Server to ONLY allow delegation from the Web Application (preventing a fake web app being setup and impersonating users to access the database).
How do we kill it?
In a production environment, you want to remove the unconstrained delegation but being operation focused, you don’t want to impact service. All of the following work will be carried out within Azure Log Analytics/Azure Sentinel as this is my correlation point.
To start with, we are going to look for Event ID 4769. This Event ID is generated every time a Kereberos Service ticket is requested, whether successful or not.
| where EventID == 4769
| parse EventData with * '"TransmittedServices">' TransmittedServices "<" * | parse EventData with * '"ServiceName">' ServiceName "<" *
| project TransmittedServices, ServiceName
| where TransmittedServices != "-"
| summarize count() by TransmittedServices, ServiceName
This query gives you a count of the number of delegation requests per service, along with which service they were delegating to. The ‘TransmittedServices’ column relates to the account doing the delegation. This should be your web server using the example above. Or if you use Azure AD App Proxy with Constrained Delegation, you will see these listed here. The ‘TransmittedServices’ in the XML contents of the event log translates to the ‘Transited Services’ attribute when you view in Event Viewer. The ServiceName column relates to the service that is being contacted. This should be your SQL Server Service using the example of the web app to SQL.
If you’ve got a whole heap of SPNs, for example the SQL Server Account is used on 50 different SQL Servers as a first port of call you might wish to just constrain to all the SQL SPN’s attached to the account.
In terms of tracking exactly which SPNs you need to delegate to, this is something I’ve struggled with. I’ve looked through the EventLogs, cranked auditing up to everything success and fail but been unable to find it. If you’re lucky to have EMS E5 and have deployed Azure ATP then you can look in here to get an idea of the SPNs that are being used within delegation.
Group Managed Service Accounts
When attempting to constrain delegation from a web server to a SQL Server running under a Group Managed Service Account, I discovered that you can’t. There was no way to find the account through the GUI. You might be able to do it via PowerShell, however I found that you have to use Resource Based Constrained Delegation.
$adobject = Get-ADComputer WebServer
Set-ADServiceAccount gmsa-SQL -PrincipalsAllowedToDelegateToAccount $adobject
The above should give you a starting point, you should have an idea now that unconstrained delegation is bad. Using the above method, I have a Web Server set up, using the Network Service for it’s identity, the Computer object is set to not allow delegation
There is a web app that connects to SQL Server and runs a basic query against a table. It all works fine. I can see in the event logs the delegation working as I’d expect. And when I look on SQL I can see that auth is all done via Kerberos.
As always, make sure you test your applications, as some will not work with constrained delegation. Although I don’t have a list it’s up to you to test. At least you know now how to identify the delegation. In the event something does break, you can go back to unconstrained delegation and do more digging to establish what and why it’s being used.
If you have an application that relies upon unconstrained delegation, you will need to set up an alert for when EventID 4769 occurs, where the unconstrained service talks to a service you’ve not allowed it to. In the event of this you should investigate.