Skip to main content

Overview

The Azure Key Vault module provides seamless integration with Azure Key Vault for .NET applications, enabling secure storage and access to sensitive information such as passwords, API keys, connection strings, and certificates. This module extends the .NET IConfiguration service, making secrets accessible through the same configuration system you already use.

Installation

Intent.Azure.KeyVault

How It Works

The module integrates Azure Key Vault as a configuration source, allowing you to:
  • Store secrets securely in Azure Key Vault
  • Access them through IConfiguration in your application
  • Automatically refresh secrets
  • Use different authentication methods

Architecture

Configuration

Basic Configuration

Add Key Vault settings to appsettings.json:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://my-vault.vault.azure.net/",
    "TenantId": "your-tenant-id",
    "ClientId": "your-client-id",
    "Secret": "your-client-secret"
  }
}

Configuration Parameters

ParameterRequiredDescription
EnabledYesEnable/disable Key Vault integration
EndpointYesYour Key Vault URL
TenantIdConditionalAzure AD tenant ID
ClientIdConditionalService principal client ID
SecretConditionalService principal secret

Authentication Methods

The module supports multiple authentication methods: Provide all three: TenantId, ClientId, and Secret:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://my-vault.vault.azure.net/",
    "TenantId": "00000000-0000-0000-0000-000000000000",
    "ClientId": "11111111-1111-1111-1111-111111111111",
    "Secret": "your-secret-value"
  }
}

2. ClientId Only (Managed Identity)

For applications already configured with managed identity:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://my-vault.vault.azure.net/",
    "ClientId": "11111111-1111-1111-1111-111111111111"
  }
}

3. Credential Discovery (Local Development)

No credentials specified - uses DefaultAzureCredential:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://my-vault.vault.azure.net/"
  }
}
DefaultAzureCredential tries authentication in this order:
  1. Environment variables
  2. Managed Identity
  3. Visual Studio credentials
  4. Azure CLI credentials
  5. Azure PowerShell credentials

Usage

Accessing Secrets

Secrets are accessed through IConfiguration just like any other setting:
public class MyService
{
    private readonly IConfiguration _configuration;

    public MyService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public async Task ConnectToDatabaseAsync()
    {
        // Secret stored in Key Vault as "DatabaseConnectionString"
        var connectionString = _configuration["DatabaseConnectionString"];
        
        // Use the connection string
        await _dbContext.Database.OpenConnectionAsync();
    }
}

Strongly-Typed Configuration

public class ApiSettings
{
    public string ApiKey { get; set; }
    public string ApiSecret { get; set; }
    public string BaseUrl { get; set; }
}

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Bind Key Vault secrets to strongly-typed configuration
        services.Configure<ApiSettings>(_configuration.GetSection("ThirdPartyApi"));
    }
}

public class ApiClient
{
    private readonly ApiSettings _settings;

    public ApiClient(IOptions<ApiSettings> settings)
    {
        _settings = settings.Value;
    }

    public async Task<string> CallApiAsync()
    {
        // ApiKey and ApiSecret come from Key Vault
        var client = new HttpClient();
        client.DefaultRequestHeaders.Add("X-Api-Key", _settings.ApiKey);
        // ...
    }
}

Secret Naming

In Key Vault

Key Vault secret names must:
  • Use alphanumeric characters and hyphens only
  • Be 1-127 characters long
  • Cannot contain colons or underscores
Example: Database--ConnectionString or ThirdPartyApi--ApiKey

In Application

The module automatically converts secret names:
  • Key Vault: Database--ConnectionString
  • Configuration: Database:ConnectionString
// Access secret stored as "Database--ConnectionString"
var connString = _configuration["Database:ConnectionString"];

// Or using GetSection
var dbConfig = _configuration.GetSection("Database");
var connString = dbConfig["ConnectionString"];

Common Scenarios

Connection Strings

Store in Key Vault:
  • Secret Name: ConnectionStrings--DefaultConnection
  • Secret Value: Server=myserver;Database=mydb;User=sa;Password=P@ssw0rd
Access in code:
var connectionString = _configuration.GetConnectionString("DefaultConnection");

API Keys

Store in Key Vault:
  • Secret Name: ExternalApis--Stripe--SecretKey
  • Secret Value: sk_live_...
Access in code:
var stripeKey = _configuration["ExternalApis:Stripe:SecretKey"];

Multi-Environment Secrets

Use different Key Vaults per environment: appsettings.Development.json:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://dev-vault.vault.azure.net/"
  }
}
appsettings.Production.json:
{
  "KeyVault": {
    "Enabled": true,
    "Endpoint": "https://prod-vault.vault.azure.net/"
  }
}

Setting Up Azure Key Vault

Create Key Vault

Azure Portal:
  1. Navigate to Create a resource → Key Vault
  2. Configure:
    • Name: Globally unique name
    • Region: Same as your app
    • Pricing tier: Standard or Premium
  3. Click Review + create
Azure CLI:
az keyvault create \
  --name my-app-vault \
  --resource-group my-resource-group \
  --location eastus

Add Secrets

