如何在 ASP.NET Core 中使用 Configuration 讀取 Azure Key-Vault 設定檔 如何在 ASP.NET Core 中使用 Configuration 讀取 Azure Key-Vault 設定檔

Published on Saturday, June 10, 2023

Azure Key-Vault

根據微軟的設計 UserSecrets 是給開發還境使用的,雖然也可以手動添加到系統內讓正式環境也能讀取 secrets.json, 但是有可能電腦重灌時沒有進行備份導致遺失正式環境的配置檔,因此微軟建議把正式環境的設定值放在 Azure Key-Vault 上。

放到 Azure 後能獲得版本控制與軟刪除的功能,可以避免人員的誤操作與誤刪除等失誤。

根據我們目前學到的流程我們可以知道,應該要有一個方法能夠把設定檔讀取下來並添加到 ConfigurationBuilder 最後建立出 ConfigurationRoot,最後在透過 IOptions 讀取回設定檔。

搜尋一段時間後發現 Azure.Extensions.AspNetCore.Configuration.Secrets Package 有提供一個 AddAzureKeyVault 方法 會添加 ConfigurationSourceConfigurationBuilder 符合我們想要的流程。

public static IConfigurationBuilder AddAzureKeyVault(
    this IConfigurationBuilder configurationBuilder,
    Uri vaultUri,
    TokenCredential credential,
    KeyVaultSecretManager manager)
{
    return AddAzureKeyVault(configurationBuilder, new SecretClient(vaultUri, credential), new AzureKeyVaultConfigurationOptions
    {
        Manager = manager
    });
}
        
public static IConfigurationBuilder AddAzureKeyVault(
    this IConfigurationBuilder configurationBuilder,
    SecretClient client,
    AzureKeyVaultConfigurationOptions options)
{
    Argument.AssertNotNull(configurationBuilder, nameof(configurationBuilder));
    Argument.AssertNotNull(options, nameof(configurationBuilder));
    Argument.AssertNotNull(client, nameof(client));
    Argument.AssertNotNull(options.Manager, $"{nameof(options)}.{nameof(options.Manager)}");

    configurationBuilder.Add(new AzureKeyVaultConfigurationSource(client, options));

    return configurationBuilder;
}

不過要訪問 Azure 資源之前需要提供憑證才能證明你的 Web App 有權限訪問 Key Vault,因此我們在使用 AddAzureKeyVault 時 也要傳入 TokenCredential 類型的憑證才能進行訪問。

我們也要安裝 Package Azure.Identity 裡面有提供多種不同的憑證,詳細可以參考文檔

簡單來說有幾種用法第一種是直接使用 DefaultAzureCredential 這個憑證可以再大部份場景中使用, 不過要注意 DefaultAzureCredential 其實是一連串憑證的組合,所以它內部會有一個運行的清單它會按照這個清單內的順序一個一個進行驗證直到某一個驗證通過為止。

  1. EnvironmentCredential
  2. WorkloadIdentityCredential
  3. ManagedIdentityCredential
  4. VisualStudioCredential
  5. VisualStudioCodeCredential
  6. AzureCliCredential
  7. AzurePowerShellCredential
  8. AzureDeveloperCliCredential
  9. InteractiveBrowserCredential

比如說使用 AzureCliCredential,如果你有安裝 Azure Cli 並且在 Shell 裡面使用 az login 進行登入,接下來 AzureCliCredential 就能直接使用你之前登入的驗證來訪問 Azure Key Vault。


Lab

接下來我們進行實做,建議是有基本的 Azure 知識再繼續閱讀。

首先先建立一個新的 Web 專案與 SecretSettings Class

dotnet new web -o HelloAzureSecret
dotnet add package Azure.Extensions.AspNetCore.Configuration.Secrets --version 1.2.2
dotnet add package Azure.Identity --version 1.9.0
// SecretSettings.cs
public class SecretSettings
{
    public string From { get; set; }
    public string Secret { get; set; }
}

接下來先前往 Azure 官網並使用預設值建立新的 Key Vault 服務。

Azure-Key-Vault-HelloAzureSecret

