# Ory Keto ReBAC 정책 및 관계 튜플 가이드

본 문서는 Baron SSO의 다형성 테넌트 구조를 지원하기 위해, Google Zanzibar 모델을 차용한 Ory Keto의 네임스페이스 및 관계 튜플(Relation Tuples) 설계 가이드를 정의합니다.

## 1. 중앙집중형 인가 백본 (Authorization Backbone)
복잡한 다단계 B2B2B 조직도 내에서의 상속 권한은 외부 백엔드의 RDBMS 논리만으로 실시간 검증하기에 과부하가 심합니다. 
따라서 조직도나 권한이 변경될 때마다 이를 Keto의 관계 튜플로 실시간 변환/전송하고, 권한 검증(Check)은 초고속 병렬 처리가 가능한 Keto 엔진으로 오프로딩(Offloading)합니다.

## 2. 네임스페이스 (Namespaces)
과거 혼용되던 `UserGroup` 네임스페이스는 폐기되며, 현재 Baron SSO는 아래 4개의 네임스페이스를 기준으로 ReBAC를 구성합니다.

1. **`User`**: 권한의 subject가 되는 사용자
2. **`Tenant`**: 모든 격리 공간 (회사, 지주사, 사내 부서, 개인 워크스페이스, 유저 그룹)
3. **`RelyingParty`**: 테넌트가 소유하는 자원/앱 (OIDC 클라이언트)
4. **`System`**: 테넌트에 종속되지 않는 전역 권한 (Super Admin 등)

## 3. 관계 튜플 규칙 (Relationship Tuples)

### 3.1 테넌트 계층 및 리더십
- **조직장 임명**: `Tenant:<조직ID>#owners@User:<유저ID>`
- **어드민 자동 상속**: `Tenant:<조직ID>#admins@Tenant:<조직ID>#owners`
- **테넌트 계층(부모-자식)**: `Tenant:<하위ID>#parents@Tenant:<상위ID>`
*(상위 테넌트의 `admins`는 하위 테넌트의 모든 권한을 상속받습니다.)*
- **DevFront 조회 범위 부여**: `Tenant:<조직ID>#developer_console_viewer@User:<유저ID>`
- **DevFront 권한 부여 범위 부여**: `Tenant:<조직ID>#developer_console_grant_manager@User:<유저ID>`

### 3.1.1 Tenant permit 원칙
- `view`: 멤버/관리자/상위 tenant 상속 기준의 tenant 조회 권한
- `manage`: 관리자/오너/상위 tenant 상속 기준의 tenant 관리 권한
- `manage_admins`: 오너 및 상위 tenant 상속 기준의 관리자 관계 관리 권한
- `create_subtenant`: `manage`를 가진 주체가 하위 tenant를 생성하는 권한
- `view_dev_console`: DevFront 진입 및 tenant 범위 RP 목록/기본 정보 조회 권한
- `grant_dev_permissions`: tenant 범위 RP 운영 관계를 부여/회수할 수 있는 상위 권한

`view_dev_console`와 `grant_dev_permissions`는 `Tenant#manage`와 별개 축으로 분리합니다. 다만 1차 구현에서는 하위호환을 위해 `manage` 또는 `manage_admins`를 가진 주체가 각각 `view_dev_console`, `grant_dev_permissions`도 함께 가지는 모델로 둡니다.

### 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`
- **RP 생성 권한 부여**: `RelyingParty:<앱ID>#creator@User:<유저ID>`
- **RP 설정 수정 권한 부여**: `RelyingParty:<앱ID>#config_editor@User:<유저ID>`
- **Client Secret rotate 권한 부여**: `RelyingParty:<앱ID>#secret_rotator@User:<유저ID>`
- **JWKS 조회 권한 부여**: `RelyingParty:<앱ID>#jwks_viewer@User:<유저ID>`
- **JWKS 운영 권한 부여**: `RelyingParty:<앱ID>#jwks_operator@User:<유저ID>`
- **Consent 조회 권한 부여**: `RelyingParty:<앱ID>#consent_viewer@User:<유저ID>`
- **Consent 회수 권한 부여**: `RelyingParty:<앱ID>#consent_revoker@User:<유저ID>`
- **Relationship 조회 권한 부여**: `RelyingParty:<앱ID>#relationship_viewer@User:<유저ID>`
- **감사 로그 조회 권한 부여**: `RelyingParty:<앱ID>#audit_viewer@User:<유저ID>`
- **상태 변경 권한 부여**: `RelyingParty:<앱ID>#status_operator@User:<유저ID>`

### 3.2.1 RelyingParty permit 원칙
- `view`: RP 상세 및 기본 메타데이터 조회 권한
- `manage`: 기존 호환용 상위 관리 권한
- `create`: RP 생성 권한
- `edit_config`: RP 일반 설정 수정 권한
- `rotate_secret`: client secret 재발급/rotate 권한
- `view_jwks`: JWKS 상태/캐시/key summary 조회 권한
- `operate_jwks`: JWKS refresh/revoke 수행 권한
- `view_consents`: consent 목록/상세 조회 권한
- `revoke_consents`: consent 회수 권한
- `view_relationships`: direct / inherited relationship 조회 권한
- `view_audit_logs`: 해당 RP의 DevFront 감사 로그 조회 권한
- `change_status`: 활성/비활성 상태 변경 권한
- `access`: 실제 서비스 로그인 및 리소스 접근 권한

1차 구현 원칙은 다음과 같습니다.
- `RelyingParty#manage`는 제거하지 않고 유지합니다.
- `manage`는 신규 세부 permit의 상위 호환 permit으로 동작합니다.
- `access`는 서비스 접근 권한이며 DevFront 운영 권한과 동일시하지 않습니다.
- `Tenant#view_dev_console`는 RP 목록/기본 정보 조회 범위를 주지만, `edit_config`, `operate_jwks`, `revoke_consents` 같은 개별 운영 액션 permit을 자동 부여하지 않습니다.
- RP 개별 운영 액션은 `RelyingParty` 세부 permit으로 직접 판정합니다.

### 3.3 유저 그룹 subject set 규칙
현재 구현에서 유저 그룹은 별도 `UserGroup` namespace를 사용하지 않고, `Tenant` namespace 내부의 유저 그룹 tenant와 subject set으로 표현합니다.

- **유저 그룹 멤버십**: `Tenant:<GroupTenantID>#members@User:<UserID>`
- **유저 그룹 전체에 tenant role 부여**: `Tenant:<TenantID>#<Relation>@Tenant:<GroupTenantID>#members`

즉, 문서에서 말하는 “유저 그룹 멤버 전체”는 실제 Keto tuple에서 `Tenant:<groupId>#members` subject set으로 표현됩니다.

## 4. 트랜잭셔널 아웃박스를 통한 정합성 확보
Keto와의 데이터 일관성 문제는 시스템의 치명적인 아킬레스건입니다. 
백엔드 DB에서 테넌트나 멤버십을 변경할 때, Keto API 직접 호출에 따른 부분 실패(Partial Failure)를 방지하기 위해 **트랜잭셔널 아웃박스(Transactional Outbox) 패턴**을 반드시 사용해야 합니다.
DB 커밋과 함께 아웃박스 테이블에 튜플 이벤트를 기록하고, 비동기 릴레이 워커가 Keto로 동기화를 보장합니다. Soft delete 발생 시 즉각적으로 Keto의 튜플을 Hard delete 하여 권한을 회수합니다.
