マルチテナント アプリケーションを使用してテナント間通信を実装する

このガイドでは、さまざまな Microsoft Entra テナントが管理する Azure サブスクリプションでホストされているサービス間で双方向のセキュリティで保護された通信を実現するソリューションを提供します。

Azure でのマルチテナント通信のセキュリティ保護は、多くのサービスに固有の制限により困難になる場合があります。 Azure マネージド ID を使用して Microsoft Entra ID からトークンを取得することで、資格情報を直接管理する必要がなくなります。 ただし、Azure マネージド ID はテナントの境界を越えて機能しないため、一般的な代替手段は、共有アクセス署名 URL などの共有シークレットを使用することです。 共有シークレットを使用する場合は、Microsoft Entra テナントの境界を越えてシークレットを安全に配布し、ローテーションする必要があることに注意してください。

このオーバーヘッドを回避する 1 つの選択肢は、ワークロードの ID を表すマルチテナント アプリケーションを作成することです。 同意プロセスを通じて、このワークロード ID を外部テナントに知らせることができ、最終的には外部テナントでサービスを認証できるようになります。

この記事では、サンプル コードするこのパターンの実装例を示します。

このパターンは、Microsoft Entra テナントの境界を越えて通信する必要があるさまざまなサービスを含むマルチテナント シナリオで再利用できます。

Architecture

テナント間通信アーキテクチャの図。

このアーキテクチャの PowerPoint ファイルをダウンロードします。

ワークフロー

次のワークフローは、前の図に対応しています。

  1. プロバイダー側の管理者は、マルチテナント アプリケーションの登録を作成し、それにクライアント シークレットを設定します。

  2. 顧客側の管理者は、テナントにサービス プリンシパルをプロビジョニングします。 このサービス プリンシパルは、プロバイダーが作成したマルチテナント アプリケーションに基づいています。 この手順は複数の方法で実行できます。 この例では、顧客のテナント管理者に提供する URL を作成することを選択しましたが、代わりに Microsoft Graph API を使用することもできます。

  3. 顧客は、この新しいサービス プリンシパルにロールベースのアクセス制御 (RBAC) ロールを適用して、Azure Service Bus へのアクセスを承認します。

  4. プロバイダーの関数アプリは、アプリケーションの登録のクライアント ID とクライアント シークレットを使用して、認証されたメッセージを顧客の Service Bus キューに送信します。

  5. 顧客の関数アプリは、マネージド ID を使用して、Service Bus トリガー経由でキューからプロバイダーのメッセージを読み取ります。

  6. メッセージを受信した後、顧客の関数アプリは通常、ステータス メッセージをプロバイダーに返す前にいくつかの作業を行います。 この場合、デモの目的で、関数アプリは、同じ Service Bus 内の別のキュー上のプロバイダーにステータス メッセージをすぐに送信します。

  7. この関数アプリは、Azure Functions がトリガーするタイマーを介して、顧客のテナントからの状態キューから読み取ります。

シナリオの詳細

プロバイダーには複数の顧客がいます。 プロバイダーと各顧客には、独自の Microsoft Entra ID テナントと Azure リソースがあります。 プロバイダーと各顧客は、Service Bus キューを介してメッセージを交換できるように、安全な双方向通信方法を必要とします。 ソリューションには、不必要な資格情報や秘密の導入を避ける、説得力のある ID ストーリーが必要です。

