web-dev-qa-db-fra.com

Comment extraire une chaîne de connexion d'Azure KeyVault?

Un site Web hypothétique se connecte actuellement en utilisant:

public SqlConnection CreateConnection()
{
   DbConnection connection = new SqlConnection();
   connection.ConnectionString = GetConnectionString();
   connection.Open();

   return connection;
}

Où la chaîne de connexion magique est stockée dans web.config:

String GetConnectionString()
{
   //Get the connection string info from web.config
   ConnectionStringSettings cs = ConfigurationManager.ConnectionStrings["db"];

   if (cs == null)
      throw new Exception("Could not locate DB connection string");

   return cs.ConnectionString;
}

Maintenant, je voudrais déplacer la chaîne de connexion du fichier web.config vers Azure KeyVault. Comment récupérer quoi que ce soit hors du coffre de clés Azure?

String GetConnectionString()
{
   //Get the connection string info from Azure KeyVault
   String connectionString = GetAzureSecret("dbConnectionString");

   if (String.IsNullOrWhitespace(connectionString)
      throw new Exception.Create("Could not connection string of Azure Key Vault");

   return connectionString;
}

Sauf que je viens de créer l'API Azure facile à utiliser. Quelle est api réelle ?

Tentative non testée

string GetAzureSecret(string key)
{
    KeyVaultClient vault = new KeyVaultClient();
    vault.OnAuthenticate += VaultClientAuthenticate;

    var sec = await vault.GetSecretAsync(Key);
    return sec.Value;
}

public static async Task<string> VaultClientAuthenticate(string authority, string resource, string scope)
{
   String clientID = "8675209";
   String clientSecret = "correct battery horse pencil";

   var authContext = new AuthenticationContext(authority);
   ClientCredential clientCred = new ClientCredential(clientID, clientSecret);
   AuthenticationResult result = await authContext.AcquireTokenAsync(resource, clientCred);

   if (result == null)
      throw new Exception("Could not acquire token");

   return result.AccessToken;
}

Lecture bonus

20
Ian Boyd

Quelle est l'api réelle?

Nous pourrions utiliser GetSecret API pour obtenir de la valeur.

Préparation:

Enregistrer l'application Azure Active Directory et attribuer un rôle

Étapes:

1.Créez KeyVault et ajoutez un secret à partir du portail Azure

enter image description here

2. Politique d'accès à la configuration

enter image description here

3.Obtenir un jeton d'accès

 var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
            ClientCredential clientCredential = new ClientCredential(appId, secretKey);
            var tokenResponse =await context.AcquireTokenAsync("https://vault.Azure.net", clientCredential);
            var accessToken = tokenResponse.AccessToken;
            return accessToken;

Remarque : La ressource pour Keyvault est https://vault.Azure.net

4.Tester avec Fiddler

enter image description here

Nous pouvons également le faire facilement avec le SDK:

1.Créez un projet de console et un fichier Utils.cs

public static string EncryptSecret { get; set; }
        static string appId = "Application ID";
        static string secretKey = "Secert key";
        static string tenantId = "TenantId";

        public static async Task<string> GetAccessToken(string azureTenantId,string azureAppId,string azureSecretKey)
        {

            var context = new AuthenticationContext("https://login.windows.net/" + tenantId);
            ClientCredential clientCredential = new ClientCredential(appId, secretKey);
            var tokenResponse =await context.AcquireTokenAsync("https://vault.Azure.net", clientCredential);
            var accessToken = tokenResponse.AccessToken;
            return accessToken;
        }

2.Ajoutez le code suivant dans la fonction principale et testez-le.

enter image description here

fichier packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Hyak.Common" version="1.0.2" targetFramework="net452" />
  <package id="Microsoft.Azure.Common" version="2.0.4" targetFramework="net452" />
  <package id="Microsoft.Azure.Common.Dependencies" version="1.0.0" targetFramework="net452" />
  <package id="Microsoft.Azure.KeyVault" version="1.0.0" targetFramework="net452" />
  <package id="Microsoft.Bcl" version="1.1.9" targetFramework="net452" />
  <package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net452" />
  <package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net452" />
  <package id="Microsoft.IdentityModel.Clients.ActiveDirectory" version="3.13.9" targetFramework="net452" />
  <package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net452" />
  <package id="Newtonsoft.Json" version="6.0.4" targetFramework="net452" />
</packages>

Nous pouvons également obtenir plus d'informations de CtrlDot mentionné document .

24
Tom Sun

Je n'ai rien contre Key Vault (je pense que c'est un excellent produit!), Mais je ne peux pas m'en empêcher, mais je pense que vous êtes en train de trop l'ingénierie.

J'utiliserais simplement la fonctionnalité intégrée Paramètres d'application dans Azure App Service :

Chaînes de connexion

Pour les applications .NET, ces chaînes de connexion sont injectées dans vos paramètres connectionStrings de configuration .NET lors de l'exécution, remplaçant les entrées existantes où la clé est égale au nom de la base de données liée.

Application Web → Paramètres d'application → Chaînes de connexion → Ajouter une chaîne de connexion et nommez-la db.

String GetConnectionString()
{
   // Get the Connection String from Application Settings (App Service) 
   // with graceful fallback to web.config
   string cs = WebConfigurationManager.ConnectionStrings["db"].ConnectionString;

   if (cs == null)
      throw new Exception("Could not locate DB connection string");

   return cs;
}

Quelle est la différence entre WebConfigurationManager et ConfigurationManager?

Mise à jour de mai 2018:

Depuis Managed Service Identity est devenu une chose, l'acquisition d'un jeton d'accès ne nécessite plus de secrets (informations d'identification de principal de service) stockés dans votre service pour accéder à Key Vault, ce qui est une bien meilleure proposition. Voici un exemple Node.js juste pour pimenter un peu cette réponse:

// Get an access token from Managed Service Identity
// on an Azure IaaS VM
async function getAccessTokenWithMSI() {
  let msi = await axios.get('http://169.254.169.254/metadata/identity/oauth2/token',
    {
      params: {
        'api-version': '2018-02-01',
        'resource': 'https://vault.Azure.net'
      },
      headers: {
        'Metadata': 'true'
      },
      timeout: 2000
    });

  return msi.data.access_token;
}

et alors:

// Get a secret from Key Vault
async function getSecret(accessToken, secretUrl) {
  let response;
  try {
    response = await axios.get(secretUrl,
      {
         params: { 'api-version': '2016-10-01' },
         headers: { 'Authorization': `Bearer ${accessToken}` },
         timeout: 3000
      });
  }
  catch (e) {
    console.log('\nError calling Key Vault:,
        e.response.status, e.response.statusText, e.response.data);
  }
  console.log('\nGet Secret response from Key Vault: ',
      JSON.stringify(response.data, null, 4));

  return response.data;
}
16
evilSnobu