Document Oracle FGA audit verification
This commit is contained in:
@@ -327,3 +327,189 @@ Authorization: Bearer <current-user-vpd-token>
|
||||
- 배포 서버 원본 소스 기준 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_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`에 맞춰 등록하는 정리가 필요하다.
|
||||
|
||||
Reference in New Issue
Block a user