From 1f6d97440f0323268f9058cbae4db66e3d5c120e Mon Sep 17 00:00:00 2001 From: devmrko Date: Tue, 14 Jul 2026 14:26:50 +0900 Subject: [PATCH] Document Oracle FGA audit verification --- .../README.md | 186 ++++++++++++++++++ 1 file changed, 186 insertions(+) diff --git a/docs/design/654-poc4-mcp-discovery-streamable-http/README.md b/docs/design/654-poc4-mcp-discovery-streamable-http/README.md index cd2ad18..44f3e62 100644 --- a/docs/design/654-poc4-mcp-discovery-streamable-http/README.md +++ b/docs/design/654-poc4-mcp-discovery-streamable-http/README.md @@ -327,3 +327,189 @@ Authorization: Bearer - 배포 서버 원본 소스 기준 Python 3.11.15 `py_compile` 통과 - 백오피스 기존 회귀 `mvn -q test` 통과 - 저장소 문서/스냅샷 커밋 및 `gitea/main` push 완료 + +## 15. 2026-07-14 Oracle FGA 감사로그 적용 확인 + +### 15.1 확인 목적 + +PoC4 MCP AI Console과 VPD 백오피스는 사용자별 Bearer token으로 정형 데이터를 조회한다. 이때 Oracle VPD는 행 접근 predicate를 적용하고, ASO/Data Redaction은 민감 컬럼 원문/마스킹을 결정한다. FGA는 그 결과로 실행된 SELECT를 DB 감사 증적으로 남기는 역할이다. + +이번 확인은 “FGA가 설계상 있어야 한다”가 아니라, 배포 서버가 바라보는 실제 ADB에 `DBMS_FGA` 정책과 감사 이벤트가 존재하는지 SQLcl로 직접 확인한 결과다. + +### 15.2 SQLcl 확인 환경 + +배포 서버에서 아래 기준으로 접속했다. 비밀번호와 wallet password는 출력하거나 저장소에 기록하지 않는다. + +| 항목 | 값 | +|---|---| +| 접속 서버 | `161.33.6.45` | +| DB 접속 env | `/home/opc/kbmcp/.env` | +| wallet directory | `/home/opc/wallet/kbaipoc` | +| SQLcl | `/home/opc/tools/sqlcl/bin/sql` | +| 접속 DB 사용자 | `ADMIN` | +| 감사 대상 schema | `POC_2` | + +SQLcl 실행 구조는 다음과 같다. + +```bash +set -a +. /home/opc/kbmcp/.env +set +a +export TNS_ADMIN="${ORACLE_WALLET_DIR:-/home/opc/wallet/kbaipoc}" + +/home/opc/tools/sqlcl/bin/sql -s /nolog +connect ${ORACLE_DB_USER}/""@${ORACLE_DSN} +``` + +### 15.3 적용된 FGA 정책 + +`DBA_AUDIT_POLICIES`와 `DBA_AUDIT_POLICY_COLUMNS`를 SQLcl로 조회한 결과, `POC_2` schema에는 FGA SELECT 정책 4건이 활성화되어 있다. + +| 객체 | 정책명 | 감사 컬럼 | 활성 | SELECT 감사 | +|---|---|---|---|---| +| `KB_CLAIMS` | `KB_FGA_CLAIMS_AMT` | `CLAIM_AMT` | `YES` | `YES` | +| `KB_CLAIMS` | `KB_FGA_CLAIMS_PAID_AMT` | `PAID_AMT` | `YES` | `YES` | +| `KB_CUSTOMERS` | `KB_FGA_CUSTOMERS_PII` | `CUST_NM`, `RRN_MASKED` | `YES` | `YES` | +| `KB_EXTERNAL_HOLDINGS` | `KB_FGA_EXT_HOLDINGS` | `EXT_INSURER`, `EXT_PRODUCT_GRP`, `EXT_PRODUCT_TYPE` | `YES` | `YES` | + +요약 쿼리 결과: + +```text +POLICY_COUNT = 4 +ENABLED_COUNT = 4 +SELECT_POLICY_COUNT = 4 +``` + +현재 DB의 정책명 계열은 모두 `KB_FGA_*`다. 저장소의 범용 적용 스크립트 `sql/adb/42_agent_ords_fga_execution_audit.sql`은 `CB_VPD_EXEC_AUDIT_` 형태의 정책을 만들도록 작성되어 있으나, 현행 ADB에는 이 계열이 아니라 `KB_FGA_*` 정책이 적용되어 있다. 따라서 운영 확인 시에는 “스크립트 파일명/예상명”보다 `DBA_AUDIT_POLICIES`의 실제 정책명을 기준으로 봐야 한다. + +### 15.4 감사 이벤트 저장 위치 + +ADB 현행 환경에서는 FGA 이벤트가 `UNIFIED_AUDIT_TRAIL`에 기록된다. + +SQLcl 확인 결과 `UNIFIED_AUDIT_TRAIL`에는 FGA 조회에 필요한 아래 컬럼이 있다. + +| 컬럼 | 용도 | +|---|---| +| `EVENT_TIMESTAMP`, `EVENT_TIMESTAMP_UTC` | 감사 발생 시각 | +| `DBUSERNAME` | SQL을 실행한 DB 사용자 | +| `CLIENT_IDENTIFIER` | ORDS/MCP 요청 식별자 | +| `OBJECT_SCHEMA`, `OBJECT_NAME` | 감사 대상 객체 | +| `ACTION_NAME` | 실행 작업. 현재는 `SELECT` | +| `FGA_POLICY_NAME` | 트리거된 FGA 정책명 | +| `SQL_TEXT` | DB가 감사한 실제 SQL | +| `RLS_INFO` | Oracle이 기록한 VPD 정책명과 predicate | +| `RETURN_CODE` | 실행 결과 코드. `0`이면 성공 | + +최근 7일 FGA 이벤트 요약: + +```text +UNIFIED_AUDIT_TRAIL event_count_7d = 525 +oldest_event = 2026-07-09 06:15:04 +newest_event = 2026-07-14 05:09:14 +``` + +반면 `DBA_FGA_AUDIT_TRAIL` 기준 최근 7일 이벤트는 0건이었다. + +```text +DBA_FGA_AUDIT_TRAIL event_count_7d = 0 +``` + +해석은 다음과 같다. + +- FGA가 미적용이라는 뜻이 아니다. +- 현재 ADB에서는 FGA 감사 행이 Unified Audit Trail에 기록되고 있다. +- 앱 구현도 이 전제를 반영해 `UNIFIED_AUDIT_TRAIL`을 먼저 조회하고, 실패할 때 `DBA_FGA_AUDIT_TRAIL`로 fallback한다. + +### 15.5 최근 감사 이벤트 예시 + +최근 이벤트는 모두 `CB_ORDS` DB 사용자로 기록되었고, `CLIENT_IDENTIFIER`에는 요청별 UUID가 들어가 있었다. 이 값으로 특정 ORDS/MCP 요청과 DB 감사 행을 연결한다. + +확인된 최근 이벤트 예: + +| 발생시각(KST) | DB 사용자 | 객체 | 정책 | 작업 | 결과 | +|---|---|---|---|---|---| +| 2026-07-14 14:09:14 | `CB_ORDS` | `KB_EXTERNAL_HOLDINGS` | `KB_FGA_EXT_HOLDINGS` | `SELECT` | `0` | +| 2026-07-14 14:06:31 | `CB_ORDS` | `KB_EXTERNAL_HOLDINGS` | `KB_FGA_EXT_HOLDINGS` | `SELECT` | `0` | +| 2026-07-14 14:06:31 | `CB_ORDS` | `KB_CLAIMS` | `KB_FGA_CLAIMS_AMT` | `SELECT` | `0` | +| 2026-07-14 14:06:31 | `CB_ORDS` | `KB_CLAIMS` | `KB_FGA_CLAIMS_PAID_AMT` | `SELECT` | `0` | + +`RLS_INFO`도 같이 기록된다. 예를 들어 `KB_CLAIMS` 이벤트에는 `KB_KB_CLAIMS_ROW_POLICY`와 해당 VPD predicate가 포함되어 있었다. 즉 FGA는 “어떤 SQL이 실행됐는가”뿐 아니라 “그 SQL에 어떤 VPD 정책이 붙었는가”를 사후 증적으로 확인하는 데 사용할 수 있다. + +### 15.6 소스 구현과 화면 연결 + +PoC4 스냅샷의 `apps/poc4/mcp_discovery_ui.py`는 감사로그 탭에서 다음 두 쿼리를 사용한다. + +| 함수 | 조회 대상 | 역할 | +|---|---|---| +| `_load_fga_inventory()` | `DBA_AUDIT_POLICIES`, `DBA_AUDIT_POLICY_COLUMNS`, `POC_2.KB_SECURITY_POLICY_CATALOG` | 현재 활성 FGA 정책과 관리 카탈로그를 표시 | +| `_load_fga_audit_events()` | `UNIFIED_AUDIT_TRAIL` | 최근 FGA 이벤트, SQL 원문, 사용자, 정책명, 결과 코드를 표시 | + +VPD 백오피스의 검증 화면은 `OrdsProbeService`에서 다음 순서로 특정 요청의 FGA 증적을 찾는다. + +1. `UNIFIED_AUDIT_TRAIL` +2. `DBA_FGA_AUDIT_TRAIL` + +조회 조건은 객체 owner/name, `ACTION_NAME = 'SELECT'`, `CLIENT_IDENTIFIER = `, `FGA_POLICY_NAME IS NOT NULL`이다. + +따라서 운영자가 봐야 할 기준은 다음이다. + +- “정책이 적용됐는가?” → `DBA_AUDIT_POLICIES.ENABLED = YES` +- “민감 컬럼 접근이 실제 발생했는가?” → `UNIFIED_AUDIT_TRAIL.FGA_POLICY_NAME IS NOT NULL` +- “어떤 VPD predicate가 붙었는가?” → `UNIFIED_AUDIT_TRAIL.RLS_INFO` +- “어떤 요청과 연결되는가?” → `CLIENT_IDENTIFIER` + +### 15.7 확인용 SQL + +운영 확인 시 사용할 수 있는 최소 SQL은 다음과 같다. + +```sql +SELECT policy.object_schema, + policy.object_name, + policy.policy_name, + policy.enabled, + policy.sel, + LISTAGG(policy_columns.policy_column, ',') WITHIN GROUP ( + ORDER BY policy_columns.policy_column + ) AS policy_columns +FROM dba_audit_policies policy +LEFT JOIN dba_audit_policy_columns policy_columns + ON policy_columns.object_schema = policy.object_schema + AND policy_columns.object_name = policy.object_name + AND policy_columns.policy_name = policy.policy_name +WHERE policy.object_schema = 'POC_2' +GROUP BY policy.object_schema, + policy.object_name, + policy.policy_name, + policy.enabled, + policy.sel +ORDER BY policy.object_name, policy.policy_name; +``` + +```sql +SELECT * +FROM ( + SELECT TO_CHAR( + event_timestamp AT TIME ZONE 'Asia/Seoul', + 'YYYY-MM-DD HH24:MI:SS' + ) AS event_time, + dbusername, + client_identifier, + object_name, + fga_policy_name, + action_name, + return_code, + DBMS_LOB.SUBSTR(sql_text, 500, 1) AS sql_text_sample, + DBMS_LOB.SUBSTR(rls_info, 500, 1) AS rls_info_sample + FROM unified_audit_trail + WHERE object_schema = 'POC_2' + AND fga_policy_name IS NOT NULL + ORDER BY event_timestamp DESC +) +WHERE ROWNUM <= 20; +``` + +### 15.8 후속 정리 필요사항 + +현재 FGA 정책 자체는 정상 적용되어 있고 감사 이벤트도 쌓이고 있다. 다만 관리 카탈로그 `POC_2.KB_SECURITY_POLICY_CATALOG`에는 `KB_CUSTOMERS`, `KB_EXTERNAL_HOLDINGS` 중심의 5개 row만 확인되며, 실제 활성 정책에 있는 `KB_CLAIMS.CLAIM_AMT`, `KB_CLAIMS.PAID_AMT` 정책 메타데이터는 카탈로그 조회 결과에 없었다. + +따라서 화면이 `DBA_AUDIT_POLICIES`를 직접 조회하는 현재 구조에서는 정책이 보이지만, 카탈로그를 운영 기준으로 삼으려면 `KB_CLAIMS` FGA 메타데이터도 `KB_SECURITY_POLICY_CATALOG`에 맞춰 등록하는 정리가 필요하다.