The best way to store secrets in your app is not to store secrets in your app
Almost every web application needs some kind of secrets like a SQL Database connection string or the primary key of a Storage Account to communicate with external services.
Certainly, we don’t store these secrets within our source code since this would expose them to every developer that has access to the code. In Azure we could store the secrets within the Application Settings in the Azure Portal:
But if a secret is used in multiple applications and we need to change it (e. g. regenerate a storage account key) we would have to do that in multiple places. A better place to store secrets in Azure is the Key Vault.
Instead of storing each secret within our app we store them in the Key Vault and configure our app to access the secrets in the vault. Now we have a single place where we can manage our secrets.
Let’s take a look at how we can access those secrets in an ASP.NET Core 2.0 web application without introducing a dependency to Key Vault in the class that uses it. To create a vault, store secrets to it and create a service principal for the access policy see Get started with Azure Key Vault.
Our secret is stored in a class called ValueSettings
:
public sealed class ValueSettings { public string TestSecret { get; set; } }
There is a ValuesController
with one HttpGet
method that returns our secret:
[Route("api/[controller]")] public class ValuesController : Controller { private readonly ValueSettings _valueSettings; public ValuesController(IOptions valueSettings) { _valueSettings = valueSettings.Value; } [HttpGet] public IActionResult Get() { return Ok(_valueSettings.TestSecret); } }
As you can see in line 6 the controller uses the options pattern to inject the actual settings. The controller doesn’t know where the secret is coming from and doesn’t have any dependencies to Azure Key Vault.
Now, let’s take a look at how we need to configure our application for that. First, we need to store the vault settings in our appsettings.json:
{ "KeyVault": { "Vault": "https://myvault.vault.azure.net/", "ClientId": "myclientid", "ClientSecret": "myclientsecret" } }
We also have a class that represents these settings:
public class KeyVaultSettings { public string Vault { get; set; } public string ClientId { get; set; } public string ClientSecret { get; set; } }
Now to configure the key vault we use the AddAzureKeyVault
extension method in the Programm.cs:
public class Program { public static void Main(string[] args) { BuildWebHost(args).Run(); } public static IWebHost BuildWebHost(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((context, config) => { config.SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json", optional: false) .AddEnvironmentVariables(); var builtConfig = config.Build(); var settings = builtConfig.GetSection("KeyVault").Get(); config.AddAzureKeyVault( settings.Vault, settings.ClientId, settings.ClientSecret); }) .UseStartup() .Build(); }
You can download the complete example from my GitHub repository.