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 シェルで実行するには、いくつかの更新プログラムが必要です。

サブスクリプションをCreateして通知を受信する

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

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

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 ドキュメントで「イベントの受け取り」を参照してください。

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

ヒント

Create、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. ストレージ アカウントをCreateします。
  2. ストレージ アカウント内のコンテナーをCreateし、名前を割り当てます。
  3. ストレージ アカウントのアクセス キーまたは接続文字列を取得します。
  4. 接続文字列をキー コンテナーに追加し、名前を付けます。 この値はシークレット名です。
  5. 次の構文に blobStoreUrl プロパティを含めて、サブスクリプションをCreateまたは再作成します。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 サービス プリンシパルは、テナントの作成時と管理操作によっては、テナントに存在しない可能性があります。 サービス プリンシパルのグローバルに一意の appId は であり 0bf30f3b-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"
}