ASP.NET Coreで作成したアプリをAzure Web Appで動かしAzure OpenAIにアクセスする場合、Microsoftのドキュメントでは認証をマネージドID認証にし、設定項目(エンドポイントなど)はKeyVaultに格納するという方法が記載されていました。ネットワーク的に制限をかける方法なども考えられますが、今回はC#のソースコードで考慮しないといけないこの2つを試してみます。
まず、マネージドID認証にする方法はこちらのドキュメントを参照します。
まず、記事の手順でAzure側の操作を行い、Azure Web AppsからOpenAIへのマネージド認証を有効にします。まず、Azure Web AppsのIdentityでStatusを有効にします。

この画面のAdd role assigmentからはアサイン済みのマネージドIDが確認でき、追加メニューもありますが一部のリソース種類のみでOpenAIは指定できませんが、OpenAIを含むリソースグループやサブスクリプションを指定することはできます。次の手順で設定するKeyVaultはここから追加できます。下の画面は次の手順まで実施したあとの様子です。今回はシステム割り当て IDを使っています。

さてコードについてですが、前回の記事のコードを書き換える場合を考えます。
まずAzure.IdentityというNuGetライブラリを追加します。次にAPIKeyを指定する代わりに、次のようにDefaultAzureCredentialのインスタンスを指定します。別のコンストラクタを呼び出すことになります。
var credentials = new DefaultAzureCredential(); var options = sp.GetRequiredService<IOptions<AzureOpenAIOptions>>().Value; var kernelBuilder = Kernel.CreateBuilder(); kernelBuilder.AddAzureOpenAIChatCompletion( deploymentName: options.ChatDeploymentName, endpoint: options.Endpoint, credentials: credentials );
ユーザー割り当てIDを使う場合は次のようになります。
var credentials = new DefaultAzureCredential( new DefaultAzureCredentialOptions { ManagedIdentityClientId = "myIdentityClientId". } );
これで認証はできましたが、このままWebAppsで動かしても前回のコードのままだとdotnet secretに設定したエンドポイントなどの情報が取得できません。そこで次の記事を参照してAzure KeyVaultに格納した情報を取得するようにします。
KeyVaultを作成して、WebAppsからのマネージドIDをアサインします。アサインの手順はOpenAIの時と同様です。次にdotnet secretに格納した情報をKeyVaultのsecretに保存しますが、secretの名前はSection--SecretNameという形式にします。AzureOpenAI--ChatDeploymentNameとAzureOpenAI--ChatDeploymentNameという名前になります。
コード側はまずAzure.Extensions.AspNetCore.Configuration.SecretsというNuGetライブラリを追加します。上の手順で追加したAzure.Identityも必要です。そしてoptionsを取得する手前に次のコードを挿入します。
builder.Configuration.AddAzureKeyVault(
new Uri($"https://{builder.Configuration["KeyVaultName"]}.vault.azure.net/"),
credentials);
ドキュメントではKeyVaultNameをConfigurationから取得していたので環境変数に設定しました。またif (builder.Environment.IsProduction())で括っていましたが、同じコードベースでAzure WebApps以外で動かす場合にEnvironmentを切り替えて別の認証を行うことを想定しているはずです。
最後に、前の記事ではAzureOpenAIOptionsクラスにApiKeyプロパティを用意していたので削除するか、null許容にしておきます。
以上の対応で冒頭に紹介した2つの対応が完了しました。