
マルチプロダクトにおける全操作を網羅する監査ログ収集基盤:設計思想と実装 - 収集編
はじめに
こんにちは。プレイドのKARTE Datahub チームでエンジニアをしている田宮です。
この記事では、プレイドのプロダクト全体に関わる横断的な機能として、特にセキュリティ要件の高いエンタープライズ企業様向けに開発した「監査ログ」のアーキテクチャについてお話しします。
KARTE Datahub とは?
プレイドでは、CXプラットフォーム「KARTE」の計測タグ経由で収集したイベントデータを元にWeb上のユーザーの行動を分析するサービスに加え、クライアント企業が社内外に保有する多種かつ大量なデータをKARTEに統合・連携して利活用できるKARTE Datahub(以下、Datahub)を提供しています。
KARTEの内外に散らばったサイロ化されたデータをDatahubに集約して、KARTEのプロダクトの中でユーザーのセグメントに活用したり、WidgetやKARTE内のアクション機能から参照したりすることができます。
「KARTE Datahubに蓄積した様々なデータを活用する|KARTE Datahub事例集 vol.1」より引用
監査ログについて
監査ログとは
- エンタープライズ環境では、大量の機密情報が扱われるため、情報漏洩や不正アクセスなどのセキュリティリスクが非常に高くなります。監査ログは、これらのリスクに対処するために、以下のような重要な役割を果たします。
- 不正アクセスの検知
- ユーザーの不審な行動やアクセスパターンを分析することで、不正アクセスを早期に検知することができます。例えば、短時間での大量ログイン試行や、通常とは異なる時間帯・場所からのアクセスなどを検知することが可能です。
- 情報漏洩の追跡
- 万が一、情報漏洩が発生した場合、監査ログを分析することで、漏洩経路や影響範囲を特定し、迅速な対応を行うことができます。
- 内部不正の抑止・発見
- 従業員による不正行為(データの改ざん、持ち出しなど)を抑止し、発生した場合の証拠として活用できます。
- セキュリティポリシーの遵守状況の確認
- システムの利用状況を監査することで、セキュリティポリシーが適切に遵守されているかを確認できます。
- 法的要件への対応
- 業界や規制によっては、監査ログの記録・保存が法的要件として義務付けられている場合があります。
- 不正アクセスの検知
エンタープライズ企業が求める「監査ログ」という名の必須要件
近年、エンタープライズ環境におけるセキュリティ要件はますます高度化しています。こうした要求に応えるため、新たに監査ログ機能を開発・提供できるようにする必要がありました。
当面の目標は、この監査ログを活用して、万が一、個人情報やアクセストークンなどの機密情報が漏洩するような事態が発生した場合でも、その動きを速やかに検知できる状態を構築することです。これにより、KARTEをより安心してご利用いただけることを目的としています。
複数プロダクトを束ねる横断プロジェクト
なぜKARTE Datahub チームが横断機能の開発プロジェクトを推進することになったか?それは、お客様の重要なデータを最も多く取り扱う「KARTE Datahub」が監査ログ導入の効果と必要性が高いプロダクトであることから、我々が開発をスタートさせることが合理的との判断からでした。
そのため、KARTE Datahubチームが他のプロダクトの模範となる「リファレンス実装」を作成し、各プロダクトはその実装に追従する形で導入を進める、という全社横断的な開発体制をとりました。
何を監査ログには入れるべきか?
監査ログ、何を入れるべきか悩みますよね。プレイドでは、特に「個人情報を含むデータの移動」や「重要な権限の変更」といったクリティカルな操作を優先的にログ収集対象としました。
ログの形式は、基本的な「いつ・誰が・何に・何をしたか」といった共通項目に加え、プロダクトごとに「変更差分」などの詳細情報を追加できる「details」フィールドを用意。これで、全体的なガバナンスと個別ニーズの両方に対応しています。
実践上の注意点として、「監査に必要な情報はしっかり記録する」。でも、「とりあえずオブジェクト丸ごと保存」は避けましょう(事故の元です!)
そして、記録するIDなどが後で見て「これ何だっけ?」とならないよう、利用者が追跡可能な情報を選ぶことも大切です。
監査ログ基盤構築のためにやったこと
-
監査ログの仕込み方
-
監査ログはまずCloud Loggingに記録され、LogルーティングによってBigQueryのテーブルに保存されます。(下図)
-
この監査ログを記録するには2つの方法があります。
-
KARTE管理画面のアプリケーションからGatewayへのレスポンスヘッダに、監査ログ情報を含める(全プロダクト共通の収集方式)
- プレイドが開発したプロダクト独自の認証基盤を利用する方式です。認証基盤に関する記事へ
- 監査ログ情報(フォーマット)をJSON化し、encodeURIComponentをかけた値を(ヘッダキー)として送信します。値の作成には監査ログ用にプレイドが開発したヘルパーライブラリを利用することで実現できます。
ヘルパーライブラリでできること
- レスポンスヘッダの組み立てを行う
- 詳細ログの組み立てを行う
- 変更前と変更後のエンティティの差分を計算しオブジェクト化することができます。これは上述の「変更差分」を「details」フィールドに格納する際のオブジェクトの生成をサポートします。
-
Cloud Loggingに直接書き込む(プロダクト固有の収集方式)
- 監査ログ書き込み専用のサービスアカウントを使用して、CloudLogging にログを書き込みます。この実装にも上記ヘルパーライブラリを利用します。基本的には Gateway へのレスポンスヘッダに監査ログを情報を含める 1. の方法で賄うことはできますが、バックグラウンドで実行されるジョブに関してはこの方式を利用する必要があります。
-
生ログについて
- 監査ログは最終的に BigQuery に集約されますが、この段階のデータ、通称「生ログ(Raw Logs)」には、全てのテナントの情報が混在しています。情報セキュリティを最優先に考え、この生ログはクライアントデータと同レベルの最高水準で保護。アクセス権限を厳しく制限し、許可された担当者のみがアクセスできるように徹底管理しています。
-
書き込み欠損に向き合う
書き込み成功率 99.99% を目指して
- 監査ログの信頼性を担保するため、Datadog で常時監視し、書き込み成功率 99.99% 以上の維持を目指しています。しかし当初、Node.jsとGoogle Cloud公式ライブラリ(
google-cloud/logging
)を使った実装では、予期せぬエラー(RST_STREAM
)が頻発し、目標達成が困難な状況に。調査の結果、ライブラリ内部のgRPC接続が不安定になることが原因と判明しました。接続インスタンスを定期的に再生成するなどの試行錯誤しましたが改善せず、最終的に通信方式をgoogleapisのREST APIを直接利用する方式に切り替えることで、ようやく安定した書き込みと目標成功率の達成を実現できました。
送信 Fallback
- 監査ログの信頼性を追求する上で、Cloud Logging への送信失敗は無視できない問題です。もちろん、基本的な対策として Exponential Backoff によるリトライ機構は組み込んでいますが、大規模なネットワーク障害や Cloud Logging 自体の長時間ダウンなど、リトライだけではカバーしきれない万が一のケースも想定しなければなりません。
- そこで私たちは、システムの耐障害性をさらに高め、重要な監査ログデータの損失リスクを最小限に抑えるために、「送信 Fallback」の仕組みを導入しました。これは、メインの Cloud Logging への送信経路が継続的に失敗した場合に備えたバックアッププランです。私たちが最終的に選択した Fallback 経路は、ログデータを一度 Google Cloud Pub/Sub のトピックに送信し、そこから BigQuery のテーブルへとストリーミング挿入するという構成です。
このアプローチの利点は以下の通りです。
- 高可用性とバッファリング: Pub/Sub は非常に可用性が高くスケーラブルなメッセージングサービスであり、Cloud Logging が不安定な状況でも、ログデータを一時的に確実に受け止めるバッファとして機能します。
- 最終的な宛先への集約: BigQuery は我々の監査ログの最終的な格納先(生ログの保存場所)であるため、Fallback 経路を経由したデータもメイン経路のデータと同じ場所にスムーズに統合でき、後のデータ管理や分析が容易になります。
この Pub/Sub を経由する Fallback 機構があることで、予期せぬ障害発生時においても、監査ログの書き込み成功率を高水準で維持し、データの完全性を守ることが可能になります。もちろん、Pub/Sub から BigQuery へのデータ連携部分の監視や、重複排除の考慮などは必要ですが、エンタープライズ向けの信頼性を担保する上で非常に効果的な構成だと考えています。
ログが消失したら?に備える
重要な監査ログデータを蓄積しているBigQueryテーブル。もし、これが何らかの理由で削除されてしまったら…?考えただけでも冷や汗が出ますが、事前に避難訓練を実施して適切な準備をしておけば、迅速な検知と復旧が可能です。
余談ではありますが、この避難訓練を実施は実は2回行いました。それはなぜかというと1度目は失敗してしまったからです(笑)このことからもわかるように、実際に避難訓練をやってみることで実は意外とうまくいかないケースが出てくることがある為、実際に実施してみることが大事なことなのだと実感します。
それでは、GCP BigQueryを利用している環境で、監査ログの生データテーブルが削除された場合に備えるための「検知」と「復旧」の方法について具体的に解説していきます。
1. テーブル削除をいち早く「検知」する仕組み
問題発生時に迅速に対応するためには、テーブルが削除されたことを即座に知る仕組みが不可欠です。ここでは2つのアプローチを紹介します。
方法1: GCP監査ログによる削除イベントの監視
BigQueryのテーブル操作はCloud Loggingに監査ログとして記録されます。これを利用し、テーブル削除イベント (google.cloud.bigquery.v2.TableService.DeleteTable
) を監視します。
-
Cloud Logging でフィルタを作成: ログエクスプローラで以下のクエリを使用し、特定のデータセット内のテーブル削除ログをフィルタリングします。コード スニペット
resource.type="bigquery_dataset" protoPayload.methodName="google.cloud.bigquery.v2.TableService.DeleteTable" protoPayload.resourceName=~"projects/your-project-id/datasets/your_dataset/tables/"
(
your-project-id
とyour_dataset
はご自身の環境に合わせてください) -
アラート通知を設定: 上記フィルタに一致するログが記録されたら、Pub/Sub シンクなどを経由して任意のモニタリングツール(例: Datadog, Slackなど)に通知を送るように設定します。これにより、テーブル削除をリアルタイムに近い形で検知できます。
方法2: Cloud Functionsによる定期的なテーブル状態監視
ログシンクの設定によっては、BigQueryテーブルが削除されても、新しいログデータが到着すると自動的にテーブルが再作成される場合がありますが、再作成以前のデータが欠損している可能性があるため、より能動的にテーブルの状態を確認することも有効です。
- Cloud Functions と Cloud Scheduler を設定: 定期的に対象のBigQueryテーブルにアクセスするCloud Functionsを作成し、Cloud Schedulerで実行します。
- データ存在確認: 関数内で、単純なテーブル存在確認だけでなく、直近のデータ(例: 1分以内)と少し前(例: 5分前)のデータの両方が存在するかを確認するクエリを実行します。これは、テーブルが自動再作成された直後でデータがまだ書き込まれていない、あるいは何らかの理由でログの書き込みが停止している状態を検知するためです。
- 異常時にアラート: データが存在しない、または期待通りでない場合にアラートを発報します。
2. BigQueryタイムトラベル機能による「復旧」手順
万が一テーブルが削除されてしまっても、BigQueryのタイムトラベル機能を使えば、削除前の状態にデータを復元できます。
前提条件:
- タイムトラベル期間: 復旧対象のテーブルが含まれるデータセットで、タイムトラベル期間が設定されている必要があります(デフォルトは7日間)。この期間内であれば、過去の任意の時点のテーブル状態にアクセスできます。
- ログシンク: Cloud LoggingからBigQueryへのログシンクが継続していること。
復旧ステップ:
-
削除時刻の特定: まず、Cloud Loggingのログエクスプローラで、前述のテーブル削除ログ (
TableService.DeleteTable
) を検索し、ログのtimestamp
フィールドから正確な削除時刻を特定します。この時刻が復元の基準点となります。 -
削除直前の状態にテーブルを復元: 特定した削除時刻(エポックミリ秒)を使って、
bq cp
コマンドでテーブルを復元します。- **削除時刻のエポックミリ秒取得 (例):**Bash
'YYYY-MM-DDTHH:MM:SS.ssssssZ' 形式のタイムスタンプをエポックミリ秒に変換 date -d '2025-04-18T10:00:00.000000Z' +%s000 # 例: 1744986000000 のような値が得られる
- **bqコマンドで復元:**Bash
bq cp your_dataset.your_auditlog_raw_table@<取得したエポックミリ秒> \ your_dataset.your_auditlog_raw_table
(
your_dataset
,your_auditlog_raw_table
,<取得したエポックミリ秒>
はご自身の環境に合わせてください)- 注意点: ログシンクによって空のテーブルが自動再作成されている場合、
bq cp
実行時に「テーブルを置換しますか?」といった確認メッセージが表示されます。後続のステップで削除後のデータもリカバリするため、ここでは「Yes」を選択してテーブルを削除時点のデータで上書き(置換)します。
-
削除時刻以降のデータを復旧: ステップ2で復元できるのは、あくまでテーブルが削除された瞬間までのデータです。削除されてから復旧作業を行うまでの間に発生したログデータは、別途リカバリする必要があります。
- 方法: Cloud Loggingには元のログデータが(設定された保持期間内であれば)残っています。削除時刻から復旧作業開始時刻までのログデータをCloud Loggingから抽出し、再度BigQueryへのログシンクパイプライン(例: Pub/Subトピックへ再投入するなど)に流し込むことで、欠損していた期間のデータをBigQueryテーブルに書き戻します。
- (この再投入プロセスは環境に合わせたスクリプトや手動操作が必要になる場合があります。実行には適切なGCP権限が必要です)
まとめ
今回の記事では、プレイドがエンタープライズのお客様からのご要望に応えるため、複数のプロダクトを横断して監査ログ基盤を作ってきた、そんな経験についてお話ししました。
「どんなログを記録すべきか?」という基本からスタートし、システムへの「仕込み方」、そして「生ログ」の信頼性をとにかく高めたい!と、書き込み成功率99.99%を目指した欠損対策や Fallback 機構の実装まで、いろいろ試行錯誤してきました。
そして、どんなに備えても予期せぬことは起こるもの。だからこそ、「ログが消えちゃったらどうする?」という万が一の事態への備えもプレイドではとても大事にしています。テーブル削除を素早く「検知」する仕組みや、BigQueryタイムトラベルを使った「復旧」手順は、サービスを守るための大切な仕組みです。こうした準備と、いざという時に動けるための「避難訓練」(復旧リハーサル)が、サービスの信頼性につながると思っています。
複数のプロダクトを巻き込んだ基盤づくりは、技術的にも組織的にも、簡単な道のりではありません。この記事でお伝えしたプレイドの経験や工夫が、同じような課題に取り組んでいる皆さんの、少しでも参考になれば嬉しいです!また、もっと詳細を知りたいという人は是非プレイドにご連絡ください!