232 lines
15 KiB
Markdown
232 lines
15 KiB
Markdown
# 설계서: DDS MCP 사용자별 END USER Context 및 권한 게시 (#617)
|
|
|
|
> **상태**: Draft — P0 스파이크 승인 전 구현 금지
|
|
> **작성**: [AI] Architect · **최종수정**: 2026-07-01
|
|
> **추적성** — Redmine: #617 · 관련 ADR: [ADR-0001](../../adr/0001-dds-mcp-service-identity.md)
|
|
> · 구현 파일: TBD · 테스트: TBD
|
|
|
|
## 1. 목적 (Why)
|
|
|
|
MCP SSE 서비스가 요청자의 권한을 대신 판단하거나 SQL에 조건을 덧붙이지 않고, 각 Tool의 DB 작업을 해당 요청자에 대응하는 Oracle Deep Data Security(DDS) END USER Context로 실행한다.
|
|
|
|
VPD 트랙은 기존 구현과 데이터 모델을 변경하지 않는다. DDS 트랙은 별도의 보호 객체, 별도의 권한 게시 모델, 별도의 런타임 Context 경로를 갖는다.
|
|
|
|
## 2. 범위 (Scope)
|
|
|
|
- **포함**
|
|
- 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 도메인/애플리케이션 등록의 실제 운영 배포. 스파이크 성공 후 별도 작업으로 분리한다.
|
|
|
|
## 3. 인수조건 (Acceptance Criteria)
|
|
|
|
- [ ] 활성 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에 변경이 없다.
|
|
|
|
## 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 두 평면
|
|
|
|
```text
|
|
권한 게시 평면
|
|
백오피스
|
|
→ 보호 데이터 객체 / 접근 역할 / 세부 권한 / 사용자·그룹 할당
|
|
→ 유효 멤버십 계산
|
|
→ DDS Publisher
|
|
→ END USER · DATA ROLE · DATA GRANT DDL
|
|
→ 게시 이력 · 검증 · 드리프트 상태
|
|
|
|
요청 실행 평면
|
|
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 해제
|
|
```
|
|
|
|
### 5.2 신원 분리
|
|
|
|
| 항목 | 의미 | 관리 주체 |
|
|
|---|---|---|
|
|
| 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 서비스 애플리케이션 |
|
|
|
|
### 5.2.1 IAM 책임 경계
|
|
|
|
```text
|
|
Provisioning (관리자 작업)
|
|
joungmin.ko@oracle.com IAM 사용자
|
|
→ OCI CLI
|
|
→ mcp-dds-service IAM 애플리케이션 등록
|
|
→ client ID / client secret을 승인된 secret store에 등록
|
|
|
|
Runtime (MCP SSE 서비스)
|
|
mcp-dds-service client credentials
|
|
→ short-lived database-access token
|
|
→ local DDS END USER Context 부착
|
|
```
|
|
|
|
MCP/ERP 업무 사용자는 IAM 사용자로 등록하지 않는다. 기존 Bearer가 식별한 `CB_APP_USER`를 local DDS END USER로 매핑한다.
|
|
|
|
### 5.3 실행 경계
|
|
|
|
`McpDdsContextExecutor`만 보호 객체용 연결을 획득한다. 이 경계는 다음 순서를 강제한다.
|
|
|
|
1. Bearer를 재검증하고 활성 애플리케이션 사용자를 찾는다.
|
|
2. 게시 완료된 DDS END USER 매핑과 lookup key 참조를 찾는다.
|
|
3. 서비스 database-access token을 획득/갱신한다.
|
|
4. 연결에 DDS END USER Context를 부착한다.
|
|
5. Tool의 제한된 DB 작업을 실행한다.
|
|
6. `finally`에서 Context를 해제한 뒤 연결을 반환한다.
|
|
|
|
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 스파이크가 승인되기 전까지 임의 구현으로 채우지 않는다.
|