Azure Alerts -> Secure Webhook -> Azure Functions with Authentication

superjohn140

John Friesen

Posted on November 14, 2020

Azure Alerts -> Secure Webhook -> Azure Functions with Authentication

Azure Alerts -> Secure Webhook -> Az Functions with Auth

I have been trying to implement Security in Azure Functions a lot recently and in the past but unfortunately, I can never accomplish it based on Microsoft documentation alone.

So, I am creating this article to help anyone trying to do the same with a nice rundown of how to set up a secure webhook between Azure Monitoring Alerts and an Azure Function HTTP endpoint.

1. Create an Azure function in your Subscription. I am calling my functions Alert-Action-Function. Any plan should work to accomplish this as we will only be creating 1 HTTP trigger function and enabling Authentication/Authorization

  • Run time .NET Core 3.1
  • Consumptions plan
  • Windows OS

2. Enable function Authentication/Authorization

  1. Open your function resource and go to the section Settings and open Authentication/Authorization. Than turn App Service Authentication to On

    Enable function Authentication/Authorization

  2. Set Action to take when the request is not authenticated to Log in with Azure Active Directory

    App Service Athentication config Part 1

  3. Under Authentication Providers click the Azure Active Directory Not Configured

    App Service Athentication config Part 2

  4. Under Management Mode select Express. Notice the Create App field, this will provide you with an auto-generated App Registry name (I will be adding “AD-App” on the end to make it more clear).

    Active Directory App Authentication config

  5. Now click ok and save. Now we have enabled the Authentication part of our function

3. Add a HTTP Trigger function

... to do tests on your setup. I like to write to blob storage so I can view the request body if needed, also b/c you can use this to see if the request is finished in real-time.

Why I do this: Azure Monitoring with Application Insights and diagnostic settings setup properly will take around 5 mins to let you see logs and around 2 mins for metrics... and that is on a good day for Azure.

GitHub repo page for this code here

    using System;
    using System.IO;
    using System.Threading.Tasks;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Azure.WebJobs;
    using Microsoft.Azure.WebJobs.Extensions.Http;
    using Microsoft.Azure.WebJobs.Extensions.Storage;
    using Microsoft.AspNetCore.Http;
    using Microsoft.Extensions.Logging;
    using Microsoft.Azure.Storage.Blob;
    /*
    ************************************************
    NOTE:
        make sure you have your AzureWebJobsStorage Environmental Variable is set when trying to run
        AND
        make sure you add this package

        dotnet add package Microsoft.Azure.WebJobs.Extensions.Storage

    ************************************************
    */

    namespace Company.Function
    {
        public static class HttpTrigger_test_blob_store
        {
            [FunctionName("HttpTrigger_test_blob_store")]
            public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
                [Blob("blobverifycontainer")] CloudBlobContainer outputContainer,
                ILogger log)
            {
                log.LogInformation("C# HTTP trigger function processed a request.");

                string requestBody = await new StreamReader(req.Body).ReadToEndAsync();

                /// write to the blob storage
                await outputContainer.CreateIfNotExistsAsync();
                var blobName = Guid.NewGuid().ToString();
                var cloudBlockBlob = outputContainer.GetBlockBlobReference(blobName);
                await cloudBlockBlob.UploadTextAsync(requestBody);

                // return blob name for easy lookup
                return new OkObjectResult(blobName);
            }
        }
    }
Enter fullscreen mode Exit fullscreen mode

4. Configure your AD App registration.

  1. In Azure Active Directory -> App registrations find and open the name from step 2.4 (the express auto-generated name if you didn’t change it)

    Azure AD App Registration

  2. Maker sure to add yourself as the Owner

    Ensure Azure AD Service principle Ownership

  3. Now go to Manifest and you will be adding to the App Roles array in the JSON editor

    Azure Sercive Principle Manifest Edit

  4. Replace with provided JSON.

    "appRoles": [
        {
            "allowedMemberTypes": [
                "Application"
            ],
            "description": "This is a role for Action Groups to join",
            "displayName": "ActionGroupsSecureWebhook",
            "id": "e14442ab-8bd5-47be-90af-695c413d9761 REPLACE WITH NEW GUID",
            "isEnabled": true,
            "lang": null,
            "origin": "Application",
            "value": "ServiceClient"
        }
    ],
    

    BUT make sure to replace the id with a new GUID. If you don’t you will get this error!

alt_text

Things to Note!!!

  • don’t worry about the tab formatting, after save and you come back it will be done for you. Just make sure your JSON is valid)
  • IMPORTANT: if you mess up the **appRoles and try to edit it later you may need to first set IsEnabled to “false”, save and then make your changes. This is something I found out the hard way.**

5. ALSO, ensure this (Integrity Check)

Make sure that the Application ID URL has been assigned to the base URL of your Azure Function.

If it has not this will an error when linking this AD App Registration to the Secure Webhook (you will get an azure notification that doesn’t give you a useful message and just says “undefined” error. (I was only able to see the real error was when I when into chrome devtools to investigate the corresponding Network call.)

Azure App Service Integrity Check

6. Create Azure Function to Alert on

  • I created a little NoiseMaker project to be an easy way to test Azure Monitor Alerts in general.
  • Link this to Application Insights. I named mine NoiseMaker as well.
  • If nothing is passed to the query string it will return a 418 (“I’m a teapot”. Look it up, it’s real)
  • Github code is here
using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;

namespace Company.Function
{
    public static class HTTP_Noise_Maker
    {
        [FunctionName("HTTP_Noise_Maker")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function *NoiseMaker* processed a request.");

            string pass = req.Query["pass"];
            string notfound = req.Query["notfound"];

            if (pass == "true")
            {
                var result = new ObjectResult("I'M OK 😁");
                result.StatusCode = StatusCodes.Status200OK;
                return result;
            }
            else if (notfound == "true")
            {
                var result = new ObjectResult("I'M NOT FOUND 😲");
                result.StatusCode = StatusCodes.Status404NotFound;
                return result;
            }
            else
            {
                var result = new ObjectResult("I'M A TEA POT 🍵");
                result.StatusCode = StatusCodes.Status418ImATeapot;
                return result;
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

7. Create your alert

Go to Azure Monitor

Create new Alert Rule

Select Resource. I am using the NoiseMaker

alt_text

Select the Condition. Server Requests are what we want to catch when a 418 happens. (You can do the same for other HTTP response codes as well)

alt_text

Then...

alt_text

Now Create the Action Group

alt_text

Give it a name and add the Secure Webhook Action and Create

alt_text

Now just finish the Alert Creation form with a Name, Description, Severity and make sure Enabled is checked. Should look like this.

alt_text

8. Finally, test it

Trigger the NoiseMaker API endpoint a couple of times (either with a browser or Postman), wait a couple of minutes for the alert to show up on the Monitoring Alert page. Then go to the Storage Account linked to your “Alert-Action-Function” you created before and you should see a new blob in “blobverifycontainer” Container.

Let me know this tutorial worked out for you in the comments below. This is my first Dev.to article and I hope it helps but If improvements need to be made (or I just used too many pictures haha) let me know.

Happy Monitoring

💖 💪 🙅 🚩
superjohn140
John Friesen

Posted on November 14, 2020

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related