How to manage secrets in .NET locally and on GitHub?

Manage Secrets .NET

A lot of software development requires secrets to interact with other systems, database, api keys etc.

It is ultimate important to secure these secrets, in a way that you are less concern who can access or se these secrets.

IMO, a best practice is to have different secrets for each environments. For example for Local , Test, UAT and production environment. But there could be situations that you have 2 keys, one for non-production and one for production, or even only 1 key.

In this article I will show you how to handle .NET project secret both locally and on GitHub.

Step 1: Create a new .NET project

We can use Visual Studio 2019/2022 or use command lines to create a new project.

md MySecretsApp
cd MySecretsApp
dotnet new console

Step 2: Initialize users secrets

With in project folder, we will initialize secrets as json outside our Visual Studio project, by running following command:

dotnet user-secrets init

You will see a successful message that has UserSecretsId and Guid Id reference:

Set UserSecretsId to 'b6b695f2-7611-4ed2-8ea9-a8a716afa697' for MSBuild project '..\MySecretsApp\MySecretsApp.csproj'.

This command will adds UserSecretsId XML tag with Guid Id reference to the project file MySecretsApp.csproj.

<PropertyGroup>
    ...
    <UserSecretsId>b6b695f2-7611-4ed2-8ea9-a8a716afa697</UserSecretsId>
</PropertyGroup>

Step 3: Now lets add secret

Now lets run another command that adds secret, in our example we have a fictive apikey.

dotnet user-secrets set apikey 4f15a66c-2e17-408d-b6f6-db9dec3d8382

This will will create a plain text key and value Secret.json file under %AppData%\Microsoft\UserSecrets with folder name same Guid Id reference.

%AppData%\Microsoft\UserSecrets\b6b695f2-7611-4ed2-8ea9-a8a716afa697\secret.json

Secret.json will contain apikey like:

{
  "apikey": "4f15a66c-2e17-408d-b6f6-db9dec3d8382"
}

This way the Secret.json will not be part of the project repository. That said, if we follow best practice as we mentioned previously. This test api key is for instance for local environment, it is suggested that you have another api key for test, UAT and production as mentioned previously.

Step 4: Lets consume the secret in our code locally.

Before we start, we need to add Microsoft.Extensions.Configuration.UserSecrets NuGet to our project.

Now in our code, we add following chunk:

using Microsoft.Extensions.Configuration;

var config = new ConfigurationBuilder()
    .AddUserSecrets<Program>()
    .Build();
string apiKey = config["apikey"];

Console.WriteLine(apiKey);

apiKey will contain our given api key secret; 4f15a66c-2e17-408d-b6f6-db9dec3d8382 as we have defined earlier.

Step 5: How to consume the secret in GitHub.

Now in GitHub we can create an apikey for test environment.

In Github repo, go to Settings -> Secrets and click add New repository secret.

Add GitHub repository secret

We will also create GitHub action yml for .net and call it mysecretsapp.yml. As we can see in mysecretsapp.yml under .github/workflows, we consume the api key we created in GitHub secrets for our test:

- name: Test
  env:
    apikey: ${{ secrets.APIKEY }}
  run: dotnet test --no-build --verbosity normal
  working-directory: MySecretsApp

Note: from my observation, it was not possible to print secret in pipeline, it can only be used in the code.

Download source code from Github.

Conclusion

This is a very simple example how isolate Secret from code base to preventing developer hard coding keys inside code and mistakenly committing it to the repository. I suggest also using tools like GitGuardian to scan the repos possible keys, password, username and etc. sensitive secrets and eventually remove them.

Leave a Reply

Your email address will not be published. Required fields are marked *