← レポート一覧
CROSS-PRODUCT API PLATFORM ON AZURE / 構成検討

共通 API 基盤の構成検討

SaaS プロダクト A・B・C の間で API をやり取りし、将来は認証基盤を1つにまとめ、プロダクト横断の集計を各プロダクトのダッシュボードに出す。そのための理想の構成と、その構成が理想である条件を整理します。

0 / 結論

結論

「理想」は条件で変わります。以下は、いただいた前提(A・B が稼働中で C を新規に作る、プロダクトごとにチームがある、Platform Engineering Team が基盤を持つ、横断集計は各プロダクトの画面に出す)で理想になる構成です。前提が変わった場合の理想は、各章の条件表と第 12 章にまとめています。

発想の是非

共通化するのは「土台」。業務 API とデータは各プロダクトが持つ

全プロダクトのデータを共通のデータモデルで提供する集約 API 層は、今回の前提では理想になりません。ゲートウェイ、サービス間の認証、顧客組織の台帳、イベント基盤、分析基盤、API 規約を Platform チームが提供し、API とデータは各プロダクトが持つ形が理想です。顧客に1つの API 契約で複数プロダクトを出す必要が出たときだけ、その部分に合成層を足します。

中央で持つもの

顧客組織と接続許可だけは Platform の台帳に置く

A の client と B の tenant は単位が違うので、どちらかに合わせません。上位の Organization、各プロダクトの単位との対応付け、プロダクト間の接続許可(Grant)を台帳に持ちます。台帳は IdP から独立させるので、IdP を何にしても、あとで移行しても残ります。

認証

サービス間は今すぐ共通化し、ユーザー認証は段階的に統合する

プロダクト間の呼び出しは、社内の Entra ID(マネージド ID と App Roles)と接続許可の照合で成立します。ユーザー認証の統合を待つ必要はありません。ユーザー認証は、共通 IdP を新設して C で使い始め、A・B のログインを移し、旧ユーザー DB の認証を止める順に進めます。

集計

画面には集計済みの値を返す API。材料は分析基盤に複製して作る

他プロダクトの API や DB から生データを集めて画面ごとに集計すると、DB 負荷、応答時間、認可の一貫性の面で成り立たなくなります。各プロダクトの DB を Fabric Mirroring で OneLake に複製し、横断集計を事前に作り、接続許可を照合する集計 API から返します

1 / 前提

前提と、判断を分ける条件

いただいた情報のうち、構成を決めるのは次の4点です。A は「1顧客 = 1 client、その下に複数 project」、B は「1顧客企業 = 1 tenant、その tenant に A の client が複数つながる」、C は管理単位が未定、ユーザーは各プロダクトが別々に持つ。

このほかに、分かっていないことで理想が変わる条件があります。この解説では下表の「今回の想定」で書き、変わった場合の構成は各章に書きます。

条件今回の想定違った場合に変わること
プロダクト数と連携の増え方A・B に C が加わり、連携の組み合わせは増えるA↔B の数本で増えないなら、直接連携と規約だけで足りる2
複数プロダクトをまとめた1つの API 契約要求なし。各プロダクトのユーザーはそのプロダクトの API を使う必要なら、ドメインの決定権を持つチームが合成 API を持つ2・8
複数プロダクトを1画面で合成する UIなし。各プロダクトの画面に横断集計を出すあるなら、その UI のチームが BFF を持つ2
子会社のデータを親会社側で見るときの承認者データの持ち主である A client の管理者が承認する契約上、親会社が全子会社分の利用権を持つなら、親の管理者が一括承認できる5
顧客企業ごとの SSO 設定不明数が多く、顧客に自分で設定させたいなら、組織モデルを持つ B2B 向け IdP が合う9
A と B のユーザーの重なり不明重なりが小さく、横断 SSO の要求もないなら、既存ユーザーの移行は急がない9
横断集計の鮮度大半の指標は数分遅れで足りる秒単位が要る指標だけ、イベント経路を別に作る11
ネットワーク分離公開 SaaS として一般的な水準ゲートウェイまで VNet 内に閉じる要件なら APIM Premium v213
2 / 発想の是非

「共通 API 基盤」という発想は正しいか

「共通 API 基盤」という言葉は、少なくとも4つの別の構成を指します。どれが正しいかは条件で決まり、今回の前提では ③ が理想です。① と ④ は条件つきで ③ と組み合わせ、② は今回の前提では選びません。

① 直接連携 + 規約 各プロダクトが互いの API を直接呼ぶ プロダクト A プロダクト B プロダクト C 連携の組み合わせごとに、認証・認可・ テナントの対応付けを実装する ② 集約 API(共通データモデル) 共通層が全プロダクトのデータを1つのモデルで出す 共通 API(Platform が持つ) Customer / Project … を共通モデルに変換 A B C 変換 各プロダクトの変更が共通モデルの改修待ちになる client と tenant の違いを1つのモデルに押し込む ③ 土台だけ共通(連邦型) API とデータは各プロダクト、横断の仕組みは Platform プロダクト A API・DB プロダクト B API・DB プロダクト C API・DB B は A の API を呼ぶ 共通の土台(Platform が提供) ゲートウェイ・サービス間認証・顧客組織台帳 イベント基盤・分析基盤・API 規約 業務データの変換や手順は土台に入れない ④ 合成層(BFF / GraphQL) 横断画面や統合 API のために束ねる層を足す 横断画面・統合 API 合成層(使う側のチームが持つ) A B C ③ の上に、必要な場合だけ足す データの持ち主は各プロダクトのまま
枠が橙の ③ が今回の前提での理想。② は Platform チームが業務データの意味まで持つ構成で、③ は持たない構成です。
構成理想になる条件今回の前提では選び方を誤っているサイン
① 直接連携 + 規約プロダクトが2〜3で、連携は数本、増える見込みがない。チーム同士が密に協力できる。統一した外部 API は要らない今だけ成立
A↔B だけの今は成立するが、C で組み合わせが増える
認証、リトライ、テナント対応付けのコードが連携ごとに重複する。どの API が誰に呼ばれているかを誰も把握していない
② 集約 API連携するシステムが多く(目安 6 以上)、各システムを規約に合わせられない(買収した製品、外部製品、改修できない既存システム)。共通化する対象が安定していて、読み取りが中心。または、複数プロダクトを1つの API 製品として売ることが事業上必須で、そのドメインの決定権を持つチームがある合わない
B は新しく、C は未着手で、ドメインモデルが動いている。書き込みもある
共通層のチームに変更依頼の列ができる。書き込みでプロダクトをまたぐトランザクションや補償処理が必要になる
③ 土台だけ共通自社開発のプロダクトを複数チームが並行して変える。プロダクト間で読み書きがある。API の使い方(認証、規約、ポータル)は揃えたいが、契約を1つにする必要はない。Platform チームがセルフサービスで提供できる合う
すべての条件に当てはまる
Platform チームが業務データの変換や処理の手順を書き始める。規約を守れないプロダクトがある
④ 合成層複数プロダクトのデータを1画面に並べる UI(スイート画面)や、複数プロダクトをまとめた API がある。その UI や API のチームが持つ今は不要
必要になったら ③ の上に足す
同じ集約を複数の画面が別々に作っている。合成層がシステム間連携の経路として使われている
③ が理想である理由 1

ドメインモデルを1つにする費用が見合わない

A の client は「契約の単位」、B の tenant は「顧客企業の単位」で、意味が違います。共通モデルにすると、どちらかの意味を歪めるか、両方を含む複雑なモデルを誰かが保守することになります。Fowler が紹介する Bounded Context の考え方では、大きなシステムのモデルを完全に統一するのは現実的でも費用に見合うものでもないとされています。Canonical Data Model も、参加するシステムが少ないうちは割に合わないと原典に書かれています。

③ が理想である理由 2

変更の判断がプロダクト側に残る

② では、A の項目追加が共通層の改修を待ちます。Thoughtworks Technology Radar は「API ゲートウェイの形をした ESB」「過度に賢い API ゲートウェイ」を Hold にしています。理由は、業務ロジックを中央の仕組みに入れると結合が強まり、特定チームへの依存が生まれるためです。

③ が理想である理由 3

揃えるべきものは揃えられる

認証方式、エラー形式、ページング、API の台帳、流量制限、監視は ③ でも全プロダクトで揃います。Azure API Management の workspaces は、Microsoft が「federated API management」と呼ぶこの形のための機能です。プロダクトチームが自分の workspace を管理し、Platform チームが全体のポリシーと監視を持ちます。

A↔B だけの今から ③ で始める理由

① でも A↔B はつながります。ただし ① でも必ず作ることになる2つ、「呼び出し元のサービスの認証」と「どの B tenant がどの A client のデータを使ってよいか」は、C が加わると作り直しになります。この2つは最初から土台に置きます。API Center や APIM workspace の整備などは、C の着手に合わせて足しても構いません。土台は最小から始めて、使われる分だけ育てます(Team Topologies の Thinnest Viable Platform)。

作るべき「共通 API 基盤」は、業務データを扱う API ではなく、各プロダクトの API を同じ方法で公開・認証・発見・連携できるようにする土台です。
3 / 全体構成

最終形の全体構成

認証の統合まで終わった最終形です。途中の段階は第 9 章に分けて描きます。青は各プロダクトチーム、緑は Platform チーム、紫は認証、橙は分析の部品です。

顧客のシステム 各プロダクトの公開 API を呼ぶ 顧客ユーザー(ブラウザ) A・B・C の画面を使う 共通 IdP Entra External ID など 顧客ユーザーのログイン 顧客企業の IdP と SSO Phase 2 で新設 Azure Front Door Premium + WAF(api.example.com など) Azure API Management(Platform が運用) 全体ポリシー: トークン検証・呼び出し元の識別・流量制限・ログ workspace A A チームが管理 workspace B B チームが管理 workspace C C チームが管理 workspace 共通 集計 API・台帳 API Entra ID(社内) サービス間の認証 マネージド ID App Roles 顧客組織台帳 Organization と親子 A client / B tenant との対応付け 接続許可(Grant) 変更はイベントで通知 Azure API Center API の台帳 規約の自動チェック プロダクト A client / project API(細かい権限もここ) DB outbox → イベント プロダクト B tenant(client を接続) API(細かい権限もここ) DB outbox → イベント プロダクト C tenant = Organization API(細かい権限もここ) DB outbox → イベント イベント基盤(Platform が運用) Event Grid namespace(ドメインイベント)/ Service Bus(順序・重複排除が要るもの) Log Analytics Application Insights 呼び出しの記録 分析基盤: Microsoft Fabric ほか(Platform が運用) データの意味と契約は各プロダクト、基盤と配信は Platform Mirroring 各 DB を複製 数十秒〜数分 OneLake プロダクト別の データ(契約付き) 横断集計 事前に集計した テーブル 配信用ストア PostgreSQL など 画面の問い合わせ用 集計 API Grant を照合 基準時刻付き 秒単位の鮮度が要る指標だけ: Eventstream → Eventhouse の経路を追加探索的な分析画面が要るなら: Power BI Embedded を併用 APIM から公開 各プロダクトチーム Platform チーム 認証 分析 点線: データの複製・参照
プロダクト間の呼び出し(例: B → A)も、外部からの呼び出しと同じく APIM を通ります。左端の点線は A・B・C の各 DB から分析基盤への複製、右端の緑の点線は台帳の Grant を集計 API が照合する経路です。
部品持つチーム役割この持ち方にする理由
各プロダクトの API・DB・ドメインモデル各プロダクト業務データの読み書き。細かい権限の判定変更の頻度も判断材料もプロダクト側にある
APIM インスタンスと全体ポリシーPlatform公開、トークン検証、流量制限、ログ認証と監視の方法を全 API で揃える
APIM の workspace各プロダクト(自分の workspace だけ変更できる)自プロダクトの API 定義とポリシーAPI の追加や変更で Platform チームの作業待ちを作らない。全体ポリシーは継承させる
API Center と規約ルールPlatform がルールを持ち、各プロダクトが守るAPI の台帳。OpenAPI への Spectral ルールの自動適用規約をレビュー依頼ではなく CI とツールで守らせる
Entra ID のアプリ登録・App Roles各プロダクトが自 API の App Roles を定義し、Platform が命名と払い出しの規約を持つサービス間の認証「誰に何を許すか」は API の持ち主が決める
顧客組織台帳PlatformOrganization、対応付け、Grantどのプロダクトにも属さないデータで、全プロダクトが同じ意味で使う
イベント基盤基盤は Platform、イベントの定義と送信は各プロダクトドメインイベントの配信イベントの意味はそれを起こしたプロダクトが決める
共通 IdPPlatformログイン、顧客企業との SSO1人1アカウントにするには、1か所で管理する必要がある
分析基盤・配信・集計 API基盤と配信は Platform、データの契約と指標の意味は各プロダクト横断集計の作成と配信指標の意味を知っているのはデータの持ち主で、基盤を共有するほうが安い
4 / 顧客組織