並且新增兩個 Secret,中間需要輸入 -- 可以用來區分 Section

JsonSettings--From MyAzureSecretSettings
JsonSettings--Secret MySecret
HelloAzureSecret-Add-New-Secret

目前預設的 Key Vault 服務是使用 Azure Role-Based Access Control(RBAC) 代表我們的帳號需要有適當的角色權限才有資格訪問 Key Vault 服務, 也就是說如果你想要使用 AzureCliCredential 這種透過帳號密碼來獲取權限憑證的方式,你就需要先幫你的帳號添加新的 Key Vault Role 才會有權限訪問。

不過今天要用的是 EnvironmentCredential 並搭配使用 Client ID/Client Secret 來獲取權限, 因此我們需要先前往 Azure Active Directory 建立一個新的 Applications 命名為 HelloAzureSecretWebApp

AAD-Create-HelloAzureSecretWebApp

我們需要紀錄下這個 Applications 的 Application (Client) IDDirectory (tenant) ID 並建立新的 Client-Secret 並紀錄 Value 值

  • Client ID: 5f006f2a-eeb8-4013-9bc0-8cd1c55bb0b4
  • Tenant ID: 82676786-5bc7-43c6-b8f8-b3ee02b0b5f3
  • Secret Value: B~N8Q~H.Kibk7OaMlbXNeHMWenrQO7a~WgGVdbfe
HelloAzureSecretWebApp-OverView HelloAzureSecretWebApp-Client-Secret

最後再回到 Key Vault 添加新的 Role,讓剛剛建立的 Application 和我們目前的帳號有權限訪問 Key Vault。

HelloAzureSecret-Add-Role

這樣資料就準備完成了,接下來回到我們的專案。

using Azure.Identity;
using HelloAzureSecret;

var builder = WebApplication.CreateBuilder(args);
builder.Configuration.AddAzureKeyVault(
    new Uri("https://helloazuresecret.vault.azure.net/"), new EnvironmentCredential());
builder.Services.AddControllers();
builder.Services.Configure<SecretSettings>(
    builder.Configuration.GetSection("JsonSettings"));
var app = builder.Build();
app.MapControllers();
app.Run();

這裡使用 EnvironmentCredential 將會使用環境變數紀錄的設定來向 Azure 取得權限,所以我們要在 launchSettings.json 先設定好環境變數而且必須要使用正確的環境變數名稱。

"https": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "https://localhost:7131;http://localhost:5242",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development",
        "AZURE_CLIENT_ID": "5f006f2a-eeb8-4013-9bc0-8cd1c55bb0b4",
        "AZURE_TENANT_ID": "82676786-5bc7-43c6-b8f8-b3ee02b0b5f3",
        "AZURE_CLIENT_SECRET": "B~N8Q~H.Kibk7OaMlbXNeHMWenrQO7a~WgGVdbfe"
      }

最後新增一個 Controller 來進行測試

// HelloController.cs

[ApiController]
[Route("[controller]")]
public class HelloController: ControllerBase
{
    private readonly IOptions<SecretSettings> _options;

    public HelloController(IOptions<SecretSettings> options)
    {
        _options = options;
    }

    [HttpGet(Name = "Get")]
    public string Get()
    {
        return _options.Value.From + ":" + _options.Value.Secret;
    }
}

如果設定都正確的話運行專案後訪問網址 https://localhost:7131/Hello 會看到能正確回傳 MyAzureSecretSettings:MySecret

你也可以將 EnvironmentCredential 換成其他驗證,例如使用 InteractiveBrowserCredential 會彈出一個網頁視窗讓你直接輸入帳號密碼 正常登入 Azure 後會取回設定值並運行專案,再次運行測試也能達到同樣的效果。


Summary

今天了解 Azure Key-Vault 的使用方式和學習了多種驗證方式,並且能正常取回設定值後添加到 ConfigurationBuilder 讓大部分的 操作流程都不需要變動,這種將設定值放在 Azure 並且搭配 Client ID/Client Secret 的方式會比直接共享 appsettings.json 來的安全許多, 不過還是要注意合理的 Client Secret 過期時間就能夠避免調許多安全性的問題。