Secure Secret Management in ASP.NET Core

published on 25 October 2024

Want to protect sensitive data in your ASP.NET Core apps? Here's what you need to know:

The Quick Version: Your app needs a different secret management approach for development vs production:

  • Development: Use Secret Manager tool
  • Production: Use Azure Key Vault or environment variables
  • Never store secrets in source code or config files

What You'll Learn:

Stage Tool Best For
Development Secret Manager API keys, connection strings
Testing Environment Variables Service credentials
Production Azure Key Vault Encryption keys, passwords

Key Steps to Implement:

  1. Development:
dotnet user-secrets init
dotnet user-secrets set "key" "value"
  1. Production:
builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{vaultName}.vault.azure.net/"),
    new DefaultAzureCredential());

Common Mistakes to Avoid:

  • Storing secrets in source code
  • Using Secret Manager in production
  • Keeping plain text passwords in config files
  • Sharing development secrets across teams

This guide shows you how to set up proper secret management from development through production, with real code examples and step-by-step instructions.

Basics of Secret Management

What Are Secrets?

Secrets in ASP.NET Core apps are sensitive data you need to protect. Think passwords, API keys, and other private info that shouldn't be public.

Here are the main types of secrets you'll deal with:

Secret Type Description Example
API Keys External service tokens auth0:clientId: "x8f9g2h3j4"
Connection Strings Database access info "DbConnection": "Server=myserver;Database=mydb"
Service Credentials System login details "ServiceUser": "admin123"
Encryption Keys Data security keys "EncryptionKey": "base64string..."

How Secret Manager Works

The .NET Secret Manager keeps your secrets in JSON format - far away from your project files. Here's where it stores them:

Operating System Location
Windows %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json
Mac/Linux ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json

"One of the most important features in building secure applications is to make sure that you keep your secrets safe." - Ervis Trupja, Web Developer

Let's break down what you need to know:

Your secrets live as key-value pairs in secrets.json. Here's what that looks like:

{
  "Auth0": {    
    "Domain": "mydomain.auth0.com",    
    "ClientId": "abc123",    
    "ClientSecret": "xyz789"  
  }
}

Quick Setup:

  1. Type dotnet user-secrets init
  2. Add secrets with dotnet user-secrets set "key" "value"
  3. Add setup steps to your README

NEVER put secrets in:

  • Your code
  • Config files
  • Public repos
  • Shared drives

Here's the thing about Secret Manager: It's perfect for development but NOT for production. Why? Because:

  • Secrets aren't encrypted
  • Anyone with machine access can read them

For production, stick to environment variables or secure vaults. Keep those secrets OUT of your app completely.

Setting Up Your Environment

Here's how to set up your development environment from scratch:

Core Tools

You'll need these 3 tools to get started:

Tool Purpose Installation Command
.NET SDK Core development platform winget install Microsoft.DotNet.SDK.7
Visual Studio 2019+ IDE with built-in tools Download from Visual Studio website
Git Version control winget install Git.Git

Project Setup

Let's break this down into simple steps:

1. Create Your Project

Fire up Visual Studio and run:

dotnet new webapi -n SecureSecrets
cd SecureSecrets

2. Add These NuGet Packages

Package Name What It Does
Microsoft.Extensions.Configuration Handles basic configs
Microsoft.Extensions.Configuration.Json Manages JSON files
Microsoft.Extensions.Configuration.UserSecrets Keeps secrets safe

3. Set Up Environment

Windows users:

$Env:ASPNETCORE_ENVIRONMENT = "Development"

Mac/Linux users:

export ASPNETCORE_ENVIRONMENT=Development

4. Update Program.cs

Drop this code into your Program.cs:

var builder = WebApplication.CreateBuilder(args);
builder.Configuration
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", false, true)
    .AddEnvironmentVariables()
    .AddUserSecrets<Program>();

5. Configure Launch Settings

Your launchSettings.json should match this:

{
  "profiles": {
    "Development": {
      "commandName": "Project",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

Scott Hunter, Director of Program Management for .NET, puts it this way: "Setting up proper environment configurations is the first line of defense in securing your application secrets. The environment setup determines how your application handles sensitive data across different stages of development."

Here's the key: Keep your development environment open for testing, but lock down staging and production tight. No exceptions.

Working with Secret Manager

Secret Manager helps you handle sensitive data during ASP.NET Core development. Here's what you need to know:

Setting Up Secret Manager

First, open your terminal and run:

dotnet user-secrets init

This adds to your .csproj file:

<PropertyGroup>
  <UserSecretsId>your-unique-guid-here</UserSecretsId>
</PropertyGroup>

Then, in Program.cs, add:

builder.Configuration.AddUserSecrets<Program>();

Key Commands

Here are the main commands you'll use:

Command What It Does How to Use It
set Adds a secret dotnet user-secrets set "ApiKey" "abc123"
list Shows secrets dotnet user-secrets list
remove Deletes a secret dotnet user-secrets remove "ApiKey"
clear Removes all dotnet user-secrets clear

Want to add multiple secrets? Use JSON:

cat ./secrets.json | dotnet user-secrets set

What You Should Know

Secret Manager has some limits:

What Details
Where It Stores Windows: %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>
Linux/Mac: ~/.microsoft/usersecrets/<user_secrets_id>
Security Not encrypted - don't use in production
Project Scope Tied to your UserSecretsId
When It Works Development mode only

Here's how to use secrets in code:

public class UserCredentials  
{  
    public string UserName { get; set; }  
    public string Password { get; set; }  
}

services.Configure<UserCredentials>(
    configuration.GetSection(nameof(UserCredentials)))
    .AddSingleton(env);

"Secret Manager is for development ONLY. For production, use environment variables, Azure Key Vault, or other secure storage." - Microsoft Docs

Your secrets file structure:

{
  "ConnectionStrings:SQLServerIdentityConnection": "your-connection-string",
  "Facebook:AppId": "your-facebook-id",
  "Facebook:AppSecret": "your-facebook-secret"
}

Setting Up Environment Variables

Here's how to set up environment variables in ASP.NET Core:

Local Development Setup

Start by adding this to your Program.cs:

var configuration = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", false, true)
    .AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true)
    .AddEnvironmentVariables()
    .Build();

Here's how to set variables on different systems:

OS Command Example
Windows CMD set set ConnectionStrings__sqlConnection="server=.\SQLEXPRESS;database=MyApp"
PowerShell $Env: $Env:ASPNETCORE_ENVIRONMENT = "Development"
Linux/Mac export export ConnectionStrings__sqlConnection="server=localhost;database=MyApp"

Using Visual Studio? Add this to launchSettings.json:

{
  "profiles": {
    "WebApi": {
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "ConnectionStrings__DefaultConnection": "Server=localhost;Database=MyApp"
      }
    }
  }
}

Production Setup

Here's what you need for each platform:

Platform Setup Method Notes
Azure App Service Application Settings Overrides local configs
Docker Environment file Use docker-compose.yml
IIS Web.config Under aspNetCore node

For Docker, add this to your file:

environment:
  - ASPNETCORE_ENVIRONMENT=Production
  - ConnectionStrings__DefaultConnection=Server=prod-db;Database=MyApp

For IIS, use this in web.config:

<aspNetCore>
  <environmentVariables>
    <environmentVariable name="ConnectionStrings__DefaultConnection" 
                        value="Server=prod-db;Database=MyApp" />
  </environmentVariables>
</aspNetCore>

Quick tips:

  • Use double underscores (__) for hierarchical keys
  • Set machine-level variables for persistence
  • Drop development settings in production
  • Keep sensitive data OUT of source control
  • Use different variables per environment
  • Store production variables securely
  • Check your environment-specific files

Adding Azure Key Vault

Azure Key Vault

Here's how to use Azure Key Vault to store your app secrets in the cloud with ASP.NET Core.

Set Up Your Key Vault

First, grab these NuGet packages:

dotnet add package Azure.Identity
dotnet add package Azure.Security.KeyVault.Secrets

Head to Azure Portal and create your vault:

Do This Here
Open Azure Portal → Create Resource
Find "Key Vault" in search
Enter Name, subscription, resource group
Finish Hit "Review + Create"

Now connect to your vault:

var client = new SecretClient(
    new Uri("https://<your-vault-name>.vault.azure.net/"),
    new DefaultAzureCredential(),
    new SecretClientOptions {
        Retry = {
            Delay = TimeSpan.FromSeconds(2),
            MaxRetries = 5,
            Mode = RetryMode.Exponential
        }
    }
);

Add this to your Program.cs:

builder.Configuration.AddAzureKeyVault(
    new Uri($"https://{keyVaultName}.vault.azure.net/"),
    new DefaultAzureCredential());

Set Up Managed Identities

Managed identities let you skip storing credentials. Here's what to do:

Action Run This
Set up identity az webapp identity assign --name "<app-name>" --resource-group "<group-name>"
Set permissions az role assignment create --role "Key Vault Secrets User" --assignee "<app-id>" --scope "<vault-resource-id>"

In Key Vault, add these permissions:

  • Get Secrets
  • List Secrets

Get your secrets in code:

var secretClient = new SecretClient(
    new Uri("<vault-url>"),
    new DefaultAzureCredential());

KeyVaultSecret secret = await secretClient.GetSecretAsync("<secret-name>");
string secretValue = secret.Value;

Quick tips:

  • Pick system-assigned identities for single apps
  • Set up retry logic for network hiccups
  • Store vault URLs in config
  • Double-check secret access after setup
sbb-itb-29cd4f6

Secret Management Tips

Here's how to keep your app's secrets safe and secure in ASP.NET Core:

Encrypting Config Values

ASP.NET Core gives you several ways to protect sensitive data. Here's what works best for different types of secrets:

Data Type Protection Method Usage
Authentication Cookies Built-in DPAPI ASP.NET Core handles this automatically
Connection Strings Azure Key Vault Keep them safe in the cloud
API Keys Environment Variables Isolate at the process level
User Secrets Secret Manager Local dev only - don't use in production

Using AWS? Here's how to encrypt with KMS:

aws kms encrypt --cli-binary-format raw-in-base64-out --key-id "key-id" --plaintext "YOUR_SECRET"

Then pop the encrypted value in your config:

{
  "Database": {
    "Password": "AQICAHhDR/VQh6Ap...rfyKsKCG2h6WVK8="
  }
}

Setting Up Access Rules

Here's what you NEED to do to lock down your secrets:

Rule What to Do
Separate Environment Secrets Use different secrets for each environment
Key Rotation Switch secrets every 90 days
Access Logging Track who's accessing what
Least Privilege Give only the access that's needed

"Never store passwords or other sensitive data in source code." - Microsoft Learn

Keep your secrets safe:

  • Add appsettings.json and .env to .gitignore
  • Use your OS's key vault
  • Create separate apps for key generation
  • Watch those production logs

"The Secret Manager tool doesn't encrypt the stored secrets and shouldn't be treated as a trusted store." - Microsoft Learn

When working with other services:

Service What to Do
Azure Resources Key Vault + managed identities
Database Access Encrypt those connection strings
API Integration Change keys without touching the app
User Authentication Set up ASP.NET Core Identity right

Testing Your Setup

Here's how to test if your secrets work correctly.

Writing Tests for Secrets

Here's what you need to set up tests:

Test Type Setup Method Example
Unit Tests .runsettings file Define variables in XML configuration
Integration Tests Environment Variables Set via dotnet test command
Azure Key Vault Tests Managed Identity Use test instance of Key Vault

Here's a simple test with xUnit and Shouldly:

public class SecretTests
{
    private readonly IConfiguration _config;

    public SecretTests(IConfiguration config)
    {
        _config = config;
    }

    [Fact]
    public void ShouldRetrieveSecret()
    {
        _config.GetValue<string>("MySecret").ShouldNotBeNull();
    }
}

For VS Code, add this to .vscode/settings.json:

{
    "csharp.unitTestDebuggingOptions": {
        "env": {
            "MySecret": "test-value"
        }
    }
}

Security Checks

Make sure your secrets are safe with these checks:

Check How to Test Pass Criteria
Access Control Try accessing with wrong permissions Access denied
Environment Isolation Check each environment's secrets Different values per environment
Key Vault Integration Test managed identity access Successful secret retrieval
User Secrets Move connection string to secrets App connects to database

Test Azure Key Vault access like this:

public class KeyVaultTests
{
    [Fact]
    public async Task ShouldAccessKeyVault()
    {
        var client = new SecretClient(
            new Uri("https://your-vault.vault.azure.net/"), 
            new DefaultAzureCredential());

        var secret = await client.GetSecretAsync("test-secret");
        Assert.NotNull(secret.Value);
    }
}

After testing:

  • Delete test secrets from Key Vault
  • Clear environment variables
  • Reset user secrets
  • Remove test certificates

"The User Secrets file is located outside the project path, reducing the risk of sensitive data being checked into source control." - Microsoft Learn

Next Steps

Here's what you need to do after setting up your secrets:

Action What to Do When
Rotate Secrets Switch out API keys and passwords Every 60 days
Check Access Update Key Vault access rules Monthly
Watch Costs Check Key Vault usage ($0.03/10K requests) Weekly
Check Security Look for weird access patterns Daily

Keep Your Setup Running Smooth

1. Watch Your Spending

Here's a heads up: Key Vault costs can sneak up on you. If you check for new values 12 times per minute, that's 518,400 monthly requests. At $0.03 per 10,000 requests, you're looking at $1.56 per secret.

2. Lock Down Your Access

What to Set Up Where to Do It What It Does
Firewall Azure Portal Blocks unwanted IPs
RBAC Azure AD Sets who gets in
Access Rules Key Vault Controls app access
Delete Protection Key Vault Settings Stops accidents

3. Split Up Your Environments

Keep things separate and clean:

Environment Name It Who Gets In
Dev dev-kv-[app] Dev team
Test test-kv-[app] QA folks
Production prod-kv-[app] Admins only

Set It Up in PowerShell

PowerShell

Here's the code to load your secrets from JSON:

$json = Get-Content 'C:\\SecretPath\\secret.json' | ConvertFrom-Json  
foreach($parentProp in $json.PSObject.Properties){  
    foreach($childProp in $parentProp.Value.PSObject.Properties){  
        $envVarName = $parentProp.Name + '__' + $childProp.Name  
        [System.Environment]::SetEnvironmentVariable($envVarName, $childProp.Value, 'Machine')  
    }  
}

Quick Tips

  • Each environment needs its own secrets
  • Look at your access logs every day
  • Clean up old secrets after you change them
  • Keep your IIS variables up to date
  • Track what you're spending in Azure

For IIS? Name your variables like this: [object]__[property] (Like ConnectionStrings__MyDBContext)

FAQs

What is the secret manager tool in an ASP.NET Core project?

ASP.NET Core

The Secret Manager tool in ASP.NET Core helps you store sensitive data while you're building your app. It puts your secrets in a JSON file at %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json on Windows - away from your project files.

Think of it like a safe for your development passwords and API keys. It's NOT for production use - just for when you're coding.

How to store secrets in production environment?

Here's what you should use in each environment:

Environment Storage Method Why It Works
Development Secret Manager Tool Keeps secrets off GitHub
Testing Azure Key Vault Controls who gets access
Production Environment Variables or Azure Key Vault Locks down secrets at server level

"Don't bundle secrets with your app code. In production, get them through environment variables or Azure Key Vault." - CyberArk Developer

What's the real difference between user secrets and environment variables?

Let's break it down:

Feature User Secrets Environment Variables
Where It's Stored Local JSON file Server-level
Security Type Plain text, your machine only Plain text, whole system
When to Use While coding In production
Who Controls It Just you System-wide

Here's the bottom line: User secrets are ONLY for development. They're perfect when you're coding, but NOT for your live app.

"The Secret Manager tool is built for one thing: keeping sensitive data safe during development." - Ottorino Bruni, Author

Related posts

Read more