Document Oracle FGA audit verification

This commit is contained in:
devmrko
2026-07-14 14:26:50 +09:00
parent a3ba76f2f4
commit 1f6d97440f

View File

@@ -327,3 +327,189 @@ Authorization: Bearer <current-user-vpd-token>
- 배포 서버 원본 소스 기준 Python 3.11.15 `py_compile` 통과 - 배포 서버 원본 소스 기준 Python 3.11.15 `py_compile` 통과
- 백오피스 기존 회귀 `mvn -q test` 통과 - 백오피스 기존 회귀 `mvn -q test` 통과
- 저장소 문서/스냅샷 커밋 및 `gitea/main` push 완료 - 저장소 문서/스냅샷 커밋 및 `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_DB_PASSWORD>"@${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_<object_id>` 형태의 정책을 만들도록 작성되어 있으나, 현행 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 = <probe request id>`, `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`에 맞춰 등록하는 정리가 필요하다.