refs #740: enforce carrier VPD by MCP user
This commit is contained in:
@@ -1,123 +1,52 @@
|
||||
# #740 HMM MCP VPD 실행 경계 복구
|
||||
# #740 HMM MCP VPD 실행 경계
|
||||
|
||||
## 배경
|
||||
## 목적
|
||||
|
||||
HMM MCP의 `search_hr_data`는 현재 `ADMIN` JDBC 세션에서
|
||||
`DBMS_CLOUD_AI_AGENT.RUN_TOOL`을 실행한다. 토큰으로
|
||||
`HMM_ACCESS_CTX`를 설정해도 `ADMIN`에는 `EXEMPT ACCESS POLICY`가 있으므로
|
||||
`ADMIN.HMM_LEAVE_BALANCES`와 `ADMIN.HMM_LEAVE_REQUESTS`의 VPD 정책이
|
||||
실제 조회에 적용되지 않는다.
|
||||
HMM MCP의 인증 사용자를 Oracle DB 세션 사용자 문맥으로 연결하고, HR 및 선사 배정 데이터를
|
||||
Oracle VPD로 제한한다. 팀원은 본인 행, 팀장은 본인과 직속 팀원 행을 조회한다.
|
||||
|
||||
컨텍스트 값이 올바른 것과 VPD가 적용되는 것은 별개의 조건이다. 보호 테이블을
|
||||
읽는 최종 SQL은 반드시 `EXEMPT ACCESS POLICY`가 없는 계정의 동일 DB 세션에서
|
||||
컨텍스트 설정과 함께 실행해야 한다.
|
||||
## 범위와 결정사항
|
||||
|
||||
## 목표
|
||||
- 포털의 사용자 preset은 각각 다른 Bearer token 환경변수를 사용한다.
|
||||
- 백오피스는 token hash로 직원을 식별하고 실제 SELECT와 같은 `CB_ORDS` 연결에
|
||||
`SET_VPD_CONTEXT`를 호출한다.
|
||||
- `ADMIN`은 `EXEMPT ACCESS POLICY`가 있으므로 Select AI `SHOWSQL` 생성만 담당한다.
|
||||
- `HMM_CARRIER_ASSIGNMENTS_V.EMPLOYEE_ID`에 `SELF`, `MANAGED_TEAM`, `ALL` 규칙을 적용한다.
|
||||
- 기존 MCP 이름 `search_carrier_performance`, 자연어 Select AI, 선사 `CARRIER_CODE` 조인과 HTML
|
||||
renderer는 유지한다. 고정 SQL이나 대체 조회 패키지를 만들지 않는다.
|
||||
|
||||
- `ADMIN`은 Select AI `SHOWSQL` 생성만 담당한다.
|
||||
- 비면제 런타임 스키마 `CB_ORDS`가 생성 SQL을 읽기 전용으로 실행한다.
|
||||
- 실행 직전 같은 `CB_ORDS` 세션에서
|
||||
`CB_ORDS_HANDLER_PKG.SET_VPD_CONTEXT`를 호출한다.
|
||||
- 실행 종료 시 성공·실패와 관계없이 `CLEAR_VPD_CONTEXT`를 호출하고 롤백한다.
|
||||
- 런타임 계정이 `ADMIN`이거나 `EXEMPT ACCESS POLICY`를 가진 경우 fail-closed 한다.
|
||||
- MCP `search_hr_data`만 새 경계로 전환하며 용어·정책 검색 도구는 기존 경로를 유지한다.
|
||||
|
||||
## 구조
|
||||
## 전체 구성
|
||||
|
||||
```text
|
||||
MCP tools/call
|
||||
└─ bearer token 해시 인증
|
||||
├─ ADMIN / DBMS_CLOUD_AI.GENERATE(..., 'showsql')
|
||||
│ └─ 허용된 HMM HR 객체만 포함한 SELECT/WITH 생성
|
||||
└─ CB_ORDS JDBC session
|
||||
├─ CB_ORDS_HANDLER_PKG.SET_VPD_CONTEXT('Bearer ...')
|
||||
│ └─ ADMIN.HMM_ACCESS_CTX_PKG.SET_USER_BY_BEARER(token)
|
||||
├─ runtime principal/컨텍스트 일치 검증
|
||||
├─ SET TRANSACTION READ ONLY
|
||||
├─ 생성 SQL 실행 → HMM_LEAVE_SCOPE_POLICY 적용
|
||||
├─ ROLLBACK
|
||||
└─ CB_ORDS_HANDLER_PKG.CLEAR_VPD_CONTEXT
|
||||
포털 사용자 preset
|
||||
→ 사용자별 Bearer token
|
||||
→ token hash로 EMPLOYEE_ID 확인
|
||||
→ ADMIN Select AI SHOWSQL 생성
|
||||
→ CB_ORDS 연결에서 SET_VPD_CONTEXT
|
||||
→ 생성 SELECT 실행
|
||||
→ HMM_CARRIER_ASSIGNMENTS_V VPD
|
||||
├─ E1001 팀장: 직속 팀원 배정 8건
|
||||
└─ E1002 팀원: 본인 배정 C001·C002 2건
|
||||
→ 허용된 CARRIER_CODE만 원격 KPI와 조인
|
||||
→ HTML renderer
|
||||
```
|
||||
|
||||
## DB 설계
|
||||
핵심은 token 소유자, DB context의 직원, VPD predicate가 동일한 요청 안에서 이어지는 것이다.
|
||||
`SET_VPD_CONTEXT`를 호출해도 `EXEMPT ACCESS POLICY`를 가진 연결에서 SELECT하면 정책이 우회된다.
|
||||
|
||||
### 런타임 스키마
|
||||
## 현재 상태
|
||||
|
||||
`CB_ORDS`에는 다음 최소 권한만 부여한다.
|
||||
2026-08-10 운영 적용 및 MCP 호출 검증을 완료했다.
|
||||
|
||||
- `CREATE SESSION`
|
||||
- `ADMIN.CB_ORDS_HANDLER_PKG` 실행
|
||||
- Select AI 프로필의 승인 객체 6개에 대한 `SELECT`
|
||||
- `HMM_ORG_TEAMS`
|
||||
- `HMM_HR_EMPLOYEES`
|
||||
- `HMM_LEAVE_BALANCES`
|
||||
- `HMM_LEAVE_REQUESTS`
|
||||
- `HMM_ATTENDANCE_DAILY`
|
||||
- `HMM_HR_TERMS`
|
||||
- 사용자별 portal token 5개가 서로 다른 hash로 직원에게 연결됨
|
||||
- `HMM_CARRIER_SCOPE_POLICY` 활성화
|
||||
- MCP E1001: `vpdEnforced=true`, 8건
|
||||
- MCP E1002: `vpdEnforced=true`, 2건, 직원 범위 E1002만 포함
|
||||
- E1002 renderer: 입력 2건, HTML에 C001·C002 포함, E1003 미포함
|
||||
|
||||
`EXEMPT ACCESS POLICY`, `SELECT ANY TABLE`, 객체 생성 `ANY` 권한은 부여하지 않는다.
|
||||
생성 SQL의 스키마 한정 여부에 영향을 받지 않도록 승인 객체에 한해
|
||||
`CB_ORDS` private synonym을 만든다.
|
||||
## 문서 지도
|
||||
|
||||
### 컨텍스트 패키지
|
||||
|
||||
`ADMIN.CB_ORDS_HANDLER_PKG`는 HTTP Authorization 값에서 Bearer 토큰을
|
||||
추출한 후 `ADMIN.HMM_ACCESS_CTX_PKG.SET_USER_BY_BEARER`를 호출한다.
|
||||
토큰 원문은 테이블이나 로그에 저장하지 않는다.
|
||||
|
||||
`CB_ORDS`에는 동일 이름의 private synonym만 제공하여 런타임 SQL에서는
|
||||
`CB_ORDS_HANDLER_PKG.SET_VPD_CONTEXT`로 호출한다. 컨텍스트 패키지 자체의
|
||||
직접 실행 권한은 런타임 계정에 노출하지 않는다.
|
||||
|
||||
`CLEAR_VPD_CONTEXT`는 HMM 컨텍스트와 client identifier를 모두 정리한다.
|
||||
유효하지 않은 인증 헤더는 컨텍스트를 먼저 지운 뒤 오류로 종료한다.
|
||||
|
||||
## 애플리케이션 설계
|
||||
|
||||
`backoffice.select-ai` 설정을 두 연결로 분리한다.
|
||||
|
||||
- 생성 연결: 기존 `db-url`, `db-username`, `db-password`, `profile`
|
||||
- 실행 연결: `runtime-db-url`, `runtime-db-username`, `runtime-db-password`
|
||||
|
||||
생성 연결은 기존 `BACKOFFICE_DB_*`를 기본값으로 사용할 수 있다. 실행 연결은
|
||||
명시적으로 설정해야 하며 생성 연결로 자동 폴백하지 않는다.
|
||||
|
||||
실행 전 다음을 검증한다.
|
||||
|
||||
1. `USER`가 `ADMIN`이 아니다.
|
||||
2. `SESSION_PRIVS`에 `EXEMPT ACCESS POLICY`가 없다.
|
||||
3. 패키지 호출 후 `HMM_ACCESS_CTX.EMPLOYEE_CODE`가 토큰 인증 결과와 일치한다.
|
||||
|
||||
하나라도 실패하면 SQL을 실행하지 않는다.
|
||||
|
||||
## 운영 설정
|
||||
|
||||
`search_hr_data`의 `executionType`을 `AGENT_TOOL`에서 `SELECT_AI`로 변경한다.
|
||||
다른 두 도구는 그대로 유지한다.
|
||||
|
||||
필수 환경값:
|
||||
|
||||
```properties
|
||||
BACKOFFICE_SELECT_AI_PROFILE=HMM_HR_DATA_GPT54_PROFILE
|
||||
BACKOFFICE_SELECT_AI_RUNTIME_DB_URL=<ADB JDBC URL>
|
||||
BACKOFFICE_SELECT_AI_RUNTIME_DB_USERNAME=CB_ORDS
|
||||
BACKOFFICE_SELECT_AI_RUNTIME_DB_PASSWORD=<secret>
|
||||
```
|
||||
|
||||
비밀번호는 Git·Redmine·로그에 기록하지 않고 서버 환경 파일에서만 관리한다.
|
||||
|
||||
## 검증 기준
|
||||
|
||||
1. `CB_ORDS`에 `EXEMPT ACCESS POLICY`가 없음을 확인한다.
|
||||
2. E1006 토큰으로 `HMM_LEAVE_BALANCES` 조회 결과의 직원은 E1006 한 명뿐이다.
|
||||
3. E1006 토큰으로 `HMM_LEAVE_REQUESTS` 조회 결과에 E1002가 없다.
|
||||
4. E1006이 E1002 휴가를 직접 요청하면 0건을 반환한다.
|
||||
5. 관리자 E1001은 권한 규칙에 따라 자기 자신과 직속 팀원 범위를 조회한다.
|
||||
6. 무효 토큰, 컨텍스트 불일치, 런타임 권한 오설정은 fail-closed 한다.
|
||||
|
||||
## 롤백
|
||||
|
||||
- 애플리케이션 환경의 `search_hr_data`를 이전 `AGENT_TOOL` 정의로 되돌리고
|
||||
이전 JAR를 재기동한다.
|
||||
- `CB_ORDS` 스키마는 즉시 삭제하지 않고 계정을 잠가 조사 가능 상태로 보존한다.
|
||||
- VPD 정책 자체와 기존 `HMM_ACCESS_CTX_PKG`는 변경하지 않는다.
|
||||
- [아키텍처와 신뢰 경계](architecture.md)
|
||||
- [적용 및 검증 절차](cookbook.md)
|
||||
- [문제 해결](troubleshooting.md)
|
||||
- [HTML 리포트 후속 처리](../hmm-html-report-mcp/README.md)
|
||||
|
||||
Reference in New Issue
Block a user