顧客組織の台帳: client と tenant の対応付け

A は「契約ごとの client」、B は「企業ごとの tenant」です。どちらかの単位に揃えるのではなく、上位に Organization(顧客組織)を置き、各プロダクトの単位を Organization に対応付けます。プロダクト間でデータを使う許可は Grant として別に持ちます。

プロダクト A client a-101 X 商事の契約 project × 3 client a-102 X 物流の契約 project × 5 顧客組織台帳 Organization の親子 X ホールディングス X 商事 X 物流 点線 = 各プロダクトの単位との対応 プロダクト B tenant b-9 X ホールディングス で 1 つ プロダクト C Organization ID を そのまま tenant にする Grant(接続許可) — 台帳に置く B tenant b-9 → A client a-101 範囲: project の読み取り・集計値 承認済み(承認: a-101 の管理者) B tenant b-9 → A client a-102 範囲: project の読み取り・集計値 承認待ち: B からは a-102 が見えない
対応付け(点線)は「同じ顧客である」ことを表すだけで、データを使ってよいかは表しません。使ってよいかは下段の Grant で表します。
揃え方 1(選ばない)

A の client を共通の単位にする

  • B の tenant(企業単位)と、1 tenant に複数 client がつながる関係を表せない
  • 親会社と子会社の関係を表せない
揃え方 2(選ばない)

B の tenant を共通の単位にする

  • A で子会社ごとに契約が分かれている事実が tenant の中に埋もれる
  • 子会社ごとに「B に見せてよいか」を決めることができなくなる
上位に Organization を置く理由

既存の単位を変えずに、関係を表せる

A と B のデータモデルと画面はそのまま残せます。企業グループの親子、どの単位が同じ顧客か、どこからどこへの利用を許したか、を台帳で表します。Atlassian の organization、Google Cloud の Organization、Slack Enterprise Grid も、上位の組織の下に製品ごとの単位を置く構成です。

IdP に組織を持たせない理由

IdP を替えても台帳が残る

Entra External ID には、顧客組織を表す専用のオブジェクトがありません。Auth0 などの Organizations 機能を使う場合でも、正本は台帳に置き、IdP へは同期するほうが、IdP の移行や併用に耐えます。Microsoft の Architecture Center も、利用権や所属は IdP ではなくアプリか専用サービスで管理するよう勧めています。

プロダクト C

Organization をそのまま C の tenant にする

C の顧客単位が企業なら、C 独自の tenant 表を作らず Organization ID を使います。3つ目の単位を増やさずに済みます。C が部署などの細かい単位を必要とするなら、C の中にその単位を作り、Organization に対応付けます。

// 台帳の最小のデータ(業務データは入れない)
Organization   (org_id, name, parent_org_id)
ProductAccount (org_id, product, account_id)        // product=A なら client_id、B なら tenant_id
Grant          (grant_id, grantee_product, grantee_account_id,
                source_product, source_account_id, scopes[],
                status, requested_by, approved_by, approved_at, expires_at, revoked_at)
Membership     (org_id, user_id, role)              // 共通 IdP を入れる Phase 2 以降
条件理想の置き方
C 以降もプロダクト間の連携が増える(今回の想定)Platform の台帳に Organization、対応付け、Grant を置く
連携は今後も B → A だけで、A は B の存在を知らなくてよいB の中の「接続した A client」の表で足りる。ただし A 側の承認記録は A が持つ
プロダクトを別会社に売却する、別々に運用する可能性が高い共有の台帳への依存を減らす。各プロダクトが接続表を持ち、台帳は参照用の複製にとどめる
顧客の組織構造が深く、プロジェクト単位の共有や委任が頻繁に変わる台帳に加えて、関係ベースの認可エンジン(OpenFGA など)を検討する。第 10 章
5 / 接続許可

接続許可(Grant)の成立のさせ方

ユーザーがプロダクトごとに別々の現状でも、Grant は作れます。B で申請し、データの持ち主である A client の管理者が A にログインして承認する流れにします。A のログインで承認者の本人確認をするので、共通 IdP を待たずに成立します。

