1
0
forked from baron/baron-sso

docs: add standalone tenant policy and update keto rebac policy

This commit is contained in:
Lectom C Han
2026-02-20 10:00:55 +09:00
parent 8ed3bd8c77
commit 3e05c4e5f6
2 changed files with 57 additions and 134 deletions

View File

@@ -1,143 +1,34 @@
# Ory Keto ReBAC 정책 및 관계 튜플 가이드
문서는 Baron SSO의 통합 권한 정책을 Ory Keto(Zanzibar 스타일 권한 엔진)에서 구현하기 위한 네임스페이스 설계와 관계 튜플(Relationship Tuples) 예제를 정의합니다.
문서는 Baron SSO의 다형성 테넌트 구조를 지원하기 위해, Google Zanzibar 모델을 차용한 Ory Keto의 네임스페이스 관계 튜플(Relation Tuples) 설계 가이드를 정의합니다.
## 0. 권한 흐름 다이어그램 (Permission Flow)
## 1. 중앙집중형 인가 백본 (Authorization Backbone)
복잡한 다단계 B2B2B 조직도 내에서의 상속 권한은 외부 백엔드의 RDBMS 논리만으로 실시간 검증하기에 과부하가 심합니다.
따라서 조직도나 권한이 변경될 때마다 이를 Keto의 관계 튜플로 실시간 변환/전송하고, 권한 검증(Check)은 초고속 병렬 처리가 가능한 Keto 엔진으로 오프로딩(Offloading)합니다.
```mermaid
graph LR
%% Subjects
U[User: 사용자]
%% Intermediate Groups
subgraph Groups [유저 그룹 / 테넌트 관리 주체]
UG_O[UserGroup: Owners / 그룹장]
UG_M[UserGroup: Members / 멤버]
end
## 2. 네임스페이스 (Namespaces)
과거 혼용되던 `UserGroup` 네임스페이스는 폐기되며, 철저한 권한 통제를 위해 아래 3개의 네임스페이스만 존재합니다.
%% Resources
subgraph Resources [테넌트 및 하위 자원]
T[Tenant: 부모 테넌트]
CT[Tenant: 자식 테넌트]
RP[RelyingParty: 앱/클라이언트]
end
1. **`Tenant`**: 모든 격리 공간 (회사, 지주사, 사내 부서, 개인 워크스페이스)
2. **`RelyingParty`**: 테넌트가 소유하는 자원/앱 (OIDC 클라이언트)
3. **`System`**: 테넌트에 종속되지 않는 전역 권한 (Super Admin 등)
%% Relations (Solid = Direct, Dash = Inherited)
U -- "owner of" --> UG_O
U -- "member of" --> UG_M
UG_O -- "becomes Admin of" --> T
UG_M -- "gets View/Manage of" --> T
T -- "controls" --> CT
T -- "owns" --> RP
%% Effective Permissions (Dash)
U -. "inherits Admin" .-> T
U -. "inherits Access" .-> CT
U -. "can manage" .-> RP
## 3. 관계 튜플 규칙 (Relationship Tuples)
%% Styles
style UG_O fill:#ff9,stroke:#333
style T fill:#dfd,stroke:#333
style RP fill:#bbf,stroke:#333
```
### 3.1 테넌트 계층 및 리더십
- **조직장 임명**: `Tenant:<조직ID>#owners@User:<유저ID>`
- **어드민 자동 상속**: `Tenant:<조직ID>#admins@Tenant:<조직ID>#owners`
- **테넌트 계층(부모-자식)**: `Tenant:<하위ID>#parents@Tenant:<상위ID>`
*(상위 테넌트의 `admins`는 하위 테넌트의 모든 권한을 상속받습니다.)*
## 1. 네임스페이스 정의 (Namespaces)
### 3.2 Relying Party (앱 자원) 제어 및 RP Admin
RP에 별도의 가상 테넌트를 만들지 않고, 자원 객체 자체의 다중 상속을 사용합니다.
- **앱 소유권 지정**: `RelyingParty:<앱ID>#parents@Tenant:<소유테넌트ID>` (소유 테넌트의 최고 관리자가 앱 관리 가능)
- **전담 관리자(RP Admin) 직접 할당**: `RelyingParty:<앱ID>#admins@User:<유저ID>`
- **Private 앱 접근 허용**: `RelyingParty:<앱ID>#access@Tenant:<소유테넌트ID>#members`
- **Public 앱 접근 허용**: `RelyingParty:<앱ID>#access@System:authenticated_users#members`
| 네임스페이스 | 역할 | 비고 |
| :--- | :--- | :--- |
| `Tenant` | 격리된 자원 공간 (Workspace) | 모든 유저 그룹은 테넌트의 한 종류임 |
| `UserGroup` | 사용자의 집합 (Specialized Tenant) | `Tenant` 네임스페이스를 상속하거나 호환됨 |
| `RelyingParty` | OAuth2 클라이언트 앱 | 특정 테넌트에 소속됨 |
| `System` | 시스템 전역 권한 | Super Admin 등을 관리 |
## 2. 핵심 정책의 Keto 구현
### 2.1 "모든 유저 그룹은 테넌트이다"
유저 그룹이 생성될 때, 해당 ID는 `Tenant` 네임스페이스에도 동시에 존재하며 동일한 상속 로직을 공유합니다.
### 2.2 "그룹장은 해당 테넌트의 어드민이다"
그룹장(Leader/Owner) 관계가 형성되면, Keto의 **Subject Set** 기능을 통해 테넌트의 `admins` 권한으로 자동 전파됩니다.
---
## 3. Keto 관계 튜플 예제 (Relationship Tuples)
Keto에 저장되는 데이터 포맷 예시입니다: `namespace:object#relation@subject`
### 3.1 사용자-그룹 관계 (Identity to Group)
| 설명 | Keto 튜플 예제 |
| :--- | :--- |
| **그룹 멤버 추가** | `UserGroup:dev-team#members@User:uuid-123` |
| **그룹장 임명 (Leader)** | `UserGroup:dev-team#owners@User:uuid-leader` |
### 3.2 그룹-테넌트 권한 전파 (Group to Resource)
| 설명 | Keto 튜플 예제 |
| :--- | :--- |
| **그룹장 -> 어드민 자동 상속** | `Tenant:dev-team#admins@UserGroup:dev-team#owners` |
| **그룹 -> 하위 테넌트 관리 권한** | `Tenant:project-alpha#manage@UserGroup:dev-team#members` |
| **그룹 -> 하위 테넌트 조회 권한** | `Tenant:project-beta#view@UserGroup:dev-team#members` |
### 3.3 테넌트-자원 소속 관계 (Hierarchy)
| 설명 | Keto 튜플 예제 |
| :--- | :--- |
| **자식 테넌트 설정** | `Tenant:child-dept#parents@Tenant:parent-corp` |
| **앱(RP) 소속 테넌트 지정** | `RelyingParty:auth-app#parents@Tenant:hanmac-family` |
---
## 4. 권한 검증 로직 (Permission Check Logic)
시스템이 권한을 확인할 때(Check API) 사용하는 로직입니다.
### 4.1 그룹장의 테넌트 관리 권한 확인
사용자 `uuid-leader``dev-team` 테넌트를 관리할 수 있는지 확인:
```bash
# 요청 (Check)
GET /relation-tuples/check?namespace=Tenant&object=dev-team&relation=manage&subject_id=uuid-leader
# Keto 내부 추론 경로
1. Tenant:dev-team#manage 권한은 Tenant:dev-team#admins에게 있음.
2. Tenant:dev-team#admins는 UserGroup:dev-team#owners를 포함함.
3. UserGroup:dev-team#owners에 User:uuid-leader가 존재함.
=> 결과: ALLOW (True)
```
### 4.2 그룹 멤버의 하위 자원(RP) 접근 확인
사용자 `uuid-123``auth-app` 설정을 볼 수 있는지 확인:
```bash
# 요청 (Check)
GET /relation-tuples/check?namespace=RelyingParty&object=auth-app&relation=view&subject_id=uuid-123
# Keto 내부 추론 경로
1. RelyingParty:auth-app#view 권한은 부모인 Tenant:hanmac-family#view에 의존함.
2. Tenant:hanmac-family#view 권한은 UserGroup:dev-team#members에게 부여됨.
3. UserGroup:dev-team#members에 User:uuid-123이 존재함.
=> 결과: ALLOW (True)
```
## 5. 정책 요약 코드 (Namespace Config - DSL Style)
이 정책을 지원하기 위한 Keto 네임스페이스 설정 스키마 개념도입니다.
```typescript
class Tenant implements Namespace {
related: {
admins: (User | UserGroup#owners)[]
members: (User | UserGroup#members)[]
parents: Tenant[]
}
permits: {
view: (ctx: Context): boolean =>
this.related.members.includes(ctx.subject) ||
this.related.admins.includes(ctx.subject) ||
this.related.parents.traverse((p) => p.permits.view(ctx)),
manage: (ctx: Context): boolean =>
this.related.admins.includes(ctx.subject) ||
this.related.parents.traverse((p) => p.permits.manage(ctx))
}
}
```
## 4. 트랜잭셔널 아웃박스를 통한 정합성 확보
Keto와의 데이터 일관성 문제는 시스템의 치명적인 아킬레스건입니다.
백엔드 DB에서 테넌트나 멤버십을 변경할 때, Keto API 직접 호출에 따른 부분 실패(Partial Failure)를 방지하기 위해 **트랜잭셔널 아웃박스(Transactional Outbox) 패턴**을 반드시 사용해야 합니다.
DB 커밋과 함께 아웃박스 테이블에 튜플 이벤트를 기록하고, 비동기 릴레이 워커가 Keto로 동기화를 보장합니다. Soft delete 발생 시 즉각적으로 Keto의 튜플을 Hard delete 하여 권한을 회수합니다.