This post was an idea that came about from a post on the Sentinel tech community here, from a contributor that asked how can we match a query with group membership data from Azure AD. The AuditLogs table will show changes to Azure AD groups, but that isn’t especially useful, we need to make sure our query is matched against a current list of users whenever the alert fires.

There a few ways I can think of to achieve this, but the one I like is to use a Logic App to query Azure AD every so often, then take the data and ingest it into a custom log, for this example lets use HighRiskUsers_CL as the custom log.

Let’s build our Logic App – if you want to use the Azure AD connector then you will need an account with a role to read group memberships (Global Reader would suffice), if you want to poll the MS Graph directly then you will need a Azure AD App Registration will equivalent MS Graph access ( would do it but may be too much depending on your stance).

I find with Logic Apps there are a thousand ways to do everything, for this I have just configured a test array with my known high risk AAD Group ID’s, you could obviously look up the MS Graph based on name and fill this array in dynamically of course, but for this example we will just list them. Set your recurrence to however often you want to update the table

Then we are going to use a couple of for each loops to iterate through each group and its members to build a small JSON payload to then send to Sentinel using the Azure Log Analytics Data Collector

The first time you write to a new table it can take up to 20 minutes, but once done you will see your table filled in with the data taken from Azure AD.

Now when you write your hunting queries you can join between your query and members of your groups. The custom table we have created is log data so just make sure you query it with the same time frame that it is updated on, so if you update it daily, use the last 24 hours of logs. Here you can see with a test query looking for a 50158 ResultType

let Alert=
| where UserPrincipalName contains "username"
| where ResultType == "50158"
| take 1;
let HighRiskUser=
| where TimeGenerated > ago(24h)
| extend UserPrincipalName = UserPrincipalName_s
| project TimeGenerated, UserPrincipalName, AADObjectID_g
| join kind=inner HighRiskUser on UserPrincipalName
| project TimeGenerated, ResultType, UserPrincipalName

And we see an alert for a user that was in the HighRiskUsers_CL that has been populated for us

You could also do this is via a Sentinel watchlist, but the Logic App doesn’t currently allow entries to be removed