アクセス制御といわゆる「ロール爆発」について最近考えたことを共有します。
RBAC(Role-based access control、ロールベースアクセス制御)は、ユーザーのロールに基づいてアクセス権限を決定するモデルです。直感的でよく使われますが、「ロール爆発」という問題が知られています。
アクセス制御の本質はシンプルだと考えています。誰が何に対してどんな操作ができるか。成熟したシステムはこれを明快に表現しています。
| システム | 主体 | 操作 | 対象 |
|---|---|---|---|
| Linux | ユーザー、プロセス | read, write, execute | ファイル |
| PostgreSQL | ロール | SELECT, INSERT, DDLなど | テーブル、列、行など |
| AWS IAM | プリンシパル | s3:ListBucketなど | リソース |
これらのシステムはRBACやABAC、ReBACといったアクセス制御モデルの名前から出発したわけではなく、自分たちのドメインにおいてアクセスとは何かを定義した結果としてこうなっています。アクセス制御モデルを選ぶときも、同じ順序で考えるべきではないでしょうか。
アクセス権がロールから自然に導かれる場合、RBACは有効です。「プログラマーはコードリポジトリにアクセスできる、私はプログラマーだ、よって私はコードリポジトリにアクセスできる」——この三段論法が成り立つなら、RBACは現実に合っています。
ロールが間違った抽象化になるとき
ロールとは英語のroleのカタカナ表記で、意味は「役割」です。アクセス制御の文脈では、ユーザーが組織の中でどういう立場・職責にあるかを指します。
問題が起きるのは、業務ルールがロールだけに基づかない場合です。例として、銀行のテラーと督促担当から始めたところに、勤務地(ロンドン、ベルリン)が加わると、「ロンドン・テラー」「ベルリン・テラー」「ロンドン・督促担当」……とロールが増殖します。
$n$ 個の二値属性があれば、アクセスパターンは最大 $2^n$ 通り。各属性が $k$ 個の値を取れば $k^n$ 通りになります。複数の独立した条件を「ロール」という1つの列に押し込めれば、爆発するのは当然です。
ロール爆発への処方箋としてよく挙げられるのがABAC(属性ベースアクセス制御)への移行です。ロールを勤務地や部署と並ぶ一属性として扱う考え方です。しかし「ABACに移行しましょう」だけでは、症状への対処に留まっているように思います。より根本的な問いは、そもそもアクセス制御がロールから導かれる設計だったのか、です。最初からそうでなかったなら、RBACはモデルの選択自体が誤りだったことになります。
ABACは本質的な複雑さを減らしてくれるわけではありません。しかし、複数の独立した条件を「ロール」という1つの人工的な列に押し込めれば、本来の複雑さの上に不必要な複雑さを重ねることになります。業務ルールが複雑なら、その複雑さを素直にモデル化するほうが健全です。
ロールも属性も適切でないとき
さらに区別すべきケースがあります。アクセス権がユーザーの属性とまったく無関係な場合です。
サブスクリプション型のアプリケーションでは、ユーザーXが機能Aにアクセスできるかどうかは、その機能を契約しているかどうかで決まります。ロールでも属性でもなく、顧客と契約の関係です。実際に「機能Aあり・機能Bなし」のようなロールを見たことがありますが、筋が違うと感じました。アクセス権はユーザーの性質ではなく契約の性質だからです。
まとめ
アクセス制御モデルを選ぶ前に問うべきことは、現実の業務においてアクセス権は何から導かれるかだと考えています。
- ロールから導かれるなら、RBACが自然に合う
- 複数の属性から導かれるなら、ABACが素直。RBACを使えばロール爆発する
- ユーザーとリソースの関係から導かれるなら、その関係を直接モデル化する
ロール爆発は、現実の複雑さを表現力の乏しいモデルに押し込んだ結果の症状だと思います。解決策はロールの整理ではなく、業務ルールの構造に合ったモデルを選ぶことです。モデルは現実に合わせるものであって、現実をモデルに合わせるものではありません。