マルチテナント アプリケーションについて知っておくべきこと

  • アプリケーション オブジェクトは、アプリケーションのグローバルに一意なインスタンスです。

  • アプリケーションが Microsoft Entra に登録されると、アプリケーション オブジェクトとサービス プリンシパル オブジェクトがテナントに自動的に作成されます。

  • サービス プリンシパル オブジェクトは、アプリケーションを使用し、アプリケーション オブジェクトを参照するすべてのテナントに作成されます。 アプリケーション オブジェクトは、対応するサービス プリンシパル オブジェクトと 1 対多の関係を持ちます。

  • アプリケーション オブジェクトはアプリケーションのグローバル表現であり、すべてのテナントにわたって使用されます。 サービス プリンシパル オブジェクトは、特定のテナントで使用されるローカル表現です。

  • テナントが保護するリソースにアクセスするための ID を確立できるように、アプリケーションが使用される各テナントでサービス プリンシパル オブジェクトを作成する必要があります。 シングルテナント アプリケーションには、そのホーム テナント内にサービス プリンシパル オブジェクトが 1 つだけあります。 このサービス プリンシパル オブジェクトは、アプリケーションの登録時に作成され、使用が許可されます。 マルチテナント アプリケーションには、各テナントで作成されたサービス プリンシパル オブジェクトもあり、そのテナントのユーザーがその使用に同意しています。

  • Microsoft Entra テナントによって保護されたリソースにアクセスするには、セキュリティ プリンシパルがアクセスを必要とするエンティティを表す必要があります。

  • アプリケーションが (登録または同意によって) テナント内のリソースへのアクセス許可を与えられると、サービス プリンシパル オブジェクトが作成されます。 このアーキテクチャは、同意フローで実装されます。

プロバイダーが顧客にメッセージを送信する方法

理想的には、プロバイダーは、顧客のキューへのメッセージの送信を担当する Azure コンピューティング リソースにマネージド ID を割り当てることができます。 顧客のテナントは、プロバイダーのテナントからのマネージド ID を信頼するように構成されています。 ただし、2 つの Microsoft Entra テナント間の真のフェデレーションは、基本的に 1 つのテナントから別のテナントへの ID の "共有" を許可しますが、現時点では不可能です。 したがって、プロバイダーは、顧客が認識する ID を使用して認証する必要があります。 プロバイダーは、顧客が知っているサービス プリンシパルとして、顧客の Microsoft Entra テナントに対して認証する必要があります。

プロバイダーが独自のテナントにマルチテナント アプリケーションを登録し、各顧客が関連するサービス プリンシパルをテナントにプロビジョニングすることをお勧めします。 その後、プロバイダーは、このサービス プリンシパルを使用して、顧客のテナントおよび顧客がホストする API に対して認証を行うことができます。 プロバイダーは、この方法でクライアント シークレットを共有する必要はありません。 資格情報の管理は、プロバイダー単独の責任です。

顧客はプロバイダーにどのようにメッセージを送りますか?

プロバイダーが読み取ることができるキューをお客様が作成またはホストすることをお勧めします。 顧客はメッセージをキューに書き込みます。 プロバイダーは、サービス プリンシパル オブジェクトを使用して、メッセージの各顧客キューを繰り返しポーリングします。 このアプローチの欠点は、プロバイダーがメッセージを受信するときにポーリング遅延が発生することです。 また、プロバイダーでは、イベントがトリガーするのを待つのではなく、ウェイクアップしてポーリング ロジックを実行する必要があるため、コードをより頻繁に実行する必要があります。 ただし、資格情報の管理は引き続きプロバイダーが単独で責任を負い、これによりセキュリティが強化されます。

考えられるもう 1 つの解決策は、プロバイダーに顧客ごとにキューを作成またはホストさせることです。 各顧客は独自のマルチテナント アプリケーションを作成し、それをサービス プリンシパル オブジェクトとしてテナントにプロビジョニングするようプロバイダーに要求します。 次に、顧客はこのサービス プリンシパル オブジェクトを使用して、プロバイダー側の顧客固有のキューにメッセージを送信します。 資格情報の管理は引き続きお客様の単独の責任となります。 このアプローチの欠点の 1 つは、プロバイダーが顧客のアプリケーションに関連付けられたサービス プリンシパルをテナントにプロビジョニングする必要があることです。 このプロセスは手動であり、プロバイダーはおそらく、新規顧客のオンボーディングのフローに手動の手順が組み込まれることを望んでいません。

