セキュリティ

Casbinとは:モデルとポリシーを分ける認可ライブラリの仕組みとPythonでのRBAC実装

Casbinとは:モデルとポリシーを分ける認可ライブラリの仕組みとPythonでのRBAC実装

Casbinは、「誰が・何に・何をしてよいか」の判定をアプリケーションの外に出すための、オープンソースの認可ライブラリです。ルールの形を書くモデルファイルと、ルールの中身を書くポリシーを分けて持つので、権限を追加する際にコードを修正する必要はありません。この記事では、PERMモデルの4セクションの読み方、pycasbinでRBACを動かすmodel.confとPythonコード、ABACやマルチテナントへの広げ方を、設定例付きで解説します。後半では、本番で詰まりやすいDB保存と複数台の同期、OPAやCedarとの使い分けまで判断します。

まとめ:Casbinは認可判定だけを受け持ちルールの形と中身を分けるライブラリ

Casbinが答えるのは「この利用者はこの操作をしてよいか」の1点です。ログインやパスワードの確認は受け持たないため、認証は別の仕組みで済ませ、その結果の利用者IDをCasbinに渡す構成になります。

手を動かす順番は次のとおりです。まずmodel.confにRBACの形を書き、policy.csvにロールと権限を並べ、enforce()を呼んで判定を確かめます。動いたら、ポリシーの置き場をファイルからデータベースへ移します。

採用してよいのは、認可を1つのアプリケーションか少数のサービスの中で完結させたい場合です。認可の判断を全社の複数言語・複数サービスで共有したいなら、OPAやCedarのような独立したポリシーエンジンのほうが合います。

Casbinの正体と認証を扱わない認可ライブラリとしての守備範囲

Casbinの公式概要は、自らを「リソースへの制御されたアクセスが必要なアプリケーション向けの認可ライブラリ」と説明しています。ACL・RBAC・ABACに加え、ReBACやドメイン付きRBACなど複数のアクセス制御モデルを、同じ書式のモデルファイルで表現できる点が特徴です。

Apache Casbinへの移管と2026年10月時点の各言語実装の版番号

Casbinは2026年2月7日にApache Software FoundationのIncubatorへ入り、公式サイトもcasbin.orgからcasbin.apache.orgへ移りました。GitHubのリポジトリもapache配下に移っています。ライセンスはApache License 2.0です。

実装 2026年10月29日時点の最新版 公開日
Go(本家) v3.11.0 2026年8月20日
Python(pycasbin) 2.8.0 2026年2月2日
Node.js(node-casbin) 5.51.1 2026年6月25日
Java(jCasbin) 1.99.0 2026年2月12日

Go版はv3.11.0のリリースページで確認できます。各実装は機能の揃い方に差があり、公式も「完全な統一はまだ達成していない」と書いています。Go以外を使うなら、必要な関数がその言語版にあるかを先に確かめてください。

Casbinが受け持つ認可判定と受け持たないログイン・ユーザー管理の線引き

公式概要には、Casbinがしないことも明記されています。ユーザー名とパスワードの確認、ユーザーやロールの一覧の管理、パスワードの保存の3つです。RBACで保持するのは「ユーザーとロールの対応」だけです。

実務では、ログインをOAuthやOpenID Connectの仕組みに任せ、受け取ったトークンから利用者IDを取り出してCasbinに渡します。認証と認可の分担はOAuth 2.0の仕組みと認証との違いで整理しています。ユーザー情報の正本は自社のユーザーテーブルかIdPに置き、Casbinには持たせません。

PERMモデルの4セクションとポリシーファイルが判定を組み立てる仕組み

CasbinはPERM(Policy・Effect・Request・Matchers)という考え方で、アクセス制御モデルを設定ファイルに落とし込みます。モデルを差し替えれば、同じenforce()呼び出しのままACLからRBACへ切り替えられます。

PERMモデルの4要素とrole_definitionによるロール定義の役割

モデル構文のドキュメントによると、モデルファイルには[request_definition]・[policy_definition]・[policy_effect]・[matchers]の4セクションが必須です。RBACを使うときだけ[role_definition]を足します。

  • request_definition:enforce()に渡す引数の並び。例はr = sub, obj, act
  • policy_definition:ポリシー1行の列の意味。例はp = sub, obj, act
  • matchers:リクエストとポリシー1行を突き合わせる式
  • policy_effect:一致した行が複数あるときの最終判定の決め方
  • role_definition:g = _, _でユーザーとロールの継承関係を宣言

matcherには&&や||が使えます。公式は、軽い比較を前に、ロール検索のような重い条件を後ろに置く順序を勧めています。

policy_effectの5種類の式とallowとdenyがぶつかったときの決まり方

