简体   繁体   中英

Best approach to load Azure Secrets in a .NET application

I'm trying to find the best solution to reload Azure Secrets in a .NET 5 application. I will write here what I have now.
First I did this:

.ConfigureAppConfiguration((context, configuration) =>
{
    var configurationRoot = configuration.Build();

    config.AddAzureKeyVault(
        new Uri(configurationRoot["KeyVault:Uri"]),
        new DefaultAzureCredential()
});

But, there is a problem. Secrets are cached until IConfigurationRoot.Reload() is called. Expired, disabled, and updated secrets in the key vault aren't respected by the app until Reload is executed or if ReloadInterval is used as an option in AddAzureKeyVault .

My second approach was to add an interval to reload the secrets automatically every 15 minutes. (And use IOptionsSnapshot instead of IOptions to get the most recent values)

.ConfigureAppConfiguration((context, configuration) =>
{
    var configurationRoot = configuration.Build();

    int reloadInterval;
    bool success = int.TryParse(configurationRoot["KeyVault:ReloadInterval"], out reloadInterval);
    config.AddAzureKeyVault(
        new Uri(configurationRoot["KeyVault:Uri"]),
        new DefaultAzureCredential(),
        new AzureKeyVaultConfigurationOptions()
        {
            ReloadInterval = TimeSpan.FromMinutes(success ? reloadInterval : 15)
        });
});

I still think that is not the best solution, because there is still a time window (in this example 15 minutes) in which the secrets in Azure can be changed and if I try to use them I will not have the latest version.
So, I tried a solution where I manually call IConfigurationRoot.Reload() when I have an error about an invalid secret. For example in MongoDbContext , if the connection string is invalid I will get a MongoConfigurationException .
Using Polly I did this:

public MongoDbContext(IOptionsSnapshot<DatabaseSettings> databaseSettings, ILogger<MongoDbContext> logger)
{
    _logger = logger;
    _databaseSettings = databaseSettings.Value;

    _policy = Policy
        .Handle<MongoConfigurationException>()
        .Retry(1, (exception, retryCount) =>
        {
             // Reload configuration
        });
    _policy.Execute(() => _mongoClient = new MongoClient(_databaseSettings.ConnectionString));

    _mongoDatabase = _mongoClient.GetDatabase(_databaseSettings.DatabaseName);
}

Or maybe this one is better:

{
    _logger = logger;
    _databaseSettings = databaseSettings.Value;

    _circuitBreakerPolicy = Policy
        .Handle<MongoConfigurationException>()
        .CircuitBreaker(1, TimeSpan.FromSeconds(10));
    _retryPolicy = Policy.Handle<MongoConfigurationException>()
        .Retry(1, (exception, retryCount) =>
        {
             // Reload configuration
        });
    _policy = Policy.Wrap(_retryPolicy, _circuitBreakerPolicy);
    _policy.Execute(() => _mongoClient = new MongoClient(_databaseSettings.ConnectionString));

    _mongoDatabase = _mongoClient.GetDatabase(_databaseSettings.DatabaseName);
}

But, with this approach it means that I should do the same thing and catch that specific exception everywhere in the application where I use a secret. Also, I wasn't yet able to inject IConfigurationRoot in this class and I don't know if is OK to do that. MongoDbContext is part of the Infrastructure project outside the WebApi project.

Use Azure.Extensions.AspNetCore.Configuration.Secrets to load the Azure secrets in .NET application

An overload of AddAzureKeyVault that takes an AzureKeyVaultConfigurationOptions parameter and allows specifying the reload interval.

configurationBuilder.AddAzureKeyVault(new AzureKeyVaultConfigurationOptions 
{ 
    Vault = configuration["KeyVaultUrl"], 
    ReloadInterval = TimeSpan.FromMinutes(10), 
}); 

OR you may try with this

Update the AddAzureAppConfiguration method to set up a refresh interval for your Key Vault certificate using the SetSecretRefreshInterval method. With this change, your application will reload the public-private key pair for ExampleCertificate every 12 hours.

config.AddAzureAppConfiguration(options => 
{ 
    options.Connect(settings["ConnectionStrings:AppConfig"]) 
            .ConfigureKeyVault(kv => 
            { 
                kv.SetCredential(new DefaultAzureCredential()); 
                kv.SetSecretRefreshInterval("TestApp:Settings:KeyVaultCertificate", TimeSpan.FromHours(12)); 
            }); 
}); 

For more details refer this link

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM