Azure でクロスディレクトリ通信を実装する
このガイドでは、さまざまな Microsoft Entra ディレクトリが管理する Azure サブスクリプションでホストされているサービス間の双方向の安全な通信を実現するためのソリューションを提供します。
Azure でのディレクトリ間通信のセキュリティ保護は、多くのサービスに固有の制限があるため、困難な場合があります。 Azure マネージド ID を使用して Microsoft Entra ID からトークンを取得することで、資格情報を直接管理する必要がなくなります。 ただし、Azure マネージド ID はディレクトリの境界を越えて機能しません。一般的な代替手段は、共有アクセス署名 URL などの共有シークレットを使用することです。 共有シークレットを使用する場合は、Microsoft Entra ディレクトリの境界を越えてシークレットを安全に配布してローテーションする必要があります。
このオーバーヘッドを回避する 1 つのオプションは、ワークロードの ID を表すマルチテナント Microsoft Entra アプリケーションを作成することです。 同意プロセスを通じて、このワークロード ID を外部ディレクトリに認識させ、最終的にアプリケーションが外部ディレクトリ内のサービスを認証できるようにします。
この記事では、 サンプル コードするこのパターンの実装例を示します。
このパターンは、Microsoft Entra ディレクトリの境界を越えて通信する必要があるさまざまなサービスがあるシナリオで再利用できます。
Architecture
このアーキテクチャの PowerPoint ファイル をダウンロードします。
ワークフロー
次のワークフローは、前の図に対応しています。
プロバイダー側の管理者がマルチテナント Entra アプリケーション登録を作成し、そのクライアント シークレットを設定します。
顧客側の管理者は、Microsoft Entra ディレクトリにサービス プリンシパルをプロビジョニングします。 このサービス プリンシパルは、プロバイダーが作成したアプリケーション登録に基づいています。 この手順は複数の方法で実行できます。 この例では、顧客ディレクトリ管理者に提供する URL を作成することを選択しましたが、代わりに Microsoft Graph API を使用できます。
顧客は、この新しいサービス プリンシパルにロールベースのアクセス制御 (RBAC) ロールを適用して、Azure Service Bus へのアクセスを承認します。
プロバイダーの関数アプリは、アプリケーションの登録のクライアント ID とクライアント シークレットを使用して、認証されたメッセージを顧客の Service Bus キューに送信します。
顧客の関数アプリは、マネージド ID を使用して、Service Bus トリガー経由でキューからプロバイダーのメッセージを読み取ります。
メッセージを受信した後、顧客の関数アプリは通常、ステータス メッセージをプロバイダーに返す前にいくつかの作業を行います。 この場合、デモの目的で、関数アプリは、同じ Service Bus 内の別のキュー上のプロバイダーにステータス メッセージをすぐに送信します。
この関数アプリは、Azure Functions によってトリガーされるタイマーを介して、顧客のディレクトリから状態キューから読み取ります。
シナリオの詳細
プロバイダーには複数の顧客がいます。 プロバイダーと各顧客には、独自の Microsoft Entra ID ディレクトリと Azure リソースがあります。 プロバイダーと各顧客は、Service Bus キューを介してメッセージを交換できるように、安全な双方向通信方法を必要とします。 ソリューションには、不必要な資格情報や秘密の導入を避ける、説得力のある ID ストーリーが必要です。
マルチテナント Entra アプリケーションについて知っておくべきこと
アプリケーション オブジェクトは、アプリケーションのグローバルに一意なインスタンスです。
アプリケーションが Microsoft Entra に登録されると、アプリケーション オブジェクトとサービス プリンシパル オブジェクトがディレクトリに自動的に作成されます。
サービス プリンシパル オブジェクトは、アプリケーションを使用し、アプリケーション オブジェクトを参照するすべてのディレクトリに作成されます。 アプリケーション オブジェクトは、対応するサービス プリンシパル オブジェクトと 1 対多の関係を持ちます。
アプリケーション オブジェクトは、アプリケーションのグローバル表現であり、すべてのディレクトリで使用されます。 サービス プリンシパル オブジェクトは、特定のディレクトリで使用されるローカル表現です。
アプリケーションが使用される各ディレクトリにサービス プリンシパル オブジェクトを作成し、ディレクトリがセキュリティで保護されているリソースにアクセスするための ID を確立できるようにする必要があります。 単一ディレクトリ アプリケーションのホーム ディレクトリに含まれるサービス プリンシパル オブジェクトは 1 つだけです。 このサービス プリンシパル オブジェクトは、アプリケーションの登録時に作成され、使用が許可されます。 マルチテナント Entra アプリケーションには、各ディレクトリに作成されたサービス プリンシパル オブジェクトもあり、そのディレクトリのユーザーがその使用に同意しました。
Microsoft Entra ディレクトリによってセキュリティ保護されているリソースにアクセスするには、セキュリティ プリンシパルがアクセスを必要とするエンティティを表す必要があります。
登録時または同意時に、アプリケーションにディレクトリ内のリソースにアクセスするアクセス許可が付与されると、サービス プリンシパル オブジェクトが作成されます。 このアーキテクチャは、同意フローで実装されます。
プロバイダーが顧客にメッセージを送信する方法
理想的には、プロバイダーは、顧客のキューへのメッセージの送信を担当する Azure コンピューティング リソースにマネージド ID を割り当てることができます。 顧客のディレクトリは、プロバイダーのディレクトリからマネージド ID を信頼するように構成されています。 ただし、2 つの Microsoft Entra テナント間の真のフェデレーションは、基本的に 1 つのディレクトリから別のディレクトリへの ID の "共有" を許可しますが、現時点では不可能です。 したがって、プロバイダーは、顧客が認識する ID を使用して認証する必要があります。 プロバイダーは、顧客が知っているサービス プリンシパルとして、顧客の Microsoft Entra テナントに対して認証する必要があります。
プロバイダーが独自のディレクトリにマルチテナント Entra アプリケーションを登録し、各顧客が関連付けられているサービス プリンシパルを自分のディレクトリにプロビジョニングすることをお勧めします。 プロバイダーは、このサービス プリンシパルを使用して、顧客のディレクトリと顧客がホストする API に対して認証を行うことができます。 プロバイダーは、この方法でクライアント シークレットを共有する必要はありません。 資格情報の管理は、プロバイダー単独の責任です。
顧客はプロバイダーにどのようにメッセージを送りますか?
プロバイダーが読み取ることができるキューをお客様が作成またはホストすることをお勧めします。 顧客はメッセージをキューに書き込みます。 プロバイダーは、サービス プリンシパル オブジェクトを使用して、メッセージの各顧客キューを繰り返しポーリングします。 このアプローチの欠点は、プロバイダーがメッセージを受信するときにポーリング遅延が発生することです。 また、プロバイダーでは、イベントがトリガーするのを待つのではなく、ウェイクアップしてポーリング ロジックを実行する必要があるため、コードをより頻繁に実行する必要があります。 ただし、資格情報の管理は引き続きプロバイダーが単独で責任を負い、これによりセキュリティが強化されます。
考えられるもう 1 つの解決策は、プロバイダーに顧客ごとにキューを作成またはホストさせることです。 各顧客は、独自のマルチテナント Entra アプリケーションを作成し、プロバイダーにサービス プリンシパル オブジェクトとしてディレクトリにプロビジョニングするよう要求します。 次に、顧客はこのサービス プリンシパル オブジェクトを使用して、プロバイダー側の顧客固有のキューにメッセージを送信します。 資格情報の管理は引き続きお客様の単独の責任となります。 このアプローチの欠点の 1 つは、プロバイダーが顧客アプリケーションに関連付けられているサービス プリンシパルをそのディレクトリにプロビジョニングする必要があるということです。 このプロセスは手動であり、プロバイダーはおそらく、新規顧客のオンボーディングのフローに手動の手順が組み込まれることを望んでいません。
サンプル コードのセットアップ
次の手順では、プロバイダーと顧客の間のクロスディレクトリ通信を設定するプロセスについて説明します。
プロバイダーのセットアップ
プロバイダーのセットアップには、マルチテナント Entra アプリケーション サービス プリンシパルを生成してプロビジョニングする手順と、顧客ディレクトリをプロビジョニングする手順が含まれています。
HTTP によってトリガーされる関数アプリを作成して、顧客ディレクトリ内の顧客の Service Bus コマンド キューに書き込むメッセージを送信します。
時間トリガー関数アプリを作成して、顧客ディレクトリ内の顧客の Service Bus 内の状態キューを定期的に確認します。
プロバイダーのディレクトリ内にマルチテナント Entra アプリケーションを作成する
まず、プロバイダーのディレクトリにマルチテナント Entra アプリケーションを作成し、その ID を顧客のディレクトリ内にプロビジョニングします。 このシナリオでは、ID はサービス プリンシパルです。 この記事の前半
マルチテナント組織オプションを選択します。
リダイレクト URI として次の Web サイトを追加します:
https://entra.microsoft.com
。 この URI は、ビジネス ニーズに合わせて変更できます。アプリケーション (クライアント) ID 値を登録してメモします。
新しいクライアント シークレットを生成する
マルチテナント Entra アプリケーションを作成したら、このサービス プリンシパルのクライアント シークレットを作成します。
生成されたシークレットを安全な場所に保存します。 シークレットとクライアント ID は、認可コード フローでコードを交換し、次のステップで ID トークンを交換するために必要なクライアント資格情報です。
Azure Functions - HTTP トリガー
HTTP 関数を使用して、顧客の Service Bus デプロイ キューにメッセージを送信することで、プロバイダーのディレクトリからデプロイを開始します。 この概念実証を開始するための配信方法として、HTTP トリガー関数を選択しました。 前に生成したサービス プリンシパルは、顧客ディレクトリにアクセスし、Service Bus 内の特定のキューに書き込む資格情報として機能します。 また、この手順を正しく機能させるには、 顧客のセットアップ を完了する必要があります。
Azure Functions - タイマー トリガー
タイマーによってトリガーされる関数を使用して、顧客のディレクトリ内からデプロイ状態キューをポーリングします。 この概念実証では、デモの目的でデプロイ状態キューを 10 秒ごとにポーリングします。 この方法により、プロバイダーのディレクトリにアクセスするためのサービス プリンシパルを顧客が持つ必要がなくなります。
顧客設定
提供された URL を変更して使用して、サービス プリンシパルをプロビジョニングします。
適切な RBAC コントロールを使用するようにプロバイダー サービス プリンシパルの範囲を設定します。
Service Bus メッセージ キューからメッセージを読み取り、別のキューにメッセージを配置する Service Bus トリガー関数を作成します。 デモ目的の場合、このフローは機能をテストするのに最適です。
Service Bus トリガー関数用にシステム割り当てマネージド ID を作成します。
システム割り当てマネージド ID Service Bus スコープを割り当てます。
プロバイダーのディレクトリから顧客のディレクトリにサービス プリンシパルをプロビジョニングする
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 テナントにプロビジョニングすることもできます。
顧客のディレクトリからアカウントでサインインします。
同意画面で、[同意する] を選択して、顧客ディレクトリにプロバイダーのアプリケーションをプロビジョニングします。 URL は最終的に
microsoft.com
にリダイレクトされます。この URL は、ID を顧客ディレクトリにプロビジョニングする目的の効果を引き続き持ちます。エンタープライズ アプリケーション に移動して、新しくプロビジョニングされたサービス プリンシパルを確認して、顧客の 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 名前空間へのアクセスを許可する
"Azure Service Bus Data Receiver" ロールをマネージド ID に必ず追加してください。
[マネージド ID] セレクターで、 [システム割り当てマネージド ID] カテゴリから [関数アプリ] を選びます。 ラベル [関数アプリ] の横にかっこで囲まれた数値が含まれている場合があります。 この数値は、システムによって割り当てられた ID を持つアプリがサブスクリプション内にいくつあるかを示します。
関数アプリで Service Bus に接続する
ポータルで、関数アプリを検索するか、 [関数アプリ] ページで関数アプリに移動します。
[アプリケーション設定] で、 [+ 新しいアプリケーション設定] を選択して、次の表に示すアプリケーション設定を新規に作成します。
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 | プリンシパル ソフトウェア エンジニア