Forum Discussion
Microsoft Sentinel - Alert suppression
Hello Tech Community,
Working with Microsoft Sentinel, sometimes, we have to suppress alerts based on information about UPN, IP, hostname, and other.
Let's imagine we need to suppress 20 combinations of UPN, IP hostname. Sometimes, sometimes, the suppressions fields should be empty or should be wildcarded (meaning it can be any value in the log that should be suppressed).
What is the best way to suppress alerts?
- Automation rules - seems not flexible and works only with entities.
- Watchlist with "join" or "where" operator - good option, but doesn't support * (wildcard)
- Hardcoded in KQL - not flexible, especially when you have SDLC processes
Please, your ideas and advice.
2 Replies
- Surya_NarayanaIron Contributor
Suppressing alerts in Microsoft Sentinel efficiently and flexibly—especially when dealing with combinations of UPNs, IPs, hostnames, and wildcard logic—is a common but tricky challenge due to limitations in wildcards, dynamic matching, and maintainability.
Here’s a breakdown of the most practical approaches—their pros, cons, and a recommended hybrid strategy.
Best Practice Recommendation (Hybrid Model)
Use a structured Watchlist with parameterized KQL filtering, combined with smart matching (regex or dynamic logic).
Step-by-Step Approach
1.Use a Sentinel Watchlist with Structured Schema
Example schema:
json
CopyEdit
[
{ "UPN": "email address removed for privacy reasons", "IP": "10.10.1.1", "Hostname": "host01" },
{ "UPN": "*", "IP": "10.10.1.1", "Hostname": "*" },
{ "UPN": "email address removed for privacy reasons", "IP": "*", "Hostname": "*" }
]
Represent * explicitly as a string for wildcard logic.
2.Use KQL with Flexible Matching
Since Watchlist does not support * natively, use dynamic joins or conditionals:
kql
CopyEdit
let suppressionList =
(_GetWatchlist('SuppressedAlerts')
| project UPN, IP, Hostname);
SecurityAlert
| extend AlertUPN = tostring(parse_json(Entities)[0].UPN), // Customize based on your alert schema
AlertIP = tostring(parse_json(Entities)[0].Address),
AlertHost = tostring(parse_json(Entities)[0].HostName)
| join kind=leftouter suppressionList
on $left.AlertUPN == $right.UPN or $right.UPN == "*"
and $left.AlertIP == $right.IP or $right.IP == "*"
and $left.AlertHost == $right.Hostname or $right.Hostname == "*"
| where isnull(UPN) // Only keep alerts that did not match suppression
You can customize this logic further to handle partial wildcards (e.g., regex match).
3.Advanced Matching with Regex (Optional)
If you want partial wildcards (e.g., domain match, subnet IP), preprocess Watchlist into a dynamic table with parse_json() and do:
kql
CopyEdit
| where AlertUPN matches regex WatchlistRegex
But note that regex matching in joins is more compute-intensive, so use with caution on large datasets.
What to Avoid
Hardcoding in KQL
- Not scalable
- Requires pipeline deployment to update
- Breaks SDLC separation
Automation Rules Alone
- Great for entity-level logic (e.g., user, host), but lacks fine-grained matching across multiple fields or wildcarding.
- AndrewBlumhardt
Microsoft
Consider that Sentinel analytic rules and XDR rules will eventually merge. Consider using allow indicators in XDR, especially where MDE is the source.
I think you will find most of your alerts are origination from detection logic in other solutions like MDE, MDI, etc. These solutions often have unique entity and alert suppression options. MDI for example has an entity filter for each rule.
For Sentinal native alerts, maybe a combination of watchlist and KQL filter. Revise the alert rule KQL with an allow list stored in a watchlist. That will make the list easier to manage and automate. I also recommend evaluating the noisy rules for validity. The first party tools like MDE, MDI, MDO, need very little add-on logic. I find that custom rules and many of the rules included with data connectors can introduce redundant, unnecessary, and noisy alerts when added to 1st party solutions. If the rules are noisy and hard to tune, check the source.