728x90
반응형
1. 개요
1.1 Casbin이란
- Casbin은 오픈소스 접근 제어(Access Control) 라이브러리로, 애플리케이션에서 권한 관리(Authorization) 기능을 유연하게 구현할 수 있게 해주는 도구이다.
- "누가(subject) 어떤 리소스(object)에 대해 어떤 행위(action)를 할 수 있는가"를 정책(policy) 기반으로 제어한다.
- 다양한 액세스 제어 모델(RBAC, ABAC, ACL 등)을 지원한다.
- Go 언어로 개발되었지만, Python, Java, Node.js 등 다양한 언어 SDK를 제공한다.

1.2 Casbin 장점
- 모델(model) 파일 + 정책(policy) 파일을 통해 접근 제어 로직을 설정하여, 코드 수정 없이 구성이 가능하다.
- 다양한 접근 제어 모델을 지원(RBAC, ABAC, 도메인 기반 RBAC, 패턴 매칭, 우선순위 등)하여 복잡한 권한 구조에도 대응 가능하다.
- 여러 언어, 여러 저장소(adapter), 분산 환경(watcher) 등 인프라 다양성이 고려된다.
1.3 Casbin이 지원하지 않는 것
- Casbin은 권한 부여(Authorization)만 담당하며, 인증(Authentication)은 제공하지 않는다.
- 사용자 생성, 비밀번호 변경, 사용 목록 관리와 같은 인증(Authentication)은 애플리케이션 레이어에서 처리하는 것이 일반적이다.
- Casbin은 user-role 매핑만 취급한다.
2. 접근제어 모델(Access Control Models)
Casbin이 지원하는 주요 모델
| ACL (Access Control List) | 가장 단순한 형태로, sub(주체), obj(대상), act(행위) 기준으로 정책을 지정한다. | 권한 구조가 간단하거나 역할이나 속성(attribute)이 많지 않은 경우 |
| RBAC (Role-Based Access Control) | 사용자에게 역할(role)을 할당하고, 역할에 정책(policy)을 매핑 → 역할을 통해 권한 부여. 역할 계층(role hierarchy) 가능. 도메인(domain) 기반 RBAC도 지원됨 | 사용자가 많고 권한을 역할 중심으로 관리하는 경우 (ex. 조직 단위, 팀, 관리자-사용자 구분 등) |
| ABAC (Attribute-Based Access Control) | 주체(subject) 또는 객체(object)의 속성(attributes)을 기준으로 접근 제어. 속성 값들(예: 부서, 소유자, 시간, 위치 등)에 따라 세밀한 정책 가능 | 권한이 역할만으로 해결 안 되고 동적인 조건(시간, 소유자, 상태 등)이 중요한 경우 |
| 우선순위 기반 모델 (Priority Model) | 여러 정책이 겹칠 때 정책들에 우선순위(priority)를 할당. 높은 우선순위 정책이 먼저 고려됨 | 정책 충돌 가능성이 있고, 특정 규칙이 다른 규칙보다 더 중요한 경우 |
- 전체 지원 모델: https://casbin.org/docs/supported-models
3. Casbin 아키텍처
3.1 PERM 메타모델
- Casbin의 접근 제어 모델은 PERM 메타 모델 (Policy, Effect, Request, Matchers) 형식으로 추상화되어 .conf 파일에 저장된다.
- PERM은 Policy, Effect, Request, Matchers 네가지 기반 요소로
- 단순히 이 설정 파일을 수정하는 것만으로 인가(Authorization) 매커니즘을 바꾸거나 업그레이드할 수 있다.
- 다양한 모델을 조합하여 자신만의 접근제어 모델을 구성할 수 있다.
- ex) RBAC(역할 기반)과 ABAC(속성 기반)을 하나의 모델에 결합하고, 동일한 정책 규칙 세트를 공유
3.1.1 Request (요청 정의)
- 접근 요청의 파라미터를 정의한다.
- 누가(subject) 어떤 객체(object)에 대해 어떤 행동(action)을 요청하는지를 정의한다.
- 기본 요청은 튜플(tuple) 형태로 주체(sub), 객체(obj), 행위(act) 세 요소를 포함해야한다.
- sub (subject): 요청을 하는 주체 (사용자, 서비스, 장치 등)
- obj (object): 접근하려는 대상 (파일, API, 리소스 등)
- act (action): 주체가 하려는 행위 (읽기, 쓰기, 삭제, 실행 등)
- 예시
r = sub, obj, act
- 요청 정의는 접근 제어 매칭 함수에 필요한 파라미터 이름과 순서를 지정한다.
3.1.2 Policy (정책 정의)
- 접근 전략을 정의하는 규칙 문서의 필드 이름과 순서를 지정한다.
- 정책은 보통 p = sub, obj, act 또는 p = sub, obj, act, eft 형식으로 표현되며, 특정 요청이 허용되는 규칙을 담는다.
- 예시
p, alice, data1, read
p, bob, data2, write
→ Alice는 data1을 읽을 수 있고, Bob은 data2를 쓸 수 있다.
- eft(effect)는 allow 또는 deny를 나타내며, eft 필드가 없으면 정책 결과는 기본적으로 allow로 간주된다.
3.1.3 Matcher (매칭 규칙)
- 요청(Request)와 정책(Policy)을 어떻게 비교할지 정의한다.
- 예시
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
- 위 Matcher는 요청의 주체, 객체, 행위가 정책과 모두 같으면 해당 정책이 매칭된다.
- 패턴 매칭(startwith, regex), in 연산자 등도 사용 가능하다.
3.1.4 Effect (효과)
- 매칭된 여러 정책 결과를 종합하여 최종 결정을 내리는 단계이다.
- 예시1
e = some(where (p.eft == allow))
→ 하나라도 allow가 있으면 최종 결과를 true
- 예시2
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
→ allow 정책이 하나 이상 있고 deny가 없을 때만 허용. 즉, deny가 하나라도 있으면 우선 거부
즉, deny가 하나라도 있으면 거부가 우선된다.
3.2 Enforcer
- Enforcer는 PERM 모델과 정책(Policy)을 실제로 실행해서 요청(Request)이 들어왔을 때 "허용/거부"를 내리는 엔진이다.
- Enforcer API 예시
import casbin
# 1. Enforcer 초기화 (모델 + 정책 로드)
e = casbin.Enforcer("model.conf", "policy.csv")
# 2. 요청 검증
sub = "alice" # 사용자
obj = "data1" # 리소스
act = "read" # 행위
if e.enforce(sub, obj, act):
print("허용: 접근 가능합니다.")
else:
print("거부: 접근이 불가합니다.")
Enforcer가 제공하는 주요 기능
- enforce(): 요청이 허용되는지 여부 확인
- add_policy(), remove_policy(): 정책 동적 추가/삭제
- add_role_for_user(), get_roles_for_user(): RBAC 지원 (사용자-역할 관계 관리)
- load_policy(), save_policy(): 정책 파일/DB 재로딩 및 저장
4. Casbin 추가 기능
4.1 Adapter
- 정책(policy)을 파일, 메모리, 데이터베이스(MySQL, PostgreSQL, MongoDB 등), Redis, 기타 저장소 등에 저장하고 불러오는 역할
- 필터링 된 정책 관리(Policy Subset Loading) 기능 → 전체 정책이 많아도 필요한 정책만 로드 가능
4.2 Watcher
- 여러 노드(서버)가 존재하는 분산 환경에서 정책이 변경되면 다른 노드들에게 알려주어 정책 일관성 유지
4.3 Management API
- 런타임에서 정책을 추가, 제거, 갱신, 존재 여부 조회 등 할 수 있는 API들
4.4 RBAC API / Role Manager
- 역할(role) 간 계층 구조를 정의하거나, 역할 간 상속 등을 관리할 수 있는 기능
- 외부 소스(LDAP, SSO)와 연계될 수 있음
4.5 정책 캐싱 & 최적화
- 정책 로드/Matcher 평가 비용이 커질 수 있기 때문에, 여러 언어에서 캐싱(caching), 배치(batch enforcement), 필터링(filtered policy), 역할 매핑(role manager) 등을 통한 성능 최적화 기능 존재
5. Casbin 사용 예시
casbin 설치
~$ pip install casbin
# DB에 정책 저장 시
~$ pip install casbin-sqlalchemy-adapter sqlalchemy
5.1 ACL 사용 예시
Model 파일(model.conf)
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act, eft
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
[matchers]
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
정책 파일 (policy.csv)
p, alice, data1, read, allow
p, bob, data2, write, allow
p, alice, data2, write, deny
casbin 사용 예시
import casbin
e = casbin.Enforcer("model.conf", "policy.csv")
print(e.enforce("alice", "data1", "read")) # True (일치 + allow)
print(e.enforce("alice", "data2", "write")) # False (deny 우선)
print(e.enforce("bob", "data2", "write")) # True
5.2 RBAC (역할 기반)
Model 파일(model_rbac.conf)
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act, eft
[role_definition]
g = _, _ ; 사용자-역할 관계를 저장하는 그룹핑
[policy_effect]
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act
# p.sub를 '역할명'으로 쓰고, g(r.sub, p.sub)로 "사용자가 그 역할을 갖는지" 확인
정책 파일 (policy_rbac.csv)
- 사용자에게 직접 권한을 부여하지 않고, "역할"에 권한을 부여
- 사용자는 역할만 부여
p, admin, *, read, allow
p, editor, data*, write, allow
p, viewer, data*, read, allow
g, alice, admin
g, bob, editor
g, chris, viewer
casbin 사용 예시
import casbin
e = casbin.Enforcer("model_rbac.conf", "policy_rbac.csv")
print(e.enforce("alice", "data42", "read")) # True (admin 역할)
print(e.enforce("bob", "data9", "write")) # True (editor 역할)
print(e.enforce("chris", "data1", "write")) # False (viewer는 read만)
5.3 ABAC (속성 기반)
Model 파일(model_abac.conf)
[request_definition]
r = sub, obj, act
[policy_definition]
# ABAC는 정책을 최소화하거나 없이 동작하는 경우가 많음(속성으로 제어)
[policy_effect]
e = some(where (allow == true)) || some(where (p.eft == allow))
# Matcher에서 조건이 true면 허용, 필요 시 정책과 혼합도 가능
[matchers]
# 소유자면 어떤 행위든 허용
# 아니면 같은 부서면 읽기만 허용
# 삭제는 관리자만 허용
m = (r.sub.name == r.obj.owner) \
|| (r.sub.dept == r.obj.dept && r.act == "read") \
|| (r.sub.role == "admin" && r.act == "delete")
casbin 사용 예시
import casbin
from types import SimpleNamespace
e = casbin.Enforcer("model_abac.conf") # 정책 파일 없이도 OK
sub = SimpleNamespace(name="alice", dept="sales", role="user")
obj = SimpleNamespace(owner="alice", dept="sales")
print(e.enforce(sub, obj, "read")) # True (소유자 or 동일부서)
print(e.enforce(sub, obj, "delete")) # False (admin만)
6. 런타임 정책 관리(Management API)
- 정책 추가, 삭제 및 DB 반영
import casbin
e = casbin.Enforcer("model.conf", "policy.csv")
# 정책 추가/삭제
e.add_policy("dave", "data3", "read", "allow")
e.add_role_for_user("erin", "editor")
e.remove_policy("alice", "data2", "write", "deny")
# 즉시 반영 저장(파일/DB 어댑터 사용 시)
e.save_policy()
# 조회
print(e.get_roles_for_user("erin")) # ['editor']
print(e.enforce("dave", "data3", "read")) # True
7. FastAPI 미들웨어 연동
from fastapi import FastAPI, Request, HTTPException
import casbin
app = FastAPI()
e = casbin.Enforcer("model.conf", "policy.csv")
@app.middleware("http")
async def casbin_authz(request: Request, call_next):
sub = request.headers.get("X-User", "anonymous")
obj = request.url.path
act = request.method.lower()
if not e.enforce(sub, obj, act):
raise HTTPException(status_code=403, detail="Forbidden")
return await call_next(request)
@app.get("/data1")
def read_data1():
return {"ok": True}
728x90
반응형
'Security > 보안' 카테고리의 다른 글
| 02. Casbin PostgreSQL 연동하기 (0) | 2025.09.19 |
|---|