ASP.NET Core/Razor pages Secret Manager

Karen Payne - Jul 3 '23 - - Dev Community

Learn how to store sensitive data during development of an application where the code will be stored in source control such as a GitHub repository so that your sensitive data is not exposed to those who should not have access to this data.

Are secrets secure?

No, secrets are stored as plain text.

Sharing with team members

About the only choice is Azure Key Vault.

What happens if I get a new computer

  • Right click on the project in solution explorer.
  • Select Manage User Secrets
  • Once the file opens, right click and select open containing folder.
  • In Windows Explorer, go up two levels, copy the folder to a removable drive and paste into the new computer

Or as indicated below, simply copy a json file which was used to initially create the secrets and run on the new computer.

Sharing secrets with your team

From Microsoft

The Secret Manager tool stores sensitive data during the development of an ASP.NET Core project. In this context, a piece of sensitive data is an app secret. App secrets are stored in a separate location from the project tree. The app secrets are associated with a specific project or shared across several projects. The app secrets aren't checked into source control.

Warning
The Secret Manager tool doesn't encrypt the stored secrets and shouldn't be treated as a trusted store. It's for development purposes only. The keys and values are stored in a JSON configuration file in the user profile directory.

What do I get here that I can't get from Microsoft?

How to properly setup secrets in a file located outside of the Visual Studio solution folder structure.

Steps to working with secrets

  1. Create a new Razor Pages or ASP.NET Core project.
  2. Open a terminal window at the root of the project.
  3. Run dotnet user-secrets init which places an entry into the project file.
<PropertyGroup>
   <TargetFramework>net7.0</TargetFramework>
   <UserSecretsId>1fe850fa-6fb3-4320-8003-b70d16d1a649</UserSecretsId>
</PropertyGroup>
Enter fullscreen mode Exit fullscreen mode
  1. From here, decide what you want to store as secrets. For this article we want to store a database connection string and settings to send email messages.

The appsettings.json

{  
  "ConnectionStrings": {
    "DefaultConnection": "Enter anything here"
  },
  "MailSettings": {
    "FromAddress": "",
    "Host": "",
    "Port": 0,
    "TimeOut": 0,
    "PickupFolder": ""
  }
}
Enter fullscreen mode Exit fullscreen mode
  1. Create a class to read MailSettings from appsettings.json
public class MailSettings
{
    public string FromAddress { get; set; }
    public string Host { get; set; }
    public int Port { get; set; }
    public int TimeOut { get; set; }
    public string PickupFolder { get; set; } = "MailDrop";
}
Enter fullscreen mode Exit fullscreen mode

For the connection string we do not need a class.

Storing data for the secrets manager

Create a folder named DotnetSecrets off the root of C to store a json file outside of the Visual Studio solution. Keeping this simple, lets call it secrets.json and add the following.

{
  "ConnectionStrings:DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=EF.NotesDatabase;Integrated Security=True",
  "MailSettings": {
    "FromAddress": "FromAddress",
    "Host": "SomeHost",
    "Port": 25,
    "TimeOut": 3000,
    "PickupFolder": "MailDrop"
  }
}
Enter fullscreen mode Exit fullscreen mode

To add the settings above, in a terminal window execute the following.

type C:\DotnetSecrets\secrets.json | dotnet user-secrets set --project "C:\VS2022\LanguageFeatures\SecretManager1\SecretManager1.csproj"
Enter fullscreen mode Exit fullscreen mode

Note
Alter the path and project name for --project above for when doing this for your project.

Validation

Right click on your project, select Manage user secrets which opens secrets.json for this project and will appear as follows.

{
  "ConnectionStrings:DefaultConnection": "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=EF.NotesDatabase;Integrated Security=True",
  "MailSettings:FromAddress": "FromAddress",
  "MailSettings:Host": "SomeHost",
  "MailSettings:Port": "25",
  "MailSettings:TimeOut": "3000",
  "MailSettings:PickupFolder": "MailDrop"
}
Enter fullscreen mode Exit fullscreen mode

Or from the terminal at the project root

dotnet user-secrets list
Enter fullscreen mode Exit fullscreen mode

In this case we get

MailSettings:TimeOut = 3000
MailSettings:Port = 25
MailSettings:PickupFolder = MailDrop
MailSettings:Host = SomeHost
MailSettings:FromAddress = FromAddress
ConnectionStrings:DefaultConnection = Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=EF.NotesDatabase;Integrated Security=True
Enter fullscreen mode Exit fullscreen mode

Reading settings into your page

  • Setup a string property for ConnectionString
  • Setup MailSettings using the class MailSettings above and is located under the Models folder.
  • Add a private field IConfiguration for dependency injection in the contructor of the page.
  • Assign the property _configuration in the page contructor.
public class IndexModel : PageModel
{
    [BindProperty]
    public string ConnectionString { get; set; }
    private IConfiguration _configuration;
    [BindProperty]
    public MailSettings MailSettings { get; set; }
    public IndexModel(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    public void OnGet()
    {
        ConnectionString = _configuration["ConnectionStrings:DefaultConnection"]!;
        MailSettings = _configuration.GetSection("MailSettings").Get<MailSettings>()!;
    }
}
Enter fullscreen mode Exit fullscreen mode
  • For OnGet read back the settings.

To validate setting have been properly read set a breakpoint on the closing bracket of OnGet, run the project and inspect the properties.

Also, in the sample project.

<div class="container">
    <h1 class="fs-4 mt-2">Using secrets in development</h1>

    <div class="row shadow mt-2 border border-primary ms-1">
        <dl>
            <dt>Connection string</dt>
            <dd>@Model.ConnectionString</dd>

            <dt>Mail settings</dt>
            <dd>@Model.MailSettings</dd>
        </dl> 
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

screenshot of index page

Set multiple secrets

Above provided how to setup multiple secrets but wanted to note that in the documentation the following is shown.

type .\input.json | dotnet user-secrets set
Enter fullscreen mode Exit fullscreen mode

If you do this the input.json file would be in the project folder and circuments using secrets. Always store secrets files outside of the solution folder.

Source code

In the following GitHub repository, in this project.

Resources

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .