マハラノビス距離を使ってKintoneの監査ログからいつもと異なる挙動のログを抽出する

  • 41
    Like
  • 1
    Comment
More than 1 year has passed since last update.

Kintoneの管理者をしていると、自社の従業員が良からぬことをしていないか気になることがありますよね?そのために監査ログという機能がありますが、どのイベントが日常的なことで、どのイベントが普段と異なるイベントなのかを判断するのは難しいかと思います。

そこで、統計学の手法でいつもとは異なる挙動のログを抽出してメールでレポートするプログラムをRubyで作ってみました。
定期的に起動するプログラムなので、サーバなどに設置してcronで動かしてもいいのですが、今回はHerokuにデプロイすることにしました。

下図のようなレポートをメールで送信します。
kintone-masked.png

機能の概要

基本的には良からぬことが起きていないかを緩やかに監視することを目的にしていますので、Kintoneの監査ログの中から、以下の3種類のログを抽出しています。

  • 書き出しを行ったログ(データエクスポートログ)
  • Kintone上で重要と位置づけられているログ(重要イベント)
  • 午前2時以降にログインしているログ(深夜ログ)

上記の3つのログをHerokuのPostgreSQLに蓄積して、過去のログと統計的な比較をすることで異常検知を行い、これを「異質なログ」としています。

Kintoneの監査ログにアクセスする方法

KintoneはREST APIを公開して様々なデータにアクセスできる素晴らしい製品ですが、残念ながら、監査ログにアクセスするためのAPIは公開されていません。
ただし、ブラウザなどで監査ログを表示させるときの挙動を見ていると、なんとなくアクセス方法がわかりましたので、それをRubyのMechanizeを使ってエミュレートすることにしました。

いつもと異なるログの判定方法

異常値検知というテーマで様々な手法がありますが、今回は教師なし学習による異常値検知: マハラノビス距離 (理論編)を参考に、対象のログの平均値からのマハラノビス距離を測定し、一定値以上であれば「異質なログ」とするようにしました。

Kintoneの監査ログの内容
Kintoneの監査ログには以下の様な情報が含まれています。

  • 日時
  • アカウント名
  • アクション
  • アクセス元IPアドレス
  • アプリID
  • アプリ名

ログのコード化
マハラノビス距離を測定するためには、1つ1つのログをベクトルとして取り扱う必要がありますので、以下のように日付やアカウント名などの文字情報を数値情報に変換して、6次元のベクトルデータに変換しました。

  • 日時
    異質なログを判定するという観点では、「いつもとはちょっと違う時間帯」というのを検知したいので、日付を除く時刻を取り扱うことにしました。
    "2016-02-14 12:54:32"であれば、時刻部分をそのまま並べて、125432 という数値データとしました。

  • アカウント名、アクション
    文字列から数値にする簡単な方法はSHA-1のようなハッシュ関数を使うことだと思います。ただし、SHA-1やMD5だと数字の桁数が大きすぎるので、CRC32を使いました。

  • アクセス元IPアドレス
    IPアドレスはRubyのIPAddrクラスを利用することで、容易にする整数のデータにできました。

  • アプリID
    アプリIDは、そのものが数値データなので、これをそのまま利用しました。

このようにして、1つ1つのログを6次元の数値ベクトルに変換して、平均値ベクトルと分散共分散行列を計算して、検査対象ログのマハラノビス距離を求めることができます。

しきい値の決め方
マハラノビス距離がいくつ以上なら異質とみなすのかはケース・バイ・ケースだと思いますが、私の場合は、前月の1ヶ月分のログのマハラノビス距離を測定することで、どのくらいの距離にログが集中していそうかを判断しました。
開発したプログラムはしきい値を環境変数 ANOMALY_LENGTH で指定できるので、適当な値をセットして、どのくらいのログが検知されるのかを試してみると良いかと思います。
(ちなみに、私の環境では10くらいがちょうど良さそうな感じでした。)

ソースコード

ソースコードはGithubで公開しました。
https://github.com/maloninc/kintone-audit

Heroku Button

また、Herokuですぐ使ってみたいという方は、Heroku Buttonを用意したので、下記の環境変数を設定することですぐに利用できると思います。

Heroku Deploy

  • ANOMALY_LENGTH:マハラノビス距離のしきい値

  • KINTONE_ADMIN_ID:Kintoneの管理者アカウント名

  • KINTONE_ADMIN_PW:Kintoneの管理者アカウントのパスワード

  • KINTONE_HOSTNAME:利用しているKintoneのドメイン名

  • SEND_TO_LIST:メール送信先(複数の場合はカンマで区切る)

上記の環境変数を設定し、「Deploy for FREE」をクリックしてデプロイが完了したら、HerokuのScheduler機能で定期的に監査ログをチェックするように指定します。

下記の「Manage App」をクリックします。
スクリーンショット 2016-02-11 11.35.45.png

「Heroku Scheduler」をクリックします。
スクリーンショット 2016-02-11 11.36.21.png

実行したい時間帯を指定して、コマンド欄には「ruby ./app.rb」を指定します。
下図の例では、日本時間午前7時に実行します。

スクリーンショット 2016-02-11 12.30.10.png

これで、毎日午前7時に前日の活動に応じたログがレポートとしてメール送信されます。

制限事項

1. 過去1ヶ月分のログの取得が面倒です

異常値の検知は前月のログが蓄積されていないと機能しません。今すぐ、異常値検知を試してみたい方は、herokuのrunコマンドで以下のように日付指定のコマンドを実行してください。ただ、下記のコマンドは 2016年1月1日分のログ取得なので、まるまる1ヶ月を取得したい場合は、本当にお手数ですが、30日分を手打ちしてください。。。
面倒な方は、実施しなくても最初の1ヶ月間は「異質なログ」の欄が「ログなし」となるだけなので、放っておいてもある程度の監視はできると思います。

$ heroku run 'ruby ./app.rb --today 2016-01-01'

2. ログが1万レコードを超えるとHerokuの無料枠では保存できなくなります

HeroicのPostgreSQLの無料枠は1万レコードまでです。これを超過すると追加のレコードが保存できなくなります。対策は、定期的に古いレコードを削除することですが、まだ、そのスクリプトを作ってません。追々作ろうかと思います。

Enjoy!