RelationshipベースのアクセスControl(ReBAC)とは
第4章・第5章で見た RBAC と ABAC は、それぞれ「役職」「属性」を権限判断の根拠としていました。 しかし現実の多くのシステムには、これらでは表現が難しい関係性が存在します。
- 共有フォルダ: 「このフォルダを共有されたユーザーはその中の全ドキュメントを閲覧できる」
- チームメンバーシップ: 「このプロジェクトのメンバーは関連するリソース群にアクセスできる」
- 推移的な親子関係: 「フォルダの閲覧権を持つ者は、サブフォルダの閲覧権も自動的に得る」
これらをRBACで実現しようとすると、共有先・メンバーシップ・ネスト構造ごとにロールを作り続けることになり、 前章で見た Role Explosion 問題が爆発的に悪化します。 ABACでも、オブジェクト間の「関係性の連鎖」を動的な属性条件として記述するのは複雑で脆くなりがちです。
ReBAC(Relationship-Based Access Control、関係ベースアクセス制御)はこの問題に正面から向き合います。 エンティティ(ユーザー・グループ・リソース)間の「関係」そのものをグラフとして表現し、 推移的な権限継承をグラフ探索として自動処理する設計思想です。
この分野を実用レベルで定義した論文が、2019年に Googleが発表した「Zanzibar」です。 Googleが抱えていた課題はスケールが違いました—— YouTube・Drive・Maps・Docs・Cloud Consoleを横断する2兆件超のACLを統一的に管理する必要があったのです。
Google Zanzibar(2019年USENIX論文)
論文タイトルは "Zanzibar: Google's Consistent, Global Authorization System"(USENIX ATC '19)。 著者はKaran Agita, Denis Altman ら Google 社員19名です。 この論文は ReBAC の「事実上の仕様書」として、今日のオープンソース実装すべてに影響を与えています。
タプル(Tuple)の構造
Zanzibar の核心はシンプルなデータ構造——タプルです。 すべての関係は次のBNF文法で表現されます。
# タプルのBNF文法
<tuple> ::= <object> '#' <relation> '@' <user>
<object> ::= <namespace> ':' <object_id>
<user> ::= <user_id> | <userset>
<userset> ::= <object> '#' <relation>
# 具体例(Google Driveモデル)
doc:readme#owner@alice # Alice は readme の owner
doc:readme#viewer@group:eng#member # eng グループのメンバーは viewer
doc:readme#parent@folder:product-docs # readme の親は product-docs フォルダこの3要素の組み合わせ——object#relation@user——だけで、 あらゆる関係性を表現できることが Zanzibar 設計の優雅さです。userset(例: group:eng#member)を使うと グループ参照が可能になり、「Aグループのメンバーは全員この権限を持つ」という間接指定ができます。
graph LR
subgraph Tuples
T1[doc:readme owner alice]
T2[doc:readme viewer group:eng member]
T3[folder:product-docs viewer bob]
T4[doc:readme parent folder:product-docs]
end
alice -->|owner| readme[doc:readme]
engGroup[group:eng] -->|member| alice
engGroup -->|member| carol
readme -->|viewer via group| engGroup
readme -->|parent| prodDocs[folder:product-docs]
prodDocs -->|viewer| bob
style readme fill:#3b82f6,stroke:#1d4ed8,color:#fff
style prodDocs fill:#8b5cf6,stroke:#6d28d9,color:#fff
style engGroup fill:#10b981,stroke:#059669,color:#fffNamespace Config — 権限の演算定義
タプルが「関係の事実」を記述するのに対し、Namespace Config は 「権限をどう演算するか」を定義します。 3種のリーフノードで構成されます。
_this: タプルに直接記録されたユーザー/usersetを参照。最も基本的な参照。computed_userset: 同じオブジェクトの別 relation から userset を計算。 例:「editor は viewer でもある」→ viewer の computed_userset として editor を指定。tuple_to_userset: 別オブジェクトの relation を辿って userset を取得。推移的継承の核心。 例:「parent フォルダの viewer は、このドキュメントの viewer でもある」。
Zanzibar のスケール実績(2018年)
| 指標 | 数値 |
|---|---|
| 格納タプル数 | 2兆件超(約100TB) |
| Check QPS | 420万/秒 |
| 全 API 合計 QPS | 1,240万/秒 |
| Check p50 レイテンシ | 3ms |
| Check p95 レイテンシ | 10ms |
| 可用性 | 99.999%超 |
Zookieとスナップショット整合性
分散システムで「正しいスナップショット」を使って権限チェックを行う問題は非自明です。 Zanzibar はこれを Zookie(ズーキー) という機構で解決しています。
Zookie の定義は「グローバルタイムスタンプをエンコードした不透明バイト列」です。 内部では Google Spanner の TrueTime(GPS・原子時計による誤差数ミリ秒の絶対時刻)を基盤としています。 クライアントからは中身が見えない(不透明)ため、バージョンとして安全に扱えます。
Zookieプロトコルの4ステップ
- コンテンツ(ACL含む)を変更したタイミングでZookieを取得する
- コンテンツ本体とZookieをアトミックに同じDBトランザクションで保存する
- ユーザーがそのコンテンツにアクセスするとき、Zookieをチェック要求に添付して送る
- Zanzibar は "at-least-as-fresh"セマンティクス でそのZookieが示す時刻以降の状態で評価する
タイムスタンプを1〜10秒単位で量子化することで、同一タイムスタンプ帯のチェック結果を キャッシュで大量に共有できます。 これが「3ms という低レイテンシ」と「2兆件というスケール」を両立させる核心的な工夫です。
New Enemy Problem
Zookieが解決する問題として論文が取り上げているのが New Enemy Problem です。 以下のシナリオを考えてください。
Zookie による解決は次のように機能します。 機密情報追記(T2)の際に取得したZookieは T2 ≥ T1 を保証します。 つまりこのZookieを添付してチェックを行えば、 Zanzibar は必ず T2 以降の状態(= Bob 削除済みの状態)でチェックを実行します。 権限剥奪が反映される前のキャッシュを掴む心配がありません。
重要な点は、Zookie の取得・保存・送信という3ステップをアプリケーション側が責任を持って行う必要があることです。 Zookieを正しく使わないと整合性保証が崩れるため、SDKやドキュメントでの徹底が求められます。
チェックアルゴリズム
Zanzibar のCheck API は再帰的なグラフ探索として定義されています。check(doc:readme, viewer, alice) という問いは以下の手順で解決されます。
doc:readme#viewerのタプルを全件取得- 直接一致(
@alice)があれば TRUE を返す(short-circuit) - usersetがあれば再帰的に展開(例:
group:eng#member→ eng のメンバー全員を展開) computed_userset(例: editor→viewer 継承)も再帰展開tuple_to_userset(例: parent フォルダの viewer)も再帰展開- 複数のブランチは並列ファンアウトで同時評価し、最初のTRUEでキャンセル
大規模グループ(数百万メンバー)の検索には Leopard インデックスを用います。 これはグループのメンバーセットを事前計算したインデックスで、 「ユーザーAとグループGの積集合が空かどうか」を O(min(|A|, |G|)) で判定できます。 分散キャッシュと Consistent Hashing によるルーティングが加わることで、 同一オブジェクトのチェックは同じノードに集約され、キャッシュヒット率が最大化されます。
OpenFGA vs SpiceDB — 詳細比較
Zanzibar の設計思想を実装したオープンソースプロジェクトは複数ありますが、 現在の主流は OpenFGA と SpiceDB の2つです。
OpenFGA(Auth0/Okta、CNCF Incubating)
OpenFGA は Auth0(現 Okta)が開発し、 2023年に CNCF Incubating プロジェクト(2025年11月時点)となったプロジェクトです。 「開発者フレンドリーなDSL」を最大の特徴としており、 人間が読みやすい記法でモデルを記述できます。
# OpenFGA モデル定義(.fga 形式)
model
schema 1.1
type user
type group
relations
define member: [user]
type document
relations
define owner: [user]
define editor: [user, group#member] or owner
define viewer: [user, group#member] or editor but not blocked
define blocked: [user]
define parent: [folder]
type folder
relations
define viewer: [user, group#member]or・and・but not という英語に近い演算子で 権限のセット演算を記述できます。 REST と gRPC の両 API を提供しており、 Grafana Labs・Canonical・Docker・Sourcegraph 等が採用しています。 GitHub Stars は 5,300+ (2025年時点)。
SpiceDB(AuthZed、Zanzibar忠実実装)
SpiceDB は AuthZed 社が開発し Apache 2.0 で公開している、 Zanzibar 論文の最も忠実な OSS 実装です。 OpenAI(ChatGPT Enterprise)・Reddit(広告アセット共有)・Netflix が採用しており、 1億件リレーションで p95=5.76ms、100万 QPS の実績があります。
// SpiceDB スキーマ(.zed 形式)
definition user {}
definition group {
relation member: user
}
definition folder {
relation viewer: user | group#member
permission view = viewer
}
definition document {
relation owner: user
relation editor: user | group#member
relation parent: folder
// permission は relation の演算として定義
permission edit = editor + owner
permission view = edit + parent->view
permission delete = owner
}
// Caveat: CEL式による条件付き権限(ABAC的な属性)
caveat within_business_hours(current_time timestamp) {
current_time.getHours() >= 9 && current_time.getHours() < 18
}Caveats は SpiceDB 独自の機能で、 CEL(Common Expression Language)式による条件を権限に付与できます。 「業務時間内のみ編集可」「承認済みの場合のみ閲覧可」のような ABAC 的な属性条件を ReBAC と組み合わせるハイブリッドが実現します。
ZedToken(Zanzibar の Zookie 相当)では4段階の一貫性レベルを選択できます。
# ZedToken の一貫性レベル(パフォーマンス vs 新鮮度のトレードオフ)
minimize_latency: # キャッシュを最大活用。最も速いが古い可能性あり
at_least_as_fresh: # 指定ZedToken以降のスナップショットで評価(推奨)
at_exact_snapshot: # 指定スナップショット正確に参照
fully_consistent: # 常に最新状態。最も遅いが最も正確OpenFGA vs SpiceDB 比較表
| 項目 | OpenFGA | SpiceDB |
|---|---|---|
| 開発元 | Auth0/Okta(CNCF Incubating) | AuthZed(Apache 2.0) |
| Zanzibar 忠実度 | 設計思想を継承・DSL最適化 | 論文の最も忠実な実装 |
| スキーマ言語 | OpenFGA DSL(.fga) | Authzed Schema Language(.zed) |
| 一貫性制御 | Consistency token | ZedToken(4段階) |
| Watch API(変更通知) | 非対応 | 対応(リアルタイム) |
| Caveat/条件付き権限 | 限定的 | CEL式で完全サポート |
| DB対応 | PostgreSQL / MySQL / SQLite | PostgreSQL / CockroachDB / MySQL / Cloud Spanner |
| 主な採用事例 | Grafana・Canonical・Docker | OpenAI・Reddit・Netflix |
| GitHub Stars | 5,300+ | 4,800+ |
ReBAC・RBAC・ABACの使い分け
3つのモデルは競合するものではなく、問題の性質に応じて使い分けるものです。
graph TD
Q{権限判断の根拠は?}
Q -->|役職・組織上の役割| RBAC[RBAC]
Q -->|エンティティ間の関係・グループ共有・フォルダ階層| ReBAC[ReBAC]
Q -->|時刻・場所・デバイス等の動的属性| ABAC[ABAC]
ReBAC -->|条件を追加したい| Hybrid[ReBAC + ABAC]
ABAC -->|ロール組み合わせが複雑| Hybrid
Hybrid -->|実装| SpiceDB[SpiceDB Caveats]
style RBAC fill:#8b5cf6,stroke:#6d28d9,color:#fff
style ReBAC fill:#3b82f6,stroke:#1d4ed8,color:#fff
style ABAC fill:#f97316,stroke:#ea580c,color:#fff
style Hybrid fill:#10b981,stroke:#059669,color:#fff
style SpiceDB fill:#10b981,stroke:#059669,color:#fff| モデル | 最適なユースケース | 苦手なケース |
|---|---|---|
| ReBAC | ドキュメント共有・チームメンバーシップ・フォルダ階層・SNSのフォロー関係 | 組織の役職・時刻・場所などの動的条件単体 |
| RBAC | 組織の職制・SaaS のプラン別権限・法規制上の役職要件 | ユーザーごとに異なるリソース権限・コンテキスト条件 |
| ABAC | 業務時間・接続元IP・デバイス状態などの動的条件 | ポリシー記述の複雑化・パフォーマンス |
| ReBAC+ABAC | 「共有されていて、かつ業務時間内」などの複合条件 | スキーマ設計の習得コスト |
理解度チェック
Google Zanzibar のタプル構造として正しい形式はどれですか?
キーボード: 1〜4 で選択、Enter で回答