B の管理者X ホールディングス プロダクト B 顧客組織台帳 プロダクト A a-101 の管理者X 商事 承認待ち ① 接続を申請 ② Grant を作成 ③ 承認依頼イベント ④ 承認依頼を表示 ⑤ A にログインして承認 ⑥ 承認者を記録 ⑦ 承認済みイベント ⑧ 接続完了を表示 本人確認は A のログインで行う 範囲・申請者を記録
⑤ で承認するまで、B からは a-101 のデータを1件も取得できません。点線の矢印はイベントです。
A 側で承認する理由

データの持ち主が決める

a-101 のデータは X 商事の契約に基づくもので、親会社の tenant で見せてよいかは X 商事側が決めることです。GitHub App のインストール、Slack の組織へのアプリ追加、Entra の cross-tenant access も、リソースを持つ側の管理者が、対象と範囲を選んで許可し、あとから取り消せる形になっています。

取り消し

A からも B からも取り消せて、すぐ効く

取り消しは台帳の Grant を無効にし、イベントで各プロダクトに知らせます。API の呼び出しと集計 API は毎回台帳を照合する(短いキャッシュ付き)ので、分析基盤のデータが数分遅れていても、取り消した時点から返らなくなります

共通 IdP の後

B の画面の中で承認できるようになる

Phase 3 以降は、B にいる人が a-101 の管理者本人かを共通 IdP のアカウントで判定できます。そのため、A の画面に移らずに B の画面で承認を完結できます。台帳と Grant のデータ構造は変わりません。

条件理想の承認のしかた
子会社ごとに契約し、データの持ち主が子会社(今回の想定)A client の管理者が承認する(上図)
親会社が全子会社分をまとめて契約し、利用権が契約で親会社にある親の Organization の管理者が、配下の client をまとめて承認できるようにする。承認の記録は同じ Grant に残す
申請者と承認者が同じ担当者で、通知を待つ流れが煩わしいA で接続コードを発行し、B に入力する方式にする。コードは短い有効期限と1回限りにする
別の Organization 間(取引先同士)で接続する両側の管理者の承認を必須にする
6 / プロダクト間の呼び出し

プロダクト間の API 呼び出し

B の画面で、接続済みの a-101 の project 一覧を出す場合です。B は社内の Entra ID でサービスとしてのトークンを取り、APIM と A の両方が「b-9 は a-101 を読んでよいか」を台帳で確かめます。リクエストに書かれた tenant ID を、確かめずに信じることはしません。

B のユーザー プロダクト B Entra ID(社内) APIM 顧客組織台帳 プロダクト A ① 集計画面を開く ② b-9 の一員か(B の DB) ③ トークン要求 マネージド ID ④ aud=A, roles=Partner.Read ⑤ GET /a/clients/a-101/projectsb-9 として ⑥ 署名・aud・roles を検証 ⑦ Grant 照合 ⑧ 許可: projects.read ⑨ 転送(照合した Grant ID を付与) ⑩ Grant と範囲を A でも再確認 ⑪ a-101 の project だけを返す
④ のトークンは「B というサービスが A の Partner.Read を持つ」ことだけを表します。どの顧客のデータを読んでよいかは、⑦ と ⑩ の台帳照合で決まります。
社内 Entra ID を使う理由

サービス間の認証は顧客向け IdP と分ける

Azure 上のサービスはマネージド ID でシークレットなしにトークンを取れます。App Roles は API ごとに定義でき、APIM の validate-azure-ad-token で検証できます。Entra External ID の client credentials は GA ですが、有料アドオンでトークン発行ごとに課金されます。また External ID のアプリ登録は単一テナント固定で、社内のマネージド ID からトークンを取る方法は文書化されていません。

二重に確認する理由

APIM は入口の粗い確認、A は最終判断

Microsoft はゲートウェイでの検証を多層防御の一段と位置づけています。オブジェクト単位の認可漏れ(OWASP API Security Top 10 の API1: BOLA)を防ぐ最終判断は、データを持つ A が行います。APIM の照合があれば、A の実装に漏れがあっても未許可の呼び出しは入口で止まります。

してはいけないこと

強い権限 + リクエストの tenant ID を信じる

「B は A の全データを読める」権限だけを与え、B が送る tenant ID で絞る実装にすると、B の不具合1つで他社のデータが返ります(confused deputy)。RFC 9700(OAuth 2.0 Security BCP)も、アクセストークンの audience と権限を最小限に絞るよう求めています。サブスクリプションキーだけでの認証もしません。

「どの顧客として呼ぶか」の伝え方は3通りある

方式しくみ理想になる条件弱点
P2: サービスのトークン + 台帳照合(上図)トークンは呼び出し元サービスと粗い権限だけを表す。顧客の範囲は APIM と受け手が台帳で確かめるユーザー認証が統合されていない(Phase 1〜2)。バッチや非同期の連携がある。連携のパターンが少ない照合を APIM と各受け手に実装する。台帳が止まると連携も止まるので、台帳の可用性とキャッシュが要る
P3: 内部 STS が範囲を絞ったトークンを発行Platform の STS が台帳を確認し、audience・顧客の範囲・操作を絞った数分有効の JWT を発行する。受け手はトークンだけで判断できる受け手のサービスが多く、台帳照合を各所で実装したくない。3 段以上の呼び出しの連鎖がある。「何のために発行したトークンか」を監査で追う必要があるSTS の運用、鍵管理、可用性を Platform が負う。Entra ID は RFC 8693 のトークン交換に対応していないので自作になる。設計は IETF の Transaction Tokens(draft-11、未 RFC)を参考にする
P1: ユーザーのトークンを引き継ぐ(OBO)B のユーザーのトークンから A 向けトークンを取り、A はそのユーザー本人の権限で判断する共通 IdP 統合後(Phase 3 以降)。連携が必ずユーザー操作から始まり、A 側でのそのユーザー個人の権限を連携にも効かせたいユーザーのいないバッチでは使えない。Entra の OBO は委任スコープだけを引き継ぎ、App Roles は引き継がない

