Your Web App Secrets in ASP .NET Core

By Shahed C on November 4, 2018

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.

ASPNETCoreLogo-300x267

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.

Web 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.

Right-click project in Solution Explorer and click Manage User Secrets

Right-click project in Solution Explorer and click Manage User Secrets

Take a look at the following sample project to see what it looks like:

 <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:

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:

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:

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:

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:

References

 

17 thoughts on “Your Web App Secrets in ASP .NET Core

  1. Pingback: Dew Drop - November 5, 2018 (#2838) - Morning Dew

  2. Pingback: Szumma #134 – 2018 44. hét – ./d/fuel

  3. df

    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.

    Reply
    1. Shahed C Post author

      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

      Reply
  4. Pingback: Generic Host Builder in ASP .NET Core | Wake Up And Code!

  5. Pingback: Key Vault for ASP .NET Core Web Apps | Wake Up And Code!

  6. Pingback: Logging in ASP .NET Core | Wake Up And Code!

  7. Pingback: Production Tips for ASP .NET Core Web Apps | Wake Up And Code!

  8. Pingback: ASP .NET Core code sharing between Blazor, MVC and Razor Pages | Wake Up And Code!

  9. Pingback: Generic Host Builder in ASP .NET Core 3.1 | Wake Up And Code!

  10. Pingback: Key Vault for ASP .NET Core 3.1 Web Apps | Wake Up And Code!

  11. Pingback: Logging in ASP .NET Core 3.1 | Wake Up And Code!

  12. Pingback: Production Tips for ASP .NET Core 3.1 Web Apps | Wake Up And Code!

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.