Tags in Microsoft Defender ATP is an extremely powerful tool to identify certain high value machines, group devices into machine groups, or for reporting through the API/PowerBI.
Tags in Microsoft Defender ATP is an extremely powerful tool to identify certain high value machines, group devices into machine groups, or for reporting through the API/PowerBI.
There are three ways to assign tags to a machine:
- Manually through the portal
- By setting a registry key
- Through the API
Most of the time, tagging machines manually isn’t a viable solution as this is a time intensive and error prone workflow. Setting it through a registry key is a good solution, but requires that your AD/SCCM structure can accommodate the (structure of the) tags you desire to use.
If you want to assign tags under specific advanced conditions, using the API is a good idea. The Microsoft Defender ATP API provides a wide variety of functions and almost all actions from the portal are also accessible through the API. Adding and removing tags can be done with one query which makes the process fast and convenient. The portal includes an API explorer which allows to easily test commands.
During a previous project, we had the requirement to assign tags according to the department of the user. The department could be identified in two different ways:
- The first three letters of the device name (which matches a specific department)
- If there is no match with the device name, the value should be retrieved through the current logged on user
For this specific use case, we built a custom solution that uses Azure Logic Apps. As a general rule, we always try to leverage Logic Apps instead of Power Automate for a couple of reason:
- Flows are bound to a user and can’t be shared easily
- Logic Apps can be monitored through Log Analytics
- Logic Apps can be managed through Azure ARM (like deployment through an ARM template, IAM, etc.)
This entire solution could be built in a serverless solution like Azure Functions, which would result in better performance. But as this solution will be maintained by SecOps, Logic Apps provided a simple programming interface and makes troubleshooting easier.
Overview.
The solution uses a few different components:
- Log Analytics to log all the actions for historical purposes
- A SharePoint list which contains a translation table to check which device name corresponds to which department
- An app registration with the permissions in both SharePoint and Microsoft Defender ATP
The complete Logic App looks like the image below, and is actually pretty complex:
The Logic App consists of the following steps:
- Retrieve all machine without the specific tag
- Check if the machine name corresponds to a department. This is checked through the first three letters of the device name, the translation table is hosted as a SharePoint list.
- If yes:
- Assign the right tag
- If no:
- Get the last logged on user of a device
- If a user is found:
- Check the user for the department value
- If the value is found:
- Assign the right tag
- If the user doesn’t have a department value
- Don’t assign a tag
- If the value is found:
- Check the user for the department value
- If no user is found:
- Don’t assign a tag
- If yes:
Deployment.
Solutions like this are mostly customer-specific and no two customer will run the same thing. This blog post is primarily meant to give you a good indication on how a solution like this is built.
The entire Logic app has been exported to an ARM template and can be found on Github.
The template can also be deployed to Azure directly with the following button:
Deployment requires a few parameters to be configured:
- PlaybookName – The name that the Logic App will receive
- WorkspaceID – ID of the Log Analytics workspace
- WorkspaceKey – Key of the Log Analytics workspace
- Username – Name of the user who is deploying the solution (used to identify the API connection)
- Attribute – Configure which extensionAttribute holds the department information
- ClientID – Application ID of the app registration
- Client Secret – Secret of the app registration
- Tenant ID
- Frequency – how much the app should run (week/day/month…)
- Interval – At what interval the app should run
- LibraryID – ID of the SharePoint library where the list resides
- ListID – ID of the SharePoint list which holds the translation table
Preparation.
In order to get this all up and running, a few preparations need to be made.
Create an app registration.
You might have noticed that I am not using the default Logic Apps connectors for all my SharePoint and MDATP actions. Although they are much easier to use, the downside is that you cannot use a service principal to authenticate to all the services. In a production scenario, it’s advised to use service principals as much as possible, as these make sure that a solution like this is not bound to a single identity (user account).
For starters, create a new app registration and configure the following permissions:
- WindowsDefenderATP – AdvancedQuery.Read.All
- WindowsDefenderATP – Machine.ReadWrite.All
- Microsoft Graph – Sites.Read.All
Create a new application secret and save it together with the application and tenant ID as we will need these later.
Configure Log Analytics.
Log Analytics is used to log all the actions that have been taken by this solution. This way, you can easily track when a certain tag has been added and for what reason. If you’d like, you can reuse an existing workspace for this; just copy the Workspace ID and key from the advanced settings of the workspace. You will need this when you deploy the solution.
Configure SharePoint.
In SharePoint, a list should be available to hold the translation table which will match computer names to department values.
First, create a new list in SharePoint.
The table needs two columns at a minimum. However, extra columns can be configured for your convenience.
The first column can be renamed to your liking and should contain the prefix of a computer name. The second column, named BA, contains the department value.
To find the library and list ID, you will need to use the Graph API.
Navigate to the Graph Explorer and execute a GET request to the following URL:
https://graph.microsoft.com/v1.0/sites/.sharepoint.com:/sites/testthle
Here, you could replace with the correct name of your tenant and testthle with the site where you created the list.
This will return the ID of the library that you can use when deploying the ARM template.
To get the List ID, navigate to the List and select ‘List settings’.
The listID can be found in the URL (highlighted in bold).
https://.sharepoint.com/sites/TestTHLE/_layouts/15/listedit.aspx?List=%7Bdcdba47f-024d-4fec-a6de-4789b6c6f5f1%7D
Details.
Going over all the bits of this solution would result in a 10-page blogpost, but I want to highlight some important steps of this process.
The best way to learn something like this, is to deploy the solution to your own tenant and dissect every step.
Querying machines.
The MDATP API supports OData filters, just like most of the other Graph API endpoints. This enables us to filter on certain conditions.
The filters helps to avoid having too much information in our Logic App, which would mean the execution of this solution would take far too long. As a general rule, I also recommend using server side filtering above filtering inside your Logic App. Logic Apps tend to struggle when you have a lot of for each loop executions, or nested statements.
An important note is that all MDATP properties support the filter parameter, a full list can be found in the docs.
In the first step of the workflow, we need to query all machines without a department tag and that are not in the servers machine group. Here, all department tags were prepended with ‘BA’.
The full query for this is as follows:
https://api.securitycenter.windows.com/api/machines?$filter=(machineTags/any(tag:startswith(tag,'BA'))+eq+false)+and+RbacGroupId+ne+738
The first parts checks all tags and checks if none start with ‘BA’, the second part checks if the machine doesn’t belong to the servers machine group. If both expressions are true, then the machine is returned. This means that the first time this solution will run, it will retrieve almost all machines (provided they don’t have a tag yet). In the subsequent executions, it will only check new machines that don’t have a tag yet.
Filtering on the machine group name is not possible, so we need use the machine group ID which we want to exclude in the search. To retrieve the machine group ID, get a machine ID of a device belonging to that group and execute a GET request through the API explorer. This will return the rbacGroupID which can be used in the filter.
Using expressions.
While writing these kind of more advanced Logic Apps, you will have to master expressions as they allow for some advanced operations. A general overview of expressions (which is actually pretty solid) can be found on the docs.
This is an example of the query used to retrieve the correct values from SharePoint:
https://graph.microsoft.com/beta/sites/thecollectiveonlinetest.sharepoint.com,56d71e6c-b2cc-44e2-ad7d-6d8618653b3b,6d422168-fe4e-4db8-9f78-f2b97508b795/lists/75b78907-217a-4c13-b89b-056aa5a12766/items?$expand=fields&$filter=fields/Title+eq+'@{substring(string(items('Loop_MachinesWithoutTag')?['computerDnsName']),0,3)}'
The expression (@{substring(string(items(‘Loop_MachinesWithoutTag’)?[‘computerDnsName’]),0,3)}) does the following:
- Retrieve the computerDnsName of the computer that is currently evaluated in the for each loop (items(‘Loop_MachinesWithoutTag’)?[‘computerDnsName’]))
- Convert this value to a string – string()
- Take the first three letters of the string using the substring() function
Sending logging data to Log Analytics.
Sending data to Log Analytics can be done using the ‘Send data’ action in Logic Apps. The only tricky part is that this action requires a JSON input object.
This is why every ‘Send data’ step is prepended with a ‘Compose’ step. This step makes it really easy to convert a string to a correctly-formatted JSON object.
Note that the ‘User’ property is formed using an expressions which concatenates the domainname and SAMaccountname.
concat(first(body('Parse_LoggedOnUser_MachineMDATP')?['Results'])?['AccountDomain'],'\',first(body('Parse_LoggedOnUser_MachineMDATP')?['Results'])?['AccountName'])
Naming convention.
Logic Apps don’t support renaming steps from the GUI itself (which Power Automate does). It’s recommended to rename the actions inside your workflow, as this improves the readability of the entire solution. If you have clearly named steps, troubleshooting a workflow will be really easy; even if you haven’t touched it in a few months…
Although renaming isn’t possible through the GUI, you can always switch over to the code view and manually change the name of the different steps there.
Note: Do not forget to change the name in all the dependent actions as well, otherwise your Logic App will fail to save!
Wrapping up.
The purpose of this blog was to give you some insights on what you can accomplish with the Microsoft Defender API and Logic Apps.
The answer? The sky is the limit!
As this API is so versatile it’s possible to automate a lot of mundane tasks in MDATP.
Interested in a custom solution like this or want to get to know us? Feel free to contact us through the website and we are happy to get in touch!