ROMANCE DAWN for the new world

Microsoft Azure を中心とした技術情報を書いています。

ASP.NET Core アプリケーションで Azure App Configuration から Azure Key Vault を参照する

前回の記事では、ASP.NET Core アプリケーションにおける Azure Key Vault の使い方を改めて考えてみました。

gooner.hateblo.jp

Key Vault と組み合わせて使うことが多いサービスに、App Configuration があります。
今回は、ASP.NET Core アプリケーションで App Configuration から Key Vault を参照する方法をまとめておきます。

Key Vault にデータベースの接続文字列を登録する

ASP.NET Core アプリケーションからアクセスする SQL Database の接続文字列を登録するシナリオを例に説明していきます。
Key Vault の Secret に WebApp21--SqlConnection という名前で、SQL Connection from Key Vault. という Value を登録します。

f:id:TonyTonyKun:20211009084920p:plain

名前に WebApp21 のプレフィックスを付けた理由は、1つの Key Vault でフロントエンドやバックエンドなど複数のアプリケーションの構成を管理する想定だからです。
JSON の階層構造で管理したいので -- で区切っています。Key Vault の名前には : を使うことができないで注意してください。

App Configuration に Key Vault 参照を追加する

App Configuration の Key Vault reference に WebApp21:SqlConnection という名前で、先ほど登録した Key Vault の Secret への参照を登録します。

f:id:TonyTonyKun:20210914170329p:plain

もう1つ動作確認用として、Key-value に WebApp21:Message という名前で、Hello Gooner from App Config. という Value を登録します。

f:id:TonyTonyKun:20211009085234p:plain

ASP.NET Core アプリケーションで Azure App Configuration と Key Vault を参照する

.NET 5 の Web API アプリケーションを作成し、必要な NuGet パッケージをインストールします。

Install-Package Azure.Identity -Version 1.4.1
Install-Package Azure.Data.AppConfiguration -Version 1.1.0
Install-Package Microsoft.Azure.AppConfiguration.AspNetCore -Version 4.5.0

開発環境以外では MSI を使って App Configuration と Key Vault に接続するように構成します。

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.ConfigureAppConfiguration((hostingContext, config) =>
            {
                var settings = config.Build();
                if (!hostingContext.HostingEnvironment.IsDevelopment())
                {
                    var appConfigUrl = settings["AppConfigUrl"];
                    config.AddAzureAppConfiguration(options =>
                    {
                        options.Connect(new Uri(appConfigUrl), new ManagedIdentityCredential())
                            .ConfigureKeyVault(kv =>
                            {
                                kv.SetCredential(new DefaultAzureCredential());
                            });
                    });
                }
            });
            webBuilder.UseStartup<Startup>();
        });

接続する App Configuration の URL は、appsettings.json で定義しておきます。

{
  "Logging": {
    "LogLevel": {
      "Default": "Critical",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "AppConfigUrl": "https://gooner0913.azconfig.io",
  "WebApp21": {
    "Message": "Hello Gooner from local."
  }
}

アプリケーションで構成情報を扱いやすくするため、POCO クラスにマッピングします。

public class MySettings
{
    public string Message { get; set; }
    public string SqlConnection { get; set; }
}

App Configuration から自分のアプリケーション情報だけを取得したいので、WebApp21 のプレフィックスを指定しています。

public void ConfigureServices(IServiceCollection services)
{
    services.Configure<MySettings>(Configuration.GetSection("WebApp21"));

    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebApplication21", Version = "v1" });
    });
}

動作確認用に、App Configuration と Key Vault から取得した値を返す API を作ります。

[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
    private readonly MySettings _settings;

    public ValuesController(IOptions<MySettings> optionsAccessor)
    {
        _settings = optionsAccessor.Value;
    }

    public ActionResult<IEnumerable<string>> Get()
    {
        return Ok(new string[] {
            _settings.Message,
            _settings.SqlConnection,
        });
    }
}

Azure 本番環境

ASP.NET Core アプリケーションをデプロイする Azure Web Apps の MSI を有効化し、App Configuration の RBAC を割り当てます。

$ az webapp identity assign --name "<Web Apps Name>" --resource-group "<Resource Group Name>"
{
  "principalId": "xxx",
  "tenantId": "yyy",
  "type": "SystemAssigned",
  "userAssignedIdentities": null
}

az appconfig show -n <App Configuration Name> --query id --output tsv
/subscriptions/<Subscription ID>/resourceGroups/<Resource Group Name>/providers/Microsoft.AppConfiguration/configurationStores/<App Configuration Name>

az role assignment create --role "App Configuration Data Reader" --assignee "xxx" --scope /subscriptions/<Subscription ID>/resourceGroups/<Resource Group Name>/providers/Microsoft.AppConfiguration/configurationStores/<App Configuration Name>

続いて、ASP.NET Core アプリケーションをデプロイする Azure Web Apps に Key Vault の Access policies を設定します。

$ az keyvault set-policy --name "<Key Vault Name>" --object-id "xxx" --secret-permissions get list

これで Web Apps 上の ASP.NET Core アプリケーションは、MSI で App Configuration に認証して Key Vault から SQL Database の接続文字列を取得できます。

f:id:TonyTonyKun:20211009091501p:plain

勘違いしやすい部分として、App Configuration から Key Vault を参照しているわけではありません。アプリケーションから Key Vault を参照しています。
Key Vault 参照を使うメリットは、アプリケーション側で Key Vault に関する情報を管理せずに、App Configuration 側で一元管理できることにあります。

ローカル開発環境

App Configuration で管理する構成情報は、appsettings.json にローカル環境用の構成情報を定義しておきます。
Key Vault で管理するセンシティブ情報については、ASP.NET Core の Secret Manger を使います。
詳しくは、前回の Key Vault の記事を参照してください。

単体テスト環境

単体テストを実行する際には、テストプロジェクト内で MySettings クラスの モックを作り、構成情報を渡すようにします。
詳しくは、前回の Key Vault の記事を参照してください。

まとめ

ASP.NET Core アプリケーションで App Configuration から Key Vault を参照する方法をまとめてみました。
すべてのアプリケーションで App Configuration を導入する必要はないと考えています。appsettings.json の切り替えで済むなら、それが適切かと思います。
1つのシステムが複数のアプリケーションで構成されていたり、構成情報が多く頻繁に変更したりするケースでは、App Configuration の導入を検討してみてください。