Use this function and logic app, to block abusive IP addresses using a custom rule, that hit a certain block limit on Azure WAF / Frontdoor. Leveraging Log Analytics Alerts.

In a previous blog I published details on how to block IP addresses from Sentinel. I recently found out Sentinel has a limit of max 10 entities, making it less suitable for sites with more traffic and frequent attacks.

For this reason, I’ve modified the script to block IP addresses straight from Log Analytics. Below step by step on how to set this up!

Azure AD App Registration
Create an App Registration in Azure AD. This will allow you to create a secret that you can use to authenticate your function app. Make sure to save the tenant ID, application ID, and secret for later use.

Set Access Rights on WAF Policy
Assign the App Registration you created in the previous step, owner rights on the WAF Policy that you want to update. This will give the function app the necessary permissions to modify the policy.

Azure Function App

Create a new .NET Function App.

Grab the code published on github, and Update the code in the cs file with your specific values. This will include the tenant ID, application ID and secret.


Create a new function, with an HTTP trigger, and name the function “BlockWAFIPLogAnalytics”, set Authorization level to “Anonymous.

If you use Visual Studio you can use that to push the app, if not, select “Develop in portal”.

Click on “Code + Test” & paste the code edited earlier as shown below.

public static string secret = "";
public static string appid = "";
public static string tenantid = "";
public static string azureid = "Azure Subscription ID";
public static string resgrp = "ResourceGroup";
public static string wafpolicyname = "WAFPolicyName";

Hit Save, go back to Overview, and copy the Function URL for later use.

Storage Account

In Azure, Create an Storage Account and a (default) table, that we will use to store the entities to be blocked in the WAF policies.

Logic App

In order to get the entities from Log Analytics Alerts to the tables in the storage accounts, and finally to the Function App, we need an Azure Logic App. Create a new Logic App with HTTP trigger.

Paste this json as the Body JSON Schema: LogicAppTrigger.json

Copy the HTTP POST URL, we need this later for Alerting.

The next part is somewhat difficult to recreate, and you’ll need to setup an connection to the Storage Account created earlier.

And finally, we add an delay, get all the entities currently in the storage account, and send it all over to the function app URL to update the WAF Policy.

Log Analytics

Create an new Alert rule in Azure Monitor Monitor – Microsoft Azure.

  • Paste the search query below
  • Dimension name = ClientIP
  • Threshold value = greater than 0
  • 5 minutes evaluation
  • Toggle advanced options & set time query range to 1 day (or longer/shorter, depending on how long you want to block ip addresses)
| where ResourceProvider == "MICROSOFT.CDN"
and Category == "FrontDoorWebApplicationFirewallLog"
and action_s == "Block"
| summarize RequestCount = count() by ClientIP = clientIP_s, UserAgent = userAgent_s, Resource
| where RequestCount > 500
| order by RequestCount desc

On the “Notifications” tab, you can optionally set an email notification to inform recipients about alerts fired and resolved.

On the “Action” tab, add an Webhook action, and paste the URL from the Logic App, and Enable the common alert schema.

And finally, set the Severity level, and toggle Automatically resolve alerts if you wish to automatically remove the IP addresses after 1 day.

WAF Policy
The last peace of the puzzle! To complete the setup, you will need to add a custom rule “BlockedIPs” to the WAF Policy. This rule will be used to block the IP addresses identified by the Azure Sentinel analytic rule. Set it to Match type IP address & Does contain + a bogus IP address.

The function app will receive the IP addresses from the logic app received by the Log Analytics Alert. Any values in this rule will be overwritten with values received.

Below a example of requests that are blocked that would not have been blocked by any other rule.

Test with Postman

You can use Postman to send json sample data to test the functionality.

Post to Logic App URL:

    "searchQuery": "AzureDiagnostics\n| where ResourceProvider == \"MICROSOFT.CDN\"\n    and Category == \"FrontDoorWebApplicationFirewallLog\"\n    and action_s == \"Block\"\n| summarize RequestCount = count() by ClientIP = clientIP_s, UserAgent = userAgent_s, Resource\n| where RequestCount > 500\n| order by RequestCount desc\n\n",
    "metricMeasureColumn": null,
    "targetResourceTypes": null,
    "operator": "GreaterThan",
    "threshold": "0",
    "timeAggregation": "Count",
    "dimensions": [
        "name": "ClientIP",
        "value": ""
    "metricValue": 1,
    "failingPeriods": {
      "numberOfEvaluationPeriods": 1,
      "minFailingPeriodsToAlert": 1
    "linkToSearchResultsUI": "",
    "linkToFilteredSearchResultsUI": "Z",
    "linkToSearchResultsAPI": "",
    "linkToFilteredSearchResultsAPI": ""

Post to Function App URL:

  "odata.metadata": "$metadata#WAFBlockIPS",
  "value": [
      "odata.etag": "W/\"datetime'2023-05-19T23%3A55%3A35.3378043Z'\"",
      "PartitionKey": "",
      "RowKey": "BLOCK",
      "Timestamp": "2023-05-19T23:55:35.3378043Z"

All done!
Keep an eye on the Azure Alerts, and optionally set an email notification. You’re just greatly improved the security for you web apps!


No responses yet

Leave a Reply

Your email address will not be published. Required fields are marked *