Key Vault Contributorを付与したのに、アプリからAzure Key Vaultのシークレットを取得できず、403エラーになることがあります。
この場合、最初に確認すべきなのは権限の種類と付与先のIDです。Key Vault Contributorは、Vaultの作成や設定変更などを行う管理プレーンのロールであり、シークレット値を読み取るデータプレーン権限を含みません。
対象Vaultのアクセス許可モデルが「Azure RBAC」か「アクセスポリシー」かを確認し、実際にKey VaultへアクセスしているマネージドIDやサービスプリンシパルへ、必要なデータプレーン権限を付与します。Azure RBAC方式でシークレット値の読み取りだけが必要なら、代表的なロールは「Key Vault Secrets User」です。「Key Vault Reader」ではシークレットの名前や属性は確認できますが、値は取得できません。([Microsoft Learn][1])
Key Vaultを管理できるのにシークレットを読めない理由
Azure Key Vaultへのアクセスは、大きく「管理プレーン」と「データプレーン」に分かれます。
| 区分 | 主な操作 | 権限を制御する仕組み |
|---|---|---|
| 管理プレーン | Vaultの作成、削除、設定変更、タグ変更など | Azure RBAC |
| データプレーン | シークレット値の取得、登録、削除、キー操作など | Azure RBACまたはアクセスポリシー |
Key Vault Contributorが対象とするのは、主に管理プレーンです。
そのため、次のような状態は矛盾ではありません。
- AzureポータルでKey Vaultを開ける
- Vaultの設定やプロパティを確認できる
- Key Vault Contributorが割り当てられている
- それでもアプリからシークレット値を取得すると403になる
Vaultを管理できることと、Vault内に保存された機密情報を読めることは、別の権限として扱われます。Microsoftの組み込みロール定義でも、Key Vault ContributorにはデータプレーンのDataActionsが含まれていません。([Microsoft Learn][1])
Key Vault関連ロールの違い
シークレット取得時に混同しやすいロールを整理すると、次のようになります。
| ロール | シークレット値の読み取り | シークレットの更新 | 主な用途 |
|---|---|---|---|
| Key Vault Contributor | 不可 | 不可 | Vaultリソース自体の管理 |
| Key Vault Reader | 不可 | 不可 | キー、証明書、シークレットのメタデータ確認 |
| Key Vault Secrets User | 可 | 不可 | アプリによるシークレット値の読み取り |
| Key Vault Secrets Officer | 可 | 可 | シークレットの作成、更新、削除など |
| Key Vault Administrator | 可 | 可 | Vault内のキー、証明書、シークレット全般の管理 |
アプリが既存のシークレットを読むだけなら、Key Vault Secrets OfficerやKey Vault Administratorを付与する必要は通常ありません。書き込みや削除まで許可してしまうため、Key Vault Secrets Userから検討するのが基本です。
また、名前に「Reader」が含まれていても、Key Vault Readerは機密値を読み取るロールではありません。シークレットの値を取得できるのは、getSecretに相当するデータアクションを持つロールです。([Microsoft Learn][1])
403エラーを切り分ける確認手順
対象Vaultのアクセス許可モデルを確認する
Azure Key Vaultのデータプレーンには、次の2種類のアクセス許可モデルがあります。
- Azureロールベースのアクセス制御
- 従来のVaultアクセスポリシー
どちらを使用しているかによって、権限の付与方法が変わります。
Azure RBAC方式のVaultにアクセスポリシーを追加しても、そのポリシーはシークレット取得の判定に使われません。反対に、アクセスポリシー方式のVaultへKey Vault Secrets Userを付与しても、データプレーンのアクセス許可としては使われません。([Microsoft Learn][2])
Azure CLIでは、次のように確認できます。
az keyvault show \
--name <vault-name> \
--resource-group <resource-group> \
--query properties.enableRbacAuthorization \
--output tsv
結果の見方は次のとおりです。
| 結果 | アクセス許可モデル |
|---|---|
true | Azure RBAC |
false | Vaultアクセスポリシー |
値が取得できない場合は、Azureポータルの対象Vaultでもアクセス許可モデルを確認してください。画面名称はポータル更新で変わる可能性がありますが、Vaultのアクセス構成または権限モデルに関する設定から確認できます。
実際にアクセスしているアプリのIDを確認する
権限の付与先は、「アプリの名前」ではなく、Key Vaultへアクセストークンを提示しているセキュリティプリンシパルです。
代表的なアクセス主体には、次のものがあります。
| 実行環境 | 実際に使われる可能性があるID |
|---|---|
| ローカル開発環境 | Azure CLIやVisual Studioにサインインしているユーザー |
| App Service、Functions、VMなど | システム割り当てマネージドID |
| 複数リソースで共通IDを使う構成 | ユーザー割り当てマネージドID |
| クライアントシークレットや証明書で認証 | サービスプリンシパル |
よくあるのは、開発者ユーザーへ権限を付けたものの、本番環境ではマネージドIDが使われているケースです。
また、ユーザー割り当てマネージドIDをAzureリソースへ接続しただけでは、アプリが必ずそのIDを使用するとは限りません。複数のIDが存在する構成では、アプリ側で使用するクライアントIDなどを明示する必要があります。
ローカル開発時のDefaultAzureCredentialは、Azure CLIやVisual Studioなどの開発者資格情報を利用することがあります。一方、Azure上ではマネージドIDを使用する構成が一般的です。ローカルで成功したという事実だけでは、本番アプリのマネージドIDにも権限があるとは判断できません。([Microsoft Learn][3])
クライアントIDとプリンシパルIDを混同しない
ユーザー割り当てマネージドIDには、クライアントIDとプリンシパルIDがあります。
- クライアントID:アプリ側で使用するマネージドIDを指定するときに使う
- プリンシパルID:Azure RBACの割り当て対象として使う
- オブジェクトID:マネージドIDではプリンシパルIDと同じ意味で扱われる
Azure CLIの--assignee-object-idには、クライアントIDではなくプリンシパルIDを指定します。([Microsoft Learn][4])
ユーザー割り当てマネージドIDのプリンシパルIDは、次の例で確認できます。
az identity show \
--resource-group <identity-resource-group> \
--name <managed-identity-name> \
--query principalId \
--output tsv
システム割り当てマネージドIDの場合は、アプリを実行しているAzureリソースの「ID」設定などからプリンシパルIDを確認します。
Azure RBAC方式でロール割り当てを確認する
VaultのリソースIDを取得する
VAULT_ID=$(az keyvault show \
--name <vault-name> \
--resource-group <resource-group> \
--query id \
--output tsv)
実際のプリンシパルに付いたロールを確認する
az role assignment list \
--assignee-object-id <principal-id> \
--scope "$VAULT_ID" \
--include-inherited \
--output table
--include-inheritedを付けると、Vault自体だけでなく、リソースグループやサブスクリプションなどの上位スコープから継承された割り当ても確認できます。([Microsoft Learn][4])
確認するときは、ロール名だけでなく、次の3点を合わせて見ます。
- 割り当て先のプリンシパルIDがアプリの実体と一致しているか
- ロールにシークレット値の読み取り権限があるか
- 割り当てスコープに対象Vaultが含まれているか
別の開発環境用Vaultや、名前の似たマネージドIDへ付与していることもあります。プリンシパルIDとVaultのリソースIDを文字列で照合するのが確実です。
読み取り専用ならKey Vault Secrets Userを付与する
アプリが既存シークレットの値を読むだけなら、Key Vault Secrets Userを候補にします。
Key Vault Secrets Userの組み込みロールIDは、次の値です。
4633458b-17de-408a-b874-0445c86b69e6
マネージドIDまたはサービスプリンシパルへ付与する例は次のとおりです。
az role assignment create \
--assignee-object-id <principal-id> \
--assignee-principal-type ServicePrincipal \
--role 4633458b-17de-408a-b874-0445c86b69e6 \
--scope "$VAULT_ID"
ロール名でも指定できます。
az role assignment create \
--assignee-object-id <principal-id> \
--assignee-principal-type ServicePrincipal \
--role "Key Vault Secrets User" \
--scope "$VAULT_ID"
継続的に使用する自動化スクリプトでは、ロール名の変更による影響を避けるため、ロールIDを使う方法が適しています。Microsoftのドキュメントでも、スクリプトでは一意のロールIDを使う方法が推奨されています。([Microsoft Learn][1])
ロールを付与するスコープ
ロールは、サブスクリプション、リソースグループ、個別のVault、個別のシークレットなどに割り当てられます。
アプリ単位、環境単位でVaultを分けている場合は、対象Vaultのスコープへ割り当てる方法が分かりやすく、権限も限定できます。
| スコープ | 特徴 |
|---|---|
| サブスクリプション | 対象が広く、通常のアプリには過剰になりやすい |
| リソースグループ | 同じグループ内の複数Vaultへ権限が及ぶ |
| Key Vault | 対象Vault内のシークレットを利用する一般的な構成 |
| 個別シークレット | 特定のシークレットだけを共有する限定的な構成 |
Microsoftは、アプリと環境ごとにVaultを分け、Vaultスコープでロールを割り当てる構成を推奨しています。個別シークレットへの割り当ては、特別な共有要件がある場合などに限定して検討します。([Microsoft Learn][1])
アクセスポリシー方式の場合の対応
対象Vaultがアクセスポリシー方式なら、Azure RBACのデータプレーンロールではなく、アクセスポリシーへアプリのIDを追加します。
既知のシークレット名を指定して値を取得するだけなら、基本的に必要なのはget権限です。
az keyvault set-policy \
--name <vault-name> \
--object-id <principal-id> \
--secret-permissions get
アプリがシークレットを列挙する必要がある場合は、要件を確認したうえでlistも追加します。
az keyvault set-policy \
--name <vault-name> \
--object-id <principal-id> \
--secret-permissions get list
ここで指定するobject-idも、権限を与えたいマネージドIDやサービスプリンシパルのオブジェクトIDです。([Microsoft Learn][5])
アクセスポリシー方式では、Key Vault ContributorなどMicrosoft.KeyVault/vaults/writeを持つユーザーがアクセスポリシーを変更し、自分自身へデータプレーン権限を付与できる構成になります。この分離の弱さから、MicrosoftはAzure RBAC方式を推奨しています。([Microsoft Learn][2])
ロールを割り当てる担当者にも権限が必要
Key Vault Contributorを持っていても、Azure RBAC方式でロール割り当てを作成できるとは限りません。
ロール割り当てには、Microsoft.Authorization/roleAssignments/writeなどの権限が必要です。代表的には、次のロールを持つ担当者が実施します。
- Owner
- User Access Administrator
- Key Vault Data Access Administrator
Key Vault Data Access Administratorは、Key Vault Administrator、Key Vault Secrets User、Key Vault Readerなど、対象となるKey Vaultデータプレーンロールの割り当てを管理するためのロールです。
Azureポータルで「ロールの割り当ての追加」が無効になっている場合や、Azure CLIでAuthorizationFailedになる場合は、アプリ側ではなく、割り当てを実行している管理者の権限を確認してください。([Microsoft Learn][1])
権限反映後は同じIDで取得を確認する
ロールを付与した後は、反映まで数分かかる場合があります。Azureポータルを使用している場合は、画面の再読み込みも行います。([Microsoft Learn][1])
確認では、管理者ユーザーではなく、実際のアプリと同じIDを使用することが重要です。
Azure CLIを同じプリンシパルで認証できている場合は、次のように戻り値をシークレットIDだけに限定できます。
az keyvault secret show \
--vault-name <vault-name> \
--name <secret-name> \
--query id \
--output tsv
この確認は、Azure CLIがアプリと同じマネージドIDまたはサービスプリンシパルで認証されている場合にのみ有効です。自分の管理者アカウントで実行して成功しても、アプリの権限が直った証明にはなりません。
アプリ側で確認する場合も、ログには次の情報だけを記録します。
- 取得成功または失敗
- HTTPステータス
- エラーコード
- リクエストID
- 実行日時
- 使用したプリンシパルID
シークレット値そのものはログへ出力しないでください。
よくある誤った対応
Key Vault Contributorを付け直す
Key Vault Contributorにはシークレット値の読み取り権限がありません。付与し直したり、上位スコープへ広げたりしても、データプレーン権限の不足は解決しません。
Key Vault Readerを追加する
Key Vault Readerは、シークレットの名前や属性などのメタデータを読むためのロールです。シークレット値の取得にはKey Vault Secrets Userなどが必要です。
開発者ユーザーへ権限を付ける
ローカルでは開発者ユーザー、本番ではマネージドIDという構成がよくあります。本番アプリが使用するプリンシパルIDへ付与しなければ、アプリの403は解消しません。
アプリ名だけで付与先を判断する
同じような名前のマネージドID、サービスプリンシパル、アプリ登録が存在することがあります。表示名ではなく、プリンシパルIDで確認します。
最初からSecrets OfficerやAdministratorを付ける
読み取りだけのアプリへ、作成、更新、削除まで可能なロールを付けるのは過剰です。必要な操作からロールを逆算します。
| アプリの操作 | 検討するロール |
|---|---|
| 既存シークレットの値を読む | Key Vault Secrets User |
| シークレットを作成、更新、削除する | Key Vault Secrets Officer |
| キー、証明書、シークレット全般を管理する | Key Vault Administrator |
| メタデータだけを確認する | Key Vault Reader |
403だけを理由にRBACへ切り替えない
アクセスポリシー方式のVaultで403が発生したからといって、原因確認をせずAzure RBAC方式へ切り替えるのは危険です。
アクセス許可モデルをAzure RBACへ変更すると、既存のアクセスポリシーによる権限は無効になります。同等のAzure RBACロールが用意されていなければ、アプリ、バッチ処理、運用ツールなどが一斉にKey Vaultへアクセスできなくなる可能性があります。([Microsoft Learn][1])
切り替えを行う場合は、少なくとも次の対象を洗い出します。
- アプリケーション
- マネージドID
- サービスプリンシパル
- 運用担当ユーザー
- バックアップや監視処理
- CI/CDパイプライン
- 証明書更新処理
- シークレットを参照するAzureサービス
403の解消だけが目的なら、まず現在のアクセス許可モデルを維持したまま、ID、権限、スコープの不一致を修正してください。
対象外となるサービス
ここまでの説明は、Azure Key Vaultのvaultsリソースを対象としています。
Managed HSMはアクセス制御の仕組みが異なるため、この記事のKey Vault Contributor、Key Vault Secrets User、Vaultアクセスポリシーに関する手順をそのまま適用することはできません。([Microsoft Learn][1])
Key Vaultの403はモデル、ID、ロール、スコープの順で確認する
Key Vault Contributorなのにアプリからシークレット取得が拒否される場合、確認する順番は次のとおりです。
- 対象VaultがAzure RBAC方式かアクセスポリシー方式か確認する
- アプリが実際に使用しているプリンシパルIDを特定する
- そのIDにデータプレーン権限が付いているか確認する
- Azure RBAC方式なら、読み取り用途にKey Vault Secrets Userを検討する
- Vault、リソースグループ、サブスクリプションなど、割り当てスコープを確認する
- 反映後はアプリと同じIDで取得を再確認する
- シークレット値はテスト結果やログへ出力しない
「Vaultを管理できるからシークレットも読める」と考えず、管理プレーンとデータプレーンを分けて確認することが、最短の切り分け方法です。
[1]: https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-guide “Grant permission to applications to access an Azure key vault using Azure RBAC | Microsoft Learn”
[2]: https://learn.microsoft.com/en-us/azure/key-vault/general/rbac-access-policy “Azure role-based access control (Azure RBAC) vs. access policies | Microsoft Learn”
[3]: https://learn.microsoft.com/en-us/dotnet/azure/sdk/authentication/user-assigned-managed-identity “Authenticate Azure-hosted .NET apps to Azure resources using a user-assigned managed identity – .NET | Microsoft Learn”
[4]: https://learn.microsoft.com/en-us/cli/azure/role/assignment?view=azure-cli-latest “az role assignment | Microsoft Learn”
[5]: https://learn.microsoft.com/en-us/azure/key-vault/general/assign-access-policy “Assign an Azure Key Vault access policy (CLI) | Microsoft Learn”

コメント