Phase 1〜2 では、A は B のユーザーが誰かを知りません。そのため連携で効く権限は「組織として許可したか」(Grant)までです。B の特定のユーザーには a-101 の一部の project しか見せない、という要件がある場合は、共通 IdP 統合後の P1 まで待つか、Grant の範囲を project 単位にして B 側で絞ります。

7 / 同期とイベント

同期 API とイベントの使い分け

「データ取得・登録・更新」は同期 API で行います。一方で、他のプロダクトで起きた変化を知るために相手の API を定期的に呼ぶ(ポーリング)と、呼び出しが増え続けます。「起きたこと」はイベントで知らせ、大量の集計は分析基盤で扱います。

場面使うもの理由
相手の今の状態を見て処理を続ける同期 API例: B の画面で a-101 の project 一覧を出す。呼び出し元が応答を必要とする
相手のプロダクトに登録・更新し、結果で次の処理が変わる同期 API + 冪等キー再試行で二重登録しないように、POST には冪等キーを必須にする
起きたことを複数のプロダクトが知るイベント(通知型)例: project のアーカイブ、Grant の取り消し。送る側は受け手を知らなくてよい。受け手は必要なら API で詳細を取りに行く
相手が止まっていても動く必要がある、よく読む小さなデータイベント(状態を載せる型)+ 受け手側の複製例: 接続済み client の名前と状態。相手の可用性に引きずられない。代わりに複製と整合の管理が増える
期間をまたぐ集計、複数プロダクトの結合分析基盤(第 11 章)運用 API や運用イベントで大量のデータを運ばない
イベント基盤理想になる条件向かない条件
Event Grid namespace件数が中程度までのドメインイベントを、複数の受け手に配る。CloudEvents 1.0 形式。受け手が冪等に処理でき、厳密な順序は要らない。受け手が閉域なら pull 配信順序保証、重複排除、トランザクションが要る。namespace の push 先は現在 Event Hubs と Webhook だけ
Service Bus トピックclient ごとなどの単位で順序が要る(セッション)。重複排除、トランザクション、デッドレターを使った業務処理。outbox の中継先大量のテレメトリや操作ログの流し込み
Event Hubs操作ログ、監査、分析用の大量のストリーム。Kafka クライアントを使いたい件数の少ない業務イベント(1件ごとのデッドレターが要る)。スキーマ互換チェックは Avro のみ
送る側の必須事項

transactional outbox で送る

業務データの更新とイベントの記録を同じ DB トランザクションで行い、別プロセスが送信します。DB は更新されたのにイベントが出ない、という不整合を防げます。

受ける側の必須事項

同じイベントが2回来ても結果が変わらない

どの Azure のメッセージ基盤も「少なくとも1回」の配信です。イベント ID か業務キーで重複を捨てます。

全プロダクト共通の規約

最初から決めて、ツールで守らせる

  • API は OpenAPI 3.x、イベントは AsyncAPI と CloudEvents
  • エラー形式は RFC 9457(Problem Details)
  • 一覧はカーソル型ページング
  • バージョンの付け方は全社で1つに決め、後方互換を守る
  • 流量超過は 429 と Retry-After
  • POST の冪等キー(IETF の Idempotency-Key は失効した draft なので、社内規約として採用する)
8 / 公開 API

顧客に公開する API

「各プロダクトのユーザーはそのプロダクトの API を使える」という要件は、最終形では次の形にします。入口のドメインとポータルは1つ、API はプロダクトごと、認証方式は全プロダクト共通です。

項目最終形理由
入口api.example.com/a/…/b/…/c/…(Front Door → APIM)あとから API ゲートウェイを入れると URL が変わる。Microsoft もゲートウェイなしの公開をアンチパターンに挙げている
開発者ポータルAPIM の開発者ポータル1つworkspace が分かれていても1つのポータルに並べられる
顧客システムの認証共通 IdP が発行する OAuth クライアント。クライアントと Organization・プロダクトの対応は台帳で持つAPI キー単独は強い認証ではない。顧客ごとの対応を台帳に置けば、IdP に組織の機能がなくても顧客を特定できる
内部向けと公開の区別同じリソースの API を使い、内部専用の操作だけ公開用とは別の APIM product にしてポータルに出さない公開 API と内部 API を二重に保守しない。内部の操作は「audience: 社内」と台帳(API Center)に記録する
顧客への通知Webhook(Standard Webhooks 形式の署名)、または Event Grid の event domainevent domain は顧客ごとにトピックを分け、権限も顧客ごとに分けられる
条件理想の構成
顧客は各プロダクトの API を個別に使う(今回の想定)上表のとおり。プロダクトごとの API のまま、使い方だけを揃える
複数プロダクトをまとめた1つの API を顧客に売る統合 API を「製品」として持つチーム(ドメインの決定権がある)を作り、APIM の後ろに合成 API を置く。Platform チームには持たせない
顧客の組織 ID をトークンに入れて受け手の実装を減らしたい組織つきのマシン間トークンを出せる IdP(Auth0 Organizations、WorkOS など)を選ぶ。Entra External ID の client credentials は組織の情報を持たない
共通 IdP の導入前各プロダクトの既存の API キーやトークンを APIM の後ろでそのまま使う。入口のドメインとポータルだけ先に揃える
9 / 認証の変遷

認証基盤の変遷(Phase 0〜4)

段階ごとに、変える対象を1つに絞ります。サービス間 → 新規プロダクト → 既存ユーザー → 旧資産の削除の順です。タブで各段階の構成を切り替えられます。橙の枠がその段階で変わる部品です。

ログイン プロダクト 共通の部品 A のユーザー B のユーザー C(未リリース) A のログイン A のユーザー表で認証 B のログイン B のユーザー表で認証 プロダクト A ユーザー表: ID・パスワード・権限 公開 API: A 独自のキー プロダクト B ユーザー表: ID・パスワード・権限 公開 API: B 独自のキー プロダクト C 未着手 プロダクト間の連携なし・共通の部品なし 顧客企業の SSO や公開 API のキーも、各プロダクトで個別に設定
Phase 0: 現状
この段階の状態
  • A と B がそれぞれユーザー表とログインを持つ
  • 公開 API の認証も各プロダクトで別
  • プロダクト間の連携はない
困っていること

同じ人が A と B に別のアカウントを持ちます。顧客企業の SSO を各プロダクトで個別に設定することになります。B が A の client を接続するとき、承認者の本人確認をどちらのユーザーで行うかも決まっていません。

次に進む条件

A↔B の連携を始める。これが Phase 1 の開始条件です。

観点Phase 0Phase 1Phase 2Phase 3Phase 4
ユーザーのログインA・B が別々A・B が別々A・B 別々、C は共通 IdP全部共通 IdP(移行期間)全部共通 IdP
ユーザーの正本各プロダクトのユーザー表同左A・B は各表、C は共通 IdP共通 IdP(旧表は検証用)共通 IdP
顧客企業の SSO各プロダクトで設定同左C は共通 IdP で設定共通 IdP に集約共通 IdP
公開 API の認証各プロダクト独自同左(入口だけ APIM)C は共通 IdP の OAuthA・B も共通 IdP を併用共通 IdP に統一
サービス間の認証なし社内 Entra ID同左同左同左
顧客の範囲の判断なし台帳の Grant同左同左Grant + 必要なら OBO
所属(誰がどの組織か)各プロダクト各プロダクト台帳(C の分)台帳(A・B・C)台帳

共通 IdP の製品は「顧客組織の機能を IdP に求めるか」で決まる

候補理想になる条件避けるべき条件確認した事実
Microsoft Entra External ID契約を Microsoft に集約したい。顧客企業ごとの SSO 設定が少なく、社内で設定作業を回せる。組織と所属を台帳で持つ前提を受け入れる顧客企業に自分で SSO を設定させたい。組織単位のロールや組織 ID 入りのマシン間トークンを IdP の標準機能で使いたい。ピーク時のログインがテナントあたり 200 リクエスト/秒を超える顧客組織を表すオブジェクトはない。JIT パスワード移行 GA(2026-03)。client credentials GA(2026-01、有料アドオンでトークン単位の課金)。SAML/WS-Fed とカスタム OIDC のフェデレーション対応。トークン発行時のクレーム追加は外部 API の応答 2 秒以内、テナント全体で 50 リクエスト/秒まで。月間アクティブユーザー 5 万まで無料
B2B 向け CIAM(Auth0、WorkOS、Descope など)顧客組織、組織単位の SSO、招待、組織単位のロール、組織つきのマシン間トークンを早く揃えたい。企業顧客の SSO 設定が増える見込みAzure 以外のベンダー契約とデータの置き場所を増やしたくない。組織データを台帳と IdP の二重で管理したくない(するなら台帳を正本にして同期する)Auth0 は Organizations と組織ごとの接続設定、組織 ID 入りの M2M トークンを持つ。WorkOS の M2M アプリは常に1組織に紐づく
Keycloak(自前運用)Organizations と RFC 8693 のトークン交換を OSS で揃えたい。IdP のパッチ適用と可用性を担える体制があるPlatform チームが小さい。Microsoft は自前 IdP の運用をアンチパターンとしているKeycloak 26 で Organizations が正式機能、26.2 で標準のトークン交換に対応
Azure AD B2C(新規では選ばない)2025-05-01 で新規販売終了。サポートは少なくとも 2030-05 まで。Architecture Center も新規には勧めていない

既存ユーザーの移し方

方式理想になる条件
一括作成 + JIT パスワード移行旧パスワードのハッシュを IdP に移せない。ユーザーにパスワード再設定を強いたくない。旧 DB を数か月残せる
一括作成 + 全員パスワード再設定旧 DB を早く止めたい。ユーザー数が少ない。ログイン頻度が低く、JIT では移行が進まない
パスワード移行なし顧客の大半が企業 IdP の SSO でログインしている。または移行を機にパスワードレスに切り替える
10 / 権限

権限はどこに置くか

認証の統合と権限の統合は別の話です。「誰か」(認証)と「どの組織に属し、どのプロダクトを契約し、プロダクト間で何を許したか」は共通化し、「プロダクトの中で何ができるか」は各プロダクトに残します。

共通 IdP

本人であること

ログイン、MFA、顧客企業との SSO。

顧客組織台帳

所属・契約・接続許可

Organization への所属と組織内の管理者、どのプロダクトを契約しているか、Grant。

各プロダクト

プロダクト内の権限

A の project ごとの編集権限、B の画面ごとの閲覧権限など。意味がプロダクトごとに違い、変更も頻繁です。

方式理想になる条件避けるべき条件
すべて各プロダクトに置くプロダクト間で共有・委任する対象がほとんどない。チームの独立性を最優先するプロダクト間の接続がある(今回はある)
所属・契約・Grant は台帳、細かい権限は各プロダクト組織、契約、プロダクト間の接続を全プロダクトで揃えたい。横断の共有は「接続した client を読む」程度の少数パターン横断の共有関係が多く、各プロダクトが同じ関係を別々に解釈し始めた
関係ベースの認可エンジン(OpenFGA など)Organization > 子会社 > client > project の階層と共有関係を、複数プロダクトが同じ意味で評価する。共有と委任が頻繁に変わる。「なぜ許可されたか」を横断で監査する必要がある。Platform が高い可用性で運用できる横断の共有が少ない。認可エンジンは全 API の単一障害点になるので、運用体制がないなら入れない

認可エンジンを後から入れる可能性に備えるなら、API から台帳への問い合わせを OpenID AuthZEN Authorization API 1.0(2026-01 に最終仕様)の形に寄せておくと、問い合わせ先を差し替えやすくなります。OpenFGA は CNCF Incubating(2025-10)です。Azure にはこの種のマネージドサービスがないので、自前で運用することになります。

11 / 横断集計

横断集計: 集計 API か、集計用データの取得か

「集計してデータを返す API」と「集計のためにデータを取得する仕組み」は、別の層の話です。画面が呼ぶのは集計済みの値を返す API、材料を運ぶのは分析基盤への複製で、両方が要ります。避けるべきなのは、プロダクト間の API で生データを運んで、使う側で集計することです。

配信層: 画面が呼ぶもの 応答時間は配信用ストアで確保する B のダッシュボード tenant b-9 のユーザー 「接続先の project 数の推移」 集計 API 台帳の Grant を毎回照合 許可された client 分だけ 集計値 + 基準時刻を返す 配信用ストア 事前集計テーブル 行ごとに顧客のキー 統合層: 集計の材料を運ぶ(分析基盤) 鮮度は既定で数分 A の DB B の DB C の DB Mirroring または CDC 運用 DB に負荷小 プロダクト別データ OneLake 契約は各チームが持つ 横断集計テーブル Grant の単位で集計しておく 生の行は B に渡さない 配信用に載せる 秒単位が要る指標だけ Eventstream → Eventhouse の経路を足す 選ばない経路 A の API で生データを全件取得して B で集計する(A の DB に負荷、client 数に比例して遅い、定義がばらつく) B が A の DB を直接読む(A のスキーマ変更で B が壊れる、A の中の認可を迂回する)
集計 API は第 3 章の構成図どおり APIM の共通 workspace から公開します。B のダッシュボードは A のデータの持ち方を知る必要がありません。
画面には集計 API を使う理由

定義・認可・負荷を1か所で扱える

  • 指標の定義が揃う: A と B の画面で「稼働中の project」の意味が同じになる
  • 他社の生データを渡さない: B が受け取るのは許可された範囲の集計値だけ
  • Grant の照合が1か所: 取り消しもすぐ効く
  • 運用 DB に負荷をかけない: Microsoft の OLTP ガイドも、大きな集計は運用 DB から分析用ストアに移すよう書いている
材料を分析基盤で運ぶ理由

API で運ぶと、呼び出し側で結合することになる

複数サービスの API を呼んで集める方式(API composition)には、大きなデータを呼び出し側のメモリで結合するという弱点があります。Microsoft のマルチテナント向けガイドも、テナントやシステムをまたぐ集計は中央の分析用ストアに発行する形を勧めています。Fabric Mirroring は Azure SQL Database、SQL Managed Instance、Cosmos DB(NoSQL)、PostgreSQL flexible server で GA です。変更は最短 15 秒間隔で反映され、複製の計算処理は Fabric 容量を消費しません(ただし容量は稼働させておく必要があります)。

持ち分

データの意味は各プロダクト、基盤と配信は Platform

各プロダクトチームは、分析基盤に出すデータの項目、意味、顧客キー、鮮度の約束を「データ契約」として持ちます(Open Data Contract Standard などの形式)。Platform チームは Mirroring、OneLake、容量、配信用ストア、集計 API の枠組みを持ちます。全部を Platform が作ると指標の追加が Platform 待ちになり、全部を各チームに任せると基盤が重複します。

方式理想になる条件避けるべき条件
(a) 表示のたびに相手の API を呼ぶ1回に扱う件数が少ない。相手が安価な集計済みエンドポイントを持っている。直前に更新した値をすぐ反映する必要がある。同時利用が少ない長期間の履歴、多数の client にまたがる集計。応答時間の目標が厳しい。プロダクト数が増える(呼び出し先の数だけ遅く、落ちやすくなる)
(b) イベントで受け取り、自プロダクトに複製使う側が必要なのは小さく安定した一部(接続中の client 一覧と件数など)。相手が止まっていても表示したい。その集計を使うのが自プロダクトだけ多くのプロダクトが多くの相手のデータを必要とする。指標の定義をプロダクト間で揃える必要がある。履歴の集計
(c) 分析基盤 + 配信用ストア + 集計 API複数のプロダクトが互いのデータを使う。指標の定義を揃えたい。履歴やプロダクト間の結合がある。Platform チームがある。大半の指標が数分遅れで足りる連携が1本だけで (a) か (b) で済む
配信用ストアを Eventhouse / Azure Data Explorer にする操作ログや時系列の指標。秒単位の鮮度。同時利用が多い(事前集計の materialized view と結果キャッシュを使う)更新で変わる業務エンティティ(client、project、契約)の結合が中心
配信用ストアを PostgreSQL / Azure SQL にする事前集計したテーブルが小さめで、顧客キーで引く。アプリ並みの応答時間と接続の扱いが欲しい。チームが SQL に慣れている大量の生データへの探索的な問い合わせ(それは分析基盤側で行う)
Power BI Embedded(アプリがデータを持つ方式)ドリルダウンやエクスポートなど探索的な画面を、アナリストが作って頻繁に変える。iframe の見た目で問題ない。エンドユーザーのライセンスは不要(A / F SKU)数値を製品の画面に深く組み込む、通知や API でも同じ数値を使う、応答時間を製品側で保証したい
Databricks SQL + Lakebase会社として Databricks を標準にしている。データエンジニアリングや ML が重い。Lakebase の synced tables で分析基盤から Postgres へ配信する(Azure で 2026-03 GA)Fabric に容量とガバナンスを寄せる方針
Fabric Warehouse / SQL エンドポイントを画面から直接呼ぶ社内向けの管理画面など、同時利用が少なく数秒の応答で足りる顧客向けの画面。一定のサブ秒応答を狙った設計ではなく、結果キャッシュは現在無効、同時セッションはワークスペースあたり 2,048

鮮度の決め方

指標ごとに次の順で判断します。既定は「5 分以内」とし、画面には必ず「◯時◯分時点」を表示します。

問いはいの場合
他のプロダクトで更新した直後に、その数字を見て操作するかその1件だけは相手の API で今の値を取る(方式 a)。一覧や集計は分析基盤のまま
数字に業務上のアラートや SLA が結びついているかその指標だけ Eventstream(CDC)→ Eventhouse の経路で秒単位にする
日・週・月の傾向を見る指標か数分〜1時間の遅れで足りる。Mirroring + 定期集計
OneLake の行レベルセキュリティは Entra ID の利用者向けで、SaaS の顧客ユーザーには使えません。「b-9 は a-101 の集計を見てよいか」は集計 API で判断し、分析基盤側の権限は集計 API のサービス ID を絞る多層防御に使います。
12 / 条件の切り替え

条件を切り替えて、既定から変わる点を見る

当てはまる条件にチェックを入れると、第 0 章の構成から変わる点が表示されます。チェックした内容はコピーできるので、質問するときに貼り付けてください。

13 / Azure の注意点

Azure で作るときに先に知っておくこと

構成に影響する制約だけを挙げます。いずれも 2026-09-13 時点の Microsoft Learn などで確認しました。

APIM の classic と v2 に移行経路はない

v2 は新規作成のみです。完全な VNet 内配置は Premium v2 と classic Premium だけで、Standard v2 は外向きの VNet 統合です。複数リージョンの単一インスタンスとセルフホストゲートウェイは classic Premium だけで、v2 にはバックアップ/復元もありません。

Standard v2 のゾーン冗長は資料が食い違う

信頼性ガイド(2026-09-09)は対応と書き、機能表は未対応のままです。作成時にしか設定できないので、Japan East で使えるかをポータルで確かめてから tier を決めます。

workspaces には未対応の機能がある

組み込みゲートウェイでの workspaces は 2026-06 に GA ですが、ポータル対応は遅れています。workspace では credential manager、synthetic GraphQL、MCP サーバー、セルフホストゲートウェイが使えず、リソース名はインスタンス全体で一意です。専用の workspace gateway にはカスタムホスト名とプライベートエンドポイントがなく、Front Door を前に置きます。

流量制限のカウンターはゲートウェイごと

rate-limit-by-key はゲートウェイごとに数えます。顧客ごとに全体で揃えた上限が必要なら quota-by-key か、入口の Front Door で制限します。v2 ではリクエスト本文のバッファ上限が 2 MiB です。

External ID のトークンは validate-azure-ad-token で検証できない

このポリシーは External ID 非対応と明記されています。顧客ユーザーのトークンは validate-jwtciamlogin.com の OpenID 構成を指定して検証します。社内 Entra ID のサービス間トークンは validate-azure-ad-token で検証できます。

External ID には顧客組織の機能がない

アプリ登録は単一テナント固定です。リクエスト上限はテナントあたり 200 / 秒、IP あたり 20 / 秒です。M2M は有料アドオンです。カスタムドメインは Front Door 経由で、全アプリを同じログインドメインに揃える必要があります(セッション Cookie がドメイン単位のため)。

Fabric の SQL は顧客向け画面から直接呼ばない

Warehouse と SQL エンドポイントは、一定のサブ秒応答を狙った設計ではありません。結果キャッシュは既知の問題で現在無効、セッションはワークスペースあたり 2,048 です。事前集計を配信用ストアに載せます。

Fabric の制限は容量単位でかかる

同じ容量で重い処理が走ると、顧客向けの問い合わせまで遅延・拒否されます。配信に使う部分は専用の容量に分け、共有容量ではサージ保護を使います。超過分の課金(preview)は通常の 3 倍です。容量を止めると Mirroring も止まります。

Fabric API for GraphQL は集計ビューを出しにくい

公開するオブジェクトには主キーが必要で、キーのない集計ビューは出せません。タイムアウトは 100 秒です。顧客向けの集計 API の代わりにはしません。

新規で使わないもの

Azure AD B2C(新規販売終了)、Cosmos DB の Synapse Link(新規プロジェクト非対応)、Cosmos DB for PostgreSQL(廃止予定、PostgreSQL の elastic clusters へ)。API Center は Japan リージョンがありません(メタデータのみの保存)。

14 / 未決事項

まだ決まっていないこと

次の項目が決まると、この解説のうち条件つきで書いた部分がどちらかに確定します。

集計

横断で出す指標の一覧と、指標ごとの鮮度・同時利用数

配信用ストアの種類(PostgreSQL か Eventhouse か)、Fabric 容量の大きさ、秒単位の経路の要否が決まります。

接続許可

Grant の承認者と範囲

子会社の管理者か親会社か、範囲は client 単位か project 単位か、操作は読み取りだけか書き込みもあるか。

認証

A・B のユーザー数、重なり、企業 SSO 利用者の割合、SSO をセルフサービスにするか

共通 IdP の製品、Phase 3 の時期、パスワード移行の方式が決まります。

既存システム

A・B の DB の種類とデータ量

Mirroring をそのまま使えるか(MySQL なら CDC か open mirroring)が決まります。

C

C の顧客単位

Organization をそのまま tenant にできるか、C の中に細かい単位を作るか。

費用・非機能

ネットワーク要件、リージョン、料金

閉域の要否で APIM の tier が決まります。APIM・Front Door・Fabric 容量・External ID(MAU と M2M)の料金は、今回の調査では取得していません。