Use your Azure Function securely

As a developer, we quickly reach for an Azure function to automate things. Azure Functions provide a powerful platform that allows us to write and run our code. It allows us to build scalable and flexible applications that can respond to events and perform tasks based on triggers. But amid this unprecedented flexibility and efficiency, we must remember that security is an essential factor when developing any application, including Azure Functions. In this blog post, we take a closer look at how to use Azure Functions securely and the best practices we should follow to protect our applications from potential threats.

When we create a new Azure function of type HttpTrigger, we see that the Run Task definition is formatted as follows:


     public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
           ...

The first parameter is the HttpTrigger attribute consisting of the following parameters:

  • AuthorizationLevel, we will discuss this in more detail in this blog post. Possible values can be:
    • Anonymous
    • User
    • Function
    • System
    • Admin
  • Then we see that the possible methods are defined for our Azure Function as a string array, namely get & post. If none are defined, the http trigger function obeys all methods
  • Followed by the Route parameter. It defines which requests the URLs respond to. If none are defined, then the name of the function is used

In addition, we have the HttpRequest parameter, which is used as an input object. For example, the body is retrieved from this when you use a post method.

Finally, we have the ILogger object, as the name suggests, this can be used to log information, but also an error.

Anonymous

Clearly, this allows the Azure function to be used by anonymous users and therefore by anyone. This is the lowest form of security, not to say that no security actually happens when the Azure function is called. This form is not recommended for use in production.


     public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
           ...

Function


     public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
           ...

When using the Function authorization level, you tell the Azure function that you want to use the host app keys defined in the Azure function. To do this, go to your Azure Function and click on App keys. Here you have a subdivision between 2 types:

  • Host keys
  • System key

For this authorization level you can use both values that are defined in the host keys subdivision, namely:

  • _master
  • Default

However, it is recommended to use the Default key here because the _master key is actually intended to be used for Azure functions with the authorization level Admin.

You can pass this key as a query parameter in the following way (replace the bold with your values):
https://AzureAppName.azurewebsites.net/api/AzureFunctionName?code=YourDefaultCode

Another way is to call your azure function url without query parameters and pass the default code with the header parameter x-functions-key

Admin


     public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Admin, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
           ...

This authorization level is the same as the Function key, but then intended to protect certain Azure functions that require more rights. For example, it is only possible to call an azure function with this authorization level with the host _master key. By passing it either as a query parameter or as a header parameter.

Is using the Admin or Function authorization level a safe way to secure your Azure function? Well not quite, it does help to secure your azure function so that it can only be called by people who have the relevant key. But once you use this in a client in production, your key can be intercepted. Both the _master and the Default key can be renewed in case of a security breach, but then this new key must also be updated in every client where the azure function is used

System

The System authorization level is used for Azure Function Extensions. You cannot create or renew this key yourself, and can only be created by the relevant Azure function extension

User

From what I understand, it was originally created to use EasyAuth but this enum parameter is a legacy unused parameter at the moment. The latest info I can find about this can be found in the comment on this issue

This is currently not used, but there is the option to secure your Azure function based on user authentication, more about this in the next heading:

Use Azure Function with Entra ID

You can secure your Azure function based on your AAD, you can do this by adding an Identity Provider in your Azure function. For this example we configure the identity provider with Mircosoft Entra ID, but you can also use others such as Apple, Facebook, Github, Google, Twitter or OpenID Connect.

First, click on the Authentication section in your Azure Function

Next click on Add identity provider

And on the next screen you can select your Identity Provider. Here we choose for the Microsoft Entra identities

Next we can see the configuration settings for the selected identity provider. Note that the identity provider uses an Entra App Registration from which the authentication will take place. Here we choose to create a new app registration.

Click on Next:Permissions > and see the permissions needed for the AAD App registration. You can add permissions if needed, but for the basics, the Graph User.Read permissions are enough, so i leave this untouched.

finally, you must give your azure function the authentication level Anonymous. The authentication is done by your identity provider that you have just configured. This works above the authentication level, so don’t worry, your Azure function is indeed secured.


     public static async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req, ILogger log)
        {
           ...

But how do you use your api now that it is secured with an identity provider? The get method is fairly simple, you can just paste your Azure function url in your browser and you will get a prompt to login, from there an ID token is generated and you are free to use your Azure function. The post method is fairly different since it doesn’t support a login redirect. To use your secured Azure Function with the post method, we have to get an access token which you can obtain with the authorize and token endpoint.

To show you how you can succesfully call your secured Azure Function, I use Postman and more specific the build in Authorization tab, which will get the code from the authorize endpoint for me and pass it to the token endpoint.

Click on the Authorization tab from your post request in Postman and choose for the OAuth 2.0 type and choose to add the authorization data to the Request Headers.

Next we need the callback url, this url can be obtained from the Entra app registration, in the Redirect Uri’s from the Authentication section.

Next you need the authorization and the token endpoint from your app registration. These 2 url’s can be obtained from the Endpoint section in the overview screen of your Azure Function

With this information, we go back to the Authentication tab in Postman and fill in the following configuration:

  • Grant Type: Authorization Code
  • Callback URL: The URL from the redirect URL’s section in the Authentication section from our App registration
  • Auth URL: The Authorize endpoint
  • Access Token URL: The Token endpoint
  • Client ID: The Client ID from your App Registration
  • Client Secret: The Client Secret from your App Registration
  • Scope: This is a concatentation of your Client ID followed by “/.default”. For example: 1a66ff2a-8201-4ed6-91d6-3d5039ec4421/.default

Next we scroll all the way down and click on Get New Access Token and after that on Use Token. After that you will see that a Bearer access token is added to the headers of your request, which with you will succesfully call your Azure Function.


Blog at WordPress.com.