Azure Event Hubs を介して変更通知を受信する

Webhook は、高スループットのシナリオで変更通知を受信する場合や、受信者が一般公開されている通知 URL を公開できない場合には適していません。 代わりに、 Azure Event Hubs を使用することもできます。

Azure Event Hubs を使用できる高スループットシナリオの例としては、大規模なリソースセットをサブスクライブするアプリケーション、頻繁に変更されるリソースをサブスクライブするアプリケーション、大規模な組織のリソースをサブスクライブするマルチテナント アプリケーションなどがあります。

この記事では、Microsoft Graph サブスクリプションを管理するプロセスと、Azure Event Hubs を介して変更通知を受信する方法について説明します。

Azure Event Hubs を使用した変更通知の受信

Azure Event Hubs は、一般的なリアルタイム イベントの取り込みと配布サービスであり、規模に合わせて構築されています。 変更通知の受け取りに Azure Event Hub を使用する方法は、次のような点で Webhook とは異なります。

  • 公開されている通知 URL には依存しません。 Event Hubs SDK は、アプリケーションに通知を中継します。
  • 通知 URL の検証に返信する必要はありません。 受信した検証メッセージは無視してかまいません。
  • イベント ハブをプロビジョニングする必要があります。
  • Azure Key Vault をプロビジョニングするか、Microsoft Graph Change Tracking サービスを Event Hub のデータ送信者ロールに追加する必要があります。

Azure Event Hubs 認証を設定する

Azure CLI を使用すると、Azure の管理タスクをスクリプト化して自動化できます。 CLI は、ローカル コンピューターにインストールされているか、Azure Cloud Shell で直接実行することができます。

# --------------
# TODO: update the following values
#sets the name of the resource group
resourcegroup=rg-graphevents-dev
#sets the location of the resources
location='uk south'
#sets the name of the Azure Event Hubs namespace
evhamespacename=evh-graphevents-dev
#sets the name of the hub under the namespace
evhhubname=graphevents
#sets the name of the access policy to the hub
evhpolicyname=grapheventspolicy
#sets the name of the Azure KeyVault
keyvaultname=kv-graphevents
#sets the name of the secret in Azure KeyVault that will contain the connection string to the hub
keyvaultsecretname=grapheventsconnectionstring
# --------------
az group create --location $location --name $resourcegroup
az eventhubs namespace create --name $evhamespacename --resource-group $resourcegroup --sku Basic --location $location
az eventhubs eventhub create --name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --partition-count 2 --message-retention 1
az eventhubs eventhub authorization-rule create --name $evhpolicyname --eventhub-name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --rights Send
evhprimaryconnectionstring=`az eventhubs eventhub authorization-rule keys list --name $evhpolicyname --eventhub-name $evhhubname --namespace-name $evhamespacename --resource-group $resourcegroup --query "primaryConnectionString" --output tsv`
az keyvault create --name $keyvaultname --resource-group $resourcegroup --location $location --enable-soft-delete true --sku standard --retention-days 90
az keyvault secret set --name $keyvaultsecretname --value $evhprimaryconnectionstring --vault-name $keyvaultname --output none
graphspn=`az ad sp list --display-name 'Microsoft Graph Change Tracking' --query "[].appId" --output tsv`
az keyvault set-policy --name $keyvaultname --resource-group $resourcegroup --secret-permissions get --spn $graphspn --output none
keyvaulturi=`az keyvault show --name $keyvaultname --resource-group $resourcegroup --query "properties.vaultUri" --output tsv`
domainname=`az ad signed-in-user show --query 'userPrincipalName' | cut -d '@' -f 2 | sed 's/\"//'`
notificationUrl="EventHub:${keyvaulturi}secrets/${keyvaultsecretname}?tenantId=${domainname}"
echo "Notification Url:\n${notificationUrl}"

手記: ここで提供されるスクリプトは、Linux ベースのシェル、Windows WSL、Azure Cloud Shell と互換性があります。 Windows シェルで実行するには、いくつかの更新プログラムが必要です。

サブスクリプションを作成し、通知を受信する

必要な Azure KeyVault サービスと Azure Event Hubs サービスを作成したら、変更通知サブスクリプションを作成し、Azure Event Hubs 経由で変更通知の受信を開始できるようになりました。

サブスクリプションを作成する

Event Hubs で変更通知を受信するサブスクリプションの作成は、Webhook サブスクリプションの作成とほぼ同じですが、 notificationUrl プロパティに重要な変更があります。 続行する前に、まず Webhook サブスクリプションの作成手順 を確認します。

サブスクリプションの作成時に、 notificationUrl は Event Hubs の場所をポイントする必要があります。

