Suppose you have your Web App and Database server hosted locally on your On-Premises servers. You want to use Azure Key Vault with your .NET application to retrieve your app settings. This allows you to avoid storing them as plain text in the appsettings.json file. In this blog post, I will show you how to integrate Azure Key Vault with your .NET application by using the Service Principle client secret. This approach can be applied to any environment even the on-premise one.
YouTube Video
I have created a YouTube video that provides a detailed, step-by-step guide on how to secure your .NET application with Azure Key Vault. However, it does not include the part where we use the Client Secret. Check the full video here
The full source code can be found here: https://github.com/mhdbouk/keyvault-configuration-demo
Create your Azure Key Vault
I’m using here Azure CLI to create the keyvault, but you can create the same using the Azure Portal.
Create Resource Group
First create the resource group where you are going to put the Azure Key Vault.
az group create --name rg-myapplication --location NorthEurope
Create Key Vault
az keyvault create --name kvmyapplication --resource-group rg-myapplication --location NorthEurope
Make sure to specify a unique name across all Azure
Add your Secret
We are going to store our On-Premise server password as a secret in the KeyVault, you can do that using the following command
az keyvault secret set --vault-name kvmyapplication --name "MyApp-ConnectionStrings--DefaultConnection" --value "Server=myServerAddress;Database=myDataBase;User Id=myUsername;Password=myPassword;"
Notice that I named the secret MyApp-ConnectionStrings--DefaultConnection
. This will be mapped to our appsettings.json
structure later in this blog post.
MyApp-
is the prefix, primarily used for our Application. In this case, we can use the same Key Vault for multiple applications.
--
is later on going to be replaced with the default Configuration Key Delimiter.
Create New App Registration
The app registration will be used to provide access between the web app and the Key Vault, by generating the needed Secret / Certificate and we will configure the Key Vault with the needed policy as well.
- Navigate to
Microsoft Entra ID
- Under
Manage
, click onApp Registrations
- Click on
New Registration
. Specify a name for it, and you can keep the Supported Account Type as Single Tenant. - Save the Application (client) ID, Object ID, and Tenant ID.
- Once created, navigate to
Certificates & secrets
. Then create aNew Client Secret
and save that secret for later.
Add Key Vault Access Policy
Now we need to allow accessing the secrets using the App Registration. Any application using the App Registration credentials should be allowed to get the secret values.
Using Azure CLI I’m going to create a new Access Policy but you can use the Azure Portal to perform the same thing.
az keyvault set-policy --name kvmyapplication --object-id app_registration_object_id --secret-permissions get list
--object-id app_registration_object_id
is the app registration object ID we receive it when creating the app registration.
We need to allow Get and List secret permissions. Make sure to specify only the needed permissions for your use case.
More Info about set-policy
here
Coding TIME
Now, in your .NET Web Application, add package references for the following packages:
Now add the following to your appsettings.json
{
// existing appsettings keys
"KeyVault": {
"url": "https://kvmyapplication.vault.azure.net/",
"clientId": "CLIENT ID HERE",
"clientSecret": "CLIENT SECRET HERE",
"tenantId": "TENANT ID HERE"
}
}
Next, navigate to Program.cs
and configure your web application with the KeyVault configuration:
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;
using KeyVaultYouTubeDemo;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
if (builder.Environment.IsProduction())
{
var keyVaultUri = new Uri(builder.Configuration["KeyVault:url"]!);
var tenantId = builder.Configuration["KeyVault:TenantId"];
var clientId = builder.Configuration["KeyVault:ClientId"];
var clientSecret = builder.Configuration["KeyVault:ClientSecret"];
builder.Configuration.AddAzureKeyVault(
keyVaultUri,
new ClientSecretCredential(tenantId, clientId, clientSecret),
new AzureKeyVaultConfigurationOptions()
{
Manager = new CustomSecretManager("MyApp"),
ReloadInterval = TimeSpan.FromSeconds(30)
}
);
}
We are configuring the Key Vault for use only in a production environment. For the development environment, it is best to use User Secrets.
Note that we are retrieving the tenantId
, clientId
, and clientSecret
from the configuration. We are using these to create a ClientSecretCredential
AzureKeyVaultConfigurationOptions
is used to specify the Manager, which prepares the secrets from the Key Vault. The ReloadInterval
ensures that our app is always refreshing the secrets from the Key Vault, eliminating the need to restart.
Now, create a new class called CustomSecretManager
and add the following to it:
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Security.KeyVault.Secrets;
namespace KeyVaultDemo;
public class CustomSecretManager : KeyVaultSecretManager
{
private readonly string _prefix;
public CustomSecretManager(string prefix)
{
_prefix = $"{prefix}-";
}
public override bool Load(SecretProperties secret)
=> secret.Name.StartsWith(_prefix);
public override string GetKey(KeyVaultSecret secret)
=> secret.Name[_prefix.Length..].Replace("--", ConfigurationPath.KeyDelimiter);
}
This class is used to load and get the keys. It retrieves all secrets starting with the prefix, allowing our Key Vault to be used with multiple applications. It also replaces the --
in the secret name with the Key Delimiter used for the configuration, which is “:
” in our case.
That’s it! Now, when you run the application, it will connect to your Key Vault to retrieve the app secrets.
Happy Coding!
Excellent post. I will share it in the ASP.NET Core News newsletter 🎉 Thank you for submitting it.
Does this work?
KeyVault:Url should be “kvmmyapplication”?
var keyVaultUri = new Uri($”https://{builder.Configuration[“KeyVault:Url”]}.vault.azure.net/”);
“url”: “https://kvmyapplication.vault.azure.net/”,
You are correct! I changed that to a Uri in the code but forgot to change it here in the blog post.
It is now updated, thank you sir