The idea is to have a web app running in Azure App Services that is using Managed Identity Service Principal. You must add this service principal in the Access Policies of your Key Vault with Read/Write access for keys and secrets. This service principal will be used by Azure App Services when the web app runs in the cloud. This is great but Managed Identities won't work when the developer is working from localhost. It will give a runtime exception.
This problem is due to the fact that you cannot use Managed Identities while running your code locally. When you run the code locally, you are running the app as yourself, or the user logged-in to Visual Studio. When your code is deployed to App Services using Managed Identity, you are running the app as the Service Principal. See existing post here: Can a "User Assigned Managed Identity" be used locally?
The error message is the following: ManagedIdentityCredential authentication unavailable. Multiple attempts failed to obtain a token from the managed identity endpoint.
What we need to do is to create an App Registration for storing a client secret. Then we will give it access to our Key Vault using the Access Policies. Our web app running locally will match the locally-stored client secret with the one stored in the App Registration and thus give access to Key Vault with an access token.
To create the registration you can use the Azure CLI command:
Create using a custom display name:
az ad sp create-for-rbac -n MyApp
This will automatically create a client secret for your app registration and return:
{
"clientId": "3f297241-beca-4818-8899-3cd520dd9d6c",
"clientSecret": "cII8Q~15IOB9mQOpUVnJ-LN5eWIIHEZI3xXRDbwC",
"subscriptionId": "c6521472-a4ca-4f9a-ae74-97c31bcf2bd6",
"tenantId": "e50ebc84-76f2-4636-b550-c3f7abc924af",
"activeDirectoryEndpointUrl": "https://login.microsoftonline.com",
"resourceManagerEndpointUrl": "https://management.azure.com/",
"activeDirectoryGraphResourceId": "https://graph.windows.net/",
"sqlManagementEndpointUrl": "https://management.core.windows.net:8443/",
"galleryEndpointUrl": "https://gallery.azure.com/",
"managementEndpointUrl": "https://management.core.windows.net/"
}
Here is the newly created app registration:

Under Certificates and Secrets, here is the client secret:

Now here is the updated code:
#region KeyVault Configuration
var keyVaultEndpoint = builder.Configuration.GetSection("KeyVault").GetValue<string>("VaultURI");
var clientId = builder.Configuration.GetSection("KeyVault").GetValue<string>("ClientId");
var tenantId = builder.Configuration.GetSection("KeyVault").GetValue<string>("TenantId");
var clientSecret = builder.Configuration.GetValue<string>("ClientSecret");
if (!string.IsNullOrEmpty(keyVaultEndpoint))
{
var azureServiceTokenProvider = builder.Environment.IsDevelopment() ?
new AzureServiceTokenProvider($"RunAs=App;AppId={clientId};TenantId={tenantId};AppKey={clientSecret}") : new AzureServiceTokenProvider();
var keyVault = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
builder.Configuration.AddAzureKeyVault(keyVaultEndpoint, keyVault, new DefaultKeyVaultSecretManager());
}
#endregion KeyVault Configuration
So basically you are passing the following parameters to build the connection string for the AzureServiceTokenProvider
to obtain a token for connecting to the Azure Key Vault:
This is the Application (client) ID of the App Registration:
- AppId=3f297241-beca-4818-8899-3cd520dd9d6c
This is the Directory (tenant) ID:
- TenantId=e50ebc84-76f2-4636-b550-c3f7abc924af
This is the client secret of the App Registration:
- AppKey=cII8Q~15IOB9mQOpUVnJ-LN5eWIIHEZI3xXRDbwC
Follow these steps to be able to run your web application locally (localhost) using Azure Key Vault
For storing the ClientSecret locally, I strongly suggest that you store it in the secrets.json
file by right-clicking the Web Project in Visual Studio and selecting Manage User Secrets
:

That's all!