マルチテナントアーキテクチャとは?
「マルチテナントアーキテクチャ」とは、ひとつのソフトウェアやインフラを複数の利用者(テナント)が共有して使う仕組みのことを指します。
たとえばクラウドサービスでは、1つのアプリケーションを何社ものお客さんが同時に使っていても、それぞれのデータや設定はしっかり分かれています。
一般的には、データベースを共通したり、スキーマをどう分けるのか、といった技術的な話が多いですが、今回は、ユーザーからみた機能として、どのようなテナントアーキテクチャにすることがよいのか、有名なSaaSがどういう戦略をとっているのかを理解していきたいと思います。
テナントとは?
- 法人の管理者がSaaSとサービス利用の契約して
- 管理者が社員や関係者を招待して
- その単位でデータや権限が管理される
そんな「組織としての利用の入れ物」です。
SaaSの比較
Slack
ビジネス向けのチームコミュニケーション(チャット)SaaS。チャンネル中心で会話・ファイル共有・通知連携を行う。
テナントまわり
- テナント:ワークスペース
- プロジェクト相当:チャンネル(Public/Private)
- チーム:チャンネルやユーザーグループで実質的に構成
- ロール:Workspace Owner / Admin / Member / Guest
利用手順
- 管理者がワークスペース作成
- メンバーをメール招待 or ドメイン連携で参加
- チャンネルを作成(部署別・案件別)
- 外部パートナーはGuestで参加(チャンネル限定)
課金
- 席課金(ユーザー数ベース)。アクティブ課金のプランあり。
- 上位プランでSAML SSO、監査ログ、保持ポリシーなど。
向き/注意
- 向き:社内情報をチャンネル外に出さず堅牢に守りたい組織。
- 注意:ワークスペース間の横断は弱め。社外コラボはGuest運用前提。
GitHub
ソースコードのホスティングと共同開発プラットフォーム。Issue/PR/Actionsで開発フローを管理。
テナントまわり
- テナント:Organization
- プロジェクト相当:Repository(+Projects機能)
- チーム:Org配下のTeamで権限束ね
- ロール:Org Owner / Member(Repo単位で Read/Write/Admin 付与)
利用手順
- 個人アカウントでログイン
- Orgを作成しメンバー招待(社内外可)
- Repo作成、Teamに権限割当
- ブランチ保護・CI/CD( Actions )設定
課金
- Org単位の席課金+一部機能上位化(Codespaces/Actionsの従量など)。
向き/注意
- 向き:社外を含むコラボが多い開発組織。個人↔組織をまたぐ働き方。
- 注意:公開/非公開の切り分け、Teamと権限設計を最初に整理すると運用がラク。
Notion
ドキュメント・データベース・タスクなどを柔軟にまとめるワークスペース。個人→チームへスムーズに拡張できる。
テナントまわり
- テナント:Workspace(個人/チーム両方あり)
- プロジェクト相当:ページ/DB(ツリーで自由に構成)
- チーム:グループ共有(Enterpriseで高度化)
- ロール:Admin / Member / Guest(ページ単位で権限きめ細かい)
利用手順
- 個人Workspaceでスタート(無料でお試し)
- チーム導入でメンバー招待、スペース/権限整理
- ページ・DBテンプレでナレッジ基盤化
- 外部共有はGuest/リンク共有で制御
課金
- 席課金(個人無料→チーム有料)。上位でSSO、権限・監査が強化。
向き/注意
- 向き:PLGで自然にスケールさせたいナレッジ系SaaSの参考モデル。
- 注意:ページ単位の共有設定が柔軟なぶん、権限ポリシーを最初に決めると事故が減る。
Auth0
認証・認可(IDaaS)。アプリ側のログイン/SSO/MFA/ユーザー管理をまるごと任せられる。
テナントまわり
- テナント:Auth0のTenant(運用空間が完全分離)
- プロジェクト相当:Application(SPA/API/Native などのクライアント定義)
- チーム:ダッシュボードの管理者グループ
- ロール:ダッシュボードRBAC(管理権限)+アプリ側のRBACは実装次第
利用手順
- Tenant作成(開発/本番を分けることが多い)
- Application登録、コールバックURL設定
- ルール・アクションでトークンにクレーム付与(例:tenant_id, roles)
- IdP連携(Google/AzureAD/Okta)やMFA設定
課金
- MAU(Monthly Active Users)中心の従量。上位でB2B/Enterprise機能。
向き/注意
- 向き:B2B SaaSのログイン基盤、SSO/SAML対応が必須な企業向け。
- 注意:Tenantが完全分離のため、環境・設定の横展開は自動化(IaC)が前提。
Google Workspace
メール(Gmail)、カレンダー、Drive/Docsを含む企業向け生産性スイート。
テナントまわり
- テナント:Google Workspace ドメイン(example.com)
- プロジェクト相当:サービス単位のリソース(ドライブの共有ドライブ等)
- チーム:組織部門/グループ(Google Groups)
- ロール:Super Admin / Admin / User(サービス別の管理役割も)
利用手順
- ドメインで契約・所有確認
- ユーザー作成(プロビジョニング)
- 組織部門やグループ作成、ポリシー適用
- SSO/端末管理/保持ポリシー設定
課金
- 席課金(ユーザー数)。プランでストレージ・セキュリティ機能が拡張。
向き/注意
- 向き:企業基盤としてのメール/ストレージ/コラボを統合管理。
- 注意:ドメイン=テナントなので、社外コラボは共有ドライブ/リンク権限の運用設計が鍵。
ChatGPT
生成AIアシスタントのSaaS。個人利用に加えて、Business/Enterprise/Edu の各プランで組織向けワークスペース(= テナント)を提供し、SSO・RBAC・監査・データ保護などの管理機能を備える。組織データは既定で学習に使われない。
テナントまわり
- テナント:ChatGPTのワークスペースが単位(Business/Enterprise/Edu)。ドメイン検証、SSO、利用状況の可視化、役割管理に対応。
- チーム/グループ:ワークスペース配下でメンバーを編成。管理者はSSO・保持・アクセス制御などのポリシーを設定できる。
- ロール:Owner / Admin / Member の3階層(権限はワークスペース管理・請求・設定などに段階化)。
- データ保護:Enterprise/Business/Edu では入力・出力の所有権は利用者側、既定で学習不使用、保存時/通信時暗号化。
利用手順
- 組織のワークスペースを作成(Business/Eduは即時、Enterpriseは営業経由)
- SSOやドメイン検証を有効化、ユーザーを招待/SCIMで同期
- 連携(コネクタやファイル、検索など)と権限・保持ポリシーを設定
- GPTsやプロジェクトを共有し、利用状況をダッシュボードで把握(役割に応じてガバナンス)
課金
- Business(旧Team):席課金。ヘルプ記載では年契 $25/席/月、月契 $30/席/月(2席以上)。
- Enterprise/Edu:見積もり(SLA、データ保持の細分、データレジデンシー、RBAC拡張などが対象)。
- 注意:APIの課金はChatGPTサブスクと別勘定(同一ではない)。
向き/注意
- 向き:組織単位での生成AI活用(SSO・監査・RBAC・保持ポリシーが必須なケース)。SOC 2やISO系列の適合、RBACや拡張SSOが求められる企業・学校に向く。
- 注意:プランで使える管理/セキュリティ機能が異なる(例:SAML SSO・専用ワークスペース・統合請求は Business/Enterprise 以上)。導入前にプラン別機能表を確認する。
ER設計をかんがえてみる
Q1. サインアップは「個人から」? それとも「法人(組織)から」?
モデルA:法人のみ
例:Google Workspace。ドメイン検証、SSO、ユーザー一括管理から開始。
向き:IT主導、規制・監査要件が強い全社導入。
モデルB:個人 → 組織へ昇格
例:Slack、Notion、GitHub、ChatGPT Team/Business。まず個人や小チームで開始、後で組織化。
向き:部門起点で広げたい、低摩擦で試したい。
モデルC:個人も法人でも参加可能
例:Figma、Miro、Airtable、Linear。個人利用も法人導入も両方に対応。
向き:自由度を保ちつつ、スムーズに組織運用へ切り替えたい。
おすすめ:モデルCを基本とする
既定は個人で開始し、「会社のドメインで始める(管理者向け)」も用意しておく。
個人組織から法人組織への移管が可能な設計にしておくと、導入が柔軟になる。
Q2. 組織の中にある単位は「Workspace」か「Project」か「Repository」か?
モデルA:Workspace(部屋・スペース)
例:Slack、Notion、Linear
- 意味:データ・権限・設定の“まとまり”
- 特徴:1つの組織に複数のワークスペースが存在する
- 用途:部門別、目的別、セキュリティ境界などに使い分け
- UIでの扱い:切り替えが大きく、横断しない前提
モデルB:Project(業務単位)
例:Jira、Asana、Figma
- 意味:ワークスペースの中にある小さめの業務単位
- 特徴:目的・期間・担当が定まっている
- 用途:案件・タスク・議事録・AI出力などの単位に向いている
- UIでの扱い:Workspace内で一覧表示や検索対象になる
モデルC:Repository(コード単位)
例:GitHub、GitLab
- 意味:1つのコードベースや構成を管理する単位
- 特徴:ブランチ・タグ・CI/CDなど技術的要素が強い
- 用途:ソフトウェア開発が前提
- UIでの扱い:Projectよりも自己完結・履歴中心
推奨モデル:Workspace+Project(+ Repository は用途次第)
Organization
→Workspace
→Project
- Workspaceが**「部屋」または「チーム」で、Projectが「案件」や「会議体」**
- リポジトリを持ちたければ、Project配下に紐付け
Q3. 組織外ユーザーをワークスペースやプロジェクトに参加させることはできるか?
モデルA:どちらも不可(完全に組織内のみ)
例:Notion(Enterprise)、ClickUp(制限あり)
- 組織に招待されていないユーザーは一切アクセス不可
- SSOやドメイン制限を前提に、ガバナンス・コンプライアンスを重視
- 外部とのコラボには向かない
モデルB:ワークスペースは不可、プロジェクトはゲストで可
例:Figma、GitHub、Slack
- ワークスペースは組織内ユーザー限定
- プロジェクト単位で「ゲストユーザー」の参加を許可可能
- ゲストには閲覧・コメントなど限定的な権限のみ
- 招待リンクやメール経由での参加
モデルC:どちらもゲストとして参加可能
例:Google Drive(共有設定による)、Airtable
- ワークスペースごとゲストユーザーを許可できる
- 管理が複雑になりやすいが、柔軟性が高い
- 共有ポリシーで制御
おすすめ:モデルBを基本とする
- 外部コラボはプロジェクト単位に限定
- ワークスペースには原則、組織内メンバーのみ
project_members.external = true
などで外部ユーザーを明示- ゲストのアクセス権限を
role_id
とpolicy
で制限
Q4. アクセス制御はどう設計すべきか?(RBAC, ABAC, PBAC)
モデルA:RBAC(ロールベースアクセス制御)
例:Slack、Notion、GitHubadmin / editor / viewer / guest
のようなロールに応じてアクセスを制御する。
実装がシンプルでUIにもわかりやすいが、細かい条件に対応しづらい。
モデルB:ABAC(属性ベースアクセス制御)
例:Google Drive、Microsoft Azure
ユーザーやリソースの属性(例:部署やタグ)に基づいて制御する。
柔軟だが、設計や運用が複雑で、権限が見えにくくなりやすい。
モデルC:PBAC(ポリシーベースアクセス制御)
例:AWS IAM、Google Cloud IAM
「誰が」「どのリソースに」「何ができるか」のルール(ポリシー)を定義して管理する。
RBACやABACを含む強力なモデルだが、初期から導入するには重い。
おすすめ:RBACを基本にし、PBACに発展できる設計にしておく
まずは role_id
をメンバーシップに持たせてRBACで始める。roles
テーブルと permissions
テーブルを切り分けておけば、将来的に柔軟なポリシー設計にも対応しやすい。
Q5. どのようなリソースと permission を定義すべきか?
リソースは、アプリケーション上の「操作対象」や「管理対象」の単位。
permission は、「誰が」「どのリソースに」「どの操作をできるか」を定義する。
モデルA:永続データをリソースとする
例:organization, workspace, project, document など
構造化されたデータを管理する場合に適しており、リソースごとに CRUD 操作を定義しやすい。
モデルB:一時的または生成系のリソース
例:summary, comment, task, notification など
ユーザー操作やAIなどにより動的に生成されるが、場合によっては閲覧や編集制御が必要になる。
モデルC:機能・操作単位をリソースと見なす
例:invitation.send, export.download, integration.connect など
個別の機能やワークフローに対してアクセスを制限したい場合に使う。
おすすめ:モデルAをベースに、必要に応じてB・Cを追加
データ構造として明確なもの(project, documentなど)をリソースとし、
特殊な操作(共有、生成、接続など)は必要に応じて別リソースとして定義する。
よく使われる permission の例:
- organization.view, organization.manage
- workspace.create, workspace.invite, workspace.delete
- project.create, project.edit, project.archive
- document.read, document.comment, document.delete
- invitation.send, integration.connect, export.download
Q6. 誰にどう permission を割り当てるべきか?(role・policy設計)
permission は定義しただけでは意味がなく、誰にどう割り当てるか(=ポリシー)が必要になる。
モデルA:roleベースで割り当てる(RBAC)
例:admin / editor / viewer / guest
事前に定義したロールに対して一括で permission を割り当てる。
UIにも反映しやすく、ユーザー管理がシンプル。
モデルB:個別のユーザーに直接 permission を付与(user-permission mapping)
特定の例外ケースに対応できるが、管理が煩雑になりやすい。
規模が大きくなるとポリシースプロール(権限の乱立)を招きやすい。
モデルC:role + context(スコープ)ベースの柔軟なポリシー設計
例:projectのadminと、workspace全体のviewerを両立する
ロールは維持しつつ、スコープごとに割り当てを変える。現代的なSaaSに多い。
おすすめ:roleベースを基本とし、必要に応じてスコープや属性で分岐できる仕組みにしておく
- まずは role → permission の構成でスタート
- 将来、project単位や一部例外に対応したくなったら policy テーブルを追加
- 個別permissionの付与は避ける(例外的に限定)
おすすめで作った場合のER図
erDiagram %% 所属関係 users ||--o{ org_members : belongs_to organizations ||--o{ org_members : has organizations ||--o{ workspaces : has workspaces ||--o{ workspace_members : has users ||--o{ workspace_members : belongs_to workspaces ||--o{ projects : has projects ||--o{ project_members : has users ||--o{ project_members : belongs_to %% 権限まわり project_members }o--|| roles : has_project_role workspace_members }o--|| roles : has_workspace_role roles ||--o{ role_permissions : defines permissions ||--o{ role_permissions : included_in %% リソース projects ||--o{ artifacts : has projects ||--o{ invitations : has projects ||--o{ summaries : has %% Billing organizations ||--o{ billing_accounts : has billing_accounts ||--o{ subscriptions : has workspaces ||--o{ usage_logs : has users ||--o{ usage_logs : has %% テーブル定義 users { uuid id PK string email string name } organizations { uuid id PK string name string org_type string primary_domain } org_members { uuid organization_id FK uuid user_id FK string role } workspaces { uuid id PK uuid organization_id FK string name } workspace_members { uuid workspace_id FK uuid user_id FK uuid role_id FK } projects { uuid id PK uuid workspace_id FK string name string kind } project_members { uuid project_id FK uuid user_id FK uuid role_id FK boolean external } roles { uuid id PK string name string scope } permissions { uuid id PK string resource string action } role_permissions { uuid role_id FK uuid permission_id FK } artifacts { uuid id PK uuid project_id FK string type string visibility uuid owner_id FK } invitations { uuid id PK uuid project_id FK string email string token timestamp expires_at } summaries { uuid id PK uuid project_id FK string content timestamp generated_at } billing_accounts { uuid id PK uuid organization_id FK string billing_email string billing_method } subscriptions { uuid id PK uuid billing_account_id FK string plan int seat_count timestamp started_at timestamp ended_at } usage_logs { uuid id PK uuid workspace_id FK uuid user_id FK string metric float amount timestamp occurred_at }