このエントリは2022/05/26現在の情報に基づいています。将来の機能追加や変更に伴い、記載内容からの乖離が発生する可能性があります。
問い合わせ
例によって以下のような問い合わせが届いた。
Azure ADに登録したアプリケーションから、Event Gridに対してイベントを発行させようとしていて、SDKでの動作は確認した。理解のため、Event GridデータプレーンのREST APIを使って挙動を確認したいのだが、どうしてもアクセストークンの取得がうまくいかない。どうしたらよいか?
問い合わせ主が呼び出しにあたって使っていたコードを拝見したところ、以下のようだった。
# (1)-a Azure ADに登録したアプリを利用
curl -X POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token \
-F grant_type=client_credentials \
-F client_id=${APP_ID} \
-F client_secret=${CLIENT_SECRET} \
-F scope={登録したアプリケーションIDのURI}/.default
# (1)-b Managed identitiesを利用
curl -g "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://eventgrid.azure.net" -H "Metadata: true"
# (2) REST APIを呼び出す
curl -X POST https://<EventGrid topicのエンドポイント>?overload=EventGridEvent&api-version=2018-01-01 \
-H "Content-Type: application/json" \
-H "Authorization: bearer {(1)-a/bで取得したアクセストークン}" \
-d '{データ}'
たぶん詳しい方は「おや?」と思われたかもしれない。

どこに問題があったのか?
問題は3件。
- Managed Identitiesを使う方法だと問題なくアクセストークンを取得できるのだが、登録アプリのときに設定されたスコープに問題があった。基本的に、スコープはトークンを取得したいリソースを指定する必要があるが、この指定だと、登録したアプリのアクセストークンを自身が取りに行く、というよくわからないことになってしまう。
- REST APIのURLが異なっていた。REST API Referenceによると、Topicホスト名を指定するような記載があるが、実際にはTopicエンドポイントを指定しなければならない。
- PublishするAPIのデータが配列ではなかった。これはREST API Referenceに明記されているが、1件だけなので配列ではなくJSONをそのまま送りつけたよう。
Publish Event Grid Events – Publish Event Grid Events
https://docs.microsoft.com/rest/api/eventgrid/dataplane/publish-event-grid-events/publish-event-grid-events
要求本文 / Request Body
https://docs.microsoft.com/rest/api/eventgrid/dataplane/publish-event-grid-events/publish-event-grid-events#request-body
REST APIの呼び出しのお作法
REST APIを使う流れは以下のような感じ。
- Managed Identityを構成、もしくはAzure ADにアプリケーションを登録
- Event GridにてRBACを構成
- EventGrid データ送信者/ EventGrid Data SenderロールをService PrincipalやManaged Identityに付与
- クライアントはAzure ADに対する認証を実施し、アクセストークンを取得。このとき、スコープやリソースはトークンを取得したいリソースを指定する。
- 登録アプリの場合、スコープは
https://eventgrid.azure.net/.default
を指定 - Managed Identitiesの場合、リソースは
https://eventgrid.azure.net
を指定
- 登録アプリの場合、スコープは
- 取得したアクセストークンをBearerトークンとして設定し、REST APIを呼び出す
- 配信イベントは配列として渡す(1個でも配列として渡す)。配列で渡さないとBad Request (HTTP 400) と以下のようなエラーメッセージが返ってくる。
{
"error": {
"code": "BadRequest",
"message": "This resource is configured to receive event in 'EventGridEvent' schema. The JSON received does not conform to the expected schema. Token Expected: StartArray, Actual Token Received: StartObject. Report 'ab484c09-3292-408b-9daa-4a1843001031:3:5/26/2022 2:17:35 AM (UTC)' to our forums for assistance or raise a support ticket.",
"details": [{
"code": "InputJsonInvalid",
"message": "This resource is configured to receive event in 'EventGridEvent' schema. The JSON received does not conform to the expected schema. Token Expected: StartArray, Actual Token Received: StartObject. Report 'ab484c09-3292-408b-9daa-4a1843001031:3:5/26/2022 2:17:35 AM (UTC)' to our forums for assistance or raise a support ticket."
}]
}
}
対策
上記の流れを以下のように修正してガイドした。
# (1)-a Azure ADに登録したアプリを利用
curl -X POST https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token \
-F grant_type=client_credentials \
-F client_id=${APP_ID} \
-F client_secret=${CLIENT_SECRET} \
-F scope=https://eventgrid.azure.net/.default
# (1)-b Managed identitiesを利用
curl -g "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://eventgrid.azure.net" -H "Metadata: true"
# (2) REST APIを呼び出す
curl -X POST https://<EventGrid topicのエンドポイント>?overload=EventGridEvent&api-version=2018-01-01 \
-H "Content-Type: application/json" \
-H "Authorization: bearer {(1)-a/bで取得したアクセストークン}" \
-d '[{データ} の配列]'