操作の記録と異常の検知/ Audit Logs & Alerting
すべての操作を残して後から辿れるようにし、システムの異常に気づいて手を打つ仕組み
「あのファイルは誰がいつ差し替えたのか」「取引先のどなたが受け取ったのか」「日次の処理が黙って失敗していないか」。どれも、起きた時点で記録されていなければ後から作れません。松葉では、利用者・社外の相手・システムのすべての操作を 1 本の追記専用の記録に集め、それを Box のメンバーには業務の履歴として、システム管理者には全社の監査ログとして見せています。あわせて、サーバの死活監視では見えない「業務が詰まっている」状態をアプリ自身が 29 種のアラートとして判定し、1 つの運用画面に集約しました。まずは実際の動きをご覧ください。
matsuba-api)は名前と役割を併記します。各章へは目次から移動できます。通読の目安は 20〜25 分です。
デモンストレーションDemonstration
2 本用意しました。1 本目は Box のメンバーが自分たちの操作履歴を辿るところ、2 本目はシステム管理者がアラートに気づいて手を打つところです。この先の各章は、ここで起きていることを分解してご説明します。
操作の記録と異常の検知の全体構成System Map
この仕組みを構成する稼働リソース(サービス・バッチ・テーブル・バケット)と、その間を流れるものを一枚にまとめました。①記録の蓄積 → ②3 つの読み口 → ③長期保管、そして独立した ④異常の検知と運用、の 4 区画で読めます。②の 3 本はどれも同じ 1 本の記録を読んでいて、書き込み経路は 1 つしかありません。各要素の詳しい役割は、この先の各章で扱います。
色の役割:teal の枠は処理サービスと主要な経路、金茶の枠は保管と社外に関わるもの、白地は補助的な要素です。区画 ③ の対象は区画 ① の audit_logs そのもので、25 ヶ月を超えた月だけが audit_archive スキーマへ移ります。区画 ② の「退避分の取り出し」は区画 ③ が置いたオブジェクトを読みます。区画 ④ は独立した仕組みですが、運用の操作そのものは区画 ① へ記録されて戻ります。
概要Overview
何を解決したか
取引先とのやり取りをメールと紙から Web に移すと、それまで受信箱と稟議書に散っていた「誰がいつ何をしたか」が、原理的には 1 か所に集められるようになります。ただし集める仕組みを作らなければ集まりません。松葉では、ファイルのアップロード・差し替え・削除・復元、フォルダの操作、メンバーの追加とロール変更、共有リンクとファイルリクエストの発行と無効化、コメント、Box の設定変更、そしてダウンロードとプレビューまで、163 種類の操作を発生した時点で記録しています。
もう 1 つの問題は、システム側の異常が誰にも届かないことでした。サーバが落ちればクラウドの監視が拾いますが、実際に困るのは「サーバは動いているのに通知メールだけ出ていない」「日次の同期が 2 日続けて失敗している」「ウイルス検査が詰まっている」といった状態です。これらはアプリの中の数字を見なければ判定できません。松葉では、アプリ自身が 29 種類の事象を判定し、1 つの運用画面に集約しています。
1 本の記録を 3 つの読み口で出す
記録を保存するテーブルは 1 本だけです。表示用に別のテーブルを設けると、同じ出来事を 2 か所へ書くことになり、片方だけ書けたときに食い違いが残ります。そこで書き込み経路を 1 本に固定し、読む側を 3 つに分けました。
| 読み口 | 見られる人 | 見えるもの | 実現手段 |
|---|---|---|---|
| 全社の監査ログ | システム管理者 | 163 種すべて。IP・端末情報・操作の詳細まで含む生のデータ | 専用の API 8 端点。理由の入力と回数の制限つき |
| Box のアクティビティ | Box のメンバー | 業務の状態を変える 48 種。ダウンロードなどの 4 種は Owner のみ。内部情報は含まない | PostgreSQL の SECURITY DEFINER 関数 1 本が、権限の判定と項目の絞り込みを兼ねる |
| 退避分の取り出し | システム管理者 | 2 年を超えてデータベースから出た月の記録(gzip 圧縮した CSV) | Cloud Storage の Archive クラスへ 15 分の署名付き URL を直接発行 |
記録が消せないことを、どうやって担保するか
監査ログの価値は「都合の悪い行を後から消せない」ことに依存します。松葉ではこれをアプリの実装で守るのではなく、データベースの権限設計で守っています。追加は誰でもできますが、更新と削除の許可規則そのものを作っていません。規則が無ければ、システム管理者であっても更新も削除もできません。参照はシステム管理者だけに開き、Box のメンバーには前述の関数経由の道しか通していません。
気づけない欠落を作らない
検知の設計でいちばん気を配ったのは「何も起きていないのか、見ていないだけなのか」を区別できる形にすることです。5 分ごとに回る 6 つの検知器は互いに独立に動かし、1 つが失敗しても残りが止まらないようにしています。1 つの失敗で全部が止まる作りにすると、この仕組み自身が「静かな欠落」を作ってしまいます。外部の監視サービスから数値が取れなかったときは、0 件と報告せず取得の失敗として扱います。前回の報告件数が読めないときは、黙るのではなく鳴らす側に倒します。
この資料の構成Pages
記録が溜まる側(記録の基盤 → 全社の監査ログ → 長期保管 → Box のアクティビティ)と、異常に気づく側(異常の検知 → アラートの運用)に分かれています。どこから読んでも読めるように書いていますが、通しで読む場合はこの一覧の順が読みやすい並びです。
設計の背景Design Rationale
記録を 1 本に集めた理由と、更新・削除の口を作らなかった理由。同じ記録を 3 つの読み口で出す構造。クラウドの監視とは別にアプリ自身の検知を持つ理由と、設計の四原則。
View Records記録の基盤The Log
記録される 163 種類の操作。1 行に入る項目と、IP・端末情報の置き場。追記だけを許すアクセス制御の三層。月ごとに子テーブルへ分ける仕組み。行為者の 6 種類と、書き込みの規律。
View Audit全社の監査ログCompany-wide Audit
9 条件の絞り込みと続きの取り方。閲覧そのものを条件なしで記録する理由。日本時間で区切る集計。19 列の CSV と、期間 31 日・10 万行での分岐。歯止め 4 つと、現時点の到達範囲。
View Archive長期保管Long-term Storage
保持 2 年と退避 25 ヶ月の 1 ヶ月の余裕。子テーブルの先行作成と切り離しの分担。退避の 4 手順と、行数・検査値を突き合わせてから消す規律。失敗したときに起きること。
View ActivityBox のアクティビティMember Timeline
メンバーに見せる 48 種と Owner だけの 4 種。権限をデータベース側で固定する 4 つの検証。出してよい項目の対応表。日本語の表示文。タイムラインの画面と Owner の CSV。
View Detection異常の検知Detection
アラート 29 種の全一覧と 7 つの系統。起票元の 4 系統。5 分ごとに回る 6 つの検知器と、そのしきい値。鳴らし直さない仕組みと自動での解決。本番での実例。
View Operationsアラートの運用Operations
計器 4 枚と絞り込み 3 種。状態で見た目を分ける規律。4 状態 × 3 操作の遷移と、手動で解決できない 2 種。失敗イベントの再投入・破棄と滞留した通知の再キュー。
View Tech採用技術Technology
仕組みを構成する技術それぞれの役割。記録側と検知側で共通にした部分、あえて分けた部分の一覧。
View Glossary用語集Glossary
本文に出てくる技術用語の定義と、稼働しているサービス・バッチ・バケット・テーブルの名前と役割の一覧。初めて読む方はここを先に開いても構いません。
View規模と主要指標Key Figures
設計上の数値です。件数の根拠はすべて共有定数の一覧か自動テストで固定されており、増減するとテストが落ちる形にしてあります。
実装の規模
| 対象 | 数 | 内訳 |
|---|---|---|
| API の端点 | 27 | 全社の監査ログ 8 / Box のアクティビティ 4 / アラート 7 / 配信の運用 8 |
| 新規テーブル | 2 | 取り出し依頼の台帳 / 退避の台帳。記録本体とアラートの器は既存 |
| データベース側の仕組み | 関数 1 + 規則 3 | メンバー向けの読み取り関数 1 本と、2 テーブルの参照・追加の規則 3 本。加えて列単位の許可 |
| バッチ | 3 + 1 | 取り出し(依頼のたび)/ 月次の退避 / 5 分ごとの検知。加えてデータベース内の週次整備 |
| 追加した記録の種類 | 9 種 | 監査ログの閲覧・取り出し・退避分の取得で 6 種、アラートの状態変更で 3 種 |
| 自動テスト | 75 ファイル | API 単体 35 / 実データベースを使う結合 7 / データベース権限 5 / 画面側の単体 21 / 共有定数の検算 4 / 画面と API の通し 3 |