Getting Started with Azure Key Vault in .NET
Reading Time: 5 minutes
The Problem
Secrets management is one of the most common security pitfalls in software development. How many times have you seen this in a codebase?
// appsettings.json - ❌ NEVER do this
{
"ConnectionStrings": {
"DefaultConnection": "Server=prod-server;Database=MyApp;User Id=admin;Password=SuperSecret123!"
},
"Stripe": {
"SecretKey": "sk_live_abc123xyz789..."
},
"SendGrid": {
"ApiKey": "SG.real-api-key-here..."
}
}
These secrets end up committed to source control, shared in Slack, emailed around, and baked into Docker images. Anyone with access to the repo - or who ever had access - can see them. When a developer leaves the company, do you rotate every secret they could have seen? Probably not.
The risks are real:
- Secrets in git history are permanent even after deletion
- Developers on local machines have production credentials
- No audit trail of who accessed which secret
- Rotating secrets requires code changes and redeployments
The Solution
Azure Key Vault provides a centralized, secure secret store with:
- Encryption at rest and in transit
- Fine-grained access control via Azure RBAC
- Full audit logging of all secret accesses
- Secret versioning and rotation support
- Seamless integration with the .NET SDK
Setting Up Azure Key Vault
Before writing any code, you need to create a Key Vault in Azure:
- Log into the Azure Portal
- Click Create a resource and search for Key Vault
- Click Create and fill in the details:
- Resource group: Select or create one
- Key vault name: Must be globally unique (e.g.,
myapp-kv-prod) - Region: Choose the same region as your application
- Pricing tier: Standard is sufficient for secrets
- On the Access configuration tab, select Azure role-based access control (RBAC)
- Click Review + create, then Create
- Once created, navigate to Access control (IAM) and add yourself as Key Vault Secrets Officer
- Go to Secrets and add your secrets (e.g.,
ConnectionStrings--DefaultConnection)
Note: Key Vault secret names use
--instead of:for nested configuration keys, because:is not allowed in secret names. The .NET configuration provider automatically handles this mapping.
Installing NuGet Packages
Add the required packages to your project:
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets
dotnet add package Azure.Identity
Azure.Extensions.AspNetCore.Configuration.Secrets- integrates Key Vault withIConfigurationAzure.Identity- providesDefaultAzureCredentialfor authentication
Configuring Key Vault in Program.cs
The cleanest way to add Key Vault is in your application’s configuration setup:
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
// Add Key Vault to the configuration pipeline
var keyVaultUri = builder.Configuration["KeyVault:Uri"]
?? throw new InvalidOperationException("KeyVault:Uri is not configured");
builder.Configuration.AddAzureKeyVault(
new Uri(keyVaultUri),
new DefaultAzureCredential()
);
// Now all Key Vault secrets are available via IConfiguration
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
var app = builder.Build();
app.Run();
Store only the Key Vault URI in your appsettings.json - it’s not a secret:
{
"KeyVault": {
"Uri": "https://myapp-kv-prod.vault.azure.net/"
}
}
Reading Secrets in Your Services
Once Key Vault is wired into IConfiguration, you access secrets exactly the same way as any other configuration value:
public class StripePaymentService : IPaymentService
{
private readonly string _secretKey;
private readonly ILogger<StripePaymentService> _logger;
public StripePaymentService(
IConfiguration configuration,
ILogger<StripePaymentService> logger)
{
_secretKey = configuration["Stripe--SecretKey"]
?? throw new InvalidOperationException("Stripe secret key is not configured");
_logger = logger;
}
public async Task<PaymentResult> ChargeAsync(decimal amount, string token)
{
// Use _secretKey safely - it came from Key Vault, never from code
_logger.LogInformation("Processing payment of {Amount}", amount);
// ... Stripe API call
}
}
For strongly-typed configuration, use the Options pattern:
// Options class
public class StripeOptions
{
public const string SectionName = "Stripe";
public string SecretKey { get; set; } = string.Empty;
public string PublishableKey { get; set; } = string.Empty;
}
// In Program.cs
builder.Services.Configure<StripeOptions>(
builder.Configuration.GetSection(StripeOptions.SectionName));
// In your service
public class StripePaymentService : IPaymentService
{
private readonly StripeOptions _options;
public StripePaymentService(IOptions<StripeOptions> options)
{
_options = options.Value;
}
}
Local Development with DefaultAzureCredential
DefaultAzureCredential is the magic that makes this work seamlessly across environments. It tries a chain of authentication methods in order:
- Environment variables (
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET,AZURE_TENANT_ID) - Workload Identity (Kubernetes)
- Managed Identity (Azure VMs, App Service, Functions, Container Apps)
- Azure CLI -
az loginon your local machine ✅ - Visual Studio credentials
- VS Code credentials
For local development, simply run az login once:
az login
az account set --subscription "Your Subscription Name"
Then grant your personal Azure account the Key Vault Secrets User role on the Key Vault in the Azure Portal. Your local dev machine will automatically authenticate using your Azure CLI session - no secrets in environment variables needed!
In production on Azure App Service or Azure Container Apps, assign a Managed Identity to your app and grant it Key Vault Secrets User - no credentials needed in production either.
Summary
Azure Key Vault with DefaultAzureCredential gives you a production-grade secrets management solution with minimal code:
- No secrets in source control - only the Key Vault URI is in config
- No secrets on developer machines - Azure CLI auth handles local dev
- No secrets in production environments - Managed Identity handles Azure hosting
- Full audit trail - every secret access is logged in Azure Monitor
- Easy rotation - update the secret in Key Vault, no code changes needed
This pattern scales from a small startup to enterprise - and your future self (and security auditors) will thank you for it.
References
- Quickstart: Azure Key Vault secrets client library for .NET: https://learn.microsoft.com/azure/key-vault/secrets/quick-create-net
DefaultAzureCredentialAPI: https://learn.microsoft.com/dotnet/api/azure.identity.defaultazurecredential- Azure Key Vault RBAC guide: https://learn.microsoft.com/azure/key-vault/general/rbac-guide