Secure On-Premise .NET Application with Azure Key Vault

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.


Stay In Touch

Subscribe to our mailing list to stay updated on topics and videos related to .NET, Azure, and DevOps!

By submitting your information, you’re giving us permission to email you. You may unsubscribe at any time.


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.

  1. Navigate to Microsoft Entra ID
  2. Under Manage, click on App Registrations
  3. Click on New Registration. Specify a name for it, and you can keep the Supported Account Type as Single Tenant.
  4. Save the Application (client) ID, Object ID, and Tenant ID.
  5. Once created, navigate to Certificates & secrets. Then create a New 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 tenantIdclientId, 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!

Recent Posts

Adding Custom Formatting to Your Classes with IFormattable
DateTime has a great feature that I often replicate in my classes: the ability for users to format the ToString output however they want. Using …
Azure-Sync: Sync your Azure App Settings to local
Azure-Sync is a handy shell script tool designed to help .NET developers working with Azure App Services. Inspired by the functionality provided by the Azure …
Implement Builders easily with Source Generator in .NET
I created a YouTube video on Source Generator in which I showcased one possible implementation. However, I feel that I didn’t fully highlight its capabilities. …
Running Integration Tests with Docker in .NET using TestContainers
Hello everyone, in today's post I will show you the easiest and cleanest way to perform integration testing of your code with database dependencies with …

3 thoughts on “Secure On-Premise .NET Application with Azure Key Vault

  1. Jhon

    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/”,

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.