サンプル コードのセットアップ

次の手順では、プロバイダーと顧客間のテナント間通信を設定するプロセスについて説明します。

プロバイダーのセットアップ

プロバイダーのセットアップには、マルチテナント アプリケーション サービス プリンシパルを生成およびプロビジョニングする手順と、顧客テナントをプロビジョニングする手順が含まれます。

  1. HTTP によってトリガーされる関数アプリを作成して、顧客のテナント内の顧客の Service Bus コマンド キューに書き込むメッセージを送信します。

  2. 顧客のテナント内の顧客の Service Bus 内のステータス キューを定期的にチェックするための、時間トリガー関数アプリを作成します。

プロバイダーのテナント内にマルチテナント アプリケーションを作成する

まず、プロバイダーのテナント内にマルチテナント アプリケーションを作成し、その ID を顧客のテナント内にプロビジョニングします。 このシナリオでは、ID はサービス プリンシパルです。 この記事の前半のアーキテクチャでは、プロバイダーのテナントから顧客のテナントにサービス プリンシパルを設定してプロビジョニングする方法について説明します。 このアーキテクチャでは、複数の Microsoft Entra テナントをプロビジョニングする方法についても概説します。

  1. マルチテナント組織オプションを選択します。

  2. リダイレクト URI として次の Web サイトを追加します: https://entra.microsoft.com。 この URI は、ビジネス ニーズに合わせて変更できます。

  3. アプリケーション (クライアント) ID 値を登録してメモします。

新しいクライアント シークレットを生成する

  1. マルチテナント アプリケーションを作成した後、このサービス プリンシパルのクライアント シークレットを作成します。

  2. 生成されたシークレットを安全な場所に保存します。 シークレットとクライアント ID は、認可コード フローでコードを交換し、次のステップで ID トークンを交換するために必要なクライアント資格情報です。

Azure Functions - HTTP トリガー

HTTP 関数を使用して、顧客の Service Bus デプロイメント キューにメッセージを送信することで、プロバイダーのテナントからデプロイを開始します。 この概念実証を開始するための配信方法として、HTTP トリガー関数を選択しました。 前に生成したサービス プリンシパルは、顧客テナントにアクセスし、Service Bus 内の特定のキューに書き込むための資格情報として機能します。 また、この手順を正しく機能させるには、顧客のセットアップを完了する必要があります。

Azure Functions - タイマー トリガー

タイマーでトリガーされる関数を使用して、顧客のテナント内からデプロイ状態キューをポーリングします。 この概念実証では、デモの目的でデプロイ状態キューを 10 秒ごとにポーリングします。 このアプローチにより、顧客はプロバイダーのテナントにアクセスするためのサービス プリンシパルを持つ必要がなくなります。

顧客設定

  1. 提供された URL を変更して使用して、サービス プリンシパルをプロビジョニングします。

  2. 適切な RBAC コントロールを使用するようにプロバイダー サービス プリンシパルの範囲を設定します。

  3. Service Bus メッセージ キューからメッセージを読み取り、別のキューにメッセージを配置する Service Bus トリガー関数を作成します。 デモ目的の場合、このフローは機能をテストするのに最適です。

  4. Service Bus トリガー関数用にシステム割り当てマネージド ID を作成します。

  5. システム割り当てマネージド ID Service Bus スコープを割り当てます。

