Security/보안

01. Casbin으로 접근제어하기

daeunnniii 2025. 9. 19. 23:03
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)를 할당. 높은 우선순위 정책이 먼저 고려됨 정책 충돌 가능성이 있고, 특정 규칙이 다른 규칙보다 더 중요한 경우

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