Secret Management in .NET Core

AZHARUL | 06-Nov-2024 09:32:07 AM | Time to read: 8 Min

In software development, secret management refers to securely storing and accessing sensitive data like passwords, API keys, and connection strings. .NET Core provides tools like secrets.json and Azure Key Vault for developers to securely manage these secrets without hardcoding them into their applications.

Why is it essential? Hardcoding secrets in source code or configuration files (like appsettings.json) that are tracked in source control can expose sensitive information. With secret management, we can separate sensitive data from application code.

This blog explains how .NET Core provides secret management capabilities to securely handle such information using tools like user secrets (for local development) and Azure Key Vault (for production-grade security). You’ll learn when to use each tool and how to seamlessly access these secrets in your applications.

 

Why Use secrets.json When We Have appsettings.json?

Though appsettings.json holds configuration data, it is meant for non-sensitive, application-specific settings, such as API base URLs, default settings, or application modes.

Key reasons for using secrets.json for sensitive data:

  • Security: Sensitive information in secrets.json is not stored in source control, protecting it from unauthorized access.
  • Environment-Specific: Each developer can have unique secrets on their local machine without affecting others.
  • Overriding Behavior: Secrets in secrets.json override values in appsettings.json during development, making it easy to test local configurations.

 

Secret Management Using secrets.json in .NET Core

The secrets.json file stores secrets locally in a secure, file-based store specific to each user. Here’s how to manage secrets with secrets.json.

Step-by-Step Example:

Create a New .NET Core Project:

  • Open Visual Studio and create a new ASP.NET Core Web Application.
  • Select Empty or Web API as the project template and set a name for your project.

Enable User Secrets:

· Right-click your project in Solution Explorer.

·  Select Manage User Secrets. Visual Studio will create-

  1.  a unique UserSecretsId in your .csproj file.
  2. a secrets.json blank file outside the project directory in %APPDATA%\Microsoft\UserSecrets\your-app-guid\secrets.json (on Windows).
<PropertyGroup>
  <UserSecretsId>your-app-guid</UserSecretsId>
</PropertyGroup>

 

Add Secrets to secrets.json:

  • In Visual Studio, right-click the project in Solution Explorer, then select Manage User Secrets. This action opens secrets.json file which is linked to your project.
{
  "ConnectionStrings": {
    "DefaultConnection": "Server=myServer;Database=myDB;User=myUser;Password=myPassword;"
  },

  "ApiKeys": {
    "GoogleMaps": "YOUR_GOOGLE_MAPS_API_KEY"
  }
}

 

Access Secrets in Code: To access secrets from secrets.json, inject IConfiguration directly into the HomeController. In this example, we use HomeController to retrieve secrets, but you could also inject IConfiguration into any other class in your project, such as a service or repository class, depending on your project’s structure and requirements.

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;

public class HomeController : Controller
{
    private readonly IConfiguration _configuration;
    public HomeController(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public IActionResult Index()
    {
        var connectionString = _configuration["ConnectionStrings:DefaultConnection"];
        var googleMapsKey = _configuration["ApiKeys:GoogleMaps"];

        return Content($"Database: {connectionString}, Google Maps Key: {googleMapsKey}");
    }
}

 

Run the Application:

  • Start the project to see if secrets are loaded correctly without exposing sensitive values directly in code or appsettings.json.

 


 

Secret Management Using Azure Key Vault in .NET Core

Azure Key Vault is a secure cloud storage solution that centralizes secret management and allows you to securely store secrets, keys, and certificates. It’s recommended for production as it provides higher security and access management.

  • Setting Up Azure Key Vault

To use Key Vault, you need an Azure account. Here’s how to integrate it into your .NET Core application:

