如何从Azure KeyVault获取连接字符串?

38
一个假想的网站目前使用:
public SqlConnection CreateConnection()
{
   DbConnection connection = new SqlConnection();
   connection.ConnectionString = GetConnectionString();
   connection.Open();

   return connection;
}

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

我想把连接字符串从web.config文件中移出,放到Azure KeyVault中。你如何从Azure Key Vault检索任何内容?

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

除了我刚刚编写的易于使用的Azure API之外,还有什么是 实际的 API?

未经测试的尝试

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

额外阅读


1
你是在指Azure KeyVault吗?这个链接https://learn.microsoft.com/en-us/azure/key-vault/key-vault-use-from-web-application能帮到你吗? - CtrlDot
@CtrlDot 是的,确实如此;将术语从“store”更改为“vault”。 - Ian Boyd
4个回答

38

2020年8月更新

现在有一种简单的方法可以通过Key Vault引用从应用服务中调用Key Vault,而无需编写任何自定义代码。

https://learn.microsoft.com/zh-cn/azure/app-service/app-service-key-vault-references

从Key Vault填充值的应用设置示例:

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

如果您不想要版本标识符:

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

为了使用密钥保管库引用,您需要先在应用服务实例和密钥保管库之间设置托管标识。

我并不反对使用密钥保管库(我认为它是一个很棒的产品!),但我认为您可能有点过度工程化。

我只会简单地使用 Azure 应用服务中内置的应用程序设置功能:

连接字符串

对于 .NET 应用程序,这些连接字符串会在运行时注入到您的 .NET 配置 connectionStrings 设置中,覆盖其中键等于链接数据库名称的现有条目。

Web 应用 → 应用程序设置 → 连接字符串 → 添加一个连接字符串,并将其命名为 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;
}

WebConfigurationManager和ConfigurationManager有什么区别?

2018年5月更新:

自从Managed Service Identity发布以来,获取访问令牌不再需要将机密(服务主体凭据)存储在您的服务中以访问Key Vault。这是一个更好的方案。下面是一个Node.js示例,只是为了使这个答案更加生动:

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

然后:

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

你解决了我的问题,但Tom按照问题所问回答了。所以他得到了采纳。但是你得到了点赞。 - Ian Boyd

36

实际的API是什么?

我们可以使用GetSecret API来获取值。

准备:

注册Azure Active Directory应用并分配角色

步骤:

1.从Azure门户创建KeyVault并添加秘密

enter image description here

2.配置访问策略

enter image description here

3.获取访问令牌

 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;

注意: Keyvault的资源为https://vault.azure.net

4.使用Fiddler进行测试

enter image description here

我们也可以使用SDK轻松完成:

1.创建一个控制台项目和一个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.在主函数中添加以下代码,并对其进行测试。

输入图像描述

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>

我们还可以从CtrlDot提到的文档中获取更多信息。


11

对于 .Net Core 已经存在 Azure Key Vault 的情况,现在非常容易。假设你的连接字符串在 appsettings.json 文件中:

{
   "ConnectionStrings": {
      "MyDatabase": "server=127.0.0.1;port=5678;database=mydb;user=FullMontyBurns;password=hunter2"
   } 
}

你需要在Startup.cs文件中进行设置:

string connectionString = configuration.GetConnectionString("MyDatabase");

在Azure Key Vault中创建一个秘密:
  • 名称: ConnectionStrings--MyDatabase
  • 值: server=127.0.0.1;port=5678;database=mydb;user=FullMontyBurns;password=hunter2

进入图像描述

现在,IConfiguration.GetConnectionString("MyDatabase") 将从密钥保管库中获取值。

那个密码对我来说只是一堆星号... :p - Ian Kemp
@kloarubeek,我遇到了一个错误,因为IConfiguration不包含GetConnectionString的定义。我在我的代码中使用如下方式。当我从appsettings中读取时,它可以正常工作,但是当我通过keyvault进行相同操作时,它会出现错误。services.AddDbContext<ConnectionStringModel>(options => options.UseSqlServer(Configuration.GetConnectionString("DBConnection"))); - Lucifer

2
其他人已经提供了关于如何与Web应用程序或Azure Function集成的上下文信息,但这里是开始使用Key Vault Secrets SDK的权威参考资料。
.NET:.NET Java:Java JavaScript:JavaScript Python:Python

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接