サービス プリンシパルを使用したローカル開発時に Azure サービスに対して Python アプリを認証する
クラウド アプリケーションを作成する場合、開発者はローカル ワークステーションでアプリケーションをデバッグおよびテストする必要があります。 ローカル開発時に開発者のワークステーションでアプリケーションを実行する場合でも、アプリで使用されるすべての Azure サービスに対して認証する必要があります。 この記事では、ローカル開発時に使用する専用のアプリケーション サービス プリンシパル オブジェクトを設定する方法について説明します。
ローカル開発用の専用アプリケーション サービス プリンシパルを使用すると、アプリ開発時に最小限の特権の原則に従うことができます。 アクセス許可のスコープは開発時にアプリに必要なものだけに設定されるため、別のアプリで使用することを目的とした Azure リソースにアプリ コードが誤ってアクセスすることはありません。 また、これにより、開発環境でアプリに過剰な特権が与えられていたためにアプリが運用環境に移されたときに発生するバグも防ぐことができます。
アプリが Azure に登録されると、アプリケーション サービス プリンシパルがアプリ用に設定されます。 ローカル開発用にアプリを登録する場合は、次の手順を実行することをお勧めします。
- アプリで作業する開発者ごとに個別のアプリ登録を作成します。 これにより、開発者ごとにローカル開発時に使用する個別のアプリケーション サービス プリンシパルが作成され、開発者が 1 つのアプリケーション サービス プリンシパルの資格情報を共有する必要がなくなります。
- アプリごとに個別のアプリ登録を作成します。 これにより、アプリのアクセス許可のスコープがアプリに必要なものだけに設定されます。
ローカル開発時に、環境変数はアプリケーション サービス プリンシパルの ID で設定されます。 Azure SDK for Python では、これらの環境変数を読み取り、この情報を使用して、必要な Azure リソースに対してアプリが認証されます。
1 - Azure にアプリケーションを登録する
アプリケーション サービス プリンシパル オブジェクトは、Azure でアプリの登録を使用して作成されます。 これを行うには、Azure portal または Azure CLI のいずれかを使用します。
Azure CLI コマンドは、Azure Cloud Shell で、または Azure CLI がインストールされているワークステーション上で実行できます。
まず、az ad sp create-for-rbac コマンドを使用して、アプリの新しいサービス プリンシパルを作成します。 このコマンドは、アプリのアプリ登録も同時に作成します。
az ad sp create-for-rbac --name <service-principal-name>
このコマンドの出力は次のようになります。 これらの値をメモするか、次の手順でこれらの値が必要になり、パスワード (クライアント シークレット) 値を再び表示できなくなるため、このウィンドウを開いたままにします。 ただし、必要に応じて、サービス プリンシパルや既存のパスワードを無効にせずに、後で新しいパスワードを追加できます。
{
"appId": "00001111-aaaa-2222-bbbb-3333cccc4444",
"displayName": "<service-principal-name>",
"password": "Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6",
"tenant": "aaaabbbb-0000-cccc-1111-dddd2222eeee"
}
2 - ローカル開発用の Microsoft Entra セキュリティ グループを作成する
通常、アプリケーションで作業する開発者は複数いるため、個々のサービス プリンシパル オブジェクトにロールを割り当てるのではなく、Microsoft Entra セキュリティ グループを作成して、アプリがローカル開発で必要とするロール (アクセス許可) をカプセル化することをお勧めします。 これには次のような利点があります。
- ロールはグループ レベルで割り当てられるため、すべての開発者に同じロールが割り当てられることが保証されます。
- アプリに新しいロールが必要な場合は、アプリの Microsoft Entra グループに追加するだけで済みます。
- 新しい開発者がチームに参加する場合は、アプリで作業するための適切なアクセス許可が開発者に与えられるように、その開発者用に新しいアプリケーション サービス プリンシパルを作成してグループに追加します。
Microsoft Entra ID でセキュリティ グループを作成するには、az ad group create コマンドを使用します。 --display-name
パラメーターと --main-nickname
パラメーターは必須です。 グループに指定する名前は、アプリケーションの名前に基づく必要があります。 また、グループの名前に "local-dev" のような語句を含め、グループの目的も示すと便利です。
az ad group create \
--display-name MyDisplay \
--mail-nickname MyDisplay \
--description "<group-description>"
コマンド出力のid
プロパティ値をコピーします。 これはグループのオブジェクトIDです。 それは後のステップで必要になります。 このプロパティは、az広告グループ表示コマンドを使用して取得することもできます。
グループにメンバーを追加するには、アプリケーション サービス プリンシパルのオブジェクト ID が必要です。これは、アプリケーション ID とは異なります。 az ad sp list を使って、使用可能なサービス プリンシパルを一覧表示します。 --filter
パラメーター コマンドは OData スタイル フィルターを受け取り、表示されているリストをフィルター処理するために使用できます。 --query
パラメーターでは、必要な列のみに制限されます。
az ad sp list \
--filter "startswith(displayName, 'msdocs')" \
--query "[].{objectId:id, displayName:displayName}" \
--output table
その後、az ad group member add コマンドを使用して、グループにメンバーを追加できます。
az ad group member add \
--group <group-name> \
--member-id <object-id>
Note
デフォルトでは、Microsoft Entraセキュリティグループの作成は、ディレクトリ内の特定の特権ロールに制限されます。 グループを作成できない場合は、ディレクトリの管理者に問い合わせてください。 既存のグループにメンバーを追加できない場合は、グループオーナーまたはディレクトリ管理者に問い合わせてください。 詳細については、「Microsoft Entraグループとグループ メンバシップの管理」を参照してください。
3 - アプリケーションにロールを割り当てる
次に、アプリで必要なリソースに対して必要なロール (アクセス許可) を決定し、それらのロールをアプリに割り当てる必要があります。 この例では、手順 2 で作成した Microsoft Entra グループにロールが割り当てられます。 役割は、リソース、リソースグループ、またはサブスクリプションの範囲で割り当てることができます。 次に、ほとんどのアプリケーションがすべてのAzureリソースを1つのリソースグループにグループ化するため、リソースグループスコープでロールを割り当てる例を示します。
azロール割り当て作成コマンドを使用して、Azureでユーザー、グループ、またはアプリケーションサービスのプリンシパルにロールが割り当てられます。 オブジェクトIDでグループを指定できます。 アプリケーション サービス プリンシパルを、appId で指定できます。
az role assignment create --assignee <appId or objectId> \
--scope /subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName> \
--role "<roleName>"
割り当て可能なロール名を取得するには、azロール定義リストコマンドを使用します。
az role definition list \
--query "sort_by([].{roleName:roleName, description:description}, &roleName)" \
--output table
たとえば、appId が 00001111-aaaa-2222-bbbb-3333cccc4444
であるアプリケーション サービス プリンシパルに、ID が aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e
であるサブスクリプションに含まれる msdocs-python-sdk-auth-example リソース グループのすべてのストレージ アカウントの Azure Storage blob コンテナとデータへの読み取り、書き込み、および削除のアクセスを許可するには、次のコマンドを使用して、アプリケーション サービス プリンシパルをストレージ BLOB データ共同作成者ロールに割り当てます。
az role assignment create --assignee 00001111-aaaa-2222-bbbb-3333cccc4444 \
--scope /subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/resourceGroups/msdocs-python-sdk-auth-example \
--role "Storage Blob Data Contributor"
Azure CLI を使用してリソースまたはサブスクリプション レベルでアクセス許可を割り当てる方法については、「Azure CLI を使用して Azure ロールを割り当てる」を参照してください。
4 - ローカル開発の環境変数を設定する
DefaultAzureCredential
オブジェクトでは、実行時に一連の環境変数でサービス プリンシパル情報を検索します。 ほとんどの開発者は複数のアプリケーションで作業するため、python-dotenv などのパッケージを使用して、開発時にアプリケーションのディレクトリに格納されている .env
ファイルから環境にアクセスすることをお勧めします。 このようにすると、Azure に対してアプリケーションを認証するために使用される環境変数のスコープが設定され、このアプリケーションのみで使用できます。
.env
ファイルには Azure のアプリケーション シークレット キーが含まれているので、ソース管理にチェックインされることはありません。 Python 用の標準の .gitignore ファイルでは、チェックインから .env
ファイルが自動的に除外されます。
python-dotenv パッケージを使用するには、まずアプリケーションにパッケージをインストールします。
pip install python-dotenv
次に、アプリケーションのルート ディレクトリに .env
ファイルを作成します。 次のように、アプリ登録プロセスから取得した値を使用して環境変数の値を設定します。
AZURE_CLIENT_ID
→ アプリ ID の値です。AZURE_TENANT_ID
→ テナント ID の値です。AZURE_CLIENT_SECRET
→アプリ用に生成されたパスワード/資格情報。
AZURE_CLIENT_ID=00001111-aaaa-2222-bbbb-3333cccc4444
AZURE_TENANT_ID=aaaabbbb-0000-cccc-1111-dddd2222eeee
AZURE_CLIENT_SECRET=Ee5Ff~6Gg7.-Hh8Ii9Jj0Kk1Ll2Mm3_Nn4Oo5Pp6
最後に、アプリケーションのスタートアップ コードで、python-dotenv
ライブラリを使用して、起動時に .env
ファイルから環境変数を読み取ります。
from dotenv import load_dotenv
if ( os.environ['ENVIRONMENT'] == 'development'):
print("Loading environment variables from .env file")
load_dotenv(".env")
5 - アプリケーションに DefaultAzureCredential を実装する
Azure SDK クライアント オブジェクトを Azure に対して認証するには、アプリケーションで DefaultAzureCredential
パッケージから azure.identity
クラスを使用する必要があります。 このシナリオでは、DefaultAzureCredential
で環境変数 AZURE_CLIENT_ID
、AZURE_TENANT_ID
、AZURE_CLIENT_SECRET
が設定されていることを検出し、それらの変数を読み取り、Azure に接続するアプリケーション サービス プリンシパル情報を取得します。
まず、azure.identity パッケージを アプリケーションに追加します。
pip install azure-identity
次に、アプリで Azure SDK クライアント オブジェクトを作成する Python コードでは、次のことが必要になります。
DefaultAzureCredential
モジュールからazure.identity
クラスをインポートします。DefaultAzureCredential
オブジェクトを作成します。- Azure SDK クライアント オブジェクト コンストラクターに
DefaultAzureCredential
オブジェクトを渡します。
この例を次のコード セグメントに示します。
from azure.identity import DefaultAzureCredential
from azure.storage.blob import BlobServiceClient
# Acquire a credential object
token_credential = DefaultAzureCredential()
blob_service_client = BlobServiceClient(
account_url="https://<my_account_name>.blob.core.windows.net",
credential=token_credential)