  1. Create an Azure Key Vault in the Azure portal.
  2. Add Secrets: Navigate to the Key Vault in Azure, select Secrets, and create secrets like ConnectionStrings--DefaultConnection or ApiKeys--ThirdPartyService.
  3. Set Up Authentication: You can use DefaultAzureCredential for local development and deployment environments if you've configured Azure credentials in your environment or for Managed Identity in Azure services.
  • Configure Key Vault in Program.cs

Install the Azure.Extensions.AspNetCore.Configuration.Secrets NuGet package:

dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets

 

In Program.cs, add Key Vault to the configuration:

using Azure.Identity;

var builder = WebApplication.CreateBuilder(args);

builder.Configuration.AddAzureKeyVault(
    new Uri("https://<Your-KeyVault-Name>.vault.azure.net/"),
    new DefaultAzureCredential());

var app = builder.Build();

Here, replace <YourVaultName> with your actual Key Vault name.

 

  • Accessing Secrets from Key Vault in Code

Access secrets using IConfiguration the same way as with user secrets:

public class MyService
{
    private readonly IConfiguration _configuration;
    public MyService(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public string GetApiKey()
    {
        return _configuration["ApiKeys:ThirdPartyService"];
    }
}

 

Environment-Specific Secret Management

.NET Core supports environment-specific configurations, allowing the application to load different secrets for Development, Staging, or Production.

Managing Secrets by Environment:
  • Development: Use secrets.json for local, non-production secrets. This allows developers to have their own environment-specific configurations.
  • Staging and Production: Use Azure Key Vault to secure secrets centrally, as they are shared by multiple developers.

Example:

To set up environment-specific configurations, you can conditionally add sources in Program.cs based on the environment:

var builder = WebApplication.CreateBuilder(args);

if (builder.Environment.IsDevelopment())
{
    builder.Configuration.AddUserSecrets<Program>();
}
else
{
    builder.Configuration.AddAzureKeyVault(new Uri("https://<YourVaultName>.vault.azure.net/"), new DefaultAzureCredential());
}

 

Best Practices for Secret Management

  1. Avoid Hardcoding Secrets: Never hardcode sensitive information directly in code or in appsettings.json.
  2. Limit Access to Secrets: Use role-based access in Azure Key Vault to limit who can access production secrets.
  3. Secure Local Secrets: Use secrets.json for local development only and avoid adding sensitive information to shared configuration files.
  4. Rotate Secrets Regularly: Ensure periodic rotation of secrets, especially for high-security applications.
  5. Audit Secret Access: Use Azure Key Vault logs to monitor who accesses secrets, especially in production.

 

Secret management in .NET Core, through User Secrets and Azure Key Vault, provides a robust way to protect sensitive information from exposure. By using User Secrets for development and Azure Key Vault for production, .NET Core developers can ensure secure management of sensitive configurations while maintaining easy access in their applications.

For real-life applications, keep local settings in appsettings.json or secrets.json and use Azure Key Vault for production to balance convenience and security effectively.

 


 

Still need appsettings.json ?

if you use secrets.json, you still typically need appsettings.json. Here’s how they work together:

Purpose:

  • appsettings.json holds non-sensitive, shared configuration data for your application, such as application settings, logging configurations, and other general information.
  • secrets.json, on the other hand, is specifically for sensitive data (e.g., connection strings, API keys) that you don’t want in source control.

Complementary Use:

  • appsettings.json is checked into source control, so it’s accessible to everyone working on the project.
  • secrets.json is excluded from source control and is stored only on your local machine, allowing you to store local, sensitive values securely during development.

Configuration Hierarchy:

  • When both appsettings.json and secrets.json are used, .NET Core merges configurations, with secrets.json taking priority for any overlapping keys. This means secrets in secrets.json will override values in appsettings.json.

For instance, you might keep a placeholder in appsettings.json:

"ConnectionStrings": {
    "DefaultConnection": "YourConnectionStringPlaceholder"
}

 

And then define the actual connection string in secrets.json:

"ConnectionStrings": {
    "DefaultConnection": "Server=myServer;Database=myDB;User Id=myUser;Password=myPassword;"
}

 

This setup ensures that the sensitive values in secrets.json override the placeholders in appsettings.json and that sensitive information is kept secure during development.

 

If you found this blog helpful, please share it with your peers and colleagues. Don't forget to subscribe to our YouTube channel(Visit Codexoom on YouTube) for more tutorials on ASP.NET Core and professional software development tips!

Thank you for joining us, and as always, happy coding! Until next time, stay curious and keep building amazing things. Take care!