1
0
forked from baron/baron-sso
Files
baron-sso/docs/adminfront-tab-level-direct-permission-design.md
2026-06-15 20:05:47 +09:00

182 lines
8.4 KiB
Markdown

# [RFC/Design] adminfront: 각 탭별 ReBAC 기반 세부 권한 직접 부여 기능 설계
## 1. 배경 및 목적
현재 `adminfront` 테넌트 상세 페이지는 대략적인 역할 기반 제어(Coarse-grained RBAC/ReBAC) 형태로만 동작합니다.
운영자는 사용자를 **"소유자(Owner)"** 또는 **"테넌트 관리자(Admin)"**로만 임명할 수 있으며, 이 역할에 의해 테넌트 하위의 4개 탭(프로필, 권한 관리, 조직 관리, 사용자 스키마)의 읽기/쓰기 권한이 통째로 결정됩니다.
하지만 더욱 세밀한 운영 권한 관리가 필요하다는 비즈니스 요구사항에 따라, **"사용자 A에게는 조직 관리 및 스키마 읽기 권한만 부여"**, **"사용자 B에게는 스키마 수정 권한만 부여"**와 같이 탭 레벨에서 세분화된(Fine-grained) 권한을 직접 지정할 수 있는 기능을 신설합니다.
이 설계는 `devfront`에서 이슈 #1029를 통해 구현 완료한 **"RP 세부 관계 직접 부여"** 철학과 완벽히 동일하며, Ory Keto(ReBAC) 및 아웃박스 정합성 엔진을 관통하여 설계됩니다.
---
## 2. 세부 설계 사양
### 2.1 Ory Keto OPL 스키마 변경 (`docker/ory/keto/namespaces.ts`)
`Tenant` 네임스페이스 하위에 각 탭별 읽기(`_viewers`)와 쓰기(`_managers`)를 결정하는 **물리적인 직접 관계(Direct Relations)**를 추가합니다.
기존 `members`, `admins`, `owners`에 의한 상속 허가 식(Permits)을 유지하여 하위 호환성 및 기존 관리체계의 안정성을 완벽히 보장합니다.
```typescript
class Tenant implements Namespace {
related: {
owners: (User | SubjectSet<System, "super_admins">)[]
admins: (User | SubjectSet<System, "super_admins">)[]
members: (User | SubjectSet<System, "super_admins"> | SubjectSet<Tenant, "admins"> | SubjectSet<Tenant, "owners">)[]
parents: Tenant[]
developer_console_viewer: (User | SubjectSet<System, "super_admins">)[]
developer_console_grant_manager: (User | SubjectSet<System, "super_admins">)[]
// 🌟 신규 직접 관계 (Direct Relations) 정의
profile_viewers: (User | SubjectSet<System, "super_admins">)[]
profile_managers: (User | SubjectSet<System, "super_admins">)[]
permissions_viewers: (User | SubjectSet<System, "super_admins">)[]
permissions_managers: (User | SubjectSet<System, "super_admins">)[]
organization_viewers: (User | SubjectSet<System, "super_admins">)[]
organization_managers: (User | SubjectSet<System, "super_admins">)[]
schema_viewers: (User | SubjectSet<System, "super_admins">)[]
schema_managers: (User | SubjectSet<System, "super_admins">)[]
}
permits = {
// 1. 프로필 (Profile) 탭 허가 규칙
view_profile: (ctx: Context): boolean =>
this.related.profile_viewers.includes(ctx.subject) ||
this.permits.manage_profile(ctx) ||
this.permits.view(ctx), // 멤버/관리자/소유자는 기본 조회 가능
manage_profile: (ctx: Context): boolean =>
this.related.profile_managers.includes(ctx.subject) ||
this.permits.manage(ctx), // 관리자/소유자는 기본 수정 가능
// 2. 권한 관리 (Permissions) 탭 허가 규칙
view_permissions: (ctx: Context): boolean =>
this.related.permissions_viewers.includes(ctx.subject) ||
this.permits.manage_permissions(ctx) ||
this.permits.view(ctx),
manage_permissions: (ctx: Context): boolean =>
this.related.permissions_managers.includes(ctx.subject) ||
this.permits.manage_admins(ctx), // 소유자는 기본 관리 가능
// 3. 조직 관리 (Organization) 탭 허가 규칙
view_organization: (ctx: Context): boolean =>
this.related.organization_viewers.includes(ctx.subject) ||
this.permits.manage_organization(ctx) ||
this.permits.view(ctx),
manage_organization: (ctx: Context): boolean =>
this.related.organization_managers.includes(ctx.subject) ||
this.permits.manage(ctx),
// 4. 사용자 스키마 (Schema) 탭 허가 규칙
view_schema: (ctx: Context): boolean =>
this.related.schema_viewers.includes(ctx.subject) ||
this.permits.manage_schema(ctx) ||
this.permits.view(ctx),
manage_schema: (ctx: Context): boolean =>
this.related.schema_managers.includes(ctx.subject) ||
this.permits.manage(ctx),
// --- 기존 마스터 및 상속 규칙 보존 ---
view: (ctx: Context): boolean =>
this.related.members.includes(ctx.subject) ||
this.related.admins.includes(ctx.subject) ||
this.related.owners.includes(ctx.subject) ||
this.related.parents.traverse((p) => p.permits.view(ctx)),
manage: (ctx: Context): boolean =>
this.related.admins.includes(ctx.subject) ||
this.related.owners.includes(ctx.subject) ||
this.related.parents.traverse((p) => p.permits.manage(ctx)),
manage_admins: (ctx: Context): boolean =>
this.related.owners.includes(ctx.subject) ||
this.related.parents.traverse((p) => p.permits.manage_admins(ctx))
}
}
```
---
### 2.2 백엔드 API 설계 (`backend/internal/handler/tenant_handler.go`)
세부 권한 부여/회수 API는 해당 테넌트의 최상위 권한 관리자만 수행할 수 있도록 **`Tenant#manage_admins`** 허가 규칙으로 강력하게 인가 보호합니다.
#### A. 세부 권한 관계 전체 조회 API
* **Endpoint**: `GET /api/v1/admin/tenants/:id/relations`
* **인가 필터**: `RequireKetoPermission(config, "Tenant", "manage_admins")`
* **반환 DTO**:
```json
{
"items": [
{
"userId": "00000000-0000-0000-0000-000000000010",
"name": "홍길동",
"email": "kildong@hmac.kr",
"relations": ["profile_managers", "schema_viewers"]
}
]
}
```
#### B. 세부 권한 관계 부여 API
* **Endpoint**: `POST /api/v1/admin/tenants/:id/relations`
* **인가 필터**: `RequireKetoPermission(config, "Tenant", "manage_admins")`
* **Payload**:
```json
{
"userId": "00000000-0000-0000-0000-000000000010",
"relation": "profile_managers"
}
```
* **동작**: 트랜잭셔널 아웃박스에 적재하여 Keto에 `Tenant:<ID>#profile_managers@User:<UserID>` 튜플 반영.
#### C. 세부 권한 관계 회수 API
* **Endpoint**: `DELETE /api/v1/admin/tenants/:id/relations`
* **인가 필터**: `RequireKetoPermission(config, "Tenant", "manage_admins")`
* **Payload**:
```json
{
"userId": "00000000-0000-0000-0000-000000000010",
"relation": "profile_managers"
}
```
* **동작**: 트랜잭셔널 아웃박스에 적재하여 Keto 내 튜플 삭제 반영.
---
### 2.3 프론트엔드 UI 설계
사용자에게 역할(Role) 외에 세부적인 설정을 직관적으로 관리할 수 있도록, 기존 **"권한 관리"** 탭 하단에 **"세부 권한 설정 (Fine-grained Permissions)"** 섹션을 신설합니다.
#### A. 구성 요소
1. **유저 검색/추가 패널**: 테넌트 소속 사용자를 검색하여 격리 설정 테이블(Matrix)에 추가합니다.
2. **세부 권한 격리 매트릭스 (Matrix Table)**:
* 컬럼: `이름` | `이메일` | `테넌트 프로필` | `권한 관리` | `조직 관리` | `사용자 스키마` | `작업`
* 각 탭 컬럼은 드롭다운 셀렉트 박스로 채워집니다:
* **`권한 없음 (None)`** / **`조회 가능 (Read)`** / **`수정 가능 (Write)`**
3. **상태 동기화 연동**:
* 셀렉트 박스에서 `조회 가능(Read)` 선택 시: `_viewers` 관계 추가(`POST`) & `_managers` 관계 회수(`DELETE`).
* 셀렉트 박스에서 `수정 가능(Write)` 선택 시: `_managers` 관계 추가(`POST`) & `_viewers` 관계 회수(`DELETE`).
* 셀렉트 박스에서 `권한 없음(None)` 선택 시: 둘 다 회수(`DELETE`).
---
## 3. 작업 계획 및 테스트 전략
1. **OPL 컴파일 및 빌드 검증**:
* namespaces.ts 수정 후 Keto OPL 테스트를 구동하여 컴파일 문법에 문제가 없는지 사전 검증합니다.
2. **백엔드 구현 및 DB 연동**:
* `tenant_handler.go`에 신규 핸들러 추가 후 gg/gorm 아웃박스 통합을 완료합니다.
3. **프론트엔드 연동 및 Matrix UI 개발**:
* `TenantAdminsAndOwnersTab.tsx` 하단부 카드에 매트릭스 테이블 영역을 추가합니다.
4. **유형 및 단위 테스트**:
* 신설된 REST API 명세를 테스트하는 고성능 백엔드 단위 테스트를 작성합니다.
* 프론트엔드에서 체크박스 변경 시 올바른 릴레이션이 트리거되는지 검증하는 Vitest 렌더 테스트를 작성합니다.