Using MSI with Azure Functions and Key Vault
There’s a relative new feature available in Azure called Managed Service Identity. What it does is create an identity for a service instance in the Azure AD tenant, which in its turn can be used to access other resources within Azure. This is a great feature, because now you don’t have to maintain and create identities for your applications by yourself anymore. All of this management is handled for you when using a System Assigned Identity. There’s also an option to use User Assigned Identities which work a bit different.
Because I’m an Azure Function fanboy and want to store my secrets within Azure Key Vault, I was wondering if I was able to configure MSI via an ARM template and access the Key Vault from an Azure Function without specifying an identity by myself.
As most of the things, setting this up is rather easy, once you know what to do.
The ARM template
The documentation states you can add an identity
property to your Azure App Service in order to enable MSI.
"identity": {
"type": "SystemAssigned"
}
This setting is everything you need in order to create a new service principal (identity) within the Azure Active Directory. This new identity has the exact same name as your App Service, so it should be easy to identify.
If you want to check out yourself if everything worked, you can check the AAD Audit Log. It should have a couple of lines stating a new service principal has been created.
You can also check out the details of which has happened by clicking on the lines.
Not very interesting, until something is broken or needs debugging.
An easier method to check if your service principal has been created is by checking the Enterprise Applications within your AAD tenant. If your deployment has been successful, there’s an application with the same name as your App Service.
Step two in your ARM template
After having added the identity to the App Service, you now have access to the tenantId
and principalId
which belong to this identity. These properties are necessary in order to give your App Service identity access to the Azure Key Vault. If you’re familiar with Key Vault, you probably know there are some Access Policies you have to define in order to get access to specific areas in the Key Vault.
Figuring out how to retrieve the new App Service properties was the hardest part of this complete post, for me. Eventually I figured out how to access these properties, thanks to an answer on Stack Overflow. What I ended up doing is retrieving a reference to the App Service in the accessPolicies
block of the Key Vault resource and use the identity.tenantId
and identity.principalId
.
"accessPolicies": [
{
"tenantId": "[reference(concat('Microsoft.Web/sites/', parameters('webSiteName')), '2018-02-01', 'Full').identity.tenantId]",
"objectId": "[reference(concat('Microsoft.Web/sites/', parameters('webSiteName')), '2018-02-01', 'Full').identity.principalId]",
"permissions": {
"keys": [],
"secrets": [
"get"
],
"certificates": [],
"storage": []
}
}],
Easy, right? Well, if you’re an ARM-template guru probably.
Now deploy your template again and you should be able to see your service principal being added to the Key Vault access policies.
Because we’ve specified the identity has access to retrieve (GET) secrets, in theory we are now able to use the Key Vault.
Retrieving data from the Key Vault
This is actually the easiest part. There’s a piece of code you can copy from the documentation pages, because it just works!
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyvaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secretValue = await keyvaultClient.GetSecretAsync($"https://{myVault}.vault.azure.net/", "MyFunctionSecret");
return req.CreateResponse(HttpStatusCode.OK, $"Hello World! This is my secret value: `{secretValue.Value}`.");
The above piece of code retrieves a secret from the Key Vault and shows it in the response of the Azure Function. The result should look something like the following response I saw in Firefox.
Using the KeyVaultTokenCallback
is exclusive to be used with the Key Vault (hence the name). If you want to use MSI with other Azure services, you will need to use the GetAccessTokenAsync
method in order to retrieve an access token to access the other Azure service.
So, that’s all there is to it in order to make your Azure Function or Azure environment a bit more safe with these managed identities.
If you want to check out the complete source code, it’s available on GitHub.
I totally recommend using MSI, because it’ll make your code, software and templates much safer and secure.