Azure  

Secure Secrets Management in ASP.NET Core: User Secrets, Azure Key Vault, and Production Best Practices

Every ASP.NET Core application depends on secrets. Database connection strings, API keys, JWT signing keys, OAuth client secrets, SMTP credentials, and cloud service tokens are all essential for application functionality. Unfortunately, these secrets are also among the most common causes of security incidents when they are accidentally committed to source control or exposed through insecure configuration.

Hardcoding secrets in configuration files or source code may seem convenient during development, but it creates significant security risks in production. ASP.NET Core provides a flexible configuration system that enables developers to manage secrets securely across development, testing, and production environments.

In this article, you'll learn how to manage secrets securely using User Secrets during development, Azure Key Vault in production, and configuration best practices that help protect sensitive information throughout the application lifecycle.

Why Secrets Management Matters

The Risks of Hardcoding Secrets

Consider the following configuration:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=sql01;Database=SalesDb;User Id=admin;Password=P@ssw0rd!"
  }
}

Although this works, storing credentials directly in configuration files introduces several risks:

  • Accidental commits to Git repositories

  • Exposure through backups

  • Shared development credentials

  • Difficult secret rotation

  • Increased security audit findings

Sensitive information should never be stored directly in application source code or tracked configuration files.

Understanding ASP.NET Core Configuration

ASP.NET Core loads configuration from multiple providers.

Typical configuration sources include:

  • appsettings.json

  • appsettings.{Environment}.json

  • Environment variables

  • User Secrets

  • Azure Key Vault

  • Command-line arguments

Configuration providers are layered, allowing secure values to override default settings without modifying application code.

Using User Secrets During Development

User Secrets provide a secure location for development-only configuration.

Initialize User Secrets:

dotnet user-secrets init

Store a connection string:

dotnet user-secrets set "ConnectionStrings:DefaultConnection" "Server=localhost;Database=SalesDb;Trusted_Connection=True;"

Read the value normally:

var connectionString =
    builder.Configuration
        .GetConnectionString("DefaultConnection");

Why Use User Secrets?

User Secrets store sensitive values outside the project directory.

This prevents accidental commits while allowing developers to access configuration through the standard ASP.NET Core configuration system without changing application code.

Using Environment Variables

Production environments often inject secrets through environment variables.

Example:

ConnectionStrings__DefaultConnection

ASP.NET Core automatically maps double underscores (__) to nested configuration keys.

Why Environment Variables?

Environment variables separate configuration from application binaries.

They work well with:

  • Docker

  • Kubernetes

  • Azure App Service

  • GitHub Actions

  • Azure DevOps

  • CI/CD pipelines

This approach simplifies deployment while avoiding sensitive configuration files.

Integrating Azure Key Vault

Azure Key Vault centralizes secret management for production applications.

Register Key Vault during startup.

builder.Configuration.AddAzureKeyVault(
    new Uri(builder.Configuration["KeyVault:VaultUri"]!),
    new DefaultAzureCredential());

Why Azure Key Vault?

Azure Key Vault provides:

  • Secure secret storage

  • Automatic secret rotation

  • Centralized management

  • Access policies

  • Audit logging

  • Hardware-backed protection options

Instead of distributing secrets across multiple servers, applications retrieve them securely at runtime.

Accessing Secrets

Once configuration providers are registered, consuming secrets remains identical regardless of their source.

var apiKey =
    builder.Configuration["PaymentGateway:ApiKey"];

Why Is This Important?

Business code does not need to know where a secret originates.

Whether the value comes from User Secrets, an environment variable, or Azure Key Vault, the application accesses it through the same configuration API.

This keeps application code simple while allowing deployment environments to determine how secrets are supplied.

End-to-End Implementation

Consider a cloud-hosted order management system.

Architecture:

Developer
     │
User Secrets
     │
     ▼
ASP.NET Core Application
     │
Configuration System
     │
     ▼
Azure Key Vault
     │
     ▼
SQL Database
Payment Gateway
Storage Account

