🆔

ユーザー割り当てマネージドIDが設定されたApp ServiceでDefaultAzureCredentialを使用する際の注意

2024/10/21に公開

はじめに

Azureではリソースに対してマネージドIDという機能があり、この機能を使うことによってパスワードなどの資格情報をユーザーが使用することなくリソースへアクセスできるようになります。
https://learn.microsoft.com/ja-jp/entra/identity/managed-identities-azure-resources/overview

今回はマネージドIDの利用で直面した問題について、備忘録としてまとめておきます。

問題について

前提条件

  • App Service
    • カスタムコンテナー (Linux)
    • 言語: Python
    • ユーザー割り当てマネージドIDを設定
      • キーコンテナーシークレットユーザーという役割を設定
  • Azure Key Vault
    • "secret-a"というシークレットを作成
      • あるサービスの接続文字列を設定
  • Application Insights, Azure Monitor
    • App Serviceのログ確認のため

やりたかったこと

  • App Service内のPythonのスクリプトからAzure Key Vaultに入れている"secret-a"というシークレットに設定されているシークレット値を取得したい
  • Azure Key Vaultの接続文字列はApp Serviceには設定しないで、マネージドIDで認証できるようにしたい

何が起きたのか?

Pythonのスクリプトで以下のように認証するためにDefaultAzureCredentialという関数を使用してマネージドIDによる認証をしようとしました。

from os import getenv

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from dotenv import load_dotenv

load_dotenv()

default_credential = DefaultAzureCredential()
keyvault_url = getenv("KEYVAULT_URL", "")

client = SecretClient(vault_url=keyvault_url, credential=default_credential)
keyvault_value = client.get_secret("secret-a").value
print(keyvault_value)

この認証をApp Serviceで実行しようとしたところ、以下のように認証エラーが起きてしまいました。

DefaultAzureCredential failed to retrieve a token from the included credentials.
Attempted credentials:
	EnvironmentCredential: EnvironmentCredential authentication unavailable. Environment variables are not fully configured.
Visit
https://aka.ms/azsdk/python/identity/environmentcredential/troubleshoot
to troubleshoot this issue.
	ManagedIdentityCredential: App Service managed identity configuration not found in environment. invalid_scope
	SharedTokenCacheCredential: SharedTokenCacheCredential authentication unavailable. No accounts were found in the cache.
	AzureCliCredential: Azure CLI not found on path
	AzurePowerShellCredential: PowerShell is not installed
	AzureDeveloperCliCredential: Azure Developer CLI could not be found. Please visit
https://aka.ms/azure-dev
for installation instructions and then,once installed, authenticate to your Azure account using 'azd auth login'.
To mitigate this issue, please refer to the troubleshooting guidelines here at
https://aka.ms/azsdk/python/identity/defaultazurecredential/troubleshoot.

以前システム割り当てマネージドIDを用いて同じような実装したときには問題なく認証が通っていたため、認証エラーが起きている原因が判明するまでに時間がかかりました。

原因

App Serviceに設定したマネージドIDがシステム割り当てマネージドIDではなく、ユーザー割り当てマネージドIDでした。ユーザー割り当てマネージドIDの場合は、別途マネージドIDのクライアントIDをスクリプト内もしくはApp Serviceの環境変数に設定する必要があるにもかかわらず、その設定ができていなかったために認証するために必要な情報が足りず、この認証エラーが起きました。

対応内容

ユーザー割り当てマネージドIDを設定した際にDefaultAzureCredentialを使用する場合はMicrosoft公式ドキュメントでは以下の2パターンのうちどちらかを対応する必要があると説明されています。

対応策1: DefaultAzureCredentialmanaged_identity_client_idという引数を使用することによりユーザー割り当てマネージドIDを使用することを明示する

from os import getenv

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
from dotenv import load_dotenv

load_dotenv()

client_id = "XXXXXXX"
default_credential = DefaultAzureCredential(managed_identity_client_id=client_id)
keyvault_url = getenv("KEYVAULT_URL", "")

client = SecretClient(vault_url=keyvault_url, credential=default_credential)
keyvault_value = client.get_secret("secret-a").value
print(keyvault_value)

対応策2: ソースコードは変更せずにApp Serviceの環境変数にAZURE_CLIENT_IDを作成し、その環境変数の値にユーザー割り当てマネージドIDのクライアントIDを設定する

AZURE_CLIENT_ID

参考資料

https://learn.microsoft.com/ja-jp/python/api/overview/azure/identity-readme?view=azure-python#specify-a-user-assigned-managed-identity-for-defaultazurecredential

対応方針

ソースコードを変更せずにローカルでもこの認証を動かせるようにしたい、かつクライアントIDを別途どのように管理するべきかを別途検討する必要があったため、今回は環境変数を設定する「対応策2」を採用しました。

結果として認証エラーは発生せず、App Service内のPythonスクリプトで資格情報を使用せずにAzure Key Vaultのシークレットの情報を取得できました。

おわりに

ユーザー割り当てマネージドIDを設定しているときにスクリプトでDefaultAzureCredentialを使用する場合は別途設定やスクリプトの改修が必要なことをまとめました。

ヘッドウォータース

Discussion