[Developer] #617 apply DDS MCP end-user authorization
This commit is contained in:
@@ -1,231 +1,110 @@
|
||||
# 설계서: DDS MCP 사용자별 END USER Context 및 권한 게시 (#617)
|
||||
|
||||
> **상태**: Draft — P0 스파이크 승인 전 구현 금지
|
||||
> **작성**: [AI] Architect · **최종수정**: 2026-07-01
|
||||
> **상태**: Implemented — OCI IAM·ADB·SSE 실증 완료
|
||||
> **최종수정**: 2026-07-02
|
||||
> **추적성** — Redmine: #617 · 관련 ADR: [ADR-0001](../../adr/0001-dds-mcp-service-identity.md)
|
||||
> · 구현 파일: TBD · 테스트: TBD
|
||||
> · 구현: `DdsMcpBearerAuthenticator`, `DdsMcpEndUserResolver`, `DdsMcpContextExecutor`, `DdsMcpSseController`
|
||||
> · DB 게시: `sql/adb/44_dds_mcp_local_end_user_setup.sql`
|
||||
> · 검증: `sql/adb/45_dds_mcp_local_end_user_test.sql`, SSE `tools/call`
|
||||
|
||||
## 1. 목적 (Why)
|
||||
## 1. 결정과 목적
|
||||
|
||||
MCP SSE 서비스가 요청자의 권한을 대신 판단하거나 SQL에 조건을 덧붙이지 않고, 각 Tool의 DB 작업을 해당 요청자에 대응하는 Oracle Deep Data Security(DDS) END USER Context로 실행한다.
|
||||
MCP Tool의 보호 SQL은 요청 Bearer가 지정한 업무 사용자의 local DDS `END USER` Context에서만 실행한다. DDS가 `DATA ROLE`과 `DATA GRANT`로 행·컬럼 접근을 집행하며, Tool은 권한 predicate를 직접 만들지 않는다.
|
||||
|
||||
VPD 트랙은 기존 구현과 데이터 모델을 변경하지 않는다. DDS 트랙은 별도의 보호 객체, 별도의 권한 게시 모델, 별도의 런타임 Context 경로를 갖는다.
|
||||
VPD 경로는 변경하지 않는다. 기존 DDS 관리의 권한 게시 경계는 MCP용 END USER/역할/grant도 함께 갱신한다.
|
||||
|
||||
## 2. 범위 (Scope)
|
||||
## 2. 토큰과 사용자 — 반드시 구분할 것
|
||||
|
||||
- **포함**
|
||||
- MCP Bearer → `CB_APP_USER` → 로컬 DDS END USER의 명시적 매핑.
|
||||
- MCP Tool 호출마다 DDS END USER Context를 부착·해제하는 실행 경계.
|
||||
- 보호 데이터 객체, 접근 역할, 테이블 세부 권한, 사용자/그룹 역할 할당을 관리하는 DDS 전용 백오피스 모델.
|
||||
- 역할·그룹의 유효 멤버십을 DDS `END USER` / `DATA ROLE` / `DATA GRANT` DDL로 게시·회수·검증하는 Publisher.
|
||||
- OCI IAM 서비스 애플리케이션 database-access token과 local END USER lookup key의 기술 스파이크.
|
||||
- **제외 (out of scope)**
|
||||
- VPD 정책, VPD 백오피스, 기존 `CB_AGENT_CTX` 경로의 변경.
|
||||
- MCP 사용자마다 OCI IAM 사용자를 생성·관리하는 기능.
|
||||
- 사용자 요청 시점의 `CREATE END USER`, `GRANT DATA ROLE`, `CREATE DATA GRANT` 수행.
|
||||
- 임의 SQL predicate 입력 및 기존 VPD `DENY 우선` 규칙의 자동 변환.
|
||||
- OCI IAM 도메인/애플리케이션 등록의 실제 운영 배포. 스파이크 성공 후 별도 작업으로 분리한다.
|
||||
| 값 | 현재 구현에서의 역할 | 사람 사용자인가 |
|
||||
|---|---|---|
|
||||
| MCP 요청 Bearer | `CB_AGENT_BEARER_KEY` 해시·만료·회수 검증 후 `CB_APP_USER`를 결정 | **예.** DB의 업무 사용자 매핑 기준 |
|
||||
| local DDS END USER | `DDS_U_<CB_APP_USER.user_id>` | **예.** DDS가 집행하는 보안 주체 |
|
||||
| OCI IAM database-access token | Confidential application의 client-credentials로 매 Tool Context attach를 승인 | 아니오. 서비스 애플리케이션 신원 |
|
||||
| OCI IAM end-user token | 향후 authorization-code/OBO 전용 확장 | 현재 MCP 인증 입력으로 사용하지 않음 |
|
||||
|
||||
## 3. 인수조건 (Acceptance Criteria)
|
||||
따라서 현재 MCP Bearer가 `CB_APP_USER`를 지정할 수 있으면 그 사용자별 DDS 권한은 적용된다. 반면 client-credentials 토큰의 `sub`/`client_id`는 서비스 애플리케이션이므로 사람 사용자를 판정하는 데 사용하면 안 된다.
|
||||
|
||||
- [ ] 활성 MCP Bearer는 정확히 하나의 활성 `CB_APP_USER`로 해석되며, DDS END USER 매핑이 없으면 Tool 실행 전에 권한 없음으로 종료된다.
|
||||
- [ ] 동일한 공용 연결 풀에서 서로 다른 두 요청자가 연속·동시 Tool을 호출해도 각 요청은 자신의 DDS END USER Context와 DATA GRANT 결과만 받는다.
|
||||
- [ ] 예외·취소·타임아웃을 포함한 모든 실행 경로에서 Context가 해제되어 다음 요청에 이전 권한이 남지 않는다.
|
||||
- [ ] 백오피스 게시기는 사용자/그룹 역할 할당과 테이블 세부 권한을 idempotent DDS DDL로 반영하며, 게시 diff·사유·결과·드리프트를 보관한다.
|
||||
- [ ] 그룹 멤버 추가/제거 후 게시하면 필요한 DDS END USER/DATA ROLE은 부여되고 불필요한 역할은 회수된다.
|
||||
- [ ] MCP Tool SQL은 권한 `WHERE`를 직접 만들지 않으며, DDS DATA GRANT가 반환 행·컬럼을 제한한다.
|
||||
- [ ] 미매핑·비활성·회수된 Bearer, 미게시 사용자, DATA GRANT 없는 사용자, Context attach 실패는 fail-closed로 처리한다.
|
||||
- [ ] VPD 회귀 테스트가 통과하며 VPD 스키마·정책·UI에 변경이 없다.
|
||||
OCI IAM JWT의 사람 사용자 claim을 그대로 DDS에 전달하려면 별도의 authorization-code 또는 OBO flow, 해당 end-user token 검증, IAM role↔DDS DATA ROLE 매핑으로 확장해야 한다. 이 경로는 현재 local END USER 모델과 혼용하지 않는다.
|
||||
|
||||
## 4. 컨텍스트 & 제약
|
||||
|
||||
- 기존 `CB_BEARER_TOKEN`/`CB_APP_USER`는 애플리케이션 논리 사용자 식별 수단이다. DDS 내장 인증 객체가 아니다.
|
||||
- 로컬 DDS END USER는 `CREATE END USER`로 별도 생성한다. ERP/MCP 사용자는 IAM 사용자가 아니어도 되지만, DDS END USER는 사용자별로 존재한다.
|
||||
- MCP SSE 서비스는 공용 DB 연결을 사용한다. DDS END USER Context는 SSE 연결 전체가 아니라 **매 Tool DB 실행 경계**마다 부착·해제한다.
|
||||
- application-mediated local END USER Context에는 서비스 애플리케이션의 database-access token이 필요하다. 개인 IAM 사용자 토큰을 장기 설정값으로 저장하지 않는다.
|
||||
- `joungmin.ko@oracle.com` IAM 사용자는 OCI CLI로 서비스 애플리케이션을 등록·관리하는 관리자일 뿐, MCP 실행 경로의 신원이나 token 발급 주체가 아니다.
|
||||
- 런타임 신원은 `mcp-dds-service` IAM 애플리케이션이다. 이 앱의 client credentials로 short-lived database-access token을 발급받는다.
|
||||
- IAM app client secret, database-access token, local END USER lookup key는 채팅·Redmine·Git에 기록하지 않는다. 배포 환경의 secret store 또는 환경 변수 참조만 허용한다.
|
||||
- 서비스 애플리케이션의 OCI IAM 등록, token 발급, TLS/DB 설정, lookup key 발급은 P0 스파이크로 검증되기 전에는 구현 사실로 간주하지 않는다.
|
||||
- DDS DATA GRANT는 additive다. 여러 DATA ROLE의 권한은 합집합이므로 VPD의 `DENY 우선` 의미를 자동 보존할 수 없다.
|
||||
- END USER 이름은 ASCII 안정 식별자 `DDS_U_<CB_APP_USER.user_id>`를 사용한다. 표시 이름·한글 로그인명과 분리한다.
|
||||
|
||||
## 5. 아키텍처 개요
|
||||
|
||||
### 5.1 두 평면
|
||||
## 3. 실제 아키텍처
|
||||
|
||||
```text
|
||||
권한 게시 평면
|
||||
백오피스
|
||||
→ 보호 데이터 객체 / 접근 역할 / 세부 권한 / 사용자·그룹 할당
|
||||
→ 유효 멤버십 계산
|
||||
→ DDS Publisher
|
||||
→ END USER · DATA ROLE · DATA GRANT DDL
|
||||
→ 게시 이력 · 검증 · 드리프트 상태
|
||||
권한 관리 / DDS 게시
|
||||
CB_APP_USER + 직접/그룹 역할 + CB_PERMISSION 규칙
|
||||
→ DDS Publisher
|
||||
→ CB_DDS_END_USER_MAP
|
||||
→ CREATE END USER DDS_U_<id>
|
||||
→ CREATE/GRANT DATA ROLE DDS_U_<id>_ROLE
|
||||
→ CREATE DATA GRANT (보호 벡터 객체)
|
||||
|
||||
요청 실행 평면
|
||||
MCP Client Bearer
|
||||
→ MCP SSE 인증
|
||||
→ CB_BEARER_TOKEN / CB_APP_USER 확인
|
||||
→ DDS END USER 매핑 확인
|
||||
→ 서비스 IAM database-access token + lookup key로 Context 부착
|
||||
→ MCP Tool DB 작업
|
||||
→ DDS DATA GRANT 집행
|
||||
→ Context 해제
|
||||
MCP SSE Tool 호출
|
||||
Authorization: Bearer <MCP bearer>
|
||||
→ 매 메시지마다 bearer 검증
|
||||
→ CB_APP_USER 확인
|
||||
→ 게시된 DDS_U_<id> map 확인
|
||||
→ OCI IAM database-access token 취득/캐시
|
||||
→ EndUserSecurityContext(name, lookup key) attach
|
||||
→ 보호 SQL 실행 (DATA GRANT 집행)
|
||||
→ finally: context clear, 연결 반환
|
||||
```
|
||||
|
||||
### 5.2 신원 분리
|
||||
SSE 연결 자체는 인증을 보조할 뿐이다. `/dds/mcp/messages`의 **매 요청마다** Bearer와 사용자를 재검증하므로, 연결을 오래 유지해도 이전 사용자 권한을 신뢰하지 않는다.
|
||||
|
||||
| 항목 | 의미 | 관리 주체 |
|
||||
## 4. 게시 모델과 운영 규칙
|
||||
|
||||
- 활성 `CB_APP_USER`마다 `CB_DDS_END_USER_MAP`에 `DDS_U_<id>`, `DDS_U_<id>_ROLE`, grant 이름과 게시 상태를 기록한다.
|
||||
- local END USER Context의 lookup key는 서비스 secret과 사용자 ID로 HMAC 파생한다. 원문/파생값은 DB·Git·Redmine·로그에 저장하지 않는다.
|
||||
- 사용자의 직접 역할과 활성 그룹 역할에서 `CB_PERMISSION` / `CB_PERMISSION_RULE` / 허용 컬럼을 계산해 벡터 보호 객체의 `DATA GRANT`를 재생성한다.
|
||||
- ALLOW가 없으면 grant를 제거하여 DDS 기본 거부 상태를 유지한다. 비활성 사용자는 data role과 grant를 회수한다.
|
||||
- 사용자 활성화·직접 역할·그룹 멤버/역할·permission rule/허용 컬럼 변경은 같은 요청 안에서 활성 사용자 전체를 bulk 재발행한다. 수동 **DDS 관리의 게시 작업**은 전체 복구·재검증용으로도 제공한다.
|
||||
- `withDataRoles(...)`는 local username+lookup-key Context에 사용하지 않는다. 역할은 게시된 local END USER grant에서만 활성화된다.
|
||||
|
||||
## 5. OCI IAM / ADB 전제조건
|
||||
|
||||
1. ADB external authentication을 `OCI_IAM`으로 등록하고 application ID와 domain URL을 설정한다.
|
||||
2. `OCI_IAM_DOMAIN_DB_CRED$` credential에 Confidential application의 client ID/secret을 보관한다.
|
||||
3. pool account에 `CREATE SESSION`, `CREATE END USER SECURITY CONTEXT`를 부여하고 TLS wallet 연결을 사용한다.
|
||||
4. application identity를 `IAM_OAUTH_CLIENT_ID=<client id>`로 등록한다. 서비스 역할을 application identity에 부여할 경우 해당 역할만 활성화된다.
|
||||
5. application은 database resource scope로 client-credentials token을 얻는다.
|
||||
|
||||
DB가 확인하는 token claim은 `resource_app_id`, `tenant_iss`, audience와 scope다. 이 값은 DB OCI IAM 설정 및 database resource registration과 일치해야 한다.
|
||||
|
||||
## 6. 구현 경계
|
||||
|
||||
| 컴포넌트 | 책임 | 실패 처리 |
|
||||
|---|---|---|
|
||||
| MCP Bearer | MCP 요청자가 어느 애플리케이션 사용자 인지 식별 | 기존 `CB_BEARER_TOKEN` |
|
||||
| 애플리케이션 사용자 | 업무 사용자·그룹·역할 할당의 기준 | `CB_APP_USER` 및 DDS 전용 할당 모델 |
|
||||
| DDS END USER | DB가 DATA ROLE/DATA GRANT를 집행하는 보안 주체 | DDS Publisher |
|
||||
| Database-access token | MCP SSE 서비스가 Context를 부착할 수 있다는 애플리케이션 신뢰 | OCI IAM 서비스 애플리케이션 |
|
||||
| `DdsMcpBearerAuthenticator` | MCP Bearer → 활성 `CB_APP_USER` | 인증 실패, SQL 미실행 |
|
||||
| `DdsMcpEndUserResolver` | 사용자 → 게시된 DDS principal | 미매핑/미게시면 거부 |
|
||||
| `DdsMcpDatabaseAccessTokenProvider` | OCI IAM service token 발급·만료 전 갱신 | Context 실행 차단 |
|
||||
| `DdsMcpContextExecutor` | attach → 제한된 SQL → clear | clear 실패 시 연결 폐기 |
|
||||
| `DdsMcpVectorSearchService` | Context 내부 보호 벡터 SQL만 실행 | DDS 오류를 안전한 MCP 오류로 변환 |
|
||||
| `DdsMcpAuthorizationChangeListener` | 권한 변경 event → 전체 local END USER grant 재발행 | 요청을 실패로 알리고 게시 상태를 확인하게 함 |
|
||||
| DDS Publisher | 기존 권한 모델 → local END USER/DATA ROLE/DATA GRANT | 부분 실패를 게시 실패로 기록 |
|
||||
|
||||
### 5.2.1 IAM 책임 경계
|
||||
Tool/Repository는 raw Bearer, client secret, lookup key 또는 `setEndUserSecurityContext`를 직접 다루지 않는다.
|
||||
|
||||
```text
|
||||
Provisioning (관리자 작업)
|
||||
joungmin.ko@oracle.com IAM 사용자
|
||||
→ OCI CLI
|
||||
→ mcp-dds-service IAM 애플리케이션 등록
|
||||
→ client ID / client secret을 승인된 secret store에 등록
|
||||
## 7. 검증 결과 (2026-07-02)
|
||||
|
||||
Runtime (MCP SSE 서비스)
|
||||
mcp-dds-service client credentials
|
||||
→ short-lived database-access token
|
||||
→ local DDS END USER Context 부착
|
||||
```
|
||||
- [x] SQLcl로 ADB 접속 및 local `END USER`, `DATA ROLE`, `DATA GRANT` catalog 생성 검증.
|
||||
- [x] OCI IAM database-access token 발급 성공. `resource_app_id`, `tenant_iss`, audience `DDSDB`, scope `DB_ACCESS_SCOPE`가 DB 설정과 일치.
|
||||
- [x] DB credential `OCI_IAM_DOMAIN_DB_CRED$`, OCI IAM application identity mapping 확인.
|
||||
- [x] `/dds/mcp/sse` endpoint event 및 `tools/list` HTTP 200 확인.
|
||||
- [x] `dds_vector_search` tool call: Bearer → application user 101 → local DDS Context attach → 보호 query 3행 반환 → context clear, HTTP 200.
|
||||
- [ ] 사용자 A→B→A 및 동시 요청의 full isolation regression을 자동화한다.
|
||||
- [ ] DDS 관리 UI publish가 MCP END USER map/grant를 같은 트랜잭션 경계에서 갱신하도록 통합한다.
|
||||
|
||||
MCP/ERP 업무 사용자는 IAM 사용자로 등록하지 않는다. 기존 Bearer가 식별한 `CB_APP_USER`를 local DDS END USER로 매핑한다.
|
||||
SSE stream은 연결을 유지하므로 client read timeout이 날 수 있다. 이는 실패 판정 기준이 아니며, Tool RPC의 HTTP 결과와 attach/query/clear 로그로 성공을 판정한다.
|
||||
|
||||
### 5.3 실행 경계
|
||||
## 8. 보안 불변식
|
||||
|
||||
`McpDdsContextExecutor`만 보호 객체용 연결을 획득한다. 이 경계는 다음 순서를 강제한다.
|
||||
1. 유효한 MCP Bearer 하나는 정확히 하나의 활성 `CB_APP_USER`와 하나의 게시된 DDS END USER로만 해석된다.
|
||||
2. Context attach 이전·clear 이후에는 보호 SQL을 실행하지 않는다.
|
||||
3. attach/query/clear 어느 단계가 실패해도 fail-closed한다.
|
||||
4. client-credentials token은 서비스 승인용이며 업무 사용자 권한 확대에 사용하지 않는다.
|
||||
5. secret, raw bearer, database-access token, lookup key는 응답·로그·Git·Redmine에 기록하지 않는다.
|
||||
|
||||
1. Bearer를 재검증하고 활성 애플리케이션 사용자를 찾는다.
|
||||
2. 게시 완료된 DDS END USER 매핑과 lookup key 참조를 찾는다.
|
||||
3. 서비스 database-access token을 획득/갱신한다.
|
||||
4. 연결에 DDS END USER Context를 부착한다.
|
||||
5. Tool의 제한된 DB 작업을 실행한다.
|
||||
6. `finally`에서 Context를 해제한 뒤 연결을 반환한다.
|
||||
## 9. 참고
|
||||
|
||||
Tool·Repository는 Context 설정 API, DATA GRANT DDL, 원시 Bearer를 직접 다루지 않는다.
|
||||
|
||||
## 6. 데이터 모델
|
||||
|
||||
기존 VPD 공통 권한 테이블은 읽거나 변경하지 않는다. DDS 게시용 모델은 별도 관리한다.
|
||||
|
||||
| 개념 | 잠정 저장 구조 | 핵심 값 |
|
||||
|---|---|---|
|
||||
| 보호 데이터 객체 | `CB_DDS_PROTECTED_OBJECT` | object owner/name, Tool 노출명, 활성 상태 |
|
||||
| 접근 역할 | `CB_DDS_ACCESS_ROLE` | 표시명, `DATA ROLE` 이름, 상태 |
|
||||
| 테이블 세부 권한 | `CB_DDS_OBJECT_GRANT` | 역할, 객체, action, 허용/제외 컬럼, 행 조건 DSL |
|
||||
| 역할 할당 | `CB_DDS_ROLE_ASSIGNMENT` | 역할, 대상 유형(USER/GROUP), 대상 ID |
|
||||
| DDS END USER 매핑 | `CB_DDS_END_USER_MAP` | `CB_APP_USER.user_id`, DDS END USER 이름, 게시 상태, lookup key 참조 |
|
||||
| 게시 실행 | `CB_DDS_PUBLISH_RUN` / 항목 | diff, 사유, 실행 결과, DDL fingerprint, 검증 결과 |
|
||||
|
||||
행 조건은 자유 SQL 문자열이 아니다. 객체별 허용 컬럼, 비교 연산자, 리터럴 타입, `ORA_END_USER_CONTEXT` 허용 경로만으로 구성된 DSL을 Publisher가 검증된 SQL predicate로 컴파일한다.
|
||||
|
||||
## 7. 함수 명세 (Function Specs)
|
||||
|
||||
| 함수 | 책임(1줄) | 시그니처(잠정) | 입력 | 출력 | 에러/실패 | 복잡? |
|
||||
|---|---|---|---|---|---|---|
|
||||
| `authenticateMcpBearer` | Bearer를 활성 업무 사용자로 해석 | `Bearer → AppUser` | Bearer | `AppUser` | 미존재·만료·회수 → deny | **복잡** |
|
||||
| `resolveDdsEndUser` | 업무 사용자의 게시된 DDS END USER를 찾음 | `AppUser → DdsPrincipal` | 사용자 ID | END USER/lookup key 참조 | 미매핑·미게시 → deny | 단순 |
|
||||
| `getDatabaseAccessToken` | 서비스용 short-lived DB access token을 제공 | `() → Token` | 서비스 IAM 설정 | token | 발급 실패 → fail closed | **복잡** |
|
||||
| `withDdsEndUserContext` | Context를 부착·DB 작업·해제를 원자적으로 수행 | `(DdsPrincipal, SqlWork) → T` | DDS principal, 작업 | 결과 | attach/query/clear 실패 | **복잡** |
|
||||
| `compileDdsPublishPlan` | 백오피스 권한 모델을 DDL diff로 변환 | `Draft → PublishPlan` | 객체/역할/할당 | DDL plan | DSL/충돌/deny 규칙 오류 | **복잡** |
|
||||
| `publishDdsPlan` | 승인된 plan을 멱등 게시하고 검증 | `PublishPlan → PublishRun` | plan, 사유 | 결과/증적 | 부분 실패·drift | **복잡** |
|
||||
| `verifyDdsIsolation` | 대표 사용자별 Context·객체·행·컬럼 결과를 확인 | `PublishRun → Verification` | 사용자 matrix | 검증 결과 | context 누수·권한 불일치 | **복잡** |
|
||||
|
||||
복잡 함수의 세부 명세는 다음 문서로 분리한다.
|
||||
|
||||
- [Bearer 인증](fn-authenticate-mcp-bearer.md)
|
||||
- [서비스 database-access token](fn-get-database-access-token.md)
|
||||
- [DDS Context 실행 경계](fn-with-dds-end-user-context.md)
|
||||
- [DDS 게시 계획 컴파일](fn-compile-dds-publish-plan.md)
|
||||
- [DDS 게시·검증](fn-publish-and-verify-dds-plan.md)
|
||||
|
||||
## 8. 흐름 / 알고리즘
|
||||
|
||||
### 8.1 권한 게시
|
||||
|
||||
1. 운영자가 보호 객체, 접근 역할, 세부 권한, 사용자/그룹 할당을 수정한다.
|
||||
2. Publisher는 그룹을 포함한 역할별 유효 사용자를 계산한다.
|
||||
3. 누락된 사용자에 대해 비밀번호 없는 DDS END USER 생성 계획을 만든다.
|
||||
4. 역할별 DATA ROLE과 객체별 DATA GRANT의 생성·교체·회수 diff를 만든다.
|
||||
5. 승인된 plan만 실행한다. 요청 실행 경로에서는 DDL을 실행하지 않는다.
|
||||
6. 게시 후 END USER/ROLE/GRANT dictionary와 대표 사용자 matrix를 확인한다.
|
||||
|
||||
### 8.2 MCP Tool 실행
|
||||
|
||||
1. MCP 요청의 Bearer를 검증한다.
|
||||
2. 사용자·DDS END USER 매핑·게시 상태를 확인한다.
|
||||
3. Context 부착 전에 미매핑/비활성/회수 상태면 권한 없음으로 중단한다.
|
||||
4. Tool의 DB 작업을 DDS Context 안에서 실행한다.
|
||||
5. 성공·실패와 상관없이 Context를 제거한다.
|
||||
6. MCP 응답에는 Tool이 반환한 DDS 제한 결과만 포함한다. END USER 이름, lookup key, database-access token은 노출하지 않는다.
|
||||
|
||||
## 9. 엣지케이스 & 에러 처리
|
||||
|
||||
| 상황 | 처리 |
|
||||
|---|---|
|
||||
| Bearer가 없거나 회수됨 | 인증 실패. DDS END USER 조회/부착을 시도하지 않는다. |
|
||||
| 사용자 매핑 없음 | 권한 없음. 요청 중 END USER를 생성하지 않는다. |
|
||||
| 사용자 비활성/게시 실패/drift | 권한 없음. 마지막 성공 게시 결과를 사용하지 않는다. |
|
||||
| Context attach 실패 | Tool SQL을 실행하지 않는다. correlation ID만 기록한다. |
|
||||
| Tool SQL 예외/취소/시간초과 | `finally`에서 Context 해제 후 안전한 오류 응답. |
|
||||
| 연결 풀 재사용 | 매 DB 작업에 새 Context를 부착하고 `finally`에서 해제한다. |
|
||||
| 그룹에서 사용자 제거 | 다음 게시에서 DATA ROLE 회수, 이후 요청은 새 게시 결과만 사용한다. |
|
||||
| 비ASCII 업무 사용자명 | `DDS_U_<id>`를 사용하며 표시명과 END USER 식별자를 분리한다. |
|
||||
| VPD DENY 규칙 | DDS 1차 모델에서 미지원. 게시 전 오류로 차단한다. |
|
||||
|
||||
## 10. 테스트 계획
|
||||
|
||||
| 인수조건 | 검증 |
|
||||
|---|---|
|
||||
| Context 사용자 격리 | 같은 공용 풀에서 A → B → A 순서와 동시 실행. `ORA_END_USER_CONTEXT.username` 및 결과 행/컬럼이 각 사용자와 일치. |
|
||||
| Context 해제 | Tool 예외·취소·타임아웃 뒤 다음 요청이 이전 사용자의 Context를 갖지 않음. |
|
||||
| 토큰 fail-closed | 미존재·만료·회수 Bearer와 미매핑 사용자 모두 SQL 실행 전 거부. |
|
||||
| 역할/그룹 게시 | 직접 사용자·그룹 추가/제거 후 예상 DATA ROLE grant/revoke와 결과 확인. |
|
||||
| 세부 권한 | 역할별 객체 차단, 행 조건, 컬럼 제외, 다중 역할 합집합을 검증. |
|
||||
| DDL 멱등성 | 동일 plan 재게시가 변경 없음으로 완료. |
|
||||
| 드리프트 | dictionary의 END USER/DATA ROLE/DATA GRANT를 의도적으로 변경한 뒤 탐지. |
|
||||
| VPD 회귀 | 기존 VPD Maven/SQL/HTTP 회귀 테스트 전체 통과. |
|
||||
| P0 스파이크 | OCI IAM 서비스 token + local END USER name/lookup key로 Context attach 성공 및 두 사용자 격리 증명. |
|
||||
|
||||
## 11. 리스크 & 대안 검토
|
||||
|
||||
### 선택: DDS 선언 게시 + MCP Context 부착
|
||||
|
||||
권한을 백오피스에서 검토·승인·게시하고, MCP Tool은 게시된 DDS 권한을 집행한다. Agent가 SQL을 만들더라도 DB가 결과를 제한한다.
|
||||
|
||||
### 대안: 기존 VPD 공통 권한 테이블을 요청마다 동적 해석
|
||||
|
||||
기존 VPD 모델과 즉시 반영 특성은 유지하지만, DDS DATA ROLE/DATA GRANT를 권한의 단일 출처로 쓰려는 목표와 맞지 않는다. VPD 트랙에 남긴다.
|
||||
|
||||
### 대안: 사용자별 IAM 계정
|
||||
|
||||
IAM token claim에서 DATA ROLE을 직접 활성화할 수 있으나 ERP/MCP 사용자 관리 주체를 IAM으로 옮겨야 한다. 이번 범위에서는 제외한다.
|
||||
|
||||
### 주요 리스크
|
||||
|
||||
- local END USER application-mediated Context에는 service IAM database-access token이 필요하다.
|
||||
- lookup key 생성/보관 방식이 미확정이다.
|
||||
- DDS 권한은 additive이므로 VPD DENY 우선 모델을 그대로 이식할 수 없다.
|
||||
- Publisher의 partial failure는 사용자별 권한 불일치를 만들 수 있으므로 실행 plan, compensation, drift 탐지가 필요하다.
|
||||
|
||||
OCI IAM 서비스 애플리케이션의 도메인·token flow·비밀 보관 방식은 되돌리기 어려우므로 ADR로 분리한다.
|
||||
|
||||
## 12. 미해결 질문 (Open Questions)
|
||||
|
||||
1. local END USER security-context lookup key의 정확한 생성 API/명령, 회전·보관 기준은 무엇인가?
|
||||
2. 현재 OCI tenancy의 Free Identity Domain에서 DDS용 application registration 및 client-credentials database-access token을 발급할 수 있는가?
|
||||
3. ADB의 TLS, identity provider, application identity, pool account에 필요한 정확한 설정·권한은 무엇인가?
|
||||
4. Java 26ai JDBC artifact/API와 현재 `dds-backoffice`의 OJDBC 버전·Spring pool이 Context attach를 지원하는가?
|
||||
5. VPD의 DENY 규칙을 DDS 1차 모델에서 명시적으로 제외할지, 제한된 조합 규칙으로 컴파일할지?
|
||||
6. Data Grant의 다중 역할 컬럼/행 합집합 의미를 실제 ADB에서 어떤 matrix로 검증할지?
|
||||
|
||||
이 여섯 항목은 P0 스파이크가 승인되기 전까지 임의 구현으로 채우지 않는다.
|
||||
- [Oracle: Configure the Database for IAM Integration](https://docs.oracle.com/en/database/oracle/oracle-database/26/ddscg/configure-database-iam-integration.html)
|
||||
- [Oracle: Prerequisites for Establishing a Local Security Context](https://docs.oracle.com/en/database/oracle/oracle-database/26/ddscg/prerequisites-establishing-local-security-context.html)
|
||||
- [Oracle: End-User Security Context Issues](https://docs.oracle.com/en/database/oracle/oracle-database/26/ddscg/end-user-security-context-issues.html)
|
||||
|
||||
Reference in New Issue
Block a user