Create and retrieve Azure Functions function keys in ARM template

One of my favorite services in Azure is Functions, which allow you to create serverless micro-services. Triggered by events, after which they run their code, Functions are perfect for the event-driven architectures we strive for these days. These events can come from various sources, like when a message is available in Service Bus, timers, an event sent from Event Grid, etc. However, the one we still use a lot is an HTTP trigger, where we expose the Function as a REST endpoint, available for consumers to call into.

Often we will have an architectural guideline, that every REST endpoint needs to be exposed through Azure API Management. Therefor, we expose these HTTP triggered Functions via API Management as well. We also have guidelines that everything is deployed as Infrastructure as Code, so we do this through ARM templates. In this post we dive into the security side of this, and how to set this up in ARM.

Security

When working with HTTP triggered Functions, there are several options for setting up their security. These consist of having anonymous authorization, where we don’t need to provide any API key, or using a function or master key. Of course, we will normally not use anonymous authorization, as we are exposing our data and processes, and as such want to limit access to these. Consequently, when exposing our Functions through API Management, we will create our Function App with a specific host key for this service.

Create host key

To create this host key, we use the following snippet in our ARM template for our Function App.

{
    "type": "Microsoft.Web/sites/host/functionKeys",
    "apiVersion": "2018-11-01",
    "name": "[concat(parameters('functionAppName'), '/default/apimanagement')]",
    "properties": {
        "name": "api-management"
    }
}

Since this is a host key, we place it into the default host. Alternatively, if we were creating a function key, we would have replaced this with the Function name.

Retrieve host key

Now that our Function App has been deployed, we can create a Function in it which gets exposed through API Management. Creation of the Function is out of scope, but if you need one just for this post you can just make one with an HTTP trigger and further use all default settings.

Next, we need to retrieve the host key of the Function App in API Management and use this in the configuration of the backend, which creates a link between API Management and the Function. For this we use the listkeys function, similar to retrieving an Azure Storage access key.

{
    "type": "Microsoft.ApiManagement/service/backends",
    "apiVersion": "2019-01-01",
    "name": "[concat(parameters('apiManagementInstanceName'), '/', parameters('functionAppName'))]",
    "dependsOn": [
        "[resourceId('Microsoft.ApiManagement/service', parameters('apiManagementInstanceName'))]"
    ],
    "properties": {
        "url": "[concat('https://', parameters('functionAppName'), '.azurewebsites.net/api')]",
        "protocol": "http",
        "resourceId": "[concat('https://management.azure.com/subscriptions/', subscription().subscriptionId, '/resourceGroups/', resourceGroup().name, '/providers/Microsoft.Web/sites/', parameters('functionAppName'))]",
        "credentials": {
            "header": {
                "x-functions-key": [
                    "[listkeys(concat(variables('functionAppId'), '/host/default/'),'2016-08-01').functionKeys.apimanagement]"
                ]
            }
        }
    }
}

After deployment, we will find that our Function is now available via API Management, without the need to create any secrets ourselves. The ARM template to deploy the resources with this post can be found on my GitHub page.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.