プロバイダーのテナントから顧客のテナントにサービス プリンシパルをプロビジョニングする

  1. client_idクエリ文字列パラメーターを独自のクライアント IDhttps://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?response_type=code&response_mode=query&scope=openid&client_id=<your_client_ID> に置き換えた後、次の URL にアクセスします。

    管理者 Microsoft Graph API 呼び出し、Azure PowerShell コマンド、または Azure CLI コマンドを使用して、サービス プリンシパルを別の Microsoft Entra テナントにプロビジョニングすることもできます。

  2. 顧客のテナントのアカウントでログインします。

  3. 同意画面で、[同意する] を選択して、顧客テナントにプロバイダーのアプリケーションをプロビジョニングします。 URL は最終的にリダイレクトされます。この URL は、microsoft.com顧客テナントに ID をプロビジョニングする目的の効果を引き続き持ちます。

  4. エンタープライズ アプリケーション に移動して、新しくプロビジョニングされたサービス プリンシパルを確認して、顧客の Microsoft Entra テナント内の ID を確認します。

プロビジョニングされたサービス プリンシパルの RBAC を設定する

プロバイダー サービス プリンシパルの設定からプロバイダー サービス プリンシパルのスコープを設定し、Service Bus 上で "Service Bus データ所有者" ロールを割り当てます。 このサービス プリンシパルは、HTTP トリガー関数によるキューへの書き込みと、タイマー トリガー関数によるキューからの読み取りの両方で使用されます。 必ず "Azure Service Bus データ所有者" ロールをサービス プリンシパルに追加してください。

Azure Functions - Service Bus トリガー

ID ベースの関数チュートリアルの手順に従って、Service Bus キューから関数トリガーを定義し、マネージド ID を設定する方法について説明します。 このガイダンスは、メッセージがキューに追加されたときに Service Bus キューから関数アプリをトリガーするのに役立ちます。 メッセージを別のキューに配置するときにも、マネージド ID を使用します。 デモの目的で、同じ関数を使用してメッセージをプッシュスルーします。

新しく作成した Service Bus 名前空間で、[アクセス制御 (IAM)] を選択します。 コントロール プレーン内のリソースにアクセスできるユーザーを表示および構成できます。

マネージド ID を使用して関数アプリに Service Bus 名前空間へのアクセスを許可する

  1. "Azure Service Bus Data Receiver" ロールをマネージド ID に必ず追加してください。

  2. [マネージド ID] セレクターで、[システム割り当てマネージド ID] カテゴリから [関数アプリ] を選びます。 ラベル [関数アプリ] の横にかっこで囲まれた数値が含まれている場合があります。 この数値は、システムによって割り当てられた ID を持つアプリがサブスクリプション内にいくつあるかを示します。

関数アプリで Service Bus に接続する

  1. ポータルで、関数アプリを検索するか、[関数アプリ] ページで関数アプリに移動します。

  2. [アプリケーション設定] で、[+ 新しいアプリケーション設定] を選択して、次の表に示すアプリケーション設定を新規に作成します。 Service BusConnection__fullyQualifiedNamespace <SERVICE_BUS_NAMESPACE>.Service Bus.windows.net.

サービス プリンシパル クライアント シークレットのライフサイクル管理

テナント間アーキテクチャにシークレットを導入する場合は、生成されたクライアント シークレットのライフサイクルを管理する必要があります。 クライアント シークレットを安全に格納、ローテーション、監視する方法については、「シークレット管理のベスト プラクティス」を参照してください。

ローカル設定

各サブディレクトリには、local.settings.json ファイルのスタブ バージョンが含まれています。これは、Azure 関数をローカルで実行するように変更できます。 Azure で設定を構成するには、アプリケーション設定を更新します。

DefaultAzureCredential コマンドは、Azure CLI 資格情報に到達する前に複数の設定を列挙します。 混乱を避けるために、az login -t <tenant ID> コマンドを実行して、ローカル関数を開発するときに正しい資格情報を付与することをお勧めします。

共同作成者

この記事は、Microsoft によって保守されています。 当初の寄稿者は以下のとおりです。

プリンシパルの作成者:

  • Audrey Long | シニア セキュリティ ソフトウェア エンジニア
  • Ashton Mickey | プリンシパル ソフトウェア エンジニア
  • John Garland | プリンシパル ソフトウェア エンジニア

次のステップ