Authenticating API calls from Azure API Management to Functions

Azure API Management is a hybrid, multi-cloud management platform for APIs across all environments. It acts as a gateway for exposing API access to the cloud-native application.

This article describes how to setup authentication in Azure API Management for requests forwarded to Azure Functions.

It is assumed that Azure API Management and Azure Functions App has been created already and has enabled Identity.

Authentication setup for Azure Function Apps and API Management

Azure Functions apps has two keys by default, host key and a default funcktionKey. Those will are used to authenticate HTTP triggers for the app. For API Management authentication, a new function key apim-auth-key for the app will be added. This will be the shared secret between API Management and Function App. When a request is forwarded from API Management to the Function App, apim-auth-key will be added in the header so that the function execution can verify the request is legitimate. Otherwise the request will be rejected with invalid authentication error.

https://ibrahim-13.github.io/assets/blog/Azure-APIM-FunctionApp-Auth.png

Adding Function Key

The following Azure CLI command will create a new function key-

# Value of the key will be generated
# Predefined value can be set with the option --key-value
az functionapp keys set --resource-group rg-demo --name azure-func-demo --key-name apim-auth-key --key-type functionKeys

If the command is successful, it will print the function key value-

{
  "id": "/subscriptions/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/resourceGroups/rg-demo/providers/Microsoft.Web/sites/azure-func-demo/host/default/functionKeys/apim-auth-key",
  "location": "Central India",
  "name": "apim-auth-key",
  "resourceGroup": "rg-demo",
  "type": "Microsoft.Web/sites/host/functionKeys",
  "value": "F0uyVNNt2NXNfO1jYvSuTx0cKJF6HIWGyk5EezpLjvcIAzFuhTlwEg=="
}

Setting up Named Value in API Management

Named Values are globally stored name-value pairs for each API Management instance. It can be used for managing constant string values across all API Management configurations and policies. Named values can also store secret values. That’s why the function key will be stored in the named values, which will be used in backed forwarding configuration.

The following Bicep script will create a named value for API Management:

var apimResourceName = 'apim-test'
var functionKey = 'F0uyVNNt2NXNfO1jYvSuTx0cKJF6HIWGyk5EezpLjvcIAzFuhTlwEg=='

// Reference to existing API Management resource
resource resourceApiManagement 'Microsoft.ApiManagement/service@2021-12-01-preview' existing = {
  name: apimResourceName
}

// Create property
resource resourcePropertiesFuncKey 'Microsoft.ApiManagement/service/properties@2019-01-01' = {
  parent: resourceApiManagement
  name: 'func-auth-key'
  properties: {
    displayName: 'func-auth-key'
    value: functionKey
    tags: [
      'key'
      'function'
    ]
    secret: true
  }
}

// Create named value
resource resourceNamesValuesFuncKey 'Microsoft.ApiManagement/service/namedValues@2021-08-01' = {
  parent: resourceApiManagement
  name: 'func-auth-key'
  properties: {
    displayName: 'func-auth-key'
    tags: [
      'key'
      'function'
    ]
    secret: true
    value: functionKey
  }
  dependsOn: [
    resourcePropertiesFuncKey
  ]
}

Adding Back-ends in API Management

backend (or API backend) in API Management is an HTTP service that implements your front-end API and its operations.

Instead of creating forwarding policy for each operation, we can create a back-end and handle authentication in there.

The following Bicep script will create a back-end for the Function App in API Management:

resource resourceBackendFunctions 'Microsoft.ApiManagement/service/backends@2021-08-01' = {
  parent: resourceApiManagement
  name: 'azure-func-demo'
  properties: {
    description: 'azure-func-demo'
    url: 'https://azure-func-demo.azurewebsites.net/api'
    protocol: 'http'
    resourceId: 'https://management.azure.com/subscriptions/${subscription().subscriptionId}/resourceGroups/${resourceGroup().name}/providers/Microsoft.Web/sites/azure-func-demo'
    credentials: {
      header: {
        'x-functions-key': [
          '{{func-auth-key}}'
        ]
      }
    }
  }
  dependsOn: [
    resourceNamesValuesFuncKey
  ]
}

Adding policy for the operation

Finally, we can set policy for an operation to use the previously created back-end and forward request to the service:

<policies>
    <inbound>
        <base />
        <set-backend-service id="backend-demo" backend-id="azure-func-demo" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

Resources