DEV Community

Cover image for Azure Alerts -> Secure Webhook -> Azure Functions with Authentication
John Friesen
John Friesen

Posted on

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

Top comments (7)

Collapse
 
elyonsnic profile image
ElyonsNIC

Great post, very detailed. I have just 1 quick question. What do you have the "User assignment required" option set to, Yes or No for the Alert_Action_Function-AD-App? I'm having a problem with my setup when the "User assignment required" is set to yes.

Collapse
 
superjohn140 profile image
John Friesen

sorry, i don't quite understand the context of the question. can you give me more detail as to what you are referring to?

Collapse
 
superjohn140 profile image
John Friesen

nvm got it. Mine if set to No.
I didn't set this myself thought.

i don't know precisely what this does but from what I gather from its tooltip it is for allowing access to this service principle to others in your Azure subscription. I think if you changed this to yes only the owner(s) will be able to see it. (i am referring to inside App registration under the All Applications and Owned Application tabs). so i would assume if you created and enabled this feature your co-worker would not be able to find it under the All Application tab.
I would recommend reading the tooltip bc this is my interpretation of it without testing it.

Thread Thread
 
elyonsnic profile image
ElyonsNIC

Thank you for looking at this. I have a user assigned in the Users and groups with Default Access but the webhook Active Directory authentication will not work. Not sure if I need a different role or permissions.

Thread Thread
 
superjohn140 profile image
John Friesen

Are you trying to allow someone else access to your service principal? I'm not sure how users and groups relates to this? More context?

If this is what you are trying to do and you allowed to have this access being a a Contributor on the subscription should be more then enough (not fine tuned authorization I know but this is an option).

Thread Thread
 
elyonsnic profile image
ElyonsNIC

I'm trying to do basically what your blog post is doing. I have a Azure function with an endpoint that I need an Azure App Configuration Event to call when an update happens to a configuration key. The event webhook needs to be set up for AAD authentication. This all works except when I turn that "user Assigned Required" option on.

Collapse
 
steasy profile image
steasy

Set "accessTokenAcceptedVersion": null, in the manifest of your app registration to "accessTokenAcceptedVersion": 2,

after that it worked for me. took me a long time to find out.

Its documented in Azure learn:
learn.microsoft.com/en-us/azure/az...