RBACの誕生 — 「人ではなく役割に権限を」という核心的洞察
1992年、NIST(米国国立標準技術研究所)のDavid Ferraiolo と Richard Kuhn は、 第15回 National Computer Security Conference において、それまでの常識を覆す論文を発表しました。 タイトルは "Role-Based Access Controls"——後に業界標準となるアクセス制御モデルの誕生です。
当時の問題意識は明確でした。第3章で見た古典的モデルには構造的な限界がありました。DAC(任意アクセス制御)は所有者が自由に権限を委譲できるため柔軟すぎてセキュリティが弱く、 トロイの木馬攻撃に対して無防備です。 一方 MAC(強制アクセス制御)は機密ラベルによる厳格な制御が可能ですが、 階層的なラベル体系は商業組織の複雑な業務要件には馴染みません。
Ferraiolo & Kuhn の核心的洞察は次の一点に集約されます。「個々のユーザーに直接権限を付与するのではなく、業務上の役割(Role)に権限を結びつけ、 ユーザーはその役割に割り当てる」——この間接化のレイヤーが、 大規模組織での権限管理を劇的にシンプルにするのです。
RBAC0〜3の4階層モデル — ANSI/INCITS 359-2004
Ferraiolo らの1992年の提唱を土台として、Ravi Sandhu(テキサス大学)が1996年に発表したRBAC96フレームワークは4つのモデルに体系化しました。 その後 Sandhu・Ferraiolo・Kuhn の共同による2000年の NIST 統一モデルを経て、 2004年に ANSI/INCITS 359-2004 として米国国家標準として制定されます。 2012年には INCITS 359-2012 に改訂されています。
RBAC0(Core RBAC) — すべての基礎
RBAC0 は4つのモデルの中で最も基本的であり、他のすべてのモデルに含まれます。 4つのエンティティと2つの関係、そしてセッション管理で構成されます。
- U(Users): システムを利用する主体。人間に限らずサービスアカウントも含む
- R(Roles): 業務上の役割(例:営業担当、経理マネージャー)
- P(Permissions): オブジェクトに対する操作の権限(例:受注データ閲覧、経費承認)
- S(Sessions): ユーザーのログインセッション。ロールを有効化する文脈
関係は2種類あります。UA(User Assignment)はユーザーとロールの多対多の対応(一人のユーザーが複数ロールを持てる)、PA(Permission Assignment)はロールと権限の多対多の対応です。 セッション内でユーザーは保持するロールの一部のみを有効化できます。 これにより最小権限の原則を実践的に実現します。
RBAC1(Hierarchical RBAC) — 組織の職制をモデル化
RBAC1 は RBAC0 にロール階層を追加します。 ロール間に偏順序(Partial Order)の包含関係を定義し、 上位ロールは下位ロールの権限をすべて継承します。
たとえば「部門長 ≥ マネージャー ≥ 一般担当者」という階層を定義すると、 部門長には部門長ロール固有の権限に加え、マネージャー・一般担当者の権限が自動的に付与されます。 組織の現実の職制ヒエラルキーを忠実に反映でき、権限の重複定義を排除できます。
RBAC2(Constrained RBAC) — 職務分離で不正を防ぐ
RBAC2 は RBAC0 に制約(Constraints)を追加します。 最重要の制約が職務分離(SoD: Separation of Duties)です。
静的職務分離(Static SoD)は、割り当て時点での制約です。 「発注担当者」と「支払承認者」を同一人物に割り当ててはならない、という制御です。 ユーザーへのロール付与(UA更新)の際にシステムが競合を検出して拒否します。
動的職務分離(Dynamic SoD)は、セッション内での同時有効化を禁止します。 同一ユーザーが「発注者」と「承認者」の両ロールを保有していても、 一つのセッションで両方を同時にアクティブにはできません。 これにより、緊急時の一時的な兼任を許容しながら、通常業務での不正を防止できます。
他の制約としては、特定ロールの同時保有者数を制限するCardinality制約(例:「CISO ロールは1名まで」)、 あるロールを得るために事前に別ロールを保有していることを要求するPrerequisite制約(例:「上級技術者を得るには技術者ロールが必要」)もあります。
RBAC3(Full RBAC) — すべての統合
RBAC3 は RBAC0・RBAC1・RBAC2 のすべての機能を統合したモデルです。 重要な点として、RBAC1 と RBAC2 は独立した拡張であり、 一方のみを採用することも可能です。 RBAC3 はその完全統合版として位置づけられています。
graph LR
subgraph Users
U1[Alice]
U2[Bob]
end
subgraph Roles
R1[経理マネージャー]
R2[経理担当者]
R3[発注担当者]
end
subgraph Permissions
P1[経費承認]
P2[帳票閲覧]
P3[発注作成]
end
subgraph Objects
O1[経費申請DB]
O2[発注システム]
end
U1 -->|UA| R1
U2 -->|UA| R2
U2 -->|UA| R3
R1 -->|継承| R2
R1 -->|PA| P1
R2 -->|PA| P2
R3 -->|PA| P3
P1 -->|操作| O1
P2 -->|操作| O1
P3 -->|操作| O2
style R1 fill:#8b5cf6,stroke:#6d28d9,color:#fff
style R2 fill:#3b82f6,stroke:#1d4ed8,color:#fff
style R3 fill:#3b82f6,stroke:#1d4ed8,color:#fffRBAC0〜3の比較
| モデル | 追加機能 | 主なユースケース | 実装複雑度 |
|---|---|---|---|
| RBAC0 | 基本要素(U/R/P/S)とUA/PA | 小〜中規模SaaS、シンプルな権限管理 | 低(5テーブル) |
| RBAC1 | ロール階層(偏順序) | 職制ヒエラルキーのある組織、ERP | 中(再帰クエリが必要) |
| RBAC2 | SoD制約(Static/Dynamic)、基数制限 | 金融・会計・コンプライアンス要件のあるシステム | 中〜高(制約チェックエンジン) |
| RBAC3 | RBAC0+1+2の統合 | 大規模エンタープライズ、規制産業(医療・金融) | 高(階層+制約の組み合わせ) |
Role Explosion 問題 — 組み合わせ爆発との戦い
RBAC の理論的な優雅さとは裏腹に、実際の企業導入で最大の壁となるのがRole Explosion(ロール爆発)問題です。
たとえば、グローバル企業が組織コンテキストに応じてロールを設計しようとすると次のようになります。
- 地域: 東京・大阪・シンガポール・ニューヨーク (4地域)
- 部門: 営業・経理・人事・技術・法務 (5部門)
- 職位: 一般・シニア・マネージャー・部門長 (4職位)
単純な組み合わせで 4 × 5 × 4 = 80ロール が必要になります。 これに権限の細分化が加わると数百〜数千ロールが発生し、 ロールの棚卸し・メンテナンス・監査が事実上不可能になります。 ある調査では、数千から数万規模のロールを抱える大企業が 「誰がどのロールを持っているのか把握できない」という状態に陥る事例が多数報告されています。
解決策1: ロール階層の活用
RBAC1 のロール階層を適切に設計することで、権限の重複を除去できます。 「東京営業マネージャー」「大阪営業マネージャー」を個別に定義するのではなく、 「営業マネージャー(地域共通)」を階層の親として定義し、 地域固有の差分のみを子ロールとして追加します。 ただし階層が深くなるとクエリパフォーマンスへの影響が生じるため、階層深度は3〜4段が実用限界とされます。
解決策2: ABACによるコンテキスト条件の追加
コンテキスト依存の権限を RBAC ではなく属性(Attribute)で表現するアプローチです。 「東京オフィスの経理部門の管理職」という組み合わせをロールとして定義する代わりに、 「ロール=経理マネージャー かつ 所属オフィス=東京」という条件として表現します。 ABAC については次の第5章で詳解しますが、 多くの実際のシステムは RBAC と ABAC のハイブリッドとして設計されています。
解決策3: ReBACによるグループ関係の活用
第6章で詳解する ReBAC(Relationship-Based Access Control)は、 「オブジェクトとの関係」で権限を表現します。 「このドキュメントの編集者グループのメンバーは編集できる」という記述は、 グループメンバーシップという関係が直接権限の根拠となるため、 ロールの爆発を構造的に防ぎます。 Google Zanzibar や OpenFGA がこのアプローチを採用しています。
実装パターン — DBスキーマ設計
RBAC0 を関係データベースで実装する場合、基本的な構成は5テーブルです。
-- ユーザー
CREATE TABLE users (
id BIGINT PRIMARY KEY,
email VARCHAR(255) NOT NULL UNIQUE
);
-- ロール(業務上の役割)
CREATE TABLE roles (
id BIGINT PRIMARY KEY,
slug VARCHAR(100) NOT NULL UNIQUE, -- 例: 'accounting_manager'
description TEXT
);
-- 権限(オブジェクト×操作の組み合わせ)
CREATE TABLE permissions (
id BIGINT PRIMARY KEY,
slug VARCHAR(100) NOT NULL UNIQUE, -- 例: 'expense:approve'
description TEXT
);
-- ロール→権限 の多対多
CREATE TABLE role_permissions (
role_id BIGINT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
permission_id BIGINT NOT NULL REFERENCES permissions(id) ON DELETE CASCADE,
PRIMARY KEY (role_id, permission_id)
);
-- ユーザー→ロール の多対多
CREATE TABLE user_roles (
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
role_id BIGINT NOT NULL REFERENCES roles(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, role_id)
);権限チェックの基本クエリは次のようになります。 ユーザー ID と権限スラグを渡し、経由するロールの存在を確認します。
-- ユーザーが特定の権限を持つか確認するクエリ
SELECT EXISTS (
SELECT 1
FROM user_roles ur
JOIN role_permissions rp ON rp.role_id = ur.role_id
JOIN permissions p ON p.id = rp.permission_id
WHERE ur.user_id = :userId
AND p.slug = :permissionSlug
) AS has_permission;ミドルウェア実装のポイント
実装上の重要な考慮点は3つあります。
① パーミッションのキャッシュ
権限チェックはリクエストごとに発生するため、DBへの都度クエリはパフォーマンスボトルネックになります。 ユーザーの全権限セットをセッション確立時にキャッシュし(Redis 等)、 権限変更時に該当ユーザーのキャッシュを即座に無効化する設計が一般的です。
② セッション管理とロール有効化
RBAC0 の仕様では、ユーザーはセッション内で保有ロールの一部のみを有効化できます。 JWT に含めるクレームとしてロールの配列を持つ場合、 セッション開始時に有効化するロールを選択させるUXが最小権限原則に沿っています。 ただし実装コストとのトレードオフから、多くのシステムでは全ロールを常に有効化する設計を採用しています。
③ 権限変更時の伝播
ロールへの権限追加・削除は、そのロールを保有するすべてのユーザーに即座に影響します。 キャッシュの無効化戦略として、ロール変更時にはそのロールを保有するユーザー全員の キャッシュキーを削除する必要があります。 ユーザーとロールの対応を逆引きできるインデックス(role_id→user_ids)をキャッシュ側で保持するか、 DB の user_roles テーブルを参照して無効化対象を特定します。
理解度チェック
RBAC2(Constrained RBAC)が RBAC0 に追加する主な機能はどれですか?
キーボード: 1〜4 で選択、Enter で回答