代码之家  ›  专栏  ›  技术社区  ›  chadb

具有实体框架“DefaultConnection”应用程序设置的Azure Key Vault

  •  4
  • chadb  · 技术社区  · 7 年前

    我试图使用Azure Key Vault来存储实体框架的web api连接字符串。理想情况下,我希望避免将关键的vault nuget包与我的数据访问代码耦合。我的dbContext类有两个构造函数:

    public MyDbContext() : base("DefaultConnection")
    { . . . }
    
    public MyDbContext(string connectionString) : base(connectionString)
    { . . . }
    

    我采用的方法是使用连接字符串定位器在dbcontext上设置静态属性:

    public interface IConnectionStringLocator
    { string Get(); }
    
    public class DefaultConnectionStringLocator : IConnectionStringLocator
    {
        public string Get()
        {
            return "DefaultConnection";
        }
    }
    
    public static IConnectionStringLocator ConnectionStringLocator { get; set; } =
        new DefaultConnectionStringLocator();
    

    我的web api项目有用于检索关键vault机密的nuget包。所以在我的全球。asax文件我有:

    protected void Application_Start()
    {
        MyDbContext.ConnectionStringLocator = new ConnectionStringLocator("DefaultConnection");
    }
    
    public class ConnectionStringLocator : IConnectionStringLocator
    {
        private  readonly string _connectionStringName;
    
        public ConnectionStringLocator(string connectionStringName)
        {
            this._connectionStringName = connectionStringName;
        }
        public string Get()
        {
            var keyVaultName = WebConfigurationManager.AppSettings.Get("KeyVaultName");
            if (keyVaultName == "develop")
                return _connectionStringName;
            else
            {
                AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
                var keyVaultClient =
                    new KeyVaultClient(
                        new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
                var defaultConnectionSecret =
                    keyVaultClient.GetSecretAsync($"https://{keyVaultName}.vault.azure.net/secrets/{this._connectionStringName}");
    
                return defaultConnectionSecret.Result.Value;
            }
        }
    }
    

    另一种选择是遵循本文 https://blog.falafel.com/keeping-secrets-with-azure-key-vault/ 但这需要我将KeyVault API包与数据访问相结合。

    具有新MSI实现的KeyVault资源: https://github.com/Azure-Samples/app-service-msi-keyvault-dotnet/

    2 回复  |  直到 7 年前
        1
  •  4
  •   chadb    7 年前

    下面是我如何解决这个问题的,以防其他人偶然发现。

    创建了一个ConfigurationManager类,该类首先尝试从密钥库中获取值,但失败时使用WebConfigurationManager读取应用程序设置。

        public static class ConfigurationManager
    {
        public static string KeyVaultName => WebConfigurationManager.AppSettings.Get("KeyVaultName");
        private static readonly Dictionary<string, string> ConfigurationCache = new Dictionary<string, string>();
        private static SecretBundle GetSecret(string secretName, string vaultName = null)
        {
            AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
            var keyVaultClient =
                new KeyVaultClient(
                    new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
            var secretUri = $"https://{vaultName ?? KeyVaultName}.vault.azure.net/secrets/{secretName}";
            var secret = keyVaultClient.GetSecretAsync(secretUri);
            return secret.Result;
        }
    
        public static string GetAppSettingValue(string secretName, string vaultName = null)
        {
            vaultName = vaultName ?? KeyVaultName;
            string key = $"{vaultName}:{secretName}";
            string value;
    
            if (ConfigurationCache.TryGetValue(key, out value))
                return value;
    
            if (string.IsNullOrEmpty(vaultName) || vaultName == "develop")
            {
                value = WebConfigurationManager.AppSettings.Get(secretName);
                ConfigurationCache.Add(key, value);
                return value;
            }
    
            var secret = GetSecret(secretName);
            value = secret.Value;
            ConfigurationCache.Add(key, value);
            return value;
        }
    
        public static void SetAppSettingValue(string secretName, string value, string vaultName = null)
        {
            vaultName = vaultName ?? KeyVaultName;
            string key = $"{vaultName}:{secretName}";
    
            if (ConfigurationCache.ContainsKey(key))
                ConfigurationCache[key] = value;
            else
            {
                WebConfigurationManager.AppSettings[key] = value;
                ConfigurationCache.Add(key, value);
            }
    
    
        }
        public static string GetConnectionStringValue(string secretName, string vaultName = null)
        {
            vaultName = vaultName ?? KeyVaultName;
            string key = $"{vaultName}:{secretName}";
            string value;
    
            if (ConfigurationCache.TryGetValue(key, out value))
                return value;
    
            if (string.IsNullOrEmpty(vaultName) || vaultName == "develop")
            {
                value = WebConfigurationManager.ConnectionStrings[secretName].ConnectionString;
                ConfigurationCache.Add(key, value);
                return value;
            }
    
            var secret = GetSecret(secretName);
            value = secret.Value;
            ConfigurationCache.Add(key, value);
            return value;
        }
    }
    

    然后在我的dbcontext类中调用Configurationmanager。GetConnectionStringValue(“DefaultConnection”)。

        public MyDbContext()
            : base(ConfigurationManager.GetConnectionStringValue("DefaultConnection"))
        {...}
    
        2
  •  0
  •   Tai Bo    4 年前

    Configuration Builders for .NET 只需在appsettings或web中使用少量XML即可连接到密钥库。配置文件。我使用了该库以及XML转换和azure devops,根据环境连接到不同的密钥库。我在我的博客里谈到了这件事 post

    推荐文章