Introduction
I recenlty had a need custom configuration in my Azure function and the default environment variable option was not sufficient as I needed to have an json array as a setting with some secrets in it. I create a simple solution to get settings from Keyvault and use it with DI.
Setup Azure Function to read secret from KeyValut using the latest SDK
Packages to install:
- Azure.Identity
- Azure.Security.KeyVault.Secrets
- Microsoft.Extensions.Configuration.AzureKeyVault
Keyvault setup
- Create a new KeyVault resource if you already don’t have one. I will skip this part how to create one in the azure Portal or Az CLI or ARM.
- In your KeyVault go to “
Access controll
” and add assign “Key Vault Secrets User
” role to your application. - Take a note of the KeyVault url as that is needed in our next step.
Azure Function setup
Jumping in to the code.
To setup thing on the Azure Function side we need to do some changes.
Firstly lets open local.host.setting.json and add a new envrionment variable AzureKeyVaultEndpoint
and for the vaule the KeyVault url that we noted down from previous step.
Secondly we need to override a mehtod called ConfigureAppConfiguration
as shown below in the Startup.cs
.
public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)
{
var builtConfig = builder.ConfigurationBuilder.Build();
var keyVaultEndpoint = builtConfig["AzureKeyVaultEndpoint"];
var context = builder.GetContext();
if (!string.IsNullOrEmpty(keyVaultEndpoint))
{
// using Key Vault, either local dev or deployed
builder.ConfigurationBuilder
.SetBasePath(context.ApplicationRootPath)
.AddJsonFile("local.settings.json", true)
.AddEnvironmentVariables()
.AddAzureKeyVault(keyVaultEndpoint, new DefaultKeyVaultSecretManager())
}
else
{
// local dev no Key Vault
builder.ConfigurationBuilder
.SetBasePath(Environment.CurrentDirectory)
.AddJsonFile("local.settings.json", true)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddUserSecrets(Assembly.GetExecutingAssembly(), true)
.AddEnvironmentVariables()
}
}
}
In this example i have added two options either read the settings from KeyVault if that has been configured or try to read it from localsettings or appsettings..
By default the settings json read from the KeyVault
will not be bind to the model you might have created. So to make this work we need to create a ServicesExtension to follow good practises. An Exmple of code would look like this:
public static IServiceCollection ConfigureMyConfiguration(this IServiceCollection services, IConfiguration configuration)
{
string? myConfigurationJson = configuration.GetSection("MyConfiguration")?.Value;
if (string.IsNullOrEmpty(myConfigurationJson))
return services;
var myConfiguration = JsonSerializer.Deserialize<MyConfigurationOption>(myConfigurationJson);
services.TryAddSingleton(myConfiguration);
return services;
}
My custom settings might look something like this:
public class MyConfigurationOption
{
public List<MyConfiguration> Setting {get;set;}
public class MyConfiguration {
public string Setting1 {get;set;}
public string Setting2 {get;set;}
...
}
}
Now we can Inject ´MyConfigurationOption´ in a contructor and use the settings we got from the KeyVault, Inaddition all secrets are now protected by the KeyVault
.