policy_effectに書ける式は決まっており、公式は「独自の式は現在の実装ではサポートしない」としています。選べるのは次の5種類です。

# 1. allow-override
e = some(where (p.eft == allow))
# 2. deny-override
e = !some(where (p.eft == deny))
# 3. allow-and-deny
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
# 4. priority
e = priority(p.eft) || deny
# 5. subjectPriority
e = subjectPriority(p.eft)
名前 判定の決まり方
allow-override allowが1行でも一致すれば許可
deny-override denyが1行も一致しなければ許可
allow-and-deny allowがあり、denyが無いときだけ許可
priority 優先度が高い行の結果を採用
subjectPriority ロール階層の深さで優先度を決める

業務システムでは3行目のallow-and-denyを選ぶ場面が多くなります。「経理ロールには請求書の閲覧を許すが、退職予定者には拒否する」のような例外をdenyの1行で足せるからです。p.eft列を省略した行はallow扱いになります。

PythonでRBACを動かす:pycasbinの導入からAPIパスの判定まで

ここからは、注文APIに管理者と担当者の2つのロールを設ける例で、model.conf・policy.csv・Pythonコードを順に書きます。API名と関数の挙動は、pycasbin 2.8.0のソースに沿って記述しています。

pip install pycasbinでの導入と旧パッケージ名casbinとの取り違え

Python版はPyPIのpycasbinとして配布されています。旧名のcasbinは1.43.0(2025年5月10日)で更新が止まり、2024年10月25日の1.36.3以降はpycasbinの名前で版を重ねています。import名は今もcasbinのままです。

pip install pycasbin==2.8.0
python -c "import casbin; print(casbin.__file__)"

落とし穴は周辺パッケージ側にあります。SQLAlchemyアダプタ1.4.0は依存先を旧名のcasbin>=0.8.1と宣言しているため、一緒に入れると旧パッケージも入り得ます。導入後にpip listでcasbinとpycasbinが両方入っていないかを確認してください。

model.confとpolicy.csvを書いてロール経由でAPIパスを認可する例

