Sensitive Configuration Data in ASP.NET Core

While working on my new side-project in ASP.NET Core, I was at the point where I needed to start storing sensitive configuration data.

Things like my DocumentDB Auth Key, Google OAuth ClientId & Secret, Twilio Auth Token, etc.

Depending on your context you may not want to be storing these types of application settings in configuration files that are committed to source control.

As you would expect, my local environment for development and once I deploy to Azure have completely different configurations.

So how do you change the configuration from local to production?

If you are used to using appSettings from the app.config and web.config, you may have been going down the road of transforming and replacing values with tools like SlowCheetah or through Octopus Deploy.

With ASP.NET Configurations, there’s a new way to do this.

Configuration

ASP.NET Core has a ConfigurationBuilder that enables you to load application settings from various places.  If you’ve loaded up a brand new ASP.NET Core app, you’re Startup looks something like this.

You have a new appsettings.json file you can use as well as an optional appsettings for each different environment.

I could use the appsettings.Development.json for local development, however as mentioned i want to keep sensitive data out of this file.

For this, I’ve now been using User Secrets.

User Secrets

ASP.NET Core adds a new way to store your sensitive data with User Secrets.

User Secrets are simply a plain text json file that are stored in your systems user profile directory.  Meaning the file is stored outside of your project directory.

There are a couple ways to manage your user secrets, first you need to add Microsoft.Extensions.SecretManager.Tools in the tools section of your project.json.

I’m unaware of how this translates to the new .csproj format.

If you are using the dotnet CLI, then you should now be able to run dotnet user-secrets --version

Next in your project.json you want to add a “userSecretsId” property in the root.  The value can be anything you want but should probably keep it unique so it doesn’t collide with another user secrets you create for any other project.

In order to load the secrets file, you need to first add Microsoft.Extensions.Configuration.UserSecrets package in your project.json

As mentioned, since I only use user secrets for local development, we can now load the secrets using the ConfigurationBuilder in our Startup

Visual Studio

If you are using Visual Studio, you can edit your user secrets file by accessing it in the context menu of your project in the solution explorer.

CLI

If you are using the dotnet CLI then you can call dotnet user-secrets [options] [command] to clear, list, remove and set secrets.

Example

Simple example would be wanting to store the connection string to a database.

 dotnet user-secrets set ConnStr "User ID=Derek;Password=CodeOpinion;"

Now within our code we can access the connection string after we built our configuration from the ConfigurationBuilder.

Production

Next post I’ll take a look at how you can use Environment Variables and specifically how to set them when deploying as an App Service within Azure.

Always enjoy hear your feedback.  Please let me know on twitter or in the comments.


 

Optimistic Concurrency in DocumentDB

Optimistic Concurrency in DocumentDBI’ve started working on new side project using ASP.NET Core.  I wanted to try a new datastore and decided to give Azure’s DocumentDB a try.

This project isn’t doing anything complicated but does contain enough real world use cases that can give me an idea of how the API works.

Concurrency

The first thing I needed to implement was how to handle concurrency.  Specifically optimistic concurrency.

In an optimistic concurrency model, a violation is considered to have occurred if, after a user receives a value from the database, another user modifies the value before the first user has attempted to modify it.

This is pretty typical when dealing with multi user environments like a web application.  Specifically in my case is:

  • Fetching out a document from DocumentDB
  • Mutating the data of the document
  • Sending the document back to to DocumentDB to be replaced

In my web application, the concurrency issue arises if the same document is being modified by multiple users at the same time.

Without having any type of concurrency, we are what is called a “Last Wins” mode.  Meaning, the last process/user that sends the document back to DocumentDB is what will be persisted.

ETags

Each document within DocumentDB has an ETag Property.

The ETag or entity tag is part of HTTP, the protocol for the World Wide Web. It is one of several mechanisms that HTTP provides for web cache validation, which allows a client to make conditional requests.

You may be familiar with ETag’s related caching.  A typical scenario is a user makes an HTTP request to the server for a specific resource.  The server will return the response along with an ETag in the response header.  The client then caches the response along with the associated ETag.

ETag: "686897696a7c876b7e"

If they client then makes another request to the same resource, it will pass a If-Non-Match header with the ETag it received.

If-None-Match: "686897696a7c876b7e"

If the resource has not changed and the ETag represents the current version, then the server will return a 304 Not modified status.  If the resource has been modified, it will return the appropriate 2XX status code along with the content new ETag header.

AccessCondition

DocumentDB uses ETags for handling optimistic concurrency.  When we retrieve a document from DocumentDB, it always contains an ETag property as apart of our document.

When we then want to send our request to replace a document, we can specify an AccessCondition with the ETag we received when we fetched out our document.

If the ETag we send is not current, the server will return a 412 Precondition Failed status code.  In our .NET SDK, this is wrapped up in a DocumentClientException.

Here is a full an example.

Demo Source Code

I’ve put together a small .NET Core sample with an XUnit test from above. All the source code for this series is available on GitHub.

Are you using DocumentDB? I’d love to hear your experiences so far along. Let me know on twitter or in the comments.


 

Collaborating with other User Groups

Collaborating with other User GroupsA few months ago I decided that collaborating with other user groups might be a really good way to add new ideas and an outside perspective on the local .NET Developers Group that I organize.

Back in November 2016 I was attending Detroit Dev Day.  I was planning on meeting with with Reid Evans who was doing a talk “A Developer’s Journey From OO to FP”.

Like most conferences, the best part was the hallway discussions.  I was sitting around and talking about user groups with Reid, Ken Cenerelli and Tom Walker.

Tom mentioned that he had recently done meetup with a presentation done by a remote speaker.

Remote Speaker

The night after the conference, I was thinking about the conversations and realized that Reid’s talk which touched on F# would probably be a really good for for my Windsor-Essex .NET Developers group.

Our group tends to focus on C# however there always seems to be interesting when the conversation revolves around F# or functional programming.

Turns out Reid was interested in doing it.  He also suggested in return that I do a talk for his Functional Knox group.

Part 1

Since our  initial conversation many months ago, we worked out a date. Reid did a Getting Started with Functional Programming in F# which was fantastic.

I’ve been given great feedback from our group about how the experience was.  Everyone enjoyed the talk and we really had no issues.

The session was done using Google Hangouts On Air with YouTube Live.  Our user group watched the talk on TV’s with great quality.

Next month I’ll be returning the favor and doing a talk for the Functional Knox group.  I will update this blog post with more details after it happens.

Collaboration

This has spawned some interesting ideas in terms of having user groups collaborate by occasionally having remote speakers.

If you run a user group and are interested in possibly collaborating in a similar way please let me know!  Also if you have any suggestions about what your user groups have done with success (or failure) please leave a comment or let me know on Twitter.