Access AAD protected Azure Functions
Tags: azure, azurefunctions, aad
Published: 2020-10-05 12:03:09

Securing resources are really important. When you create APIs or other web sites and expose to public internet, it is necessary to protect your endpoints if you.

IP restriction is the common way to limit the clients who can access the endpoint. However, it is getting more difficult to manage all public IPs of the clients these days because clients access your services from anywhere.

On Microsoft Azure, **Azure Active Directory (AAD)** protects your APIs/Webs through OAuth 2.0, OpenID Connect, SAML and etc.. When you use PaaS such as Azure Web Apps / Azure Functions, just turning on the feature let you protect your endpoints.

This post explains how to protect your APIs with AAD on Azure and access them.

## Prerequisites

This post doesn't explain what Azure Active Directory (AAD) is. If you are interested in it, you can check this.

- [Application and service principal objects in Azure Active Directory](https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals)

If you haven't created Azure Web Apps or Azure Functions, I recommend you to create them first.

- [Quickstart: Create an ASP.NET Core web app in Azure](https://docs.microsoft.com/en-us/azure/app-service/quickstart-dotnetcore?pivots=platform-windows)

- [Quickstart: Create a function in Azure using Visual Studio Code](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp)

## Create Azure Functions

First of all, you need to create Azure resources that host your API.
Create your HTTPTrigger Function [Quickstart: Create a function in Azure using Visual Studio Code](https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp).
You can publish your own API in minutes.

After deploying your HTTPTrigger Function to Azure, call it from cURL command, [Postman](https://www.postman.com/) or any other tools that create HTTP requests.
If the authentication level is set `function`, you can call your API with the Function key `code=xxxx` in query parameter or `x-functions-key: xxxx` in request header.
For more details, check [Azure Functions HTTP trigger](https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?tabs=python#authorization-keys).

![postmanrequest](https://keyomuradev.azureedge.net/postman_func_http.png)

Fig 1. Successful Postman Requests

## Enable AAD Authentication

In **Development or Staging** environment, you can use **Function Keys** to protect your Function App. However, in **Production**, it is difficult to manage your Function Key securely when you distribute the key to all clients that call the Function.
Once the key is leaked, you have to change the setting for all apps.

To secure your app and manage the authentication/authorization, you can use **Azure Active Directory (AAD)**.
AAD assign unique ID with each app, and each authentication is logged.

In Azure Web App / Azure Functions, you can enable AAD auth feature from Azure portal or commands,
thought **AAD auth is not available for Azure Function Linux consumption plan** (Oct.2020).
See [Configure your App Service or Azure Functions app to use Azure AD login](https://docs.microsoft.com/en-us/azure/app-service/configure-authentication-provider-aad).

> This feature is currently not available on Linux Consumption plan for Azure Functions

After you enabled the feature for your Function App, it returns `HTTP 401 unauthrized` because AAD protects your endpoint.

![unauthorized requests](https://keyomuradev.azureedge.net/unauthorized.png)

Fig 2. Unauthorized Requests to Function App

## Get Access Token to Authenticate

In order to access AAD protected Function App, you need to get **access token** from AAD for the Function App.
In case of API call, set `Bearer` token to `Authroization` header.

You need to create client application on AAD to authenticate Function App.
If you use [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli), you can create client AAD app for testing like below.

```bash
az ad sp create-for-rbac -n "TestAuthClientApp"
```

It outputs the result as JSON. Store your `appId` and `password` to authenticate Function App.

![azcli result](https://keyomuradev.azureedge.net/res_azcli.png)

Fig 3. Azure CLI result

To get access token for the Function App, copy Function App AAD ID as target from Azure Portal.
You can check from **[Authentication/Authorization]** blade.

![Function App ID](https://keyomuradev.azureedge.net/server.png)

Fig 4. Function App ID

Call `https://login.microsoftonline.com/<Your AAD Tenant ID>/oauth2/token` to get access token.
When you use cURL, below command works.

```bash
curl -X POST https://login.microsoftonline.com/<TENANT ID>/oauth2/token  \
  -F grant_type=client_credentials \
  -F resource=<Web App CLIENT ID> \
  -F client_id=<Client Application ID> \
  -F client_secret=<SECRET>
```

![Request Access Token](https://keyomuradev.azureedge.net/get_token.png)

Before requesting Function App, you need to change AAD App Setting for Function App. Check `Access tokens` to enable program to get `access_token` with implicit grant flow.

![Request App](https://keyomuradev.azureedge.net/implicit_grant.png)

## Request Function App with Token

Function App and request with `Authroization:Bearer xxxx` header, which needs **white space** between `Bearer` and `token` then you should get `HTTP 200 OK`.

Now you can set function auth level from `function` to `anonymous` because AAD protects your API.

![Request App](https://keyomuradev.azureedge.net/request_app.png)

## Next Step

Now you protect your API with AAD. However, you still need to manage AAD client app credentials. More secure way is to use **Managed Identity** that enable Function App to authenticate Azure services without secrets.
If your code runs on specific services such as Web App or Function App where Managed Identity enabled, Azure manage their authentication automatically.

[What are managed identities for Azure resources?](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview)

{% link https://dev.to/kemurayama/access-aad-protected-app-with-managed-identity-4gmm %}