Using secrets safely in development with .NET Core

Posted by

Today we are going to use “User Secrets” to manage secrets in our .NET Core development environment. It’s important to keep secrets out of your source code, but sometimes, even with a key vault/ secrets manager, it’s unavoidable and we need to manage these secrets locally.

In our project, integration test projects don’t work with Managed Identity (formerly known as Managed Service Identity or MSI). Instead we were forced to use a client id/ client secret combination. User secrets work by using a local configuration file, that isn’t tracked in source control. Note that these should never be production secrets, just what is required to develop against your development and test environments.

Adding user secrets

To add user secrets, we right click on our project, and select “Manage User Secrets”. This usually prompts you to add the required packages, accept this and add these packages from NuGet.

After the NuGet packages are installed, a new secrets.json file will open up. Here we will add secrets, in the same format as appsettings.json. These secrets are stored locally, and not checked into source control – each individual developer will need to do this step.

Now we update the startup to read the user secrets. As this is in our test project, we have a BaseIntegration class.

Next we update our appsettings.json file, to remove the secrets from our source code, which you can see indicated in red below – we used empty strings.

Now when we run our tests, we can verify that it’s reading from the secrets.json file.

Updating Azure DevOps

What about when we push to Azure DevOps – do we need a secrets.json file there too? Not exactly, in Azure DevOps we have a connection to our Key Vault, can use the client secret and Redis connection string from the Key Vault.

First, we need to update the pipeline to edit our appsettings.json configuration file with the secrets. This PowerShell loads the json settings file, and updates the appsettings we need to update from variables we store in Azure Key Vault, before saving it back to the appsettings file again. This is the YAML for the PowerShell that will work for us:

- displayName: 'Update AppSettings file before testing'
  powershell: | 
    $pathToJson = "SamLearnsAzure/SamLearnsAzure.Tests/appsettings.json"
    $a = Get-Content $pathToJson | ConvertFrom-Json
    $a.AppSettings.ClientSecret = ${{parameters.clientSecret}}
    $a.AppSettings.RedisConnection =  ${{parameters.redisConnection}} 
    $a | ConvertTo-Json | set-content $pathToJson

What about GitHub?

What do we need to do to replicate this in GitHub actions? Fortunately, there is an action for this, instead of the PowerShell above. First we just put our secrets in the GitHub secrets manager, and then use this YAML to set the properties in the AppSettings file:

- name: Variable Substitution appsettings file for tests
  uses: microsoft/variable-substitution@v1
  with:
    files: 'SamLearnsAzure/SamLearnsAzure.Tests/appsettings.json'
  env:
    AppSettings.ClientSecret: "${{ secrets.ClientSecret}}"
    AppSettings.RedisConnection: "${{ secrets.RedisConnection }}"

Summary

We’ve completely removed the last secrets in our code. Note that as we removed them, we also recycled them, to ensure that the old secrets couldn’t continue to be used. User Secrets aren’t perfect, but help to keep our project and source code secret free.

References

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s