ROMANCE DAWN for the new world

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

Azure Council Experts 定例会で Azure Bicep の話をしてきました

Azure Council Experts 定例会で、Azure Bicep の入門編のセッションに登壇しました。
これまでの ACE は会員企業向けのクローズドなイベントを開催していましたが、今後は誰でも参加できるオープンな形式にリニューアルしました。このイベント後には、会員企業のみのクローズドな会も用意していて、2部構成となっています。

a-c-e.connpass.com

Bicep は従来の ARM テンプレートの課題を解決する良いプロジェクトで積極的に使っていきたいので、その思いを話してきました。

speakerdeck.com

ASP.NET Core アプリケーションで Azure Key Vault の使い方を改めて考えてみた

11 月に .NET 6 がリリースされることもあり、現時点での ASP.NET Core アプリケーションにおける Azure Key Vault の使い方を改めて考えてみました。
データベースの接続文字列や API Key などのセンシティブな情報は、アプリケーションのリポジトリ内では管理したくありません。
アプリケーションとセンシティブな情報を分離させる構成を実現する方法にはいつくかありますが、現時点では次の方針がシンプルでいいのではと考えています。

  • Azure の本番環境では、Azure Key Vault を使って Managed Service Identity(MSI)で認証する
  • ローカルの開発環境では、ASP.NET Core の Secret Manger を使う
  • 単体テストでは、センシティブな情報のモッククラスを作る

上記の方針に従って、実際に構成を作って試してみます。

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

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

f:id:TonyTonyKun:20210912095856p:plain

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

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

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

Install-Package Azure.Identity -Version 1.4.1
Install-Package Azure.Extensions.AspNetCore.Configuration.Secrets -Version 1.2.1

開発環境以外では MSI を使って 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 keyVaultUrl = settings["KeyVaultUrl"];
                    config.AddAzureKeyVault(new Uri(keyVaultUrl), new DefaultAzureCredential());
                }
            });

            webBuilder.UseStartup<Startup>();
        });

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

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "KeyVaultUrl": "https://xxx.vault.azure.net/"
}

アプリケーションで SQL Database の接続文字列を扱いやすくするため、POCO クラスにマッピングします。

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

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

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

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

動作確認のため、SQL Database の接続文字列を返す API を作ります。

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

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

    [HttpGet]
    public ActionResult<string> Get()
    {
        return Ok(_settings.SqlConnection);
    }
}

Azure 本番環境

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

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

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

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

f:id:TonyTonyKun:20210912114101p:plain

Azure ポータルから設定する場合は、こちらの記事を参照してください。
gooner.hateblo.jp

ローカル開発環境

Visual Studio の機能でローカル開発環境から Key Vault に接続することはできますが、環境によって上手く認証できなかったり、デバッグ実行が遅くなったりするので、今回は使いません。
ASP.NET Core の Secret Manger を使って、プログラマーが開発用の構成情報を管理してコードを書いていくようにします。
docs.microsoft.com

secrets.json ファイルには、このように SQL Database の接続文字列を定義します。

{
  "WebApp20": {
    "SqlConnection": "SQL Connection for Secret Manager."
  }
}

Visual Studio のプロジェクトを右クリックしたユーザーシークレットの管理から定義してもいいですが、アプリケーションのリポジトリとは別で管理する JSON ファイルを dotnet user-secrets コマンドで読み込ませるほうが便利です。

$ type .\webapp20-secrets.json | dotnet user-secrets set --project "C:\Users\thara\source\repos\WebApplication20\WebApplication20"

これでローカル環境では、secrets.json から取得した SQL Database の接続文字列を使って開発できます。

単体テスト環境

単体テストを実行する際には、テストプロジェクト内で MySettings クラスの モックを作り、SQL Database の接続文字列を渡すようにします。

public class ValuesControllerTest
{
    [Fact]
    public void Get_ReturnsOkResult()
    {
        var settings = new MySettings()
        {
            SqlConnection = "SQL Connection for Unit Test."
        };
        IOptions<MySettings> options = Options.Create(settings);
        var controller = new ValuesController(options);

        // Act
        var actionResult = controller.Get();

        // Assert
        var result = Assert.IsType<OkObjectResult>(actionResult.Result);
        Assert.Equal(settings.SqlConnection, (result.Value as string[])[0]);
    }
}

これでローカル開発でも CI/CD のパイプラインでも、実行環境の影響を受けずに単体テストを実行することができます。

まとめ

現時点での ASP.NET Core アプリケーションにおける Azure Key Vault の使い方を改めて考えてみました。
アプリケーションの要件やチームの文化などにもよりますが、ベースはこの方針がいいかなと思っています。
セキュリティという観点では、Key Vault 自体を閉域網構成で管理したい話もあるので、そちらは追加で検討が必要です。

Microsoft MVP for Microsoft Azure を再受賞しました

2021年7月1日付けで、Microsoft Most Valuable Professional (MVP) アワードを再受賞しました。受賞カテゴリは、Microsoft Azure です。
5 年目の受賞となり、青い 5 Years のリングが貰えたのでちょっと嬉しい。

f:id:TonyTonyKun:20210907173855j:plain

昨年の主な活動内容

新型コロナウイルスの影響により今までのようなオフラインの活動は難しくなり、JAZUG を中心としたコミュニティの運営や登壇はほとんどできませんでした。

jazug.connpass.com

初めてのオンライン開催となった de:code 2020 には MVP パーソナルスポンサーとして参加し、Azure Pipelines でデプロイする .NET Core 向けの YAML ファイルのサンプルを公開しました。

gooner.hateblo.jp

クラウドデベロッパーちゃんねるで、ちょまどさんと Azure Kubernetes Service のセッション動画を公開したりしました。

gooner.hateblo.jp

ブログでは、例年に比べると記事を多めに書きました。とくに Azure Synapse Analytics については、新たにノウハウを学んだ領域なのでアウトプットも多めです。

gooner.hateblo.jp

例年であれば、1年間の活動内容に対する審査が行われ、再受賞が決まります。
今年は世界中の MVP たちがコロナ禍におけるコミュニティ活動に苦労したことが配慮され、すべての MVP が再受賞ということになりました。

今年の活動目標

さっそく今月末に JAUGの 11 周年イベントがあるので、Azure Synapse Analytics のネタで LT する予定です。
jazug.connpass.com

コミュニティ運営としては、Azureもくもく会@新宿を 4 月からオンラインで再開しているので継続していきたいです。
参加した人が来てよかったなと思えるように、何かを1つでも持ち帰って貰えるような場にできるといいなと。
azure-mokumoku.connpass.com

あと、お仕事が関係しているところもありますが、企業コミュニティの Azure Council Experts(ACE)です。
会員企業の参加メリットを出しつつ、もっとオープンに活動していけるような運営を検討しているので、こちらもうまく軌道に乗せたいところです。
www.a-c-e.biz

正直なところ、コロナ禍でコミュニティ活動へのモチベーションが下がっていたので、今年は New Normal な活動スタイルを模索しつつ楽しんでいけたらと思います。