第2回「ユーザープリンシパルが対話操作でトークンを取得するパターン」— Microsoft Entra IDの認証の話(Azure周りの自動化編)
この記事の内容
- ユーザープリンシパルが対話的に認証してトークンを取得するフローを解説します
- PowerShellの
Connect-AzAccountコマンドを使ったブラウザ認証の手順を紹介します - 取得したトークンをAzure REST APIに渡してリソースグループを作成する方法を示します
New-AzResourceGroupのような高レベルコマンドが裏で行っていることを明らかにします- 対話認証では自動化が難しい理由と、次回のサービスプリンシパルへの布石を説明します
はじめに
本記事は、Microsoft Entra ID(Azure Active Directory)の認証について解説する全7回シリーズの第2回です。前回は「裏でトークンを取得してAPIに投げているだけ」という認証の本質をご紹介しました。今回はそれを踏まえて、一般ユーザーが対話的に認証を行うパターンを詳しく見ていきます。
「自分の処理を自動化したい」「でもパスワードをスクリプトに直接書くのは避けたい」という方に参考になる内容です。
対話認証の全体像
今回扱う構成要素は次の3つです。
- ユーザー — 認証を行う主体
- Microsoft Entra ID(Azure AD) — 認証を行い、トークンを返すサービス
- Azureサービス(REST API) — 今回はリソースグループの作成を行う対象
ユーザーがEntra IDと対話的にやり取りを行い(IDやパスワードの入力など)、認証が成功するとトークンが発行されます。そのトークンを使ってAzureのREST APIを叩くことで、リソース操作が可能になります。
Connect-AzAccountによる対話認証
PowerShellのAzモジュールでは、以下のコマンドで対話的に認証できます。
Connect-AzAccount
このコマンドを実行すると、ブラウザが起動し、Microsoft365のサインイン画面が表示されます。アドレスバーには以下のようなURLが表示されます。
これは認証フローの入り口となるURLです。スコープやクライアントIDなどのパラメータが含まれており、OAuth2.0の認可エンドポイントに対してリクエストが行われていることがわかります。
ブラウザとアカウントの紐付けについて
Connect-AzAccountは直前まで使用していたブラウザで新しいタブを開く動作をします。複数のブラウザでアカウントを使い分けている場合は、使用したいブラウザで事前に新しいタブを開いておくと意図したアカウントで認証しやすくなります。
多要素認証(MFA)への対応
Entra IDでは、管理者がさまざまな認証方法を構成できます。
- パスワード認証
- Microsoft Authenticatorアプリへの通知
- パスキー(FIDO2)
- セキュリティキー
パスワードレス認証を設定している場合は、Authenticatorアプリに通知が届き、表示された番号を入力することで認証が完了します。
また、エンタープライズ環境では条件付きアクセスによって、社内ネットワーク外からのアクセスには追加認証を要求するといった制御も可能です。アプリケーション側は「認証が通ったかどうか」だけを見ればよく、認証方式の詳細管理はEntra IDに委ねることができます。これが認証基盤として非常に優れている点です。
現在の認証コンテキストを確認する
Connect-AzAccount後、以下のコマンドで現在の認証状態を確認できます。
Get-AzContext
出力には次の情報が含まれます。
| 項目 | 内容 |
|---|---|
| Name | コンテキスト名(サブスクリプション名+テナントIDなど) |
| Account | 認証したアカウント(例: user@example.com) |
| Environment | 接続先Azureクラウド(AzureCloud / AzureChinaCloud など) |
| Subscription | 操作対象のサブスクリプションID |
| Tenant | 認証に使用したEntra IDのテナントID |
サブスクリプションの切り替え
複数のサブスクリプションを管理している場合は、操作対象を明示的に選択する必要があります。
# 利用可能なサブスクリプション一覧を取得
Get-AzSubscription
# 名前でフィルタリングして取得する例
Get-AzSubscription | Where-Object { $_.Name -like "*target*" }
# サブスクリプションIDで切り替え
Select-AzSubscription -SubscriptionId "<サブスクリプションID>"
トークンを直接取得する
認証後は以下のコマンドでアクセストークンを取得できます。
Get-AzAccessToken
取得したトークンには有効期限があります(概ね1時間程度)。トークンには発行元のテナントID情報も含まれており、Azure ADごとにテナントを指定してトークンを取得する必要があります。
取得したトークンはjwt.ioなどのサイトで内容を確認できます。前回の動画でブラウザが自動的に取得していたトークンと同様の構造であることがわかります。
REST APIでリソースグループを作成する
取得したトークンを変数に格納し、Azure REST APIを使ってリソースグループを作成する例を示します。
# トークンを取得して変数に格納
$token = (Get-AzAccessToken).Token
# サブスクリプションIDをコンテキストから取得
$subscriptionId = (Get-AzContext).Subscription.Id
# リソースグループ名とロケーションを指定
$resourceGroupName = "test-resourcegroup-1"
$location = "japaneast"
# REST APIのURLを構築
$uri = "https://management.azure.com/subscriptions/$subscriptionId/resourcegroups/$($resourceGroupName)?api-version=2021-04-01"
# ヘッダーを構築
$headers = @{
"Authorization" = "Bearer $token"
"Content-Type" = "application/json"
}
# ボディを構築
$body = @{
location = $location
} | ConvertTo-Json
# PUTリクエストでリソースグループを作成
Invoke-RestMethod -Method Put -Uri $uri -Headers $headers -Body $body
レスポンスにprovisioningState: Succeededが返ってくれば成功です。Azureポータルでも作成されたリソースグループを確認できます。なお、APIが受け付けてからリソースが実際にポータルに反映されるまでには若干のタイムラグがある点に注意してください。
New-AzResourceGroupコマンドの裏側
毎回REST APIを直接組み立てるのは手間がかかります。実際には以下のコマンドレットで同じことができます。
New-AzResourceGroup -Name "test-resourcegroup-2" -Location "japaneast"
このコマンドは、内部的に以下の処理をすべて自動で行っています。
- 認証済みトークンを自動取得
- サブスクリプションIDをコンテキストから取得
- REST APIのURLを構築
- リクエストを送信
普段の運用ではNew-AzResourceGroupなどの高レベルコマンドを使えばよいのですが、裏でどのような仕組みが動いているかを理解することが重要です。
対話認証と自動化の限界
Connect-AzAccountによる対話認証はユーザーが手動で操作する場面には適しています。しかし、スクリプトを定期的に自動実行したい場合には問題が生じます。
- ブラウザが起動してユーザーの入力を待つ
- 多要素認証のためにスマートフォン操作が必要になる
- 1時間ごとのトークン再取得が自動化できない
これらの制約から、完全自動化にはサービスプリンシパルを使う方法が必要になります。次回はサービスプリンシパルを使った認証フローについて解説します。
まとめ
今回は、ユーザープリンシパルが対話操作でトークンを取得するパターンを解説しました。
Connect-AzAccountでブラウザを通じた対話認証が行える- 認証方式(パスワード・MFA・パスキーなど)はEntra IDの管理者が構成でき、アプリ側は認証結果だけを使えばよい
Get-AzAccessTokenで取得したトークンをAuthorizationヘッダーに付与することで、Azure REST APIを直接呼び出せるNew-AzResourceGroupなどの高レベルコマンドは、このトークン取得とAPI呼び出しを内部で自動処理している- 対話認証は自動化に向かないため、定期実行スクリプトにはサービスプリンシパルの利用が必要になる
次回は、完全に自動化を実現するためのサービスプリンシパルを使った認証について解説します。