Azure Key Vault as a Configuration Provider in .NET

Every .NET application has secrets — database connection strings, API keys, certificates. The question isn't whether you need secret management; it's whether your current approach will survive an audit.

Azure Key Vault integrates directly into the .NET configuration system. Your code reads IConfiguration["ConnectionStrings:Database"] as usual, but the value comes from Key Vault instead of appsettings.json. No code changes needed downstream.

Adding the Configuration Provider

Install the Azure.Extensions.AspNetCore.Configuration.Secrets package and wire it into your host builder:

Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(
    new Uri("https://my-vault.vault.azure.net/"),
    new DefaultAzureCredential());

var app = builder.Build();

That's it. Every secret in the vault is now available through IConfiguration. The provider loads all secrets at startup and caches them in memory.

Secret Naming Conventions

Key Vault doesn't allow colons in secret names, but .NET configuration uses colons as section separators. The convention is to use double hyphens (--) in Key Vault, which the provider translates to colons:

Key Vault Secret Name Configuration Key
ConnectionStrings--Database ConnectionStrings:Database
Smtp--Host Smtp:Host
Smtp--Port Smtp:Port

This means you can bind to options classes seamlessly:

Example.cs
builder.Services.Configure<SmtpOptions>(
    builder.Configuration.GetSection("Smtp"));
Example.cs
public class SmtpOptions
{
    public string Host { get; set; } = string.Empty;
    public int Port { get; set; }
    public string ApiKey { get; set; } = string.Empty;
}

The ApiKey value comes from a Key Vault secret named Smtp--ApiKey, but your code never knows the difference.

Filtering Secrets with Prefixes

In shared vaults, you may want to load only secrets relevant to your application. Use a custom key vault manager to filter and transform secret names:

Example.cs
builder.Configuration.AddAzureKeyVault(
    new Uri("https://my-vault.vault.azure.net/"),
    new DefaultAzureCredential(),
    new PrefixKeyVaultSecretManager("MyApp"));
PrefixKeyVaultSecretManager.cs
public class PrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

    public PrefixKeyVaultSecretManager(string prefix)
    {
        _prefix = $"{prefix}--";
    }

    public override bool Load(SecretProperties properties)
    {
        return properties.Name.StartsWith(_prefix, StringComparison.OrdinalIgnoreCase);
    }

    public override string GetKey(KeyVaultSecret secret)
    {
        return secret.Name[_prefix.Length..]
            .Replace("--", ConfigurationPath.KeyDelimiter);
    }
}

A secret named MyApp--ConnectionStrings--Database becomes ConnectionStrings:Database in configuration, and secrets without the MyApp-- prefix are ignored entirely.

Reloading Secrets

By default, secrets are loaded once at startup. For long-running applications, you may want periodic reloading:

Example.cs
builder.Configuration.AddAzureKeyVault(
    new Uri("https://my-vault.vault.azure.net/"),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        ReloadInterval = TimeSpan.FromMinutes(5)
    });

This polls Key Vault every five minutes and updates the configuration values in place. Combined with IOptionsSnapshot<T>, your services pick up new values on the next scope without a restart.

Be mindful of Key Vault throttling limits. A five-minute interval is reasonable for most applications. Don't set it to seconds.

Local Development

For local development, you don't want to hit Key Vault at all. Use the configuration precedence system — values in appsettings.Development.json or user secrets override Key Vault:

Example.cs
if (builder.Environment.IsProduction())
{
    builder.Configuration.AddAzureKeyVault(
        new Uri(builder.Configuration["KeyVault:Uri"]!),
        new DefaultAzureCredential());
}

Or use dotnet user-secrets to store development values locally. They sit outside your project directory and never end up in source control.

Authentication

DefaultAzureCredential handles authentication across environments:

No connection strings or client secrets needed in your configuration provider setup. The credential chain tries each method in order until one succeeds.

What Doesn't Belong in Key Vault

Key Vault is for secrets — values that would cause harm if exposed. Don't put every configuration value there:

Key Vault as a configuration provider is one of the cleanest patterns in the Azure/.NET ecosystem. It requires minimal code, respects the standard configuration hierarchy, and eliminates an entire class of security risks.