在 .NET 应用程序中加载 Azure Secrets 的最佳方法

问题描述

我正在尝试寻找在 .NET 5 应用程序中重新加载 Azure Secrets 的最佳解决方案。我会把我现在所拥有的写在这里
首先我是这样做的:

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

    config.AddAzurekeyvault(
        new Uri(configurationRoot["keyvault:Uri"]),new DefaultAzureCredential()
});

但是,有一个问题。秘密被缓存,直到 IConfigurationRoot.Reload()调用。在执行重新加载之前,或者如果 ReloadInterval 用作 AddAzurekeyvault 中的选项,应用程序不会遵守密钥保管库中过期、禁用和更新的机密。

我的第二种方法添加一个间隔,每 15 分钟自动重新加载机密。 (并使用 IOptionsSnapshot 而不是 IOptions获取最新值)

.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)
        });
});

我仍然认为这不是最好的解决方案,因为还有一个时间窗口(在本例中为 15 分钟),可以在其中更改 Azure 中的机密,如果我尝试使用它们,我将不会获得最新版本.
因此,我尝试了一种解决方案,当我遇到有关无效机密的错误时,我手动调用 IConfigurationRoot.Reload()。 例如在 MongoDbContext 中,如果连接字符串无效,我将得到一个 MongoConfigurationException
使用 Polly 我做到了:

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);
}

或者这个更好:

{
    _logger = logger;
    _databaseSettings = databaseSettings.Value;

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

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

但是,使用这种方法意味着我应该做同样的事情并在应用程序中使用秘密的任何地方捕获特定的异常。另外,我还不能在这个类中注入 IConfigurationRoot,我不知道这样做是否可以。 MongoDbContext 是 WebApi 项目之外的基础设施项目的一部分。

解决方法

使用Azure.Extensions.AspNetCore.Configuration.Secrets 在 .NET 应用程序中加载 Azure 机密

采用AddAzureKeyVault参数并允许指定重新加载间隔的AzureKeyVaultConfigurationOptions重载。

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

或者你可以试试这个

更新 AddAzureAppConfiguration 方法以使用 SetSecretRefreshInterval 方法为 Key Vault 证书设置刷新间隔。进行此更改后,您的应用程序将每 12 小时重新加载 ExampleCertificate 的公私密钥对。

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

有关详细信息,请参阅此link