ユーザー割り当てマネージドIDが設定されたApp ServiceでDefaultAzureCredentialを使用する際の注意
はじめに
Azureではリソースに対してマネージドIDという機能があり、この機能を使うことによってパスワードなどの資格情報をユーザーが使用することなくリソースへアクセスできるようになります。
今回はマネージドIDの利用で直面した問題について、備忘録としてまとめておきます。
問題について
前提条件
- App Service
- カスタムコンテナー (Linux)
- 言語: Python
-
ユーザー割り当てマネージドIDを設定
- キーコンテナーシークレットユーザーという役割を設定
- Azure Key Vault
- "secret-a"というシークレットを作成
- あるサービスの接続文字列を設定
- "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パターンのうちどちらかを対応する必要があると説明されています。
DefaultAzureCredential
にmanaged_identity_client_id
という引数を使用することによりユーザー割り当てマネージドIDを使用することを明示する
対応策1: 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)
AZURE_CLIENT_ID
を作成し、その環境変数の値にユーザー割り当てマネージドIDのクライアントIDを設定する
対応策2: ソースコードは変更せずにApp Serviceの環境変数に参考資料
対応方針
ソースコードを変更せずにローカルでもこの認証を動かせるようにしたい、かつクライアントIDを別途どのように管理するべきかを別途検討する必要があったため、今回は環境変数を設定する「対応策2」を採用しました。
結果として認証エラーは発生せず、App Service内のPythonスクリプトで資格情報を使用せずにAzure Key Vaultのシークレットの情報を取得できました。
おわりに
ユーザー割り当てマネージドIDを設定しているときにスクリプトでDefaultAzureCredential
を使用する場合は別途設定やスクリプトの改修が必要なことをまとめました。
Discussion