Files
vpd-permission-poc/docs/design/744-windows-ad-dds-end-user-mapping/README.md
2026-08-04 14:24:07 +09:00

82 lines
5.6 KiB
Markdown

# 설계서: Windows AD 기반 DDS END USER 매핑 테스트 (#744)
> **상태**: OIDC JWT → MCP 매핑 검증 완료 · DDS data grant 검증 대기
> **최종수정**: 2026-08-04
> **추적성**: Redmine #744 · 선행 설계: [DDS MCP END USER Context](../617-dds-mcp-end-user-context/README.md)
## 1. 목적과 범위
Microsoft Entra ID 테넌트가 아직 준비되지 않은 상황에서, OCI 격리 네트워크의 Windows Server AD DS를 이용해 업무 사용자 디렉터리와 DDS END USER 매핑을 먼저 검증한다.
이 환경은 **Microsoft Entra access token을 Oracle DB가 직접 검증하는 환경이 아니다.** AD DS는 사용자·그룹·UPN을 제공하고, 이후 Keycloak 또는 별도 검증 서비스가 AD LDAP을 기반으로 발급·검증한 토큰의 안정적인 subject를 MCP의 업무 사용자로 해석한다. Entra tenant와 app registration이 준비되면 OIDC issuer/audience/JWKS 검증 경로로 교체 또는 병행한다.
## 2. 격리 인프라
| 항목 | 구성 |
|---|---|
| 네트워크 | `handson-vcn`의 전용 `10.0.2.0/28` public subnet |
| Windows VM | `hmm-ad-dss-test-isolated`, Windows Server 2022, 2 OCPU / 16 GB |
| 관리 접근 | RDP TCP/3389은 작업자 공인 IP 한 곳에만 NSG로 허용 |
| OIDC HTTPS | `https://ad.cloud-handson.com` (Caddy TLS reverse proxy → Keycloak) |
| 서브넷 보안 목록 | 인바운드 전부 차단, Windows Update 및 테스트용 아웃바운드만 허용 |
| 도메인 | `dds.test` (AD DS forest/domain) |
이 VM은 테스트 전용이다. 기존 공유 public subnet의 NAT 경로를 변경하지 않으며, 비용 발생 리소스이므로 검증 종료 뒤 중지 또는 삭제를 결정한다.
## 3. 식별자와 권한 흐름
```text
AD 사용자 (UPN: alice@dds.test, objectGUID)
│ LDAP / OIDC bridge
검증된 Bearer claims
iss, aud, exp, sub = 불변 외부 subject
│ MCP bearer authenticator
CB_EXTERNAL_IDENTITY_BINDING
issuer + subject -> CB_APP_USER.user_id
CB_DDS_END_USER_MAP
user_id -> DDS_U_<user_id> local END USER
ORA_END_USER_CONTEXT + DDS DATA GRANT / 권한 함수
```
`sub`는 Keycloak이 발급하는 안정적인 federated-user 식별자다. AD objectGUID는 원천 디렉터리의 감사 식별자로 유지하되, 실제 권한 키는 **검증된 JWT의 `iss + sub`**로 고정한다. UPN은 로그인 화면·감사 표시용으로 보관할 수 있지만 권한 키로 신뢰하지 않는다. `iss + sub` 조합이 유일하지 않거나, 매핑이 없거나, 사용자가 비활성이면 요청은 fail-closed로 거부한다.
## 4. 구현 단계
1. Windows Server에 AD DS를 설치하고 `dds.test` forest를 생성한다.
2. 테스트 사용자 `dds-alice`, `dds-bob`와 권한 그룹을 만들고, LDAP 조회와 인증을 확인한다.
3. AD LDAP과 연동한 OIDC bridge(예: Keycloak)를 별도 서비스로 구성한다. bridge가 내는 JWT의 `iss`, `aud`, `exp`, JWKS 서명을 MCP가 검증한다.
4. `issuer + sub`에서 `CB_APP_USER``CB_DDS_END_USER_MAP`을 해석하도록 백오피스/DB 매핑을 추가한다.
5. alice/bob의 서로 다른 `DDS_U_*` context에서 동일 MCP tool 호출 결과가 권한에 따라 달라지는지 검증한다.
6. 매핑 누락, 만료 토큰, 다른 issuer/audience, 비활성 계정은 모두 거부되는 regression을 추가한다.
## 4.1 현재 테스트 bridge
`database/adb/47_dds_ad_identity_test_setup.sql`은 HMM DB의 기존 업무 사용자 원천을 변경하지 않는다. 스크립트가 만든 `CB_EXTERNAL_IDENTITY_BINDING`에는 최종 OIDC issuer와 Keycloak이 실제로 발급한 subject만 보관한다.
| AD 사용자 | OIDC issuer | JWT `sub` | HMM application user | DDS END USER |
|---|---|---|---:|---|
| `dds-alice` | `https://ad.cloud-handson.com/realms/dds-test` | `11cf09c9-4713-4145-85cd-e3397d4a2405` | 1 | `DDS_U_1` |
| `dds-bob` | `https://ad.cloud-handson.com/realms/dds-test` | `d9610e18-a327-4dda-9496-69e5a2067460` | 2 | `DDS_U_2` |
`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**다.
## 5. Entra ID로 전환할 때
Entra tenant가 확보되면 AD DS/bridge 테스트에서 확인한 `issuer + immutable subject -> CB_APP_USER -> DDS END USER` 계약은 유지한다. 바뀌는 부분은 token issuer와 JWKS 검증 설정뿐이다. Entra의 claim 이름(`oid`, `sub`, `preferred_username` 등)은 실제 발급 토큰을 확인한 뒤 결정하며, `sub` 단독이 아니라 tenant/issuer 경계를 반드시 포함한다.
## 6. 완료 기준
- [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 호출에서 데이터 행/열 결과가 달라진다.
- [ ] 미매핑·만료·issuer/audience 불일치 요청은 데이터 접근 전에 거부된다.
- [ ] 종료 시 테스트 VM과 전용 네트워크 리소스의 정리 여부 및 비용 상태를 Redmine에 기록한다.