This is the fifth of a new series of posts on ASP .NET Core. This week, we’ll be looking at app secrets for ASP .NET Core projects, for use in development environments.
Protecting Application Secrets During Development
Most web apps need to store some configuration information that can be accessed by the application during runtime. This may include database connection strings and API keys, which are not user-specific confidential values, but are still sensitive pieces of information that need to be protected.
Once in a while, a developer may accidentally commit such sensitive information to public repositories such as Github. Quoting this blog post from the Azure website, “Keep in mind that removing a published secret does not address the risk of exposure. The secret may have been compromised, with or without your knowledge and is still exposed in Git History. For these reasons, the secret must be rotated and/or revoked immediately to avoid security risks.”
This blog post intends to prevent you from ever making that mistake in the first place. You may download the following sample project to follow along.
AppSecretDemo: https://github.com/shahedc/AppSecretDemo
Ways to Protect your Secrets
When I first started this blog in 2013, I published a blog post about protecting your web application secrets, “All Your Database Are Belong To Us!”. This post went into detail about setting up separate config files for each environment (Debug/Release/etc) and then explained how to use the configSource property in the XML-based configuration file to hide developer-specific settings.
<connectionStrings configSource="ConnectionStrings.config"> </connectionStrings>
This approach requires some initial setup and would still require each developer to maintain these settings in the same location of their source code, while hiding the secret settings file from Source Control.
With ASP .NET Core, it’s much easier to use App Secrets to store such configuration information. Your team can decide on some common terms such as SecretConnString and SecretApiKey, while each developer maintains the values in their local App Secrets.
IMPORTANT: Please note that App Secrets should never be used to store passwords or sensitive data. Also, do not use production secrets in dev/staging/testing environments.
Secret Manager and User Secrets
Before you use the Secret Manager for your ASP .NET Core application, I would suggest peeking into your file system to see where the secrets are being stored. Depending on your operating system, this location may vary.
Windows File system path: %APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json MacOS X File system path: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json Linux File system path: ~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
So what is the value for <user_secrets_id>? You can automatically generate this alphanumeric id in Visual Studio by right-clicking your project in Solution Explorer and then selecting Manage User Secrets from the popup context menu.
Take a look at the following sample project to see what it looks like:
- AppSecretDemo project file: https://github.com/shahedc/AppSecretDemo/blob/master/AppSecretDemo.csproj
<PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> <UserSecretsId>aspnet-AppSecretDemo-BBE1E521-9552-49CD-AE15-5EBB308A44E7</UserSecretsId> </PropertyGroup>
On my local development machine, the Secret Manager stores the secret values in the following location:
C:\Users\<username>\AppData\Roaming\Microsoft\UserSecrets\aspnet-AppSecretDemo-BBE1E521-9552-49CD-AE15-5EBB308A44E7
I would recommend using the dotnet CLI commands to set your secret values, as this approach will also help you work in any environment, e.g. Visual Studio Code. If you don’t auto-generate the UserSecretsId, you could manually add the Id yourself in the .csproj file using a GUID of your own choice.
CLI Commands for User Secrets
To add new secret values, I could edit the aforementioned secrets.json file for my application. But personally, I prefer to use the CLI. Here are some common CLI commands you can use.
To set some values:
> dotnet user-secrets set "SecretValues:SecretApiKey" "0123456" > dotnet user-secrets set "SecretValues:SecretConnString" "secret-conn"
Your secrets.json file may look like the following sample, shown below. Note that the values have been flattened instead of showing as nested JSON values. If you were to manually edit the file in Visual Studio (or any text editor), you could introduce a cleaner nested format if you wish. But I would suggest letting the user-secrets CLI tool pick the format it wants.
{ "SecretValues:SecretApiKey": "0123456", "SecretValues:SecretConnString": "secret-conn" }
To view the current list of values:
> dotnet user-secrets list
To remove a specific value:
> dotnet user-secrets remove "SecretValues:SecretApiKey"
To clear ALL values:
> dotnet user-secrets clear
BUT WAIT… where is the project name here? Which project does it clear values for? Typically, you would run this command in a specific folder location that contains your .csproj file. To run against a specific project in a specified folder, use the ––project flag followed by the complete path to the desired project folder.
> dotnet user-secrets set "SecretValues:ServiceApiKey" "0123456" --project "<project_location>"
Retrieving the Values
You may retrieve the values via a Configuration object of type IConfiguration. Below are a couple of examples of this.
In the Startup.cs class, you can retrieve Configuration values during app startup in the ConfigureServices() method.
using Microsoft.Extensions.Configuration; ... public class Startup { private string _SecretApiKey = null; private string _SecretConnString = null; public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } ... public void ConfigureServices(IServiceCollection services) { ... _SecretApiKey = Configuration["SecretValues:SecretApiKey"]; _SecretConnString = Configuration["SecretValues:SecretConnString"]; } ... }
For more information, check out the “Convenience Methods” section at the following URL:
- App startup in ASP .NET Core: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-2.1#convenience-methods
Within a Razor page or MVC View, you can inject an IConfiguration object to access @Configuration within the View itself. Take a look at the Index.cshtml page in the sample to see how it works.
@page @model IndexModel @using Microsoft.Extensions.Configuration @inject IConfiguration Configuration <ul> <li>API Key: @Configuration["SecretValues:SecretApiKey"]</li> <li>Conn String: @Configuration["SecretValues:SecretConnString"]</li> </ul>
For more information, check out the official documentation at the following URL:
- Access config in a Razor Page or MVC View: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1
NOTE: For obvious reasons, please don’t display your secret values in a real-world application. 🙂
Next Steps: Deploying to the Cloud
Once you have your User Secrets set up in your development environment, you may have realized that none of the above will work for a cloud-deployed Web App in Azure. Fortunately, there are some great options for you in Azure.
You can use Azure Key Vault to store and retrieve your application secrets safely:
- Azure Key Vault: https://docs.microsoft.com/en-us/azure/key-vault/
For a detailed tutorial on how to use Azure Key Vault for your ASP .NET Core webapp, check out the following tutorial in the official documentation at:
- App Settings in Key Vault: https://docs.microsoft.com/en-us/azure/key-vault/vs-secure-secret-appsettings
This approach will allow you to continue using User Secrets in development and use Azure Key Vault in a cloud-deployed environment.
To host your web app in an on-prem environment with IIS, you can use environment variables for your environment, or set up app secrets on your own server, if you have access to do so.
If you’re interested in reading about what others are doing, check out these StackOverflow answers:
- Prod Secrets in ASP .NET Core 2.x: https://stackoverflow.com/a/49880148/482200
- Non-Azure ASP .NET Core Secrets: https://stackoverflow.com/a/50502721/482200
References
- Securely saving secret application settings for a web application (in Azure): https://docs.microsoft.com/en-us/azure/key-vault/vs-secure-secret-appsettings
- Configure an Azure web application to read a secret from Key vault tutorial: https://docs.microsoft.com/en-us/azure/key-vault/tutorial-web-application-keyvault
- Safe storage of app secrets in development in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=windows
- Configuration in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-2.1
- Convenience Methods for App startup in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-2.1#convenience-methods
Pingback: Dew Drop - November 5, 2018 (#2838) - Morning Dew
Pingback: Szumma #134 – 2018 44. hét – ./d/fuel
When I try to use `dotnet user-secrets set` commands from outside a project directory I get an error that says “Could not find a MSBuild project file” and it wants me to specify one. Make sure you are in the project directory when issuing the commands.
Take a look at the section above that says “To run against a specific project in a specified folder, use the ––project flag followed by the complete path to the desired project folder.” Please note that there are 2 hyphens in front of ––project to specify the full project folder path.
For more information, read the “Set a secret” section in the official docs:
https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-2.1&tabs=windows#set-a-secret
thank you @shahedc, We needed something like this when we had an initiation secure all our applications.
You’re welcome, thanks for reading!
Pingback: Generic Host Builder in ASP .NET Core | Wake Up And Code!
Pingback: Key Vault for ASP .NET Core Web Apps | Wake Up And Code!
Pingback: Logging in ASP .NET Core | Wake Up And Code!
Pingback: Production Tips for ASP .NET Core Web Apps | Wake Up And Code!
how could i download the book
The 2019 ebook is available for download from the release announcement:
https://wakeupandcode.com/release-asp-net-core-a-z-ebook/
A direct link to the PDF version can be accessed via the following link:
http://bit.ly/aspnetcore-pdf
Pingback: ASP .NET Core code sharing between Blazor, MVC and Razor Pages | Wake Up And Code!
Pingback: Generic Host Builder in ASP .NET Core 3.1 | Wake Up And Code!
Pingback: Key Vault for ASP .NET Core 3.1 Web Apps | Wake Up And Code!
Pingback: Logging in ASP .NET Core 3.1 | Wake Up And Code!
Pingback: Production Tips for ASP .NET Core 3.1 Web Apps | Wake Up And Code!