Azure Portal:
  1. Open your Key Vault
  2. Navigate to Secrets
  3. Click + Generate/Import
  4. Enter secret name and value
Azure CLI:
az keyvault secret set \
  --vault-name my-app-vault \
  --name "Database--ConnectionString" \
  --value "Server=myserver;Database=mydb;..."

Grant Access

For Service Principal:
az keyvault set-policy \
  --name my-app-vault \
  --spn <client-id> \
  --secret-permissions get list
For Managed Identity:
# Get the managed identity principal ID
az webapp identity show \
  --name my-webapp \
  --resource-group my-resource-group \
  --query principalId -o tsv

# Grant access
az keyvault set-policy \
  --name my-app-vault \
  --object-id <principal-id> \
  --secret-permissions get list

Local Development

Option 1: Azure CLI Authentication

  1. Install Azure CLI
  2. Sign in:
    az login
    
  3. Set subscription:
    az account set --subscription "My Subscription"
    
  4. Use credential discovery in appsettings.Development.json:
    {
      "KeyVault": {
        "Enabled": true,
        "Endpoint": "https://dev-vault.vault.azure.net/"
      }
    }
    

Option 2: User Secrets (Development Only)

For local development, use .NET user secrets instead of Key Vault: appsettings.Development.json:
{
  "KeyVault": {
    "Enabled": false
  }
}
Configure user secrets:
dotnet user-secrets init
dotnet user-secrets set "Database:ConnectionString" "Server=localhost;..."
dotnet user-secrets set "ExternalApis:Stripe:SecretKey" "sk_test_..."

Advanced Features

Secret Versioning

Key Vault maintains version history:
// Always gets latest version by default
var secret = _configuration["MySecret"];

// Access specific version (requires direct Key Vault client)
var client = new SecretClient(
    new Uri("https://my-vault.vault.azure.net/"),
    new DefaultAzureCredential());

var specificVersion = await client.GetSecretAsync(
    "MySecret", 
    "version-id-here");

Automatic Refresh

Secrets are cached and automatically refreshed:
// Configure refresh interval in Program.cs
builder.Configuration.AddAzureKeyVault(
    new Uri(vaultUri),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        ReloadInterval = TimeSpan.FromMinutes(5)
    });

Prefix Filtering

Load only secrets with specific prefix:
builder.Configuration.AddAzureKeyVault(
    new Uri(vaultUri),
    new DefaultAzureCredential(),
    new AzureKeyVaultConfigurationOptions
    {
        Manager = new PrefixKeyVaultSecretManager("MyApp")
    });

public class PrefixKeyVaultSecretManager : KeyVaultSecretManager
{
    private readonly string _prefix;

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

    public override bool Load(SecretProperties secret)
    {
        return secret.Name.StartsWith(_prefix);
    }

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

Best Practices

Always use managed identities in Azure instead of storing service principal credentials:
// Good - No credentials in code or config
var credential = new DefaultAzureCredential();
var client = new SecretClient(vaultUri, credential);

// Avoid - Credentials in config
var credential = new ClientSecretCredential(tenantId, clientId, secret);
Grant only the minimum required permissions:
  • Development: Get, List
  • Production: Get only
  • CI/CD: Get, Set, Delete (for deployment automation)
Implement secret rotation strategy:
  • Set expiration dates on secrets
  • Monitor expiring secrets
  • Use automated rotation where possible
  • Test secret rotation process
Use separate Key Vaults for each environment:
  • Development: myapp-dev-kv
  • Staging: myapp-staging-kv
  • Production: myapp-prod-kv
Enable diagnostic logging:
  • Track secret access
  • Monitor failed authentication attempts
  • Set up alerts for unusual activity
  • Review audit logs regularly

Certificates

Key Vault can also store certificates:
public class CertificateService
{
    private readonly CertificateClient _client;

    public CertificateService(IConfiguration configuration)
    {
        var vaultUri = configuration["KeyVault:Endpoint"];
        _client = new CertificateClient(
            new Uri(vaultUri),
            new DefaultAzureCredential());
    }

    public async Task<X509Certificate2> GetCertificateAsync(string certName)
    {
        var certificate = await _client.GetCertificateAsync(certName);
        return new X509Certificate2(certificate.Value.Cer);
    }
}

Troubleshooting

Common Issues

Issue: Access Denied
Azure.RequestFailedException: The user, group or application does not have secrets get permission
Solution: Grant proper access policies in Key Vault Issue: Vault Not Found
Azure.RequestFailedException: Vault not found
Solution: Check endpoint URL and ensure Key Vault exists Issue: Authentication Failed
Azure.Identity.AuthenticationFailedException
Solution:
  • Verify credentials are correct
  • Ensure DefaultAzureCredential can find credentials
  • Check network connectivity to Azure

Enable Diagnostic Logging

using Azure.Core.Diagnostics;

// Enable logging
using var listener = AzureEventSourceListener.CreateConsoleLogger();

Resources

Key Vault Documentation

Official Microsoft documentation

Best Practices

Security and operational guidance

Managed Identities

Using managed identities

Secret Rotation

Implementing secret rotation

Build docs developers (and LLMs) love