ASP.NET Best Way to Store Secrets
All over the development world, we use configuration files to store important values for our applications. Values differ from each other, and some require to be stored in a secure way. Such as database credentials or AUTH secrets.
Introduction
Our goal in this article is to review common types where we can store values and what benefits we can get with each way. In the begging, we should understand the reason why we need to make all these efforts to store credentials or other secrets especially. It`s too dangerous to add secrets directly to config files and push these changes to the control version system (CVS) such as git.
It is pretty simple to answer this question. All developers who will work on a project get access to the secret values. You can be sure in your team that they never reveal internal company`s data to others, but their working machines could be hacked in different ways. The best practice would be to separate code and secret configuration values.
But we need access to these values for our application. .NET provides a few values on how we can separate secrets from code.
- Generate configuration file during deployment and add it to deploy artifacts. ( it`s not a .net feature, as you can understand )
- Environment variables
- Azure Key Vault
Generate configuration file during deployment
This flow requires additional efforts to maintain secrets. The responsible person who will do it will have access to all secrets, and it is still a vulnerability of all projects. Such files could be generated per environment, and a dev version could be added to CVS to help developers run the project on a local machine without additional efforts.
Environment variables
We need to define instruction for developers on variables they need to set up in the local environment. Also, the DevOps team is responsible for proper maintenance of these secrets and proper rotation of them.
Azure Key Vault
This way stores secrets in Azure, and as a single source of truth, it provides good practices to rotate secret values and store them encrypted.
Hands-On
In order to follow examples, you need to add the next packages to your solution:
Microsoft.Extensions.Configuration — a base package that contains classes to work with configuration.
Microsoft.Extensions.Configuration.Binder — gives a convenient way to get typed values from configuration.
Microsoft.Extensions.Configuration.Json — allows loading JSON configuration files.
Microsoft.Extensions.Configuration.AzureKeyVault — adds azure key vault provides to configuration.
Azure.Extensions.AspNetCore.Configuration.Secrets — this package allows reading secrets from the azure key vault.
Azure.Identity — contains authentication classes that are used to access the key vault.
Let`s run the following commands in the console to add packages to the project:
1 | dotnet add package Microsoft.Extensions.Configuration |
The configuration file has a simple structure with the default configuration:
1 | { |
Don`t forget to update file properties and copy the file into the output directory:
1 | using Azure.Extensions.AspNetCore.Configuration.Secrets; |
Let`s review an example to understand what happens.
We create ConfigurationBuilder and add 2 provides one that allows us to read values from JSON files. And we can grab a configuration that is stored directly in JSON without any request to Azure. Also, we added AzureKeyVaultProvider, and now our configuration can read secrets from Azure. To properly configure AzureKeyVaultProvider, we need to pass the key vault URL and credentials, which should be used to access the key vault.
You can check how DefaultAzureCredential works in the next image:
As you can notice, an additional configuration was provided to AzureKeyVaultProvider that tells to reload settings from KeyVault every 3 seconds. Please be careful with this configuration. Azure changes 0.03$ per 10k requests at the moment of writing the article. The application will check for new value in Azure for key 12 times per minute. With simple math calculations:
12 * 60 min * 24hours * 30 days = 518400 requests / 10000 * 0.03 = 1.5552$ per month.
It`s just for a single secret and single application instance per month.
Also, you should remember that in order to map the JSON setting page in Azure, you should follow the dash notation as in the following image:
Conclusion
If you are going to host your application in Azure, it`s better to follow best practices and store your secrets in Azure Key Vault. Just be aware of how often your application loads data from the key vault because it can increase your monthly bill. Good luck.