Day 13 說雲端線的稽核證據是一張 floor setting 截圖。地端線沒有這種東西,要自己產出兩樣:每一筆判定的完整記錄,以及證明規則與模型在什麼時候變成什麼版本。今天做這兩件事。
Day 5 的三層判定結構加上 Day 4 的模式標記,展開成完整 schema:
{
"ts": "2026-10-12T09:31:07.412+08:00",
"request_id": "a1b2c3",
"app_id": "credit-assistant",
"direction": "in",
"source": "user | rag | tool | memory",
"guard_mode": "normal | degraded",
"policy_version": "2026.10.02-r3",
"model_version": "shieldgemma-2b-inj@sha256:…",
"l1": {"hits": ["DL-0007", "PII-TW-ID"], "action": "escalate", "latency_ms": 0.4},
"l2": {"score": 0.62, "action": "escalate", "latency_ms": 41},
"l3": {"verdict": "block", "confidence": 0.88, "category": "goal_hijack",
"reason": "要求忽略先前指令並輸出設定", "latency_ms": 1320},
"final_action": "block",
"content_hash": "sha256:…",
"content_sample": null
}
四個設計決定:
content_sample 預設 null,只在事件調查時依授權流程從另一個受控儲存區取回。policy_version 與 model_version 每筆都帶。事後追查「那天為什麼放行」時,能對到當時的規則與模型。guard_mode 每筆都帶。Day 4 那個問題——降級的三小時發生了什麼——答案就在這個欄位的篩選結果。輸出格式用 SIEM 吃得下的:JSON lines 到 syslog 或直接寫檔讓 agent 收。欄位命名對齊常見的 schema(例如 OCSF 或 ECS 的自訂擴充),讓 SIEM 端的 parser 不用重寫。
# audit-sink 設定
output:
- type: file
path: /var/log/guard/audit.jsonl
rotate: daily
- type: syslog
host: siem.internal
port: 6514
tls: true
Day 21 把整套東西跑在斷網環境。現在要更新它——新規則、新閾值、重訓的模型、新的 eval 集。
guard-update-2026.10.02-r3/
├── manifest.json ← 版本、內容清單、每個檔案的 sha256、簽章
├── rules/ ← 完整的 YAML 規則檔(不是 diff)
├── thresholds.yaml
├── models/ ← 可選;有重訓才放,含 sha256
├── eval/ ← 對應版本的 eval 集(弱化版)與預期結果
└── CHANGELOG.md
policy_version。guardctl verify guard-update-2026.10.02-r3.tar.gz --pubkey /etc/guard/release.pub
guardctl stage guard-update-2026.10.02-r3.tar.gz
guardctl test --staged # 跑包內 eval,比對預期結果
guardctl promote --staged # 通過才切換,並寫一筆 version-change 事件進稽核日誌
promote 那一筆稽核事件,就是上面第三條 SIEM 規則要比對的東西。
Model Armor 這邊沒有更新包要管,但 Day 8 講的 filter 升版要當成同一件事處理:升版前跑 eval、記錄版本變更、進變更管理。流程一樣,只是動手的人不同。
Day 30:混合架構收尾。Model Armor 當前線、地端護欄當後盾,共用 eval 集與稽核格式——以及這 30 天的 commit 軌跡與我沒做到的事。
Instagram @aid3fend。
更多 AI 資安筆記:aid3fend.com