2017-09-20 2 views
1

J'essaie d'utiliser Azure Key Vault pour stocker mes chaînes de connexion à l'API Web pour Entity Framework. Idéalement, je voudrais éviter de coupler les paquets clés de coffre-fort avec mon code d'accès aux données. Ma classe dbContext a deux constructeurs:Azure Key Vault avec Entity Framework Paramètre d'application "DefaultConnection"

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

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

Mon code utilise le constructeur qui obtient la parameterless chaîne de connexion de la configuration Web. Il y a des endroits où j'instancie un nouvel objet MyDbContext, qui interdit une solution utilisant l'injection.

La route que je pris est de définir une propriété statique sur mon dbcontext avec un localisateur de chaîne de connexion:

public interface IConnectionStringLocator 
{ string Get(); } 

public class DefaultConnectionStringLocator : IConnectionStringLocator 
{ 
    public string Get() 
    { 
     return "DefaultConnection"; 
    } 
} 

public static IConnectionStringLocator ConnectionStringLocator { get; set; } = 
    new DefaultConnectionStringLocator(); 

Mon projet web api a les paquets de NuGet pour récupérer les secrets clés de voûte. Donc, dans mon fichier Global.asax J'ai ceci:

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

je publiais cela et il fonctionne, mais il ne « sens » à droite.

Une autre option serait de suivre cet article https://blog.falafel.com/keeping-secrets-with-azure-key-vault/ mais il me demander de coupler les paquets de l'API keyvault avec mon accès aux données.

Je suis à la recherche de commentaires et de direction. Je devrais ajouter que la raison pour laquelle je veux utiliser le coffre-fort est parce qu'il me permettra d'avoir des administrateurs azur qui peuvent voir les paramètres de l'application en ligne sans avoir accès à la base de données SQL via la chaîne de connexion.

ressources keyvault avec la nouvelle implémentation MSI: https://github.com/Azure-Samples/app-service-msi-keyvault-dotnet/

Répondre

0

Voici comment je résolu ce, au cas où quelqu'un d'autre trébuche sur elle.

Créé une classe ConfigurationManager qui tente d'abord d'obtenir la valeur du coffre-fort, mais en cas d'échec, il utilise WebConfigurationManager pour lire les paramètres de l'application.

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

Puis dans ma classe dbcontext Je demande à Configurationmanager.GetConnectionStringValue ("DefaultConnection").

public MyDbContext() 
     : base(ConfigurationManager.GetConnectionStringValue("DefaultConnection")) 
    {...}