forked from baron/baron-sso
88 lines
6.7 KiB
Markdown
88 lines
6.7 KiB
Markdown
# 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 하여 권한을 회수합니다.
|