- はじめに
- マネージドID接続のソースコード
- マネージドID接続を使うときの悩みどころ
- DefaultAzureCredential を使おう
- DefaultAzureCredential は何をやっているのか
- ハマったこと①:App Configurationのロール割り当て設定
- ハマったこと②:ゲストアカウントの場合はオプションにテナントIDを指定する必要がある
- ハマったこと③:複数バージョンのVisual Studioがインストールされていると認証エラーが発生する
- まとめ
はじめに
エンタープライズ サービス部の乙黒です。 この投稿は NEXTSCAPE Advent Calendar 2022 の3日目の記事です。
この記事ではAzureのApp ServiceからApp Configurationへ接続する場合を例に、ローカルデバッグ時の認証とAzure上でのマネージドID認証をワンコードで書く方法について紹介します。
注意点
- Visual Studio 2022で.NET 6のWeb APIを開発し、Azure App Serviceへデプロイすることを前提に記述しています。
- 実運用ではシークレット情報はKey Vaultに保存し、App Configurationを繋げていますが、簡素化のために省いています。
- Azure App ConfigurationやマネージドIDについての説明は省きますので、下記の記事などをご参照ください。
マネージドID接続のソースコード
この記事を参考にして、Program.csでの接続設定のコードは次のようになります。
var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddAzureAppConfiguration(options => { options.Connect( new Uri("https://{App Configurationのリソース名}.azconfig.io"), new ManagedIdentityCredential()); });
見ての通り、ソースコードで指定されているのはApp ConifgurationのエンドポイントURLのみです。ソースコードや設定ファイルに接続文字列、シークレット情報を記述する必要がなくなるため、管理が楽になります。
マネージドID接続を使うときの悩みどころ
App Configurationへの接続に限らず、マネージドIDを使ってAzureのリソース間を繋げるときに厄介なのが
- マネージドIDはAzure上でしか動作しない
という点です。つまり、上に挙げたソースコードだと、ローカルデバッグ時に認証エラーが起きてしまいます。
シンプルにこれを解決しようとすると #if ディレクティブを利用して
- デバッグ構成のときは接続文字列で認証
- リリース構成のときはマネージドIDで認証
と分ける方法がパッと思いつきます。コードにするとこんな感じです。
var builder = WebApplication.CreateBuilder(args); #if DEBUG builder.Configuration.AddAzureAppConfiguration("{App Configurationへの接続文字列}"); #else builder.Configuration.AddAzureAppConfiguration(options => { options.Connect( new Uri("https://{App Configurationのリソース名}.azconfig.io"), new ManagedIdentityCredential()); }); #endif
この例には
- ローカル デバッグ中は リリース ビルド側にビルドエラーになるようなバグがあっても見落とされがちになる。
- パッケージ化したい場合は使えない
等の問題があります。
DefaultAzureCredential を使おう
この問題を解決するのが DefaultAzureCredential です。DefaultAzureCredential を使えば、ローカルデバッグ時の認証とAzure上でのマネージドID認証をこんな風にワンコードで書くことができます。
var builder = WebApplication.CreateBuilder(args); builder.Configuration.AddAzureAppConfiguration(options => { options.Connect( new Uri("https://{App Configurationのリソース名}.azconfig.io"), new DefaultAzureCredential()); });
DefaultAzureCredential は何をやっているのか
この記事を書いている時点で日本語翻訳されていないのですが、こちらに仕様が書かれています。
簡単に言うと、
- 様々な認証方式を順に試して、成功したら処理を抜ける
ということをやっています。
認証を試行する順序の2番目のManagedIdentityCredentialがあり、Azure上にデプロイされたときはマネージドID認証が使われることになります。
また、Visual Studioでローカル デバッグしているときは4番目の VisualStudioCredentialを使って、Visual Studioにサインインしているアカウントで認証が行われます。
以下、実際にデバッグ実行してみたところ、上手くいかずにハマった点がいくつかあったため、紹介しておきます。
ハマったこと①:App Configurationのロール割り当て設定
- Visual Studioからデバッグするユーザーには「App Configuration データ閲覧者」を割り当てる必要がある。
こちらの記事にも書いてありますが、「閲覧者」、「共同作成者」、「所有者」のいずれもApp Configurationデータの読み取り割アクセス権を持ちません。 データを読み取るには「App Configuration データ閲覧者」を割り当てる必要があります。
ハマったこと②:ゲストアカウントの場合はオプションにテナントIDを指定する必要がある
Visual Studioからデバッグするユーザーが異なるAADテナントから参加している場合、DefaultAzureCredentialOptionsでテナントIDを指定しないと認証が通りません。
var builder = WebApplication.CreateBuilder(args); var credentialOptions = new DefaultAzureCredentialOptions() { TenantId = "{テナントID}" }; builder.Configuration.AddAzureAppConfiguration(options => { options.Connect( new Uri("https://{App Configurationのリソース名}.azconfig.io"), new DefaultAzureCredential(credentialOptions)); });
ハマったこと③:複数バージョンのVisual Studioがインストールされていると認証エラーが発生する
Visual Studio 2022 でデバッグしていたところ、どうしても認証が通らず、深みにハマりました。
認証エラーのメッセージを見てみると、Microsoft.Asal.TokenService.exeのパスが「2019」になっていました。
Process "C:\Program Files\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\Asal\TokenService\Microsoft.Asal.TokenService.exe" has failed with unexpected error: (以下省略)
私の環境ではVS 2019とVS 2022の2つのバージョンのVisual Studioがインストールされており、どういう訳かVS 2022でのデバッグ中もVS 2019のexeが実行されてしまい、一向にトークンが取得できない状況になっていました。 環境変数を修正すれば正常化する可能性もありますが、私の場合はVS 2019が既に不要だったため、アンインストールすることで正常化しました。
まとめ
ローカルデバッグ時の認証とAzure上でのマネージドID認証をワンコードで書く方法について紹介させていただきました。 Azure Functionsへの応用やKeyVaultとの接続についても、機会がありましたら書かせていただきたいと思います。