My question is about the C# code of reading secrets stored in the Key Vault as configuration transparently. For example currently I have this appsettings.json:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "mydomain.com",
"TenantId": "...coming from Connected Services/Secrets",
"ClientId": "...coming from Connected Services/Secrets",
"ClientSecret": "...coming from Connected Services/Secrets",
"CallbackPath": "/signin-oidc",
"Scopes": "access_as_user"
},
In development time those secrets are configured using Services/Secrets, so the secrets are not pushed to the repo.
How can I use and configure a configuration reader in the release build, which reads those configuration values from my Azure Key Vault transparently? In transparently I mean, the application itself is not aware where the configured secret is coming?
For example I have the statement builder.Configuration.GetSection("AzureAd")
and I would like this work transparently...
(I do know how to deploy my ASP.NET Core App to Azure App Services, how to create secrets in Azure Key Vault, and how to give access to the deployed App Service to the Key Vault, so this question is not about those)
You could do the following.
For hierarchical Keys in the KeyVault, you can create them like:
AzureAd--Secret1
AzureAd--Level1--Secret2
Your local secrets should be configured in your
secrets.json
. Right click on your project: "Manage User Secrets".
Introduce a IS_LOCAL
Flag to your launchSettings.json
:
"Your project Local": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5000",
"launchUrl": "api/v2/swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"IS_LOCAL": "true"
}
Then in your Startup.cs
or Program.cs
:
if (!env.IsLocal())
{
configuration.AddAzureKeyVault(
new Uri(configuration.GetValue<string>("YourKeyToAzureKeyVaultCredentials")),
new DefaultAzureCredential());
}
IsLocal()
is an Extension:
public static class HostEnvironmentExtensions
{
public static bool IsLocal(this IHostEnvironment _)
=> Environment.GetEnvironmentVariable("IS_LOCAL")?.Equals("true") ?? false;
}
And also in your Program.cs
:
services.Configure<YourConfiguration>(configuration);
YourConfiguration
Class should look like this:
public class YourConfiguration
{
public SecretConfiguration AzureAd{ get; set; }
}
And the SecretConfiguration
is just a POCO class:
public class SecretConfiguration
{
public string Secret1{ get; set; }
public string Secret2{ get; set; }
}
Now you can transparently inject YourConfiguration
Class in your services - and it will use your secrets.json
in local mode or your Azure Key Vault
on the server:
// When Service is Scoped
public class ServiceA (IOptionsSnapshot<YourConfiguration> configuration)
{
public void SomeMethod()
{
var secret1 = configuration.Value.AzureAd.Secret1;
}
}