본문으로 건너뛰기

ABAC란 무엇인가? 예제를 통한 속성 기반 접근 제어

ABAC란 무엇인가?​

**Attribute-based access control (ABAC)**은 사용자가 누구인지 또는 어떤 역할을 보유하고 있는지 조회하는 대신, **속성(attributes)**을 규칙과 평가하여 요청을 허용하거나 거부합니다. 참조 정의를 SP 800-162에 발표한 NIST는 입력을 네 가지 종류로 분류합니다:

속성예시
주체 (사용자 또는 서비스)부서, 보안 등급, 고용 유형, 나이
객체 (리소스)소유자, 부서, 분류, 상태
작업읽기, 편집, 승인, 삭제
환경시간대, IP 주소 또는 네트워크, 디바이스, 위치

규칙은 이러한 속성에 대한 조건입니다. 예를 들어 "사용자가 문서와 같은 부서에 속하고 업무 시간 중이라면 문서를 읽을 수 있다"는 규칙이 있습니다. 규칙이 명명된 사용자나 역할 대신 속성을 참조하므로, 새로운 사용자나 새로운 문서가 추가될 때 규칙을 추가하지 않아도 자동으로 적용됩니다.

Casbin은 ABAC을 간단하게 유지합니다: Enforce()에 구조체나 객체를 전달하고 matcher에서 해당 필드를 참조합니다. 전체적인 응용 프로그램 예제는 Go, Node.js with Express, Python with Flask의 ABAC 튜토리얼에서 확인할 수 있습니다.

ABAC vs RBAC​

RBAC는 사용자의 역할을 기반으로 판단합니다: "편집자는 문서를 편집할 수 있다". ABAC은 속성을 기반으로 판단합니다: "소유자는 문서를 편집할 수 있다". 역할은 어떤 권한을 허용하는지와 누가 그 역할을 보유하고 있는지 목록으로 나열할 수 있으므로 감사(audit)가 쉽습니다. 반면 속성은 소유권, 부서, 시간 등 특정 레코드와 컨텍스트에 대한 규칙을 표현할 수 있으며, 이는 역할만으로는 각 레코드마다 하나의 역할을 생성하지 않고는 표현할 수 없습니다. 대부분의 응용 프로그램에서는 두 방식을 결합하여 사용합니다: 역할은 사용자가 접근할 수 있는 기능을 결정하고, 속성 조건은 사용자가 접근할 수 있는 레코드로 범위를 좁힙니다. 접근 제어 모델 선택하기에서는 하나의 예시를 통해 ACL, RBAC, ABAC 및 ReBAC을 비교하고, 단일 Casbin 모델에서 RBAC과 ABAC을 조합하는 방법을 보여줍니다.

장점과 단점​

  • 강점: 소유권("오직 본인 소유의 것만"), 컨텍스트(업무 시간, 사무실 네트워크), 자체 라벨이 포함된 데이터(부서, 지역, 민감도). 하나의 규칙으로 여러 역할 부여를 대체할 수 있습니다.
  • 약점: 감사(audit). "누가 이 문서를 읽을 수 있나요?"라는 질문에 직접적인 답이 없으며, 모든 사용자에 대해 규칙을 평가해야 합니다. 또한 규칙에는 속성이 필요하므로, 일반적으로 애플리케이션은 체크 전에 레코드를 로드해야 합니다.

최소 예제:

