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 look 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 the 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, and 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 individually in IIS, you can use the 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 has to be updated to the 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 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 website will look like this, with the Secret Key becoming 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.