설계서: DDS MCP 사용자별 END USER Context 및 권한 게시 (#617)
상태: Draft — P0 스파이크 승인 전 구현 금지 작성: [AI] Architect · 최종수정: 2026-07-01 추적성 — Redmine: #617 · 관련 ADR: ADR-0001 · 구현 파일: 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 GRANTDDL로 게시·회수·검증하는 Publisher. - OCI IAM 서비스 애플리케이션 database-access token과 local END USER lookup key의 기술 스파이크.
- MCP Bearer →
- 제외 (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 도메인/애플리케이션 등록의 실제 운영 배포. 스파이크 성공 후 별도 작업으로 분리한다.
- VPD 정책, VPD 백오피스, 기존
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.comIAM 사용자는 OCI CLI로 서비스 애플리케이션을 등록·관리하는 관리자일 뿐, MCP 실행 경로의 신원이나 token 발급 주체가 아니다.- 런타임 신원은
mcp-dds-serviceIAM 애플리케이션이다. 이 앱의 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 두 평면
권한 게시 평면
백오피스
→ 보호 데이터 객체 / 접근 역할 / 세부 권한 / 사용자·그룹 할당
→ 유효 멤버십 계산
→ 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 책임 경계
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만 보호 객체용 연결을 획득한다. 이 경계는 다음 순서를 강제한다.
- Bearer를 재검증하고 활성 애플리케이션 사용자를 찾는다.
- 게시 완료된 DDS END USER 매핑과 lookup key 참조를 찾는다.
- 서비스 database-access token을 획득/갱신한다.
- 연결에 DDS END USER Context를 부착한다.
- Tool의 제한된 DB 작업을 실행한다.
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 누수·권한 불일치 | 복잡 |
복잡 함수의 세부 명세는 다음 문서로 분리한다.
8. 흐름 / 알고리즘
8.1 권한 게시
- 운영자가 보호 객체, 접근 역할, 세부 권한, 사용자/그룹 할당을 수정한다.
- Publisher는 그룹을 포함한 역할별 유효 사용자를 계산한다.
- 누락된 사용자에 대해 비밀번호 없는 DDS END USER 생성 계획을 만든다.
- 역할별 DATA ROLE과 객체별 DATA GRANT의 생성·교체·회수 diff를 만든다.
- 승인된 plan만 실행한다. 요청 실행 경로에서는 DDL을 실행하지 않는다.
- 게시 후 END USER/ROLE/GRANT dictionary와 대표 사용자 matrix를 확인한다.
8.2 MCP Tool 실행
- MCP 요청의 Bearer를 검증한다.
- 사용자·DDS END USER 매핑·게시 상태를 확인한다.
- Context 부착 전에 미매핑/비활성/회수 상태면 권한 없음으로 중단한다.
- Tool의 DB 작업을 DDS Context 안에서 실행한다.
- 성공·실패와 상관없이 Context를 제거한다.
- 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)
- local END USER security-context lookup key의 정확한 생성 API/명령, 회전·보관 기준은 무엇인가?
- 현재 OCI tenancy의 Free Identity Domain에서 DDS용 application registration 및 client-credentials database-access token을 발급할 수 있는가?
- ADB의 TLS, identity provider, application identity, pool account에 필요한 정확한 설정·권한은 무엇인가?
- Java 26ai JDBC artifact/API와 현재
dds-backoffice의 OJDBC 버전·Spring pool이 Context attach를 지원하는가? - VPD의 DENY 규칙을 DDS 1차 모델에서 명시적으로 제외할지, 제한된 조합 규칙으로 컴파일할지?
- Data Grant의 다중 역할 컬럼/행 합집합 의미를 실제 ADB에서 어떤 matrix로 검증할지?
이 여섯 항목은 P0 스파이크가 승인되기 전까지 임의 구현으로 채우지 않는다.