refs #744: configure OCI IAM DDS context test

This commit is contained in:
devmrko
2026-08-04 16:18:22 +09:00
parent 35782b8a50
commit cbc645466b
2 changed files with 62 additions and 5 deletions

View File

@@ -84,6 +84,8 @@ public class DdsMcpVectorSearchService {
log.info("DDS vector query completed with {} rows", rows.size());
return new DdsMcpVectorSearchResult(vector.query(), vector.embeddingMode(), rows.size(), List.copyOf(rows));
} catch (java.sql.SQLException exception) {
log.warn("DDS vector query failed: sqlState={}, errorCode={}",
exception.getSQLState(), exception.getErrorCode());
throw new AppException("DDS_QUERY_FAILED: DDS 보호 객체를 조회할 수 없습니다.");
}
});

View File

@@ -1,6 +1,6 @@
# 설계서: Windows AD 기반 DDS END USER 매핑 테스트 (#744)
> **상태**: OIDC JWT → MCP 매핑 검증 완료 · DDS data grant 검증 대기
> **상태**: OIDC JWT → MCP → OCI IAM → DDS context 및 Alice/Bob 권한 차이 검증 완료
> **최종수정**: 2026-08-04
> **추적성**: Redmine #744 · 선행 설계: [DDS MCP END USER Context](../617-dds-mcp-end-user-context/README.md)
@@ -44,6 +44,32 @@ ORA_END_USER_CONTEXT + DDS DATA GRANT / 권한 함수
`sub`는 Keycloak이 발급하는 안정적인 federated-user 식별자다. AD objectGUID는 원천 디렉터리의 감사 식별자로 유지하되, 실제 권한 키는 **검증된 JWT의 `iss + sub`**로 고정한다. UPN은 로그인 화면·감사 표시용으로 보관할 수 있지만 권한 키로 신뢰하지 않는다. `iss + sub` 조합이 유일하지 않거나, 매핑이 없거나, 사용자가 비활성이면 요청은 fail-closed로 거부한다.
### 사용자 인증과 DB 접속 신뢰의 분리
이 PoC에는 서로 다른 두 신뢰 체인이 있다. 둘을 같은 OAuth token으로 혼동하지 않는다.
```text
[업무 사용자 인증]
AD user -> Keycloak (AD LDAP 인증) -> Keycloak JWT
-> MCP validates iss + sub -> DDS_U_1 / DDS_U_2 선택
[DB 접속 신뢰]
MCP service -> OCI IAM DDS_MCP_SERVICE_TEST (client credentials)
-> database-access token -> Oracle DB
-> 선택된 local DDS END USER context attach
```
| 역할 | 현재 담당 | 하는 일 |
|---|---|---|
| AD 사용자 인증 | Keycloak | AD LDAP의 계정·비밀번호를 확인하고 Keycloak JWT를 발급 |
| 업무 사용자 식별 | MCP | 검증된 Keycloak `iss + sub`를 HMM application user와 local DDS END USER에 매핑 |
| DB 접속 애플리케이션 신뢰 | OCI IAM credential app | MCP service가 database-access token을 받아 Oracle DB에 신뢰된 application임을 증명 |
| 최종 데이터 권한 | Oracle Deep Sec | attach된 local DDS END USER의 DATA ROLE과 DATA GRANT로 행·열을 제한 |
따라서 OCI IAM credential app은 현재 AD 사용자를 직접 로그인시키지 않는다. OCI IAM은 MCP service의 database-access token 발급자이며, Oracle DB가 해당 service client를 application identity로 신뢰하게 한다. AD 사용자가 어떤 DDS END USER가 되는지는 MCP가 결정한다.
향후 OCI IAM을 사용자 인증의 중심으로 바꾸려면 Keycloak을 OCI IAM의 외부 IdP(OIDC 또는 SAML)로 federation하고, AIPF/MCP가 OCI IAM user token을 받도록 변경한다. 그 경우 Oracle DB도 OCI IAM user token의 issuer·group claim을 직접 검증할 수 있다. 현재 PoC의 local DDS END USER 매핑과는 별도의 확장 경로다.
## 4. 구현 단계
1. Windows Server에 AD DS를 설치하고 `dds.test` forest를 생성한다.
@@ -64,7 +90,7 @@ ORA_END_USER_CONTEXT + DDS DATA GRANT / 권한 함수
`dds-mcp` client는 access token audience에 `dds-mcp`를 포함한다. MCP는 Keycloak JWKS에서 JWT 서명과 `iss`, `aud`, 만료 시간을 검증한 뒤에만 위 매핑을 조회한다. 실제 `/dds/mcp/messages` 초기화 요청에 Alice JWT를 넣어 성공 응답을 확인했다.
단계는 END USER와 DATA ROLE만 게시한다. 각 DATA ROLE에는 data grant를 만들지 않았으므로 데이터 도구 호출은 여전히 **default deny**다.
초기 게시 단계에서는 END USER와 DATA ROLE만 만들고 default deny로 시작한다. 현재 테스트에서는 Alice에만 vector view SELECT data grant를 추가했고 Bob은 grant 없이 유지한다.
## 4.2 AIPF MCP 등록 값
@@ -131,7 +157,36 @@ AIPF의 **Edit MCP server** 화면에서 다음 값으로 등록한다. AIPF는
| Alice/Bob 데이터 차이 | 같은 `dds_vector_search` 호출에서 반환 행이 다름 | 대기 — OCI IAM DB service credential 및 DDS DATA GRANT 필요 |
| 미매핑 토큰 거부 | 매핑 없는 `iss + sub`의 MCP 호출이 `AUTHORIZATION_DENIED` | 구현 완료, 회귀 검증 대기 |
`dds_vector_search`는 현재 유일한 DDS MCP 도구이며 입력값은 `query`(필수), `limit`(1~100), `embeddingMode`(`DEMO` 또는 `AI`)다. 데이터 권한 차이 검증은 서비스 identity의 OCI IAM 설정과 Alice 허용/Bob 거부 DDS grant를 반영한 뒤에 완료한다.
`dds_vector_search`는 현재 유일한 DDS MCP 도구이며 입력값은 `query`(필수), `limit`(1~100), `embeddingMode`(`DEMO` 또는 `AI`)다. service identity와 Alice 허용/Bob 거부 DDS grant를 반영해 권한 차이까지 검증했다.
## 4.4 OCI IAM database-access token 구성
Keycloak access token은 MCP의 업무 사용자 식별과 `iss + sub` 매핑에만 사용한다. Oracle Deep Sec context를 열 때는 별도의 OCI IAM database-access token이 필요하다. 이 토큰은 `DDS_MCP_SERVICE_TEST` confidential client가 client credentials flow로 받고, DB는 해당 client ID를 application identity로 신뢰한다.
```text
AD user -> Keycloak token -> MCP user mapping -> local DDS END USER
\
OCI IAM DDS_MCP_SERVICE_TEST -- database-access token --> Oracle Deep Sec context
```
구성 순서는 OCI IAM database resource(`DDS_ORACLE_DB_TEST`)와 scope(`DB_ACCESS_SCOPE`) 생성, OCI IAM service client 생성, Autonomous DB의 OCI IAM identity provider/credential 등록, 그리고 `CREATE APPLICATION IDENTITY ... MAPPED TO 'IAM_OAUTH_CLIENT_ID=...'` 순서다. 이 단계는 Autonomous DB의 외부 인증 구성을 변경할 수 있으므로 기존 설정을 먼저 조회하고 Redmine에 기록한다.
### 적용 결과와 검증
| 구성 요소 | 적용값 | 상태 |
|---|---|---|
| OCI IAM database resource | `DDS_ORACLE_DB_TEST` / `DB_ACCESS_SCOPE` | 적용 완료 |
| OCI IAM service client | `DDS_MCP_SERVICE_TEST`, client credentials만 허용 | 적용 완료 |
| Autonomous DB identity provider | `OCI_IAM`, database resource app ID와 OCI IAM domain URL 등록 | 적용 완료 |
| DB signing-key credential | `OCI_IAM_DOMAIN_DB_CRED$` | 적용 완료 |
| DB application identity | `DDS_MCP_SERVICE_TEST` → OCI IAM service client ID | 적용 완료 |
| HMM DDS MCP runtime | client ID·secret·scope를 권한 제한 환경 파일로 로드 | 적용 완료 |
| Alice data grant | `DDS_U_1_ROLE` → `CB_VECTOR_SEARCH_DOCUMENTS` SELECT | 적용 완료 |
| Bob data grant | 없음 | default deny |
database-access token은 `resource_app_id`, `tenant_iss`, scope가 DB identity provider 등록과 모두 일치해야 한다. OCI IAM domain URL은 token의 issuer와 같은 정규형(`:443` 포함)을 사용했다. 포트가 빠진 URL로 등록하면 Oracle이 `ORA-52602`(invalid database access token)으로 context 사용을 거부한다.
2026-08-04 검증 결과는 다음과 같다. 동일한 `dds_vector_search` 호출에서 Alice는 DDS context attach 후 query가 성공했고, Bob은 data grant가 없어 보호 객체 조회가 거부됐다. 현재 HMM knowledge chunk 데이터가 없으므로 Alice의 성공 응답 행 수는 `0`이다. 이는 권한 허용과 데이터 존재 여부를 구분한 결과다.
## 5. Entra ID로 전환할 때
@@ -142,7 +197,7 @@ Entra tenant가 확보되면 AD DS/bridge 테스트에서 확인한 `issuer + im
- [x] `dds.test` AD forest와 두 테스트 사용자가 생성되었다.
- [x] Keycloak LDAP bridge가 HTTPS OIDC JWT를 발급하고 각 사용자가 서로 다른 안정 subject를 가진다.
- [x] MCP가 JWT signature/issuer/audience를 검증하고 `issuer + sub` 매핑을 해석한다.
- [ ] subject 매핑을 통해 각 요청에 대응하는 DDS END USER context만 attach된다.
- [ ] 서로 다른 권한의 동일 MCP 호출에서 데이터 행/열 결과가 달라진다.
- [x] subject 매핑을 통해 각 요청에 대응하는 DDS END USER context만 attach된다.
- [x] 서로 다른 권한의 동일 MCP 호출에서 데이터 행/열 결과가 달라진다.
- [ ] 미매핑·만료·issuer/audience 불일치 요청은 데이터 접근 전에 거부된다.
- [ ] 종료 시 테스트 VM과 전용 네트워크 리소스의 정리 여부 및 비용 상태를 Redmine에 기록한다.