ふくふくHukuhuku Inc.
EP.10Democracy 12分公開: 2026-05-10

監査ログ・利用ログ・異常検知:誰が何を見たかを把握する

民主化のDay 0から監査ログを設計する。bigquery / snowflake のジョブログを長期保存DWHに複製し、PII参照・営業時間外実行・コスト爆発を検知する仕組み、月次レビュー会の進め方まで。

#監査ログ#コンプライアンス#異常検知
シェア

EP.02 のアンチパターン AP5 で書いたとおり、監査ログは民主化の Day 0 から設定しないと、後から取り戻せない。本記事では、ログの 取得 → 保存 → 検知 → レビュー の 4 段を実装目線で整理します。

1. ログの取得( ネイティブ機能)

DWHクエリ実行ログアクセス追跡
`INFORMATION_SCHEMA.JOBS_*`Cloud Audit Logs (Data Access)
`ACCOUNT_USAGE.QUERY_HISTORY``ACCOUNT_USAGE.ACCESS_HISTORY`
Redshift`STL_QUERY` / `SVL_QUERY_REPORT`Audit Logging ()

2. 長期保存 DWH に複製

ネイティブのログは 保持期間が短い ことが多い(BigQuery JOBS_BY_PROJECT は 180 日)。コンプライアンス上 3 年〜7 年保管 が必要なケースに備え、自社の DWH の専用スキーマに毎日 して長期保存します。

BigQuery: 毎日ジョブログを長期保存テーブルに UNION ALL
SQL
CREATE TABLE IF NOT EXISTS `audit.jobs_archive`PARTITION BY DATE(creation_time)OPTIONS (  partition_expiration_days = 2555  -- 7年保存)AS SELECT * FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT WHERE FALSE;
-- 日次バッチで前日分を appendINSERT INTO `audit.jobs_archive`SELECT *FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECTWHERE DATE(creation_time) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);

3. 検知ルール 5 セット

ルール 1: 高コストクエリ

前日 100 GB 超 / コスト $1超のクエリ
SQL
SELECT user_email, query, total_bytes_billed / 1e9 AS gb, creation_timeFROM `audit.jobs_archive`WHERE DATE(creation_time) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)  AND total_bytes_billed > 100 * 1e9;

ルール 2: テーブル参照

PII を含むテーブルへの非ホワイトリストアクセス
SQL
WITH pii_tables AS (  SELECT table_id FROM `audit.pii_table_registry`)SELECT user_email, query, creation_timeFROM `audit.jobs_archive` j,     UNNEST(j.referenced_tables) rtWHERE rt.table_id IN (SELECT table_id FROM pii_tables)  AND user_email NOT IN (SELECT email FROM `audit.pii_authorized_users`)  AND DATE(creation_time) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY);

ルール 3: 営業時間外実行

深夜・早朝の対話的クエリ(バッチユーザは除外)
SQL
SELECT user_email, query, creation_timeFROM `audit.jobs_archive`WHERE DATE(creation_time) = DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY)  AND EXTRACT(HOUR FROM creation_time AT TIME ZONE 'Asia/Tokyo') NOT BETWEEN 7 AND 22  AND user_email NOT IN (SELECT email FROM `audit.batch_service_accounts`);

ルール 4: 退職者アクセス

HR システムと突合して退職済みユーザのアクセス検知
SQL
SELECT j.user_email, j.creation_time, hr.termination_dateFROM `audit.jobs_archive` jJOIN `hr.terminated_users` hr ON j.user_email = hr.emailWHERE j.creation_time > hr.termination_date;-- アカウント停止漏れの検知。退職翌日には DWH から弾く運用設計が前提

ルール 5: 急激な行動変化

個人レベルでクエリ数が前月比 5 倍
SQL
WITH monthly AS (  SELECT user_email,         DATE_TRUNC(DATE(creation_time), MONTH) AS month,         COUNT(*) AS query_count  FROM `audit.jobs_archive`  GROUP BY 1, 2)SELECT cur.user_email, cur.query_count AS this_month, prev.query_count AS prev_month,       cur.query_count / prev.query_count AS ratioFROM monthly curJOIN monthly prev ON cur.user_email = prev.user_email                 AND prev.month = DATE_SUB(cur.month, INTERVAL 1 MONTH)WHERE cur.month = DATE_TRUNC(CURRENT_DATE(), MONTH)  AND cur.query_count >= 50  AND cur.query_count / prev.query_count >= 5.0;

4. 月次レビュー会の進め方

アラートの対応で終わらず、月 1 回 30 分のレビュー会「異常事象 + 改善提案」を回すと、長期的に組織の感度が上がります。

セクション時間内容
先月の異常事象サマリー5分5 ルールごとの件数、目立つケース
代表ケース掘り下げ15分1-2 件深掘りして「これは事故?正常?」を判断
改善アクション決定10分ルールの調整、教育施策、ガードレール強化など

観測すべき

  • 監査ログのカバレッジ(DWH の全クエリのうち何 % が長期保存されているか)
  • ルール 1-5 の月次件数推移(増加トレンドは要警戒)
  • 異常クエリ検知から対応までのリードタイム
  • 退職者アクセス(ルール 4)件数 = 0 を維持

次の話

EP.11 では、非エンジニアに教える『最小集合』 を全部教えなくていい。何を教えて、何を教えないか。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp