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:#fff
Zanzibar タプルのグラフ表現: doc:readme は owner(alice)・viewer(group:eng)・parent(folder:product-docs) の3つのタプルを持つ。bob は prodDocs への viewer 関係を通じて readme にも推移的にアクセスできる

Namespace 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 QPS420万/秒
全 API 合計 QPS1,240万/秒
Check p50 レイテンシ3ms
Check p95 レイテンシ10ms
可用性99.999%超

Zookieとスナップショット整合性

分散システムで「正しいスナップショット」を使って権限チェックを行う問題は非自明です。 Zanzibar はこれを Zookie(ズーキー) という機構で解決しています。

Zookie の定義は「グローバルタイムスタンプをエンコードした不透明バイト列」です。 内部では Google Spanner の TrueTime(GPS・原子時計による誤差数ミリ秒の絶対時刻)を基盤としています。 クライアントからは中身が見えない(不透明)ため、バージョンとして安全に扱えます。

Zookieプロトコルの4ステップ

  1. コンテンツ(ACL含む)を変更したタイミングでZookieを取得する
  2. コンテンツ本体とZookieをアトミックに同じDBトランザクションで保存する
  3. ユーザーがそのコンテンツにアクセスするとき、Zookieをチェック要求に添付して送る
  4. 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) という問いは以下の手順で解決されます。

  1. doc:readme#viewer のタプルを全件取得
  2. 直接一致(@alice)があれば TRUE を返す(short-circuit)
  3. usersetがあれば再帰的に展開(例: group:eng#member → eng のメンバー全員を展開)
  4. computed_userset(例: editor→viewer 継承)も再帰展開
  5. tuple_to_userset(例: parent フォルダの viewer)も再帰展開
  6. 複数のブランチは並列ファンアウトで同時評価し、最初のTRUEでキャンセル

大規模グループ(数百万メンバー)の検索には Leopard インデックスを用います。 これはグループのメンバーセットを事前計算したインデックスで、 「ユーザーAとグループGの積集合が空かどうか」を O(min(|A|, |G|)) で判定できます。 分散キャッシュと Consistent Hashing によるルーティングが加わることで、 同一オブジェクトのチェックは同じノードに集約され、キャッシュヒット率が最大化されます。

OpenFGA vs SpiceDB — 詳細比較

Zanzibar の設計思想を実装したオープンソースプロジェクトは複数ありますが、 現在の主流は OpenFGASpiceDB の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]

orandbut 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 比較表

項目OpenFGASpiceDB
開発元Auth0/Okta(CNCF Incubating)AuthZed(Apache 2.0)
Zanzibar 忠実度設計思想を継承・DSL最適化論文の最も忠実な実装
スキーマ言語OpenFGA DSL(.fga)Authzed Schema Language(.zed)
一貫性制御Consistency tokenZedToken(4段階)
Watch API(変更通知)非対応対応(リアルタイム)
Caveat/条件付き権限限定的CEL式で完全サポート
DB対応PostgreSQL / MySQL / SQLitePostgreSQL / CockroachDB / MySQL / Cloud Spanner
主な採用事例Grafana・Canonical・DockerOpenAI・Reddit・Netflix
GitHub Stars5,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、「役職」ならRBAC、「動的属性」ならABAC。SpiceDB Caveats はReBAC+ABACのハイブリッドを実現
モデル最適なユースケース苦手なケース
ReBACドキュメント共有・チームメンバーシップ・フォルダ階層・SNSのフォロー関係組織の役職・時刻・場所などの動的条件単体
RBAC組織の職制・SaaS のプラン別権限・法規制上の役職要件ユーザーごとに異なるリソース権限・コンテキスト条件
ABAC業務時間・接続元IP・デバイス状態などの動的条件ポリシー記述の複雑化・パフォーマンス
ReBAC+ABAC「共有されていて、かつ業務時間内」などの複合条件スキーマ設計の習得コスト

理解度チェック

問題 0 / 40%
Q1

Google Zanzibar のタプル構造として正しい形式はどれですか?

キーボード: 1〜4 で選択、Enter で回答