Getting Key Vault Secrets in Azure Functions
For triggers, bindings, and environment variables
NOTE: Updated on 11/28 to reflect new key vault and function capabilities
One of the common questions around building Azure Functions is how to deal with secrets that a function needs. We know we shouldn’t be putting secrets in the code. Another sometimes satisfactory alternative is place secrets as an app setting. However, since these app settings are retrievable via clear-text through the API/Portal, and would need to be replicated to each function app that needs the secret, some prefer to leverage Azure Key Vault.
Here are the steps to build an Azure Function which can retrieve secrets at runtime. The below uses C# compiled class libraries, but the same underlying pieces can be used with any Azure Function language or binding.
Creating the Key Vault
I followed the instructions here to create a key vault in my Azure Subscription. After the key vault was created I ran this command to add the secrets to the vault.
az keyvault create -n mySuperSecretVault -g jeffhollan-keyvault -l westusaz keyvault secret set --vault-name mySuperSecretVault -n eventHubConnectionString --value '{MyEventHubConnectionString}'az keyvault secret set --vault-name mySuperSecretVault -n superSecret --value 'I love Azure Functions'
Now authorized identities can retrieve this secret as needed in a central, secure location. One way to access is create my own custom application identity, or “service principal”, which I could use to access the secret. The rub with that approach though is in order to retrieve a valid token for a service principal I need to provide an application secret — which itself is… a secret. With the announcement of Azure managed service identities, I can now give my resource (in this case, a function) an identity and give it permissions just as it were another user.
Configuring the Azure Function
After creating the Azure Function, I enabled a managed service identity for the function app. This will now add an identity in my Azure active directory I can give permissions to any resource I may need.
After enabling the managed service identity, I went into my key vault and added an access policy so my Azure Function app had permissions to read secrets.
The last step is to fetch the secret when I run the app.
Retrieving secrets from a function
Starting in the fall of 2018 I don’t have to make any code changes in order to access secrets in key vault.
Here’s a sample Azure Event Hub triggered function that makes a simple log message. In this case this app has two secrets: the Event Hubs connection string, and the private variable superSecret
.
When running locally I can use local.settings.json
to have local stored values to develop and test off of. This can connect to a development Event Hub and use some development secret.
However, once I publish, I just have to modify the Application Settings to resolve the right values as secrets.
Configuring the App Settings
In the Azure Portal (or via Visual Studio / VS Code / CLI / whatever tool you want to use to manage app settings), I need to associate some app settings to correspond to the secrets in key vault. To do that I will create two new application settings for SuperSecret
and EventHubConnectionString
that mirror the local.settings.json
— but instead of having the secrets in the app settings, I will point to where the secrets are in my key vault. It should be noted that the key vault secret ID is itself not a secret, it’s just an address of where the secret can be found.
I browsed to my key vault and found the secrets I needed and copied their address or Secret Uri (it looks something like https://{name}.vault.azure.net/secrets/{secret}/{id}
) and then added special app settings that will fetch the secret from that source when the app instantiates on an instance. This means the secret only gets fetched once per instance, and not every execution (so I don’t have to worry about key vault throttles).
The app setting key is EventHubConnectionString
and the value is something like @Microsoft.KeyVault(SecretUri={theSecretUri})
.
When done configuring, here’s what my app settings looked like to get my secrets:
If I wanted to, I could make any of these app settings into key vault references, including things like the AzureWebJobsStorage
account.
Once I click save, I’m done. The function instance will restart, authenticate to key vault using the managed service identity I configured, resolve the key vault secrets and store them in the appropriate environment variables, and my code can now trigger on the Event Hub and log the message as written.