접근권한 정본(Canonical) 모델
GenD의 접근권한은 2축 직교 모델입니다. 신규 데이터 기능을 추가할 때 이 문서의 규칙을 따르면 격리·권한이 자동으로 정합됩니다.
설계 근거 전문:
docs/superpowers/specs/2026-05-31-access-control-canonical-model-design.md
2축 원칙
- 격리 축(워크스페이스) — "어느 격리 컨테이너에 진입 가능한가". 가장 바깥에서 fail-closed로 평가.
- 권한 축(역할·그룹·grant) — "그 안에서 무엇을 할 수 있는가".
데이터 행/열 동적 필터(ABAC)는 가장 나중에 적용되는 별도 레이어입니다.
책임 매트릭스
| 레이어 | 정체 | 통제 대상 | 파생 | 평가 순서 |
|---|---|---|---|---|
| L0 Workspace | /tenants/<slug> | 테넌트 격리 — 모든 데이터 모델 workspace_id | active workspace (X-Workspace-Slug) | 1 (가장 바깥, fail-closed) |
| L1 부서 | /tenants/<slug>/<dept> | 워크스페이스 내 팀 칸막이 — resource_group_id | active workspace 하위 dept 그룹 | 2 |
| L2 Role | admin/analyst/viewer | 행위 권한(능력) | Keycloak realm role | 라우터 진입 게이트 |
| L3 ResourceGroup/DataGrant | 컨테이너 grant | catalog/schema/table 부여 + 상속 | DataGrant 테이블 | 3 |
| L4 ABAC | row_filter/column_mask | 데이터 행·열 동적 필터 | AccessPolicy | 4 (가장 나중) |
| clearance | /tenants/<slug>/clearance/<level> | AI/RAG 처리 가능 데이터 등급 | active workspace 하위 | LLM 엔드포인트 |
데이터 라우터에서 scope_query 사용법
모든 데이터 평면 라우터는 list/get/update/delete 쿼리에 scope_query 하나만 호출합니다. 개별 apply_* 헬퍼를 직접 부르지 마세요.
from gend_api.services.access.scope import build_scope_context, scope_query
@router.get("/items")
async def list_items(
ctx = Depends(build_scope_context),
db: AsyncSession = Depends(get_db),
):
stmt = scope_query(select(Item), ctx, Item)
return (await db.execute(stmt)).scalars().all()
- 단건 조회(
get)에도 동일하게 적용해 IDOR을 막습니다(스코프 밖이면 404). scope_query는workspace_id/resource_group_id컬럼이 없는 모델에 호출되면NotImplementedError로 fail-closed 됩니다 — 데이터 평면 모델 전용입니다.
새 데이터 라우터를 추가할 때
- 라우터의 조회/변경 쿼리를
scope_query로 감쌉니다. apps/api/tests/test_scope_guard.py의_DATA_PLANE_ROUTERS에 라우터 이름을 등록합니다.- 즉시 마이그레이션이 어려우면
_SCOPE_ALLOWLIST에 이슈 번호와 함께 추가합니다 — allowlist 잔여 = 남은 작업. - CI 가드(
test_scope_guard.py)가 데이터 라우터의scope_query미사용을 빌드 실패로 차단합니다.
단계 로드맵
| Phase | 내용 | 상태 |
|---|---|---|
| P0 | scope_query 골격 + CI 가드 (L0/L1 실동작, L3/L4 pass-through) | ✅ 완료 |
| P1 | 부서/clearance 네임스페이싱 + Keycloak sync + ResourceGroup NOT NULL | 예정 |
| P2 | 파일럿 라우터(saved_query·query·feature) 적용 + E2E | 예정 |
| P3 | DataGrant.workspace_id + ABAC 엔진 연결 | 예정 |
| P4 | 전 라우터 마이그레이션 + M3 workspace_id NOT NULL | 예정 |
| P5 | LLM clearance 테넌트화 + notebook 격리 | 예정 |