Imagine you have an appsetting.json
file that contains sensitive information such as your database server password, secret keys, and hash values for hashing.
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"MyDBContext": "Server=.;Database=SecretDemo;user id=sa;password=abCd@@123; TrustServerCertificate=True;"
},
"Credentials": {
"Algorithm": "SHA256",
"SecretKey": "ABCD1234",
"Salt": "abcd!@#$"
},
"IPAdress": "192.168.0.1"
}
To safeguard this confidential information, consider using Microsoft.Extensions.Configuration.UserSecrets
. This tool enables proper secret management in your projects. First, install it from the NuGet packages. Then, right-click your project and select ‘Manage User Secrets’. This will create a secret.json
file.
Next, move the sensitive details from your appsetting.json
to the secret.json
file. In my case, the file looks like this:
{
"ConnectionStrings": {
"MyDBContext": "Server=.;Database=SecretDemo;user id=sa;password=abCd@@123; TrustServerCertificate=True;"
},
"Credentials": {
"SecretKey": "ABCD1234",
"Salt": "abcd!@#$"
}
}
And my appsetting.json will looks like this:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Credentials": {
"Algorithm": "SHA256"
},
"IPAdress": "192.168.0.1"
}
Here, I’ve transferred what I consider confidential information to secret.json
. For instance, within the configuration object “Credentials”, I have three properties: “SecretKey”, “Salt”, and “Algorithm”. Believing the first two to be sensitive, I moved them to secret.json
, leaving “Algorithm” in the config file as it’s not sensitive.
To show it works under secret.json, I will print those values out in html page. The backend and front end code are like following:
public IndexModel(ILogger<IndexModel> logger, IConfiguration configuration)
{
_logger = logger;
_configuration = configuration;
}
public void OnGet()
{
MyDBContext = _configuration["ConnectionStrings:MyDBContext"];
SecretKey = _configuration["Credentials:SecretKey"];
Salt = _configuration["Credentials:Salt"];
//...omitted code
<div>
<p>The value of MyDBContext is: @Model.MyDBContext </p>
<p>The value of SecretKey is: @Model.SecretKey </p>
<p>The value of Salt is: @Model.Salt </p>
</div>
The output will look like this, displaying all values even though some are in secret.json
If you deploy your web app to IIS, you’ll need to manage your secrets differently as your secret.json
file won’t be deployed. You must set your secrets directly in IIS.
In IIS, go to the ‘Features View’ and double-click “Configuration Editors”. Under the section system.webServer/aspNetCore
, you will see the following options:
Select the environmentVariables, click the ‘3 dots’ button on the right to add. You can then add your secret variable.
Follow this naming convention for your variables: [object][underscore][underscore][property]. For instance, if the object name for the connection string is “ConnectionStrings”, and the property name is “MyDBContext”, the environment variable should be “ConnectionStrings__MyDBContext”. Remember to use TWO underscores; using only one gave me a massive headache during my initial environment variable setup. Once you’re done, close the window and click “Apply” to save your changes in IIS.
After launching the website, you’ll notice that the app now captures and stores your secret information.
If you do not want to set the variables one by one in IIS, you can use Powershell command to load it. First, save your secret.Json file to one path (for my case I save it to C:\SecretPath), and execute the following command:
$json = Get-Content 'C:\SecretPath\secret.json' | ConvertFrom-Json
foreach($parentProp in $json.PSObject.Properties){
foreach($childProp in $parentProp.Value.PSObject.Properties){
$envVarName = $parentProp.Name + '__' + $childProp.Name
[System.Environment]::SetEnvironmentVariable($envVarName, $childProp.Value, 'Machine')
}
}
# This command is for if your secret object do not have nested properties
# $json = Get-Content 'C:\SecretPath\secret.json' | ConvertFrom-Json
# foreach($prop in $json.PSObject.Properties){
# [System.Environment]::SetEnvironmentVariable($prop.Name, $prop.Value, 'Machine')
# }
After running the command, execute Get-ChildItem Env:
to list all environment variables in your machine. As you can see below, my credentials have been added.
And if you use this method, the source code have to be updated to following to get the environment variables.
MyDBContext = Environment.GetEnvironmentVariable("ConnectionStrings__MyDBContext", EnvironmentVariableTarget.Machine);
SecretKey = Environment.GetEnvironmentVariable("Credentials__SecretKey", EnvironmentVariableTarget.Machine);
Salt = Environment.GetEnvironmentVariable("Credentials__Salt", EnvironmentVariableTarget.Machine);
If you want to update the value of the credentials, you just change the values of your secret.json, and repeat the above Powershell command to load the secret.json again.
If you want to delete the environment variables, you can execute the following Powershell command to delete it.
[System.Environment]::SetEnvironmentVariable(“YourEnvironmentVariable”, $null, ‘Machine’)
For example, I wanted to delete my SecretKey properties from Credentials, so my Powershell command will be like this:
[System.Environment]::SetEnvironmentVariable("Credentials__SecretKey", $null, 'Machine')
And my web site will looks like this, with the Secret Key become null.
In conclusion, Microsoft.Extensions.Configuration.UserSecrets
is an excellent tool for managing secrets. It’s especially beneficial when working in a team as storing sensitive information outside the config file can prevent inadvertent data exposure during code check-ins.