[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

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

[matchers]
m = r.sub == r.obj.Owner

따라서 r.obj는 Owner 필드가 있는 객체여야 하며, Casbin은 리플렉션을 통해 이를 읽습니다. Go에서는 다음과 같이 정의할 수 있습니다:

type testResource struct {
Name string
Owner string
}

JSON 문자열도 전달할 수 있습니다. JSON 처리를 활성화하면 Casbin이 이를 파싱합니다:

e, _ := NewEnforcer("examples/abac_model.conf")
e.EnableAcceptJsonRequest(true)

data1Json := `{ "Name": "data1", "Owner": "bob"}`

ok, err := e.Enforce("alice", data1Json, "read")
if err != nil {
// Handle JSON parsing errors
fmt.Printf("Enforcement failed: %v\n", err)
return
}

활성화되면 { 또는 [로 시작하는 모든 매개변수는 JSON으로 파싱됩니다. 잘못된 JSON은 명확한 오류를 발생시키며, 다른 문자열은 그대로 유지됩니다.

// Valid JSON - automatically parsed
validJSON := `{"Name": "alice", "Age": 25}`
ok, err := e.Enforce(validJSON, "data1", "read") // Works correctly

// Invalid JSON - returns descriptive error
invalidJSON := `{"Name": "alice",}` // Trailing comma is invalid in JSON
ok, err := e.Enforce(invalidJSON, "data1", "read")
// Returns: "failed to parse JSON parameter at index 0: ..."

// Plain string - no parsing attempted
plainString := "alice"
ok, err := e.Enforce(plainString, "data1", "read") // Treated as plain string
노트

JSON 매개변수 지원 활성화 시 약 1.1배에서 1.5배 사이의 성능 오버헤드가 발생합니다.

환경 속성​

요청은 sub, obj, act 외에도 더 많은 정보를 포함할 수 있습니다. 환경을 위한 필드를 추가하고 다른 객체처럼 Enforce()에 전달합니다. 다음 모델은 소유자가 언제든 자신의 문서를 편집할 수 있도록 하고, 같은 부서의 사람들이 9:00부터 18:00 사이에 문서를 읽을 수 있도록 합니다:

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

[policy_definition]
p = sub, obj, act

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

[matchers]
m = r.sub.Name == r.obj.Owner || (r.act == "read" && r.sub.Department == r.obj.Department && r.env.Hour >= 9 && r.env.Hour < 18)
type User struct{ Name, Department string }
type Doc struct{ Name, Owner, Department string }
type Env struct{ Hour int }

doc := Doc{Name: "design.md", Owner: "alice", Department: "design"}
bob := User{Name: "bob", Department: "design"}

ok, _ := e.Enforce(bob, doc, "read", Env{Hour: 10}) // true
ok, _ = e.Enforce(bob, doc, "read", Env{Hour: 22}) // false: outside business hours
ok, _ = e.Enforce(bob, doc, "edit", Env{Hour: 10}) // false: bob is not the owner

ABAC 사용법​

  1. matcher에서 속성을 참조합니다 (예: r.sub.Role, r.obj.Owner).
  2. 구조체나 클래스 인스턴스(또는 JSON)를 Enforce()에 전달합니다.
경고

ABAC 속성 접근은 요청 요소(r.sub, r.obj, r.act)에서만 작동합니다. 정책은 구조체나 클래스 정의를 저장할 수 없으므로 p.sub과 같은 정책 요소에서는 ABAC을 사용할 수 없습니다.

팁

Matcher는 동시에 여러 속성을 참조할 수 있습니다. 예: m = r.sub.Domain == r.obj.Domain.

팁

정책에서 CSV 파싱과 충돌할 수 있는 쉼표가 필요한 경우, 표현식을 큰따옴표로 감쌉니다. 예: "keyMatch("bob", r.sub.Role)"는 원치 않는 분리를 방지합니다.

eval()을 사용한 복잡한 규칙​

더 복잡한 조건의 경우, 표현식을 policy에 넣고 eval()로 평가하여 모델은 작게 유지하고 정책은 유연하게 관리할 수 있습니다.

eval()을 사용한 모델 구성:

[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) && r.obj == p.obj && r.act == p.act

p.sub_rule은 enforce 시점에 평가되는 요청 속성에 대한 표현식입니다. 정책 예시:

p, r.sub.Age > 18, /data1, read
p, r.sub.Age < 60, /data2, write

FAQ​

ABAC이 RBAC보다 나은가요? 일반적으로 어느 쪽이 더 낫다고 할 수 없습니다. ABAC은 더 세밀한 규칙을 표현할 수 있고, RBAC은 검토하기가 더 쉽습니다. 먼저 역할을 사용하고, 소유권이나 시간 창(window)처럼 역할만으로 충분하지 않은 부분에 속성 조건을 추가하세요.

ABAC과 PBAC의 차이점은 무엇인가요? ABAC은 판단 기준(속성)을 설명하고, PBAC은 규칙 관리 방식(런타임에 평가되는 정책 데이터)을 설명합니다. 위의 eval() 패턴은 둘 다에 해당합니다: 정책으로 저장된 속성 조건.

ABAC과 XACML이 같은 건가요? 아닙니다. XACML은 ABAC 정책을 작성하기 위한 OASIS 표준 언어입니다. Casbin은 XACML을 사용하지 않으며, 규칙은 모델의 matcher에 작성하거나 정책 행으로 저장합니다.

코딩 없이 ABAC을 시도해 볼 수 있나요? 네. 온라인 에디터에서 ABAC 예제를 선택하여 matcher와 요청을 수정해 보세요.

Comments are powered by giscus and GitHub Discussions. They load from giscus.app and GitHub only after you click the button below.