Oracle Active Data Guard 環境における ReadOnly Standby の監査ログの取り扱い

# はじめに
## Oracle Active Data Guardとは
[Oracle Data Guard](https://docs.oracle.com/en/database/oracle/oracle-database/23/sbydb/oracle-data-guard-concepts.html) を用いると Oracle Database をリアルタイムに複製することが可能になり高可用性を担保できます。またOracle Active Data Guard の機能を利用すると複製先のスタンバイDBを ReadOnly で参照することが可能になります。

この機能は DR 観点だけでなく参照を分散させることで、パフォーマンスの向上も期待できます。

## 統合監査とは
[Oracle 統合監査](https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/introduction-to-auditing.html#GUID-16E8E421-CFCE-4584-B09B-88F01D51B152)を用いると Oracle Database 内の様々なアクション(SQLやバックアップ、DataPumpなど)に対して柔軟に監査設定を行うことができます。

# 本記事の目的
Database によっては統合監査が必要になることがあります。そして Database が Oracle Active Data Guard を用いて ReadOnly スタンバイを持っていたら、そちらの監査も必要となります。

ただ、 ReadOnly スタンバイは当然書き込みができないので監査ログは spillover file という実ファイルに書き出されます。そこで本記事ではこの spillover file の取り扱いについての検証結果を共有したいと思っています。

# 検証結果
## 前提
- spillover file は `$ORACLE_BASE/audit/<ORACLE_SID>` に格納される
  - PDB の場合は上記のディレクトリ以下に GUID でディレクトリが作成され、そこに出力される
  - ファイル名は `ora_audit_XXXX.bin` という形になっている(XXXXの桁数は未定)
- 検証する DB のバージョンは19c

## 検証1. spillover fileを OS コマンドで確認できるか
実際に出力された spillover file を OS コマンド(strings)で確認できるか見てみました
- ここでは結果を [UNIFIED_AUDIT_TRAIL](https://docs.oracle.com/cd/G11854_01/refrn/UNIFIED_AUDIT_TRAIL.html) 表のカラム名でマスクしています
- 実際にはバイナリ形式で保存されており、暗号化はされていません
```bash
$ strings ora_audit_1234.bin
ANG Spillover Audit File
ORAAUDNG
<OS_USERNAME>
<USERHOST>
<TERMINAL>
<AUTHENTICATION_TYPE>
<DBUSERNAME>
<CLIENT_PROGRAM_NAME>
<OS_PROCESS>
<OBJECT_SCHEMA>
<OBJECT_NAME>
<SQL_TEXT>
<UNIFIED_AUDIT_POLICIES>
<CURRENT_USER>
ORAAUDNG
...次の監査ログ
```

改行はちょっと特殊なことがあるにしても、簡易的な確認でしたらこのファイルを直接確認するのも手軽で簡単かと考えられます。

## 検証2. プライマリ側に持っていって確認できるか
出力された spillover file をプライマリDBの `$ORACLE_BASE/audit/<ORACLE_SID>` に格納して確認できるか試しました。

```sql
-- GUID確認
SQL> SELECT name, guid FROM v$pdbs ORDER BY 1;

NAME       GUID
---------- --------------------------------
TESTPDB    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

-- 適当な spillover file をプライマリの `$ORACLE_BASE/audit/<ORACLE_SID>/<GUID>` に配置
-- プライマリでみられるか確認
SQL> SET LINE 300 tab off
COL ACTION_NAME FORMAT A15
COL DBUSERNAME FORMAT A20
COL OBJECT_SCHEMA FORMAT A20
COL OBJECT_NAME FORMAT A20
COL EVENT_TIMESTAMP FORMAT a30
select dbusername, action_name, object_schema, object_name, xs_sessionid, TO_CHAR(EVENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') from unified_audit_trail where object_name = 'DUMMY' and action_name = 'SELECT';

DBUSERNAME           ACTION_NAME     OBJECT_SCHEMA        OBJECT_NAME          XS_SESSIONID                                                       EVENT_TIMESTAMP
-------------------- --------------- -------------------- -------------------- ------------------------------------------------------------------ ------------------------------
DUMMY                SELECT          DUMMY                DUMMY                000000000000000000000000000000000000000000000000000000000000000000 25-02-27 12:49:11.733615
```

この時 `XS_SESSIONID` が0埋めされているのがスタンバイ側のものなので、プライマリから確認できることがわかりました([参考](https://support.oracle.com/epmos/faces/DocContentDisplay?id=2714585.1))。
このように単純なコピーでプライマリで確認できるので `DBMS_AUDIT_MGMT.LOAD_UNIFIED_AUDIT_FILES` あたりで読み込んでよしなにすればいいと考えられます。

## 検証3. 適当に作成したDBで確認できるか
出力された spillover file を全く関係のない DB に持っていって確認ができるか試してみました。

今回はDBを docker で作成していますが、オンプレの DB でも問題ないかと思います。

- 統合監査を有効にした DB 作成
```bash
$ mkdir unified_audit && cd unified_audit

## startupファイル作成
$ cat << 'EOF' > 01_stop_db.sh
bash /home/oracle/shutDown.sh immediate
EOF
$ cat << 'EOF' > 02_enable_unified_audit.sh
cd $ORACLE_HOME/rdbms/lib
make -f ins_rdbms.mk uniaud_on ioracle ORACLE_HOME=$ORACLE_HOME
mkdir -p /opt/oracle/audit; chown -R oracle:oinstall /opt/oracle/audit
EOF
$ cat << 'EOF' > 03_start_db.sh
bash /home/oracle/startUp.sh
EOF
$ cat << 'EOF' > 04_check_db.sql
SELECT VALUE FROM V$OPTION WHERE PARAMETER = 'Unified Auditing' ORDER BY 1;
EOF

## compose.yaml作成
$ cat << 'EOF' > compose.yaml
services:
  oracle-db:
    image: container-registry.oracle.com/database/enterprise:19.3.0.0
    container_name: oracle-db
    ports:
      - "1521:1521"
    environment:
      - ORACLE_PWD=Welcome123##
      - ENABLE_ARCHIVELOG=true
    volumes:
      - ./01_stop_db.sh:/opt/oracle/scripts/startup/01_stop_db.sh
      - ./02_enable_unified_audit.sh:/opt/oracle/scripts/startup/02_enable_unified_audit.sh
      - ./03_start_db.sh:/opt/oracle/scripts/startup/03_start_db.sh
      - ./04_check_db.sql:/opt/oracle/scripts/startup/04_check_db.sql
    restart: always
EOF

## 起動
$ docker compose up -d
[+] Running 2/2
 ✔ Network unified_audit_default  Created                                                                                                                                                0.1s
 ✔ Container oracle-db            Started   

$ docker compose logs oracle-db -f
...snip...
oracle-db  | The Oracle base remains unchanged with value /opt/oracle
oracle-db  | #########################
oracle-db  | DATABASE IS READY TO USE!
oracle-db  | #########################
oracle-db  |
oracle-db  | Executing user defined scripts
oracle-db  | /opt/oracle/runUserScripts.sh: running /opt/oracle/scripts/startup/01_stop_db.sh
oracle-db  | Performing shutdown immediate
oracle-db  |
oracle-db  | SQL*Plus: Release 19.0.0.0.0 - Production on Thu Feb 27 06:28:35 2025
...snip...
oracle-db  |
oracle-db  | /opt/oracle/runUserScripts.sh: running /opt/oracle/scripts/startup/04_check_db.sql
oracle-db  |
oracle-db  | VALUE
oracle-db  | ----------------------------------------------------------------
oracle-db  | TRUE ← ★いけた
```

- 監査ファイル渡してみて確認
```bash
## spillover file 置く
$ sudo chown 54321:54321 ora_audit_1234.bin
$ sudo chmod 644 ora_audit_1234.bin
$ docker compose cp ora_audit_1234.bin oracle-db:/opt/oracle/audit/ORCLCDB/
[+] Copying 1/0
 ✔ oracle-db copy ora_audit_1234.bin to oracle-db:/opt/oracle/audit/ORCLCDB/ Copied

## docker container にアクセスして確認
$ docker compose exec oracle-db bash
bash-4.2$ chmod 600 $ORACLE_BASE/audit/ORCLCDB/ora_audit_0197.bin
bash-4.2$ ls -l $ORACLE_BASE/audit/ORCLCDB/
total 20
-rw------- 1 oracle oinstall 1024 Feb 27 06:29 ora_audit_00.bin
-rw------- 1 oracle oinstall 1536 Feb 27 05:14 ora_audit_1234.bin
-rw------- 1 oracle oinstall 1024 Feb 27 06:29 ora_audit_03752.bin
-rw------- 1 oracle oinstall 5120 Feb 27 06:29 ora_audit_0849.bin
bash-4.2$ sqlplus -S / as sysdba << 'SQL'
> SET LINE 300 tab off
> COL ACTION_NAME FORMAT A15
> COL DBUSERNAME FORMAT A20
> COL OBJECT_SCHEMA FORMAT A20
> COL OBJECT_NAME FORMAT A20
> COL EVENT_TIMESTAMP FORMAT a30
> select dbusername, action_name, object_schema, object_name, xs_sessionid, TO_CHAR(EVENT_TIMESTAMP, 'YYYY-MM-DD HH24:MI:SS') from unified_audit_trail where object_name = 'DUMMY' and action_name = 'SELECT';
> SQL
 
DBUSERNAME           ACTION_NAME     OBJECT_SCHEMA        OBJECT_NAME          XS_SESSIONID                                                       EVENT_TIMESTAMP
-------------------- --------------- -------------------- -------------------- ------------------------------------------------------------------ ------------------------------
DUMMY                SELECT          DUMMY                DUMMY                000000000000000000000000000000000000000000000000000000000000000000 25-02-27 12:49:11.733615
```

このように unified_audit_trail からの確認が可能なことがわかりました。

既存のDBで直ぐに確認するのが難しそうでしたら、この方法は手軽で良いかと考えています。

# まとめ
以下の3つの方法が確認方法としては可能でした
1. OS コマンド(`strings`)で確認
2. プライマリ DB で確認
3. 全く関係のない DB で確認( docker で構築したDBでも可能)

簡易的に確認するだけだったら 1 or 3 で十分な場面もあるかと考えられます。

他のシステムへの連携などを考えるとプライマリなどの監査ログとまとめて扱える 2 の方法がシンプルで良いと考えられます