Config and secrets in .NET Core 2.0

There are a few ways to manage environment-specific configuration in the new version of .NET Core, and those ways are much better documented than I remember them being a year ago.

So, first of all, they provide appsettings.json and separate that out by environment. This is early days for my app development, so I'm not sure if the environment gets switched out automagically or how that whole process works for deployment and tests. But it looks promising, and seems pretty easy to use, so I won't go any more into it here.

Regarding secret management, here are the methods that I see listed as of 2018-03-07. Here is a Microsoft article about them.

The "secrets.json" file provided directly by Microsoft

There is a pretty good article about it here. It's also called the "Secret Manager tool".

I'm guessing this will be the direction they continue with, since they've already kind of integrated it into the GUI. They've also left some cliffhangers like "don't rely on the file not being encrypted since it might be in the future" (!!). But right now, it's really just a json file that's stored in your user profile directory. Given that, "Secret Manager tool" sounds a little haughty for what it is.

And that all looked great until I got to the end of the article where they talk about deployment. Mind you, I haven't played around with this yet myself - it could be totally easy and straightforward - but they say you have to either use Web app configuration or VS CI/CD.

Assuming that "web app configuration" is referring to the stuff that you define in Program.cs, using that kind of defeats the purpose because it essentially puts you back to square one. "How do I store the secrets?" Except now you're storing them differently in dev and prod, so it gets kind of weird.

Cuz look, I'll just copy and paste a portion of how the default web app configuration is set in the WebHost class:

The following defaults are applied to the returned Microsoft.AspNetCore.Hosting.WebHostBuilder: use Kestrel as the web server, set the Microsoft.AspNetCore.Hosting.IHostingEnvironment.ContentRootPath to the result of System.IO.Directory.GetCurrentDirectory, load Microsoft.Extensions.Configuration.IConfiguration from 'appsettings.json' and 'appsettings.[Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName].json', load Microsoft.Extensions.Configuration.IConfiguration from User Secrets when Microsoft.AspNetCore.Hosting.IHostingEnvironment.EnvironmentName is 'Development' using the entry assembly, load Microsoft.Extensions.Configuration.IConfiguration from environment variables

So we see that secrets are only loaded for dev. What about prod!? Well maybe you'll put them in environment variables...

Ugh. You see? This option is no good.

Environment variables

The old classic. This looks pretty straightforward if you're a fan of this method. If you look at that doc quote above, you'll see that environment variables are basically supported out of the box. Great!

Just using a regular secrets.json file

Ok, this one isn't explicitly listed, but it's implied. I think a lot of people prefer environment variables, but this was always my favorite method for Django. They both result in secrets stored in plaintext, so I don't feel too bad about it.

Here's what you do:

  • Create a secrets.json file
  • Add that file to your gitignore
  • Add that file to your configuration in Program.cs
public static IWebHost BuildWebHost(string[] args) =>  
    WebHost.CreateDefaultBuilder(args)
        .ConfigureAppConfiguration((builderContext, config) =>
        {
            config.AddJsonFile("./Conf/secrets.json", optional: false, reloadOnChange: true);
        })
        .UseStartup<Startup>()
        .Build();

That will append your secrets.json file to the rest of the configuration methods that they throw on by default.

  • Done!

So there you have it. Secrets. I'll update this as I get deeper into creation and deployment and stuff changes.

Issues

  1. When I tried to run the publish script, my appsettings were lost because they were being sent into the ./publish directory, which isn't where appsettings gets read from by default. They should really be in the directory above that one. So I ended up having to specify an output directory. For some reason that abolished the publish dir and fixed the issue. I suspect it's a .NET core bug, but what do I know.

Here is the publish command for reference:

dotnet publish -c Debug --output ../deploy/

I also think it might be possible to throw an error and fail fast whenever this happens by explicitly including your appsettings file (like with the secrets file), but I'm not sure if that would overwrite any other behavior. As I dig deeper, I'll update this.

Resources

  • MSDN goes pretty deep into config and some more complex options
  • More docs - I feel like Microsoft has really invested in documentation in the last year or so. It's great.