使用 KeyVault 机密覆盖 Azure 应用服务中和本地的应用程序设置

Using KeyVault secrets to override appsettings in Azure App Service and locally

正在尝试从 C# 应用服务中的 KeyVault 检索机密。

本地机器:

蔚蓝

appsettings.json

...
"KeyVaultName" : "abc123",
"Secrets": {
    "One" : "@Microsoft.KeyVault(Secreturi=[uri to secret copied from Azure blade])"
}
...

Program.cs

...
using Azure.Extensions.AspNetCore.Configuration.Secrets;
using Azure.Identity;
...
public static IHostBuilder CreateHostBuilder(string[] args)
    {
        return Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, config) =>
            {
                var builtConfig = config.Build();
                var secretClient = new SecretClient(
                    new Uri($"https://{builtConfig["KeyVaultName"]}.vault.azure.net/"),
                    new DefaultAzureCredential());
                config.AddAzureKeyVault(secretClient, new KeyVaultSecretManager());
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }

结果

我刚刚得到 @Microsoft ... 值,我希望它映射到密钥库中的值。

似乎有些不对劲,因为我必须两次定义 keyvault 的名称,一次在 SecretClient 中,一次在 @Microsoft.KeyVault 引用中。

看来我混合了两种从 KeyVault 获取机密的方法。

配置提供商

我在 Program.cs 中添加的是一个将机密映射到配置集合中的配置提供程序。在 Startup.cs 中放置一个断点并检查配置集合中的值验证了这一点。

我应该做的是将秘密命名为 Secret--One,它将映射并覆盖本地配置值 { "Secret: { "One" : "..." } }。不能使用环境变量配置映射中使用的 :__,因为这些字符在机密名称中不受支持。

感觉我在这里仍然遗漏了一些东西,所以请在评论或其他答案中更新。

应用设置中的 KeyVault 参考

另一方面,如果您想使用在 Azure 应用程序设置(应用服务配置)边栏选项卡上设置的环境变量来覆盖配置值,则可以使用 KeyVault 引用。

这个问题是您仍然需要另一种方法来确保您不会在本地保守秘密并冒着将它们提交给源代码控制的风险。

有关此方法的详细信息,请参阅

参考资料

我喜欢做的是让正常的配置首先发生在强类型对象上。所以如果我有一个包含秘密的配置,但它也有一些东西可以留在这样的配置中:

"ComplianceSettings": {
"Url": "https://www.somecomplianceservice.com",
"Password": "Stored In Azure key vault",
"UserName": "Stored In Azure key vault"
}

所以我让它正常读取:

var complianceSettingsConfig = configuration.GetSection(Constants.ComplianceSettingsKey); // constant value is "ComplianceSettings"
services.Configure<ComplianceSettings>(complianceSettingsConfig);

ComplianceSettings 只是一个具有 Url、密码、用户名属性

的 Poco

那么只要我 program.cs 像这样正确设置:

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

               var azureServiceTokenProvider = new AzureServiceTokenProvider();
               var keyVaultClient = new KeyVaultClient(
                   new KeyVaultClient.AuthenticationCallback(
                       azureServiceTokenProvider.KeyVaultTokenCallback));

               builder.AddAzureKeyVault(
                   configuration["KeyVault:KeyVaultUrl"],
                   keyVaultClient,
                   new DefaultKeyVaultSecretManager());
 })

“KeyVault:KeyVaultUrl”只是 appsettings.json 中的另一个配置条目,因为 section:key 如下所示:

"KeyVault": {
"KeyVaultUrl": "https://<your-url-to-kv>.vault.azure.net/"
}

如果您在控制器的构造函数中注入 IOptions,您将看到您拥有所有本地值和来自 Azure KeyVault 的 NONE。我认为这是您的实际问题....如果不是,那么也许这对其他人有帮助 ;)

发生的事情是,所有这些 services.Configure() 事情都发生在 Azure 数据存在之前。所以我们需要像这样挂钩 PostConfigure 来覆盖 keyvault 中的值:

services.PostConfigure<ComplianceSettings>(options =>
{
    options.UserName = configuration.GetValue<string>(Constants.ComplianceUserNameKey);
    options.Password = configuration.GetValue<string>(Constants.CompliancePasswordKey);
 });

Constants.ComplianceUserNameKey 和 Constants.CompliancePasswordKey 保存密钥库中实际密钥的名称。所以基本上,当 PostConfigure 触发时,它会在 configuration.GetValue 中查找您指定的键。这次 keyvault 机密已加载到配置中,因此您只需根据它们在 keyvault 中的名称查找它们,然后用新值覆盖强类型对象中的属性。

我通常使用如下扩展方法:

public static class ServicesExtensions
{
    public static IServiceCollection AddConfiguration(this IServiceCollection services, IConfiguration configuration)
    {
       // All configuration gets loaded here
       // same as above, just gets PostConfigure if it needs
       // to load secrets, if not its just a GetSection() and Configure()
    }
 }

然后只需添加到 ConfigureServices

services.AddConfiguration(Configuration);

希望对某人有所帮助!

您可以通过在应用服务的应用设置中引用它来使用不带任何 nuget 包的 keyvault 引用。

只需单击复制图标,即可从密钥库中复制您的机密的“uri”

在您的应用程序设置下的应用程序设置中添加一个新设置并使用此 syntax 引用 keyvault 机密。

@Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/)

分步指南here