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

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.

2 thoughts on “How to manage secrets in .NET locally and on GitHub?”

  1. The provided example is very nice and helpful.
    But How to use it for ASP .NET Web App? Main question is – How to access GitHub Secret after the application is deployed on the server?
    Scenario –
    If we stored database connection string Or any Keys in GitHub Secret. Now, how to access the GH secrets after the website is build and deployed? Is it accessible? I think your provided example only works for console app or any Job process only.
    If you have any solution, please let me know. Thank you so much !

    Reply
    • Thank you for your comment, Amar.

      Before answering your question, let’s talk about the example I provided. The idea of my example is not to solve all secret problems, it solves secrets problem related to GitHub actions.

      For instance, when you build a NuGet package and want to publish it on nuget.org, you need to save the secret of nuget.org somewhere both for local development but also on GitHub. GitHub action consumes the secret to publish the NuGet package. It could be an API that you need to access while building, testing, or whatever use case. Back to your question.

      It is possible to use this solution for the asp.net web app to for example access API while you build, test, or the publishing process, but when you have published the asp.net web app for instance on Azure App Service, then Azure App Service can not access GitHub action secrets, so to serve secrets for your application on Azure, you need to use Azure KeyVault.

      Therefore it gives more meaning to save secrets on Azure KeyVault or other cloud Secret Management tools for that database connection. I plan to write article series regarding Azure KeyVault secrets in GitHub action and Azure DevOps.

      Reply

Leave a Comment