セイテクエンジニアのブログ かつて山市良と呼ばれたおじさんのブログ vol.59 いきなりのMicrosoft Graph REST API|Azure&Entra IDスクリプト大作戦(6)
2024年11月11日配信
執筆者:山内 和朗
Azureのリソース情報取得にAzure REST APIを使用したのは、クライアント側にAzure PowerShellやAzure CLIをインストールする必要がなく、PowerShellのInvoke-WebRequest、Invoke-RestMethodコマンドレットやCurlコマンドなど、HTTPクライアントを使用できるからです(vol.56およびvol.57を参照)。Microsoft Graph REST APIでも同じようにできるはずです。
これまでにAzureのサービスにサービスプリンシパルを使用して接続し、Azure REST APIからリソース情報を取得したり、テンプレートを生成、取得したりする方法を学んできました。前回(vol.58)は、Microsoft Graph PowerShellとGraph Explorerを使用して、Microsoft Graphのサービスにアクセスするには、アクセス許可を要求する必要があり、アクセス許可によっては、管理者の同意が必要であることを知りました。これらの知識と経験があれば、Microsoft Graph REST APIに非対話型認証で接続し、リソース情報を取得する一連の操作をスクリプト化できるはずです。
前回に引き続き、Azureで使用したのとは異なる、グローバル管理者権限を持つ評価用のMicrosoft 365サブスクリプションを使用します。Microsoft Graphサービスに非対話型認証で接続するために、「サービスプリンシパル」を準備します。非対話型認証は、サービスプリンシパルの他に、マネージドIDでもサポートされています。
今回は、Azureのときと同様に、パスワード(クライアントシークレットの値)ベースの認証を有効にしたサービスプリンシパルを用意しました(証明書ベースの認証を使用することもできます)。具体的な手順は、以下のドキュメントで説明されています。
Microsoft ID プラットフォームにアプリケーションを登録する|Microsoft Graph(Microsoft Learn)
「Microsoft管理センター」(https://entra.microsoft.com/)にグローバル管理者のユーザーでサインインし、「ID > アプリケーション > アプリの登録」を開いて、「+新規登録」をクリックします。アプリケーションの表示名として分かりやすい名前(例: msgapp)を入力し、アカウントの種類として「この組織ディレクトリのみに含まれるアカウント(<テナント名> のみ - シングル テナント)」を選択し、「登録」をクリックします(画面1)。「リダイレクト URI(省略可能)」の指定は不要です。これについては後で設定します。
画面1 Microsoft Entra管理センターの「アプリの登録」で、Microsoft Graphサービスへのアクセスに使用するサービスプリンシパルを作成する
登録したアプリケーションの「認証」を開き、「+プラットフォームの追加」をクリックして、「モバイルアプリケーションとデスクトップ アプリケーション」を選択し、カスタムリダイレクトURLに「http://localhost」と入力して、「構成」をクリックします(画面2)。
画面2 「モバイルアプリケーションとデスクトップ アプリケーション」を選択し、カスタムリダイレクトURLに「http://localhost」と入力
登録したアプリケーションの「証明書とシークレット」を開き、「+新しいクライアントシークレット」をクリックして、有効期限付き(無制限は不可)のクライアントシークレットを追加します。クライアントシークレットが追加されたら、その「値」の横にある「クリップボードにコピー」を使用して、クライアントシークレットの値を(メモ帳などに貼り付けて)控えておきます(画面3)。また、アプリケーションの「概要」を開き、「アプリケーション(クライアント)ID」と「ディレクトリ(テナント)ID」も同じように控えておきます(画面4)。
画面3 クライアントシークレットを追加し、その値を控えておく
画面4 アプリケーションの「アプリケーション(クライアント)ID」と、このMicrosoft 365テナントの「ディレクトリ(テナント)ID」も控えておく
Azure REST APIのアクセスでは、Azureのリソースの「アクセス制御(IAM)」で必要最小限のアクセス許可を与えます。サブスクリプションレベルで「閲覧者」ロールを割り当てれば、すべてのリソース情報を「閲覧者」として参照できましたが、個々のリソースレベルでロールを割り当てることもできます。
Microsoft Graphサービスの場合、Azureはまったく関与しません。そもそも、今回使用している(評価用に新たに用意した)Microsoft 365のテナントのユーザーには、Azureサブスクリプションが紐づいていません。では、どのようにアクセス許可を与えるのかというと、以下のドキュメントで説明されているように、アプリケーションの「APIのアクセス許可」で必要なアクセス許可の要求を追加し、「<テナント名> に管理者の同意を与える」をクリックして、事前に管理者の同意を行っておくのです。
ユーザーなしでアクセスを取得|Microsoft Graph(Microsoft Learn)
例えば、ユーザーの一覧を取得させるには、アプリケーションの「APIのアクセス許可」にある「+アクセス許可の追加」をクリックして、「APIアクセス許可の要求」でMicrosoft APIの一覧から「Microsoft Graph」を選択し、「アプリケーションの許可」を選択して、アクセス許可の一覧から「User > User.Read.All」をチェックし、「アクセス許可の追加」をクリックします(画面5)。アプリケーションの「APIのアクセス許可」に戻ったら、「<テナント名> に管理者の同意を与える」をクリックして、状態が「<テナント名> に付与されていません」から「<テナント名> に付与されました」に変更されたことを確認します(画面6)。なお、前回のMicrosoft Graph PowerShellやGraph Explorerでは、ユーザー(ユーザープリンシパル)でより権限の小さい「User.ReadBasic.All」を使用できましたが、アプリケーション(サービスプリンシパル)によるAPIアクセスの場合は最低でも「User.Read.All」が必要です。
画面5 アプリケーションの「APIのアクセス許可」でMicrosoft Graph APIの「User.Read.All」のアクセス許可に対する要求を追加する
画面6 「<テナント名> に管理者の同意を与える」をクリックすると、状態が「<テナント名> に付与されました」となり、管理者による同意が事前に行われたことになる
サービスプリンシパルを使用してMicrosoft Graphサービスにアクセスするために、最初にアクセストークンを取得します。PowerShell(管理者として開く必要はありません)の場合は、次のようなコマンドラインを実行します(画面7)。
$tenantid = "ディレクトリ(テナント)ID" $clientid = "アプリケーション(クライアント)ID" $clientsecret = "クライアントシークレットの値" $tokenendpoint = "https://login.microsoftonline.com/$tenantid/oauth2/v2.0/token" $body = @{ grant_type = "client_credentials" scope = "https://graph.microsoft.com/.default" client_id = $clientid client_secret = $clientsecret } $tokenresponse = Invoke-RestMethod -Method Post -Uri $tokenendpoint -Body $body -ContentType "application/x-www-form-urlencoded" $accesstoken = $tokenresponse.access_token |
画面7 Microsoft Graphサービスにアクセスするためのアクセストークンを取得する
アクセストークンの取得方法はAzure REST APIとよく似ていますが、トークンエンドポイントが違う点に注意してください。Azure REST APIではトークンエンドポイントとして「https://login.microsoftonline.com/テナントID/oauth2/token」を使用しましたが、Microsoft Graphではこのトークンエンドポイントは使用できません。代わりに、「https://login.microsoftonline.com/テナントID/oauth2/v2.0/token」を使用する必要があります。また、アクセストークン要求時のBODYコンテンツには、「resource」と値「https://management.azure.com/」のペアの代わりに「scope」と値の「https://graph.microsoft.com/.default」のペアを指定する必要があります。
ちなみに、トークンエンドポイントとして「https://login.microsoftonline.com/テナントID/oauth2/token」を使用した場合や、「scope」指定が無い場合、Microsoft Graph REST APIに対するHTTP要求は「 (401) 許可されていません」エラーで失敗しました。
続いて、Microsoft Graph REST APIを呼び出して、応答を取得します。テナントのすべてのユーザーの一覧を取得したい場合は、以下のリファレンスの「ユーザー > User > 一覧表示する」に見つかります。前回紹介したGraph Explorerを使用すると、目的のAPIが簡単に見つかります。
Microsoft Graph REST API v1.0 エンドポイント リファレンス|Microsoft Graph(Microsoft Learn)
PowerShellでAPIからリソース情報を取得するには、アクセストークンを取得したのと同じPowerShellウィンドウで引き続き、次のコマンドラインを実行します(画面8)。
$headers = @{ 'Authorization' = "Bearer $accesstoken" 'Content-Type' = 'application/json' } $requesturi = "https://graph.microsoft.com/v1.0/users" $ret = (Invoke-RestMethod -Uri $requesturi -Headers $headers -Method Get) $ret.Value |Select DisplayName,Mail, UserPrincipalName $ret |ConvertTo-Json |
(プレーンテキストで表示)
Microsoft Graph REST APIの応答は、JSON形式です。Azureの時も触れましたが、Invoke-RestMethodはJSON形式をPowerShellオブジェクトに自動変換し、PowerShellで扱いやすくしてくれます。ConvertTo-Jsonコマンドレットを利用すれば、JSON形式に戻すことができます。
画面8 Microsoft Graph REST APIにGETメソッドを送信して、ユーザー一覧を取得
今回の例は、ユーザーの一覧の取得という簡単なものでした。サービスプリンシパルには、そのために必要な「User.Read.All」のアクセス許可しか付与していません。目的のリソース情報の取得に、どんなアクセス許可が必要になるのかについては、一つ一つ調べていくしかないでしょう。
「Microsoft Graph REST API v1.0 エンドポイント リファレンス」の各APIには、必要なアクセス許可が特権の小さいものから大きいものという順番で掲載されています。例えば、ユーザー一覧をアプリケーションから取得する場合は、「User.Read.All」「User.ReadWrite.All」「Directory.Read.All」「Directory.ReadWrite.All」のいずれかのアクセス許可が必要であり、このうち「User.Read.All」が最も特権の小さいアクセス許可です。通常のユーザー(ユーザープリンシパル)の場合は、さらに特権の小さい「User.ReadBasic.All」を使用できます。