Azure Functions Tips: where are our Function App keys?
Tags: azure, azurefunctions
Published: 2023-05-10 09:15:00

## Introduction
Azure Functions give you a built-in way to secure the calls for Http trigger functions. If you look at the following simple Azure Functions:

```csharp
[FunctionName("Echo")]
public IActionResult Echo(
    [HttpTrigger(AuthorizationLevel.Function, "post", Route = "echo")] HttpRequest req,
    ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");

    return new OkObjectResult(req.Body);
}
```

You can notice the argument `AuthorizationLevel.Function` of the `HttpTrigger` attribute. According to the official documentation ([here for more info](https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook-trigger?pivots=programming-language-csharp&tabs=python-v2%2Cin-process%2Cfunctionsv2#attributes)), that value:  

> is a string value that indicates the kind of authorization key that's required to access the function endpoint.

It means that, if you enable that feature, you need to invoke the Http endpoint with an URL like the following:

```url
https://myfunctionapp.azurewebsites.net/api/echo?code=<API_KEY>
```

If you prefer, you can send the key using the header `x-functions-key` instead the query string. 
The possible values for the `AuthorizationLevel `enumeration are:

| Value        | Description     | 
|--------------|-----------------|
| anonymous    | No API key is required      | 
| function     | A function-specific API key is required. This is the default value when a level isn't specifically set.  |
| admin        | The master key is required |

Azure portal gives you the capability to manage both function-specific keys and master keys:

![The Azure portal admin keys management](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uz9j3onee1gugwbnob0t.png)

![The Azure portal specific function keys management](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uqngjgoxi4ppz3y19ocd.png)


## Default keys store
As you can see from the previous images, you can add more than one key both in the system group than for each single function.
But the question is: **where are stored these keys?**

By default, the Function App retrieves (and saves, of course) all the keys you create in a Storage Account.
The connection string of the Storage Account is stored in the `AzureWebJobsStorage` configuration.
The Function App uses this Storage Account for the timer triggers info, the Event Hub checkpoint and, also, as store for the different Keys you have in it.
If you open the Storage Account page, you can find a container called `azure-webjobs-secrets` as shown in the following picture:

![The secret container in the Storage Account](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fddxa4wtee0atleggwbl.png)

In this container you find a folder for each Function App that uses it as store and inside folders you can see the JSON blobs that contain the secrets:

![The secret blobs in the Function App folder](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h0lgjahnloivi3q3jlsx.png)

As you can see in the previous image, you have one blob for each function (in our sample, we have only the `echo.json` blob for the `echo` function) and one blob (`host.json`) for the system keys.
The echo.json has the following schema:

```json
{
  "keys": [
    {
      "name": "default",
      "value": "CfDJ.........HaTQ",
      "encrypted": true
    }
  ],
  "hostName": "keyvaultkeysfuncapp.azurewebsites.net",
  "instanceId": "1cb21680e4253c2794483f9b01c5c800",
  "source": "runtime",
  "decryptionKeyId": "MACHINEKEY_DecryptionKey=Qzlp8wEKnbM33X1gHAREIGNJee8Ii6e6GEmnt5jT4j8=;"
}
```

You have the array `keys` that contains all the keys you create for the specific function.
The key is a JSON Web Key (JWK) key ([rfc definition](https://www.rfc-editor.org/rfc/rfc7517)) and you can add, remove or modify a key changing the JSON blob (I suggest to use the Azure portal or the CLI command, but if you want you can change directly in the blob).

To generate a JWK kay you can use the following C# snippet (or you can find a lot of on-line tools):

```csharp
using System.Security.Cryptography;
using System.Text.Json;

class Program
{
    static void Main()
    {
        // Create a new RSA key pair
        using (var rsa = RSA.Create())
        {
            // Export the public key as a JWK
            var jwk = Base64UrlEncode(rsa.ExportRSAPublicKey());
            Console.WriteLine(jwk);
		}
	}

	static string Base64UrlEncode(byte[] data)
	{
		return Convert.ToBase64String(data)
			.Replace('+', '-')
			.Replace('/', '_')
			.Replace("=", "");
	}
}
```

If you set a key with wrong format, the Azure portal doesn't show it. 

## Change the default storage
You can use a secondary storage for the secrets.
To do that, you can set the setting called `AzureWebJobsSecretStorageSas` with the Shared Access Signature of the secondary storage. 

So, imagine you create the storage account called `myfunckeysstorage`.
You need a container inside it (to store the JSON blobs) as shown in the following picture:

![The container to store our secrets](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mw9g0f7w3dca289i3in2.png)

Of course, you can call it as you want.
Now you need to generate the Shared Access Token to use in the Function App setting. To generate the SAS, you can open the container and use the option "Shared access tokens" as shown in the following picture:

![Create the SAS in the Azure portal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ea6eb1sllqlx8ucs39b9.png)

To set the new storage as secret store for the Function App, you need to add the setting `AzureWebJobsSecretStorageSas` with the value of the URL with SAS you generate in the previous step.

![The new secret store in the Function App configurations](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jbio1ehk73jue6jzdhg.png)