モデルはRBACに、URLのパターン一致を足した形にします。keyMatch2は:idや*を含むRESTのパスと照合する組み込み関数です。1つ目をmodel.conf、2つ目をpolicy.csvとして保存します。

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && r.act == p.act
p, role_admin, /api/orders/*, GET
p, role_admin, /api/orders/*, DELETE
p, role_staff, /api/orders/:id, GET
g, alice, role_admin
g, bob, role_staff

pの行が「ロールに許す操作」、gの行が「ユーザーへのロール付与」です。ロール名にrole_の接頭辞を付けているのは、RBACのドキュメントが「ユーザーとロールに同じ名前を使わない」よう求めているためです。同名だとCasbinは両者を区別できません。

Enforcerで判定を呼び出しロールを追加するPythonコードと戻り値

Enforcerにモデルとポリシーを読ませ、enforce()に利用者・パス・HTTPメソッドを渡します。戻り値はTrueかFalseです。

import casbin

e = casbin.Enforcer("model.conf", "policy.csv")

print(e.enforce("alice", "/api/orders/42", "DELETE"))  # True(role_admin)
print(e.enforce("bob", "/api/orders/42", "GET"))       # True(role_staff)
print(e.enforce("bob", "/api/orders/42", "DELETE"))    # False

# 新しい担当者にロールを付与する(ファイル運用ではメモリ上の変更)
e.add_role_for_user("carol", "role_staff")
print(e.enforce("carol", "/api/orders/7", "GET"))      # True

# ロール経由で継承した権限まで含めて一覧する
print(e.get_implicit_permissions_for_user("bob"))

get_roles_for_user()は直接付与したロールだけを返し、get_implicit_roles_for_user()は階層をたどった結果を返します。監査用に「この人は実際に何ができるか」を出すなら後者を使います。ロール階層の深さは既定で10段が上限です。

Webフレームワークに組み込むときは、ミドルウェアで全リクエストにenforce()を通し、Falseなら403を返します。個別のハンドラに判定を書き散らすと、付け忘れた1本からIDORや権限昇格といった認可バイパスが起きます。

ABACとマルチテナントへ広げるときのeval関数とドメイン付きRBAC

ロールだけでは表しきれない条件は、属性で判定するABACか、テナントごとにロールを分けるドメイン付きRBACで受けます。どちらもモデルの書き換えだけで対応できます。

属性をリクエストに渡してeval()で役職レベルを判定する書き方

ABACのドキュメントでは、matcher内でr.sub.Ageのようにリクエストの属性を参照します。条件式をポリシー側に置くときはeval()を使います。属性を参照できるのはリクエスト側だけで、ポリシーの列には構造体を入れられません。次の3つをabac_model.conf・abac_policy.csv・Pythonコードとして使います。

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub_rule, obj, act

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = eval(p.sub_rule) && keyMatch2(r.obj, p.obj) && r.act == p.act
p, r.sub.level >= 3, /api/invoices/:id/approve, POST
p, r.sub.level >= 1, /api/invoices/:id, GET
from dataclasses import dataclass
import casbin

@dataclass
class User:
    name: str
    level: int

e = casbin.Enforcer("abac_model.conf", "abac_policy.csv")
print(e.enforce(User("sato", 3), "/api/invoices/10/approve", "POST"))    # True
print(e.enforce(User("suzuki", 1), "/api/invoices/10/approve", "POST"))  # False

役職レベルや部署のような属性は、判定のたびにアプリ側で最新値を引いて渡します。属性条件を増やす前に、RBACとの役割分担をABACの仕組みとRBACとの使い分けで確認しておくと、ポリシーが散らかりません。

g = _, _, _で同じ利用者にテナントごとの別ロールを割り当てる方法

SaaSのように1人が複数の会社(テナント)に属する場合は、ドメイン付きRBACを使います。role_definitionの引数を3つにし、3つ目にテナントを入れます。モデルとポリシーの組は次のとおりです。

[request_definition]
r = sub, dom, obj, act

[policy_definition]
p = sub, dom, obj, act

[role_definition]
g = _, _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub, r.dom) && r.dom == p.dom && r.obj == p.obj && r.act == p.act
p, admin, tenant1, data1, read
g, alice, admin, tenant1
g, alice, user, tenant2

aliceはtenant1では管理者、tenant2では一般利用者として判定されます。テナントIDをリクエストから取るときは、URLやヘッダーの値をそのまま使わず、ログイン中の利用者が本当にそのテナントに属するかをアプリ側で照合してから渡してください。

本番運用で詰まる3箇所:DBアダプタ・複数台の同期・ルール数の上限

ファイルで動いたCasbinを本番へ出すと、ポリシーの置き場・サーバー間の整合・ルール数の3つで設計が要ります。ここを決めずに出すと、権限を外したのに一部のサーバーでは操作できる、という事故になります。

SQLAlchemyアダプタでポリシーをDBに置くときのAutoSaveの挙動

Casbinはポリシーの読み書きをアダプタに任せます。PythonではSQLAlchemyアダプタのほか、Django ORMやPeewee用などが用意されています。

import os
import casbin
import casbin_sqlalchemy_adapter

# 接続文字列は環境変数から渡す(例: SQLAlchemy形式のPostgreSQL URL)
adapter = casbin_sqlalchemy_adapter.Adapter(os.environ["AUTHZ_DATABASE_URL"])
e = casbin.Enforcer("model.conf", adapter)

# AutoSave 対応アダプタでは、この1行がそのままDBの行追加になる
e.add_policy("role_staff", "/api/customers/:id", "GET")

AutoSaveに対応したアダプタでは、add_policy()のような個別の変更がその場でDBへ反映され、既定で有効です。一方のsave_policy()は保存先を消して全行を書き直すため、ルールが多い環境で呼ぶと遅くなります。公式表ではMongoEngineとPymongoのアダプタがAutoSave非対応です。

複数台構成でWatcherを入れないと権限の剥奪が他のサーバーに届かない問題

Enforcerは起動時にポリシーをメモリへ読み込みます。サーバーが2台以上あると、1台で権限を外しても、残りのサーバーのメモリには古いルールが残ったままです。

これを防ぐのがWatcherです。ポリシーを変えたEnforcerがRedisやEtcd、PostgreSQLなどを通じて他のインスタンスへ通知し、受け取った側がポリシーを読み直します。Python用にはRedis・Etcd・PostgreSQL・RabbitMQのWatcherがあります。ロードバランサーの後ろに2台以上置くなら、Watcherは最初から入れてください。

数百万ルール規模での性能劣化とテナント単位のポリシー部分読み込み

性能のドキュメントは、ルールが数百万件に達すると判定と読み込みの両方が遅くなり得ること、単一のEnforcerで毎秒1万件超のリクエストは目安を超えることを挙げています。

対策の優先順位は、まずユーザー個人ではなくロールに権限を付けてルール数を減らすことです。公式はテナントあたり100件未満を目安にしています。それでも多いときは、ポリシーの部分読み込みでテナント単位に必要な行だけを読み込みます。

Casbinを採用する条件とOPA・Cedarを選ぶべき場面の判断

認可を外に出す手段はCasbinだけではありません。比較の相手は、ポリシー言語Regoで書くOpen Policy Agent(OPA)と、AWSが開発したCedarです。

アプリケーション内で完結する認可にCasbinを採用してよい条件

次の条件に当てはまるなら、Casbinを選んで構いません。

  • 認可を判定するのが1つのアプリケーションか、同じ言語で書いた少数のサービスである
  • 権限の大半がRBACで表せ、属性条件は一部の操作に限られる
  • 判定をネットワーク越しにせず、プロセス内のライブラリ呼び出しで済ませたい
  • ポリシーを自社のデータベースに置き、管理画面から追加・削除したい

4つ目は、Casbinの管理APIがそのまま管理画面の裏側になる点で、ほかの選択肢より実装量が少なく済みます。権限の画面設計からAPIの認可まで一体で作る場合は、API開発・システム連携の範囲として相談いただけます。

OPAやCedarを選ぶべき場面とCasbinを入れなくてよい小規模な場合

Casbinを選ばないほうがよい場面もはっきりしています。Go・Java・Pythonなど複数言語のサービスが同じ認可ルールを共有する場合、言語版ごとの機能差が運用の負担になります。この場合に合うのは、PDPを別プロセスに立てられるOPAです。ポリシーの静的検証や、AWSのAmazon Verified Permissionsとの連携を重視するならCedarです。

逆に、ロールが「管理者」と「一般」の2つしかない社内ツールなら、Casbinは過剰です。フレームワーク標準の権限機能やデコレータで十分で、モデルファイルの学習と保守のほうが重くなります。目安は、ロールが5つを超えるか、テナントが分かれるかです。ロール設計そのものの考え方はRBACの仕組みと導入判断にまとめています。

よくある質問

Casbinを検討するときによく出る疑問に、公式ドキュメントの記述をもとに答えます。

Casbinはログイン機能も提供しますか?

提供しません。公式概要は、ユーザー名とパスワードの確認、ユーザーやロールの一覧管理、パスワードの保存をCasbinの対象外としています。ログインはOAuth 2.0やOpenID Connect、あるいはフレームワークの認証機能で行い、確定した利用者IDをenforce()の第1引数に渡す構成にします。Casbinが保存するのは、ユーザーとロールの対応、ロールと権限の対応だけです。

pip install casbinとpip install pycasbinはどちらが正しいですか?

2026年10月時点で更新が続いているのはpycasbinです。PyPIの旧名casbinは1.43.0(2025年5月10日)で止まり、pycasbinは2.8.0(2026年2月2日)まで進んでいます。どちらもimport casbinで読み込むため、両方が入ると古いほうを読む恐れがあります。アダプタが旧名に依存している場合もあるので、導入後にpip listで確認してください。

Casbinのポリシーはどのデータベースに保存できますか?

アダプタを差し替えて、MySQL・PostgreSQL・SQLite・MongoDB・Redisなどに保存できます。Pythonで使えるものとして公式の一覧に載っているのは、SQLAlchemy・Django ORM・Peewee・Tortoise ORM・SQLModel用のアダプタです。既存のORMに合わせて選ぶのが手堅く、管理画面から権限を編集するならAutoSave対応のアダプタを選ぶと、変更がその場でDBに反映されます。

CasbinとOPAはどちらを選べばよいですか?

判定をプロセス内で済ませ、ポリシーを自社DBで管理したいならCasbinが向きます。複数言語のサービスやKubernetesの受け入れ制御など、組織全体で同じポリシーを共有したいならOPAが候補です。OPAはRegoという専用言語を覚える必要があり、判定のたびに別プロセスへ問い合わせる構成では応答遅延の設計も要ります。1つの業務システムの認可ならCasbinから始めるのが現実的です。

Casbinのモデルを試しに動かす方法はありますか?

公式サイトのオンラインエディタで、モデルとポリシーとリクエストを貼り付けて判定結果を確かめられます。手元で試すなら、この記事のmodel.confとpolicy.csvをそのまま保存し、pip install pycasbinのあとにPythonコードを実行する手順です。本番のポリシーを変える前には、想定するリクエストと期待値の組を単体テストに書いておくと、ルール変更の影響を機械的に確かめられます。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.27 テックブログ Brotli 脆弱性:CVE-2026-111497の影響確認とNode.js・Python・.NETの更新手順
  2. 2026.10.28 テックブログ リンツ不正アクセス:314万件の対象確認とパスワード強制リセット後の対処
  3. 2026.10.27 テックブログ Joshin(ジョーシン)不正アクセス:最大600万件の対象とサブスク初期パスワードの対処
  4. 2026.10.23 テックブログ Renta!はいつ再開?不正アクセスでメールアドレス等が流出したおそれ・再開時のパスワード再設定と運営側の対応
  5. 2026.10.28 テックブログ 楽天トラベル不正アクセス:最大約260万件の対象確認とカード下4桁の詐欺対策

RELATED POSTS 関連記事

目次