監査ログは「物語」であって、証拠ではない
ほとんどの監査証跡は、運用者が編集できるテーブルの行にすぎない。その差は問題が起きた日まで見えない — そしてその日、手元に残っているのはログだけだ。
どのシステムも「監査ログはあります」と言う。だが「証拠があります」と言えるシステムは、ほとんどない。
この差は言葉遊びではない。監査ログが答えるのは「システムは何が起きたと言っているか」。証拠が答えるのは「あなたを信用していない相手に対して、何が起きたと証明できるか」だ。大半の実装は前者を静かに提供し、部屋にいる全員が後者だと思い込んでいる。
問題の形
典型的な監査証跡はただのテーブルだ。タイムスタンプ、実行者、アクション、そしてコンテキストのJSONが並ぶ。それを書き込むのは、アクションを実行したのと同じアプリケーションで、書き込み先は同じデータベース、使うのは同じ認証情報だ。
つまり、そのデータベースに届く者は誰でも監査ログを書き換えられる。その集合は、たいていのチームが認めたがらないほど大きい。アプリケーション自身、本番アクセスを持つ運用エンジニア、バックアップのリストア処理、深夜2時に誰かが流したマイグレーションスクリプト、そして以上のどれかを侵害した攻撃者。
もう一つ、静かな欠陥がある。削除は痕跡を残さない。行が消されても、テーブルは完全に整合したままだ — 単に「そのイベントが最初から存在しなかった世界」を描写するだけである。ページ数を数える者が外部にいなければ、追記型の物語を改竄するのは簡単だ。
「封印」が満たすべき条件
記録が証拠として機能するには、三つの性質が同時に成り立たなければならない。
- 各レコードが自分自身の内容にコミットしている。 書き込み時点で、正規化されたシリアライズに対するハッシュを計算する。後からフィールドを変えれば、ハッシュが合わなくなる。
- 各レコードが、それ以前のレコードにコミットしている。 ハッシュを連鎖させれば、あるレコードを消すと後続のリンクがすべて壊れる。削除が沈黙ではなくなる。
- そのコミットメントに、書き込み側が持たない鍵で署名がなされている。 ここが省略される。アプリケーションが再計算できるハッシュチェーンは、アプリケーションが書き直せるハッシュチェーンだ。運用者以外の誰かが、ある時点のチェーンの状態を証言しなければならない。
三つ目を欠くと、事故には耐えるが敵には耐えない完全性システムができあがる。その「敵」には、半年後、弁護士が同席する部屋で圧力にさらされている自分自身も含まれる。
なぜ省略されるのか
最初の二つが安価で、三つ目が分散システムの問題だからだ。
レコードのハッシュ化はマイクロ秒で済む。チェーンはルックアップ一回だ。だが「書き込みシステムがアクセスできない鍵で署名する」は、別の信頼境界を意味する。別の鍵管理者、別の障害モード、レイテンシ予算、署名者に到達できないときどうするかの決断。これは本物のエンジニアリングであり、だからチケットになり、チケットは来四半期になる。
その間に監査画面はリリースされる。正しく見えるし、実際に正しい — その正しさが争われる瞬間までは。
テスト
二つのカテゴリーを分ける質問は一つだけで、問うのに10秒もかからない。
本番データベースにアクセスできる誰かが、去年3月のレコードのフィールドを一つ書き換えたら、どこかの何かが気づくか?
正直な答えがノーなら、それはログだ。デバッグにも、サポートにも、障害の再構成にも役立つ、良いログだ。ただ、誰かが「何が起きたか」を争ってきた日に必要になるものではない、というだけである。
その日は滅多に来ない。来たとき、残っているのはたいていログだけで、その有用性は誰も重要だと言わなかったアーキテクチャ上の選択によって、とっくの昔に決まっている。
Axowlは、アイデンティティ・承認・監査イベントを書き込みと同時に封印する — ハッシュ連鎖の上で、書き込みサービスが持たない鍵によって。仕組みを見る