Workflow:

  1. Developers use User Secrets during local development.

  2. The application reads configuration through the standard configuration system.

  3. In production, secrets are retrieved from Azure Key Vault.

  4. Managed identities authenticate the application without storing credentials.

  5. Business services consume secrets without knowing their underlying source.

This approach provides a consistent programming model while significantly improving security across environments.

Secret Rotation

Production secrets should never remain unchanged indefinitely.

A typical rotation process includes:

  1. Create a new secret.

  2. Update the secure secret store.

  3. Restart or refresh application configuration if required.

  4. Validate application functionality.

  5. Remove the old secret.

Planning for secret rotation reduces operational risk and supports security compliance requirements.

Configuration Source Comparison

Configuration SourceDevelopmentProductionRecommended
appsettings.jsonYes (non-sensitive settings)LimitedYes
User SecretsYesNoYes
Environment VariablesYesYesYes
Azure Key VaultOptionalYesYes
Hardcoded ValuesNoNoNever

Each configuration provider serves a specific purpose, but sensitive production credentials should always be stored in a secure secret management solution.

Best Practices

  • Never commit secrets to source control.

  • Use User Secrets for local development.

  • Store production secrets in Azure Key Vault or an equivalent secret manager.

  • Use managed identities whenever possible.

  • Rotate secrets regularly.

  • Restrict access using the principle of least privilege.

  • Separate application configuration from secret values.

  • Audit secret access.

  • Remove unused credentials promptly.

Common Mistakes

One common mistake is storing production credentials in appsettings.json. Even private repositories can become compromised, making tracked configuration files an unsuitable location for secrets.

Another issue is sharing the same credentials across development, testing, and production environments. Each environment should use separate credentials to reduce the impact of accidental exposure.

Developers also sometimes hardcode API keys directly into application code during testing and forget to remove them before deployment.

Testing and Validation

Before deploying an application, validate the following:

  • User Secrets load correctly during development.

  • Environment variables override default configuration.

  • Azure Key Vault connectivity succeeds.

  • Managed identity authentication works.

  • Missing secrets generate meaningful errors.

  • Secret rotation procedures are documented.

  • Access permissions follow least-privilege principles.

  • Configuration works consistently across environments.

Automated deployment validation helps identify configuration issues before applications reach production.

Performance Considerations

Secret retrieval generally occurs during application startup or configuration loading, resulting in minimal runtime overhead.

To maintain good performance:

  • Avoid repeatedly requesting secrets.

  • Cache configuration values where appropriate.

  • Use managed identities to simplify authentication.

  • Monitor Key Vault latency.

  • Minimize unnecessary configuration lookups.

  • Handle temporary connectivity failures gracefully.

Security should never be sacrificed for marginal performance gains.

Security Considerations

Secrets management is only one part of an application's overall security posture.

Follow these recommendations:

  • Encrypt communication using HTTPS.

  • Enable audit logging for secret access.

  • Protect managed identities.

  • Restrict Key Vault permissions.

  • Remove unused secrets.

  • Monitor unusual access patterns.

  • Enable backup and recovery for secret stores.

  • Include secret management in regular security reviews.

Strong operational practices are just as important as secure storage.

Troubleshooting

Secret Value Is Missing

Verify that the correct configuration provider is registered and that the expected configuration key exists in the current environment.

Azure Key Vault Access Fails

Confirm that the application's managed identity or service principal has permission to read secrets from the vault.

Incorrect Configuration Is Loaded

Review the configuration provider order. Later providers override earlier ones, so provider registration order directly affects which values are returned.

Development Configuration Works but Production Fails

Ensure production secrets exist in the secure secret store and that environment-specific configuration is correctly deployed.

Conclusion

Managing secrets securely is a fundamental requirement for production ASP.NET Core applications. User Secrets provide a safe development experience, environment variables simplify cloud deployments, and Azure Key Vault offers centralized, enterprise-grade secret management for production environments. By separating secrets from application code, planning for secret rotation, and following secure configuration practices, developers can build applications that are easier to manage, more secure, and better prepared for modern deployment environments.