Key Vault を使用している場合、 notificationUrl プロパティは次のようになります。 EventHub:https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?tenantId=<domainname>、次の値を使用します。

  • azurekeyvaultname - キー コンテナーを作成したときに付けた名前。 DNS 名で見つけることができます。
  • secretname - シークレットを作成したときに付けた名前。 Azure Key Vault の [シークレット] ページで見つけることができます。
  • domainname - テナントの名前。たとえば、contoso.com。 このドメインは Azure Key Vault へのアクセスに使用されるため、Azure Key Vault を保持する Azure サブスクリプションで使用されるドメインと一致することが重要です。 この情報を取得するには、作成した Azure Key Vault の概要ページに移動し、サブスクリプションをクリックします。 ドメイン名がディレクトリ フィールドの下に表示されます。

注:

重複するサブスクリプションは許可されません。 サブスクリプション要求に、既存のサブスクリプションに含まれている changeTypeリソース に同じ値が含まれている場合、要求は HTTP エラー コード 409 Conflictで失敗し、エラー メッセージ Subscription Id <> already exists for the requested combination

通知を受信する

変更通知が Event Hubs によってアプリケーションに配信されるようになりました。 詳細については、Event Hubs ドキュメントで「イベントの受け取り」を参照してください。

アプリケーションで通知を受信するには、「 イベント ハブの構成」に記載されている手順と同様に、"リッスン" アクセス許可を持つ別の共有アクセス ポリシーを作成し、接続文字列を取得する必要があります。

ヒント

Azure KeyVault で設定したのと同じ接続文字列を再利用するのではなく、Event Hubs メッセージをリッスンするアプリケーション用の別のポリシーを作成します。 この分離は、ソリューションの各コンポーネントが必要なアクセス許可のみを持っていることを確認することで、最小限の特権の原則に従います。

検証通知の処理

アプリケーションは、新しいサブスクリプションを作成するたびに検証通知を受け取ります。 これらの通知は無視してください。 次の例は、検証メッセージの本文を表します。

 {
    "value":[
        {
            "subscriptionId":"NA",
            "subscriptionExpirationDateTime":"NA",
            "clientState":"NA",
            "changeType":"Validation: Testing client application reachability for subscription Request-Id: 522a8e7e-096a-494c-aaf1-ac0dcfca45b7",
            "resource":"NA",
            "resourceData":{
                "@odata.type":"NA",
                "@odata.id":"NA",
                "id":"NA"
            }
        }
    ]
}

大きなペイロードを持つリッチ通知のサブスクリプション

Event Hubs の最大メッセージ サイズは 1 MB です。 リッチ通知を使用すると、この制限を超える通知が予想される場合があります。 Event Hubs を介して 1 MB を超える通知を受信するには、サブスクリプション要求に BLOB ストレージ アカウントを追加する必要もあります。

ストレージを設定し、サブスクリプションを作成する

  1. ストレージ アカウントを作成します
  2. ストレージ アカウントにコンテナーを作成します。 コンテナー名は、 microsoft-graph-change-notificationsに設定する必要があります。
  3. ストレージ アカウントのアクセス キーまたは接続文字列を取得します
  4. 接続文字列をキー コンテナーに追加し、名前を付けます。 この値はシークレット名です。
  5. 次の構文で blobStoreUrl プロパティを含め、サブスクリプションを作成または再作成します。 blobStoreUrl: "https://<azurekeyvaultname>.vault.azure.net/secrets/<secretname>?tenantId=<domainname>"

リッチ通知を受け取る

Event Hubs が 1 MB を超える通知ペイロードを受信すると、通知には、リッチ通知に含まれる リソースresourceDataおよび encryptedContent プロパティは含まれません。 通知には、代わりに、これらのプロパティが格納されているストレージ アカウント内の BLOB を指す ID を持つ additionalPayloadStorageId プロパティが含まれています。

Microsoft Graph Change Tracking アプリケーションが見つからない場合はどうなりますか?

Microsoft Graph Change Tracking サービス プリンシパルは、テナントの作成時と管理操作によっては、テナントに存在しない可能性があります。 サービス プリンシパルのグローバルに一意の appId0bf30f3b-4a52-48df-9a82-234910c4a086 され、次のクエリを実行して、テナントに存在するかどうかを確認できます。

GET https://graph.microsoft.com/v1.0/servicePrincipals(appId='0bf30f3b-4a52-48df-9a82-234910c4a086')

サービス プリンシパルが存在しない場合は、次のように作成します。 この操作を実行するには、呼び出し元アプリに Application.ReadWrite.All アクセス許可を付与する必要があります。

方法 1

POST https://graph.microsoft.com/v1.0/servicePrincipals
Content-type: application/json

{
    "appId": "0bf30f3b-4a52-48df-9a82-234910c4a086"
}

方法 2

POST https://graph.microsoft.com/v1.0/servicePrincipals(appId='0bf30f3b-4a52-48df-9a82-234910c4a086')
Content-type: application/json
Prefer: create-if-missing

{
    "displayName": "Microsoft Graph Change Tracking"
}