MapR-DBとAudit機能について 中編

[前編](https://qiita.com/bigt23/items/5a220cce8674abf9e379)はdataレベルのAuditログの出力方法まで紹介しました。
中編となる今回は、まず出力されたAuditログ中のIDを複合し、解析する方法をご紹介します。
次に本シリーズの最初のモチベーションであったMapR-DBへのアクセスに関するdataレベルのAudit機能とCDCの比較を行います。

# Auditログ中のidの復号と解析 

## idの復号

出力されたAuditログはファイル名やユーザがMapR内部で利用するidで記録されているため、内容を把握する上ではこのidをファイル名に復号する必要があります。
復号には[`expandaudit`コマンド](https://mapr.com/docs/61/ReferenceGuide/r_expand_audit_logs.html)を利用して、以下のように実行します。
ここではクラスタ名*ov*のVolume名*enable_audit*で発生したAuditログをMFSの*/tmp*以下に出力します。

```bash
$ /opt/mapr/bin/expandaudit -cluster ov -volumename enable_audit -o /tmp/
$ hadoop fs -ls -R /tmp/
drwxr-xr-x   - root root          2 2018-11-21 00:59 /tmp/27878493
drwxr-xr-x   - root root          1 2018-11-21 00:59 /tmp/27878493/ov0
drwxr-xr-x   - root root          7 2018-11-24 17:16 /tmp/27878493/ov0/5660
-rwxr-xr-x   3 root root     390421 2018-11-21 00:59 /tmp/27878493/ov0/5660/DBAudit.log-2018-11-20-001.json
-rwxr-xr-x   3 mapr mapr      70984 2018-11-24 17:16 /tmp/27878493/ov0/5660/DBAudit.log-2018-11-21-001.json
-rwxr-xr-x   3 mapr mapr     161876 2018-11-24 17:16 /tmp/27878493/ov0/5660/DBAudit.log-2018-11-24-001.part.json
-rwxr-xr-x   3 root root     490736 2018-11-21 00:59 /tmp/27878493/ov0/5660/FSAudit.log-2018-11-20-001.json
-rwxr-xr-x   3 mapr mapr      80291 2018-11-24 17:16 /tmp/27878493/ov0/5660/FSAudit.log-2018-11-21-001.json
-rwxr-xr-x   3 mapr mapr        459 2018-11-24 17:16 /tmp/27878493/ov0/5660/FSAudit.log-2018-11-22-001.json
-rwxr-xr-x   3 mapr mapr     423813 2018-11-24 17:16 /tmp/27878493/ov0/5660/FSAudit.log-2018-11-24-001.part.json
drwxr-xr-x   - root root          1 2018-11-21 00:59 /tmp/27878493/ov1
drwxr-xr-x   - root root          0 2018-11-24 17:16 /tmp/27878493/ov1/5660

```

Auditログが出力されているのが確認できました。
とりあえず中身を見てみましょう。

```bash
$ hadoop fs -cat /tmp/test/27878493/ov0/5660/FSAudit.log-2018-11-24-001.part.json
...
{"timestamp":{"$date":"2018-11-24T15:17:12.431Z"},"operation":"LOOKUP","user":"mapr","uid":5000,"ipAddress":"10.10.75.127","srcPath":"/enable_audit/set_audit","srcFid":"2305.32.397698","srcName":"100.yaml._COPYING_","VolumeName":"enable_audit","volumeId":27878493,"status":2}
{"timestamp":{"$date":"2018-11-24T15:17:12.433Z"},"operation":"CREATE","user":"mapr","uid":5000,"ipAddress":"10.10.75.81","parentPath":"/enable_audit/set_audit","parentFid":"2305.32.397698","childPath":"/enable_audit/set_audit/100.yaml._COPYING_","childFid":"2305.235.398104","childName":"100.yaml._COPYING_","VolumeName":"enable_audit","volumeId":27878493,"status":0}
{"timestamp":{"$date":"2018-11-24T15:17:12.440Z"},"operation":"WRITE","user":"mapr","uid":5000,"ipAddress":"10.10.75.127","srcPath":"/enable_audit/set_audit/100.yaml._COPYING_","srcFid":"2305.235.398104","VolumeName":"enable_audit","volumeId":27878493,"status":0}
{"timestamp":{"$date":"2018-11-24T15:17:12.440Z"},"operation":"LOOKUP","user":"mapr","uid":5000,"ipAddress":"10.10.75.127","srcPath":"/enable_audit/set_audit","srcFid":"2305.32.397698","srcName":"100.yaml","VolumeName":"enable_audit","volumeId":27878493,"status":2}
{"timestamp":{"$date":"2018-11-24T15:17:12.441Z"},"operation":"RENAME","user":"mapr","uid":5000,"ipAddress":"10.10.75.81","srcPath":"/enable_audit/set_audit","srcFid":"2305.32.397698","dstPath":"/enable_audit/set_audit","dstFid":"2305.32.397698","srcName":"100.yaml._COPYING_","dstName":"100.yaml","VolumeName":"enable_audit","volumeId":27878493,"status":0}
{"timestamp":{"$date":"2018-11-24T15:17:15.834Z"},"operation":"CHPERM","user":"mapr","uid":5000,"ipAddress":"10.10.75.81","srcPath":"/enable_audit/set_audit/100.yaml._COPYING_","srcFid":"2305.235.398104","permissions":"0777","VolumeName":"enable_audit","volumeId":27878493,"status":0}
{"timestamp":{"$date":"2018-11-24T15:17:19.001Z"},"operation":"DELETE","user":"mapr","uid":5000,"ipAddress":"10.10.75.127","parentPath":"/enable_audit/set_audit","parentFid":"2305.32.397698","childPath":"/enable_audit/set_audit/100.yaml","childFid":"2305.235.398104","childName":"100.yaml","VolumeName":"enable_audit","volumeId":27878493,"status":0}
...
```

ユーザID, ファイルパスが復元されていますね。
前回の記事で`/enable_audit/set_audit/`と`/enable_audit/non_set_audit/`ディレクトリを対象に操作を行いましたが、Auditログに記載が残ったのは`/enable_audit/set_audit/`への操作のみでした。
こちらも設定どおりですね。

```
$ hadoop fs -cat /tmp/tmp/27878493/ov0/5660/FSAudit.log-2018-11-24-001.json | grep set_audit | wc -l
942
$ hadoop fs -cat /tmp/tmp/27878493/ov0/5660/FSAudit.log-2018-11-24-001.json | grep non_set_audit | wc -l
0
```

ところで、ファイルパスは `expandaudit指定パス`/`VolumeID`/`ホスト名`/`MFSポート`/`Auditファイル名`.log-YYYY-mm-DD-`Index`.json のような形式を取ります。
Auditログは実際にクライアントから処理を受け付けてデータ処理を行ったホストのローカルVolume上で記録されますが、`expandaudit`を実行することで引数に受け取ったパス上に出力されます。
また、出力先の`VolumeID`の下位のディレクトリに上記の処理を受け付けたホスト名がディレクトリとして記録されます。
今回行った処理はデータの生成や削除処理のため、マスターコンテナを持つノードに処理が集中しますが、読み込みのみの処理を行う場合には、負荷分散のためレプリカを持つノードにもアクセスが発生しますので、Auditの出力先もレプリカを持つ全てのノードが対象となります。
`Index`についてはMFSを再起動するたびにローテーションされますので、MFSを稼働しっぱなしの場合は001のみとなります。
また、`expandaudit`は出力パスに存在する復元対象のファイルが存在する場合、このファイルが前日までのデータの場合、もしくは当日のデータでも既にローテーションされ最新のIndexがついていない場合、読み込みは行いません。
最新のIndexがつく当日のデータに関しては、`expandaudit`を何度実施しても毎回ファイル全てを読み込みますが、この場合出力されたファイルの拡張子は`part.json`となります。
そのため、例えばMFSの再起動が発生しない状況で１日1回`expandaudit`を実行するようなルーチンを組んだ場合、前日までのデータの読み込みは発生しません。

## データの解析

idの復号が終わったところで解析に移りたいと思います。
といっても単なるjsonファイルなので、どのようにでも解析できますね。
例えばDrillを使うと、以下のようなクエリで内容を参照できます。

```shell
$ sqlline -u jdbc:drill:drillbit=ov0 -n mapr -p mapr
0: jdbc:drill:drillbit=ov0> select `timestamp`, `user`, `srcPath`, `VolumeName` from dfs.`/tmp/27878493/*/5660/FSAudit.log-*.json` where `operation` = 'WRITE' and `timestamp` > '2018-11-25 08:00:00';
+--------------------------+-------+----------------------------------+---------------+
|        timestamp         | user  |             srcPath              |  VolumeName   |
+--------------------------+-------+----------------------------------+---------------+
| 2018-11-25 08:34:21.052  | mapr  | /enable_audit/set_audit/7.yaml   | enable_audit  |
| 2018-11-25 08:34:21.206  | mapr  | /enable_audit/set_audit/5.yaml   | enable_audit  |
| 2018-11-25 08:34:21.47   | mapr  | /enable_audit/set_audit/1.yaml   | enable_audit  |
| 2018-11-25 08:34:21.491  | mapr  | /enable_audit/set_audit/6.yaml   | enable_audit  |
| 2018-11-25 08:34:21.673  | mapr  | /enable_audit/set_audit/10.yaml  | enable_audit  |
| 2018-11-25 08:34:21.676  | mapr  | /enable_audit/set_audit/3.yaml   | enable_audit  |
| 2018-11-25 08:34:21.869  | mapr  | /enable_audit/set_audit/4.yaml   | enable_audit  |
| 2018-11-25 08:34:22.047  | mapr  | /enable_audit/set_audit/9.yaml   | enable_audit  |
| 2018-11-25 08:34:22.116  | mapr  | /enable_audit/set_audit/8.yaml   | enable_audit  |
| 2018-11-25 08:34:22.161  | mapr  | /enable_audit/set_audit/2.yaml   | enable_audit  |
| 2018-11-25 08:34:22.173  | mapr  | /enable_audit/set_audit/0.yaml   | enable_audit  |
+--------------------------+-------+----------------------------------+---------------+
11 rows selected (0.346 seconds)
```

必要に応じてワイルドカードを使えば、クラスタ中のどのノードで実行しているかを意識せずに済みます。


# MapR-DBのAudit機能とCDCの比較

さて、本編の主題であったはずのChangeDataCapture(CDC)機能との比較についてまとめましょう。

[CDCの紹介時](https://qiita.com/bigt23/items/ec9dd7012b7ed9c89665)に行ったものと同様の処理をしてみます

```shell
mapr@ov0[3920] mapr dbshell
====================================================
*                  MapR-DB Shell                   *
* NOTE: This is a shell for JSON table operations. *
====================================================
Version: 6.0.1-mapr

MapR-DB Shell
maprdb mapr:> insert /enable_audit/set_audit/db/test  --value '{"_id":"3011", "USERNAME":"王騎", "total_score":286, "PROP":{"intellligence":95, "power":98, "lead":93}}'
Document with id: ""3011"" inserted.
maprdb mapr:> update /user/mapr/db/test --id "3011" --m '{ "$set":[{"USERNAME":"王騎(おうき)"},{"total_score":290} ] }'
The table specified by the path '/user/mapr/db/test' was not found.
maprdb mapr:> update /enable_audit/set_audit/db/test --id "3011" --m '{ "$set":[{"USERNAME":"王騎(おうき)"},{"total_score":290} ] }'
Document with id: "3011" updated.
maprdb mapr:> delete /enable_audit/set_audit/db/test --id "3011"
Document with id: "3011" deleted.
```

CDCには紹介時と同様、テーブルへの変更の具体的な値が補足されています。

```bash
$ java -cp target/maprdb-cdc-sample-1.0-SNAPSHOT.jar:`mapr clientclasspath` com.mapr.samples.db.cdc.json.DumpCDC /user/mapr/stream/cdc cdcTopic1
==== Start DumpCDC with /user/mapr/stream/cdc:cdcTopic1===
{
  "type" : RECORD_INSERT,
  "documentId : 3011,
  "recordOpTime : 1543500728818,
  "recordServerOpTime : 1543500728818,
  "insertData" : {
    "PROP : {"intellligence":95,"lead":93,"power":98},
    "USERNAME : 王騎,
    "total_score : 286.0  }
}
{
  "type" : RECORD_UPDATE,
  "documentId : 3011,
  "recordOpTime : 1543500874960,
  "recordServerOpTime : 1543500874960,
  "updateData" : {
    USERNAME : 王騎(おうき)
 }
  "updateData" : {
    total_score : 290.0
 }
}
{
  "type" : RECORD_DELETE,
  "documentId : 3011,
  "recordOpTime : 1543500907168,
  "recordServerOpTime : 1543500907168,
}
```

では次にAuditログを確認します

```bash
$ /opt/mapr/bin/expandaudit -cluster ov -volumename enable_audit -o /tmp/
$ hadoop fs -ls -R /tmp/27878493/ | grep DBAudit
...
〜中略〜
...
-rwxr-xr-x   3 mapr mapr      21383 2018-11-29 09:20 /tmp/27878493/ov0/5660/DBAudit.log-2018-11-29-001.part.json
-rwxr-xr-x   3 mapr mapr        528 2018-11-29 09:20 /tmp/27878493/ov1/5660/DBAudit.log-2018-11-29-001.part.json
-rwxr-xr-x   3 mapr mapr        527 2018-11-29 09:20 /tmp/27878493/ov2/5660/DBAudit.log-2018-11-29-001.part.json


$ sqlline -u jdbc:drill:drillbit=ov0 -n mapr -p
0: jdbc:drill:drillbit=ov0> select `timestamp`,`operation`,`user`,`uid`,`ipAddress`,`VolumeName`, `volumeId`, `tablePath` from dfs.`/tmp/27878493/ov0/5660/DBAudit.log-2018-11-29-001.part.json` order by `timestamp`;
+--------------------------+------------------+-------+-------+---------------+---------------+-----------+----------------------------------+
|        timestamp         |    operation     | user  |  uid  |   ipAddress   |  VolumeName   | volumeId  |            tablePath             |
+--------------------------+------------------+-------+-------+---------------+---------------+-----------+----------------------------------+
| 2018-11-29 08:34:03.467  | DB_TABLECREATE   | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:34:03.516  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:34:03.52   | DB_TABLEINFO     | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:34:03.526  | DB_CFCREATE      | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:34:03.527  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:34:03.53   | DB_TABLEINFO     | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:35:54.68   | DB_CFSCAN        | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:35:54.683  | DB_TABLEINFO     | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:35:54.715  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:02.828  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:09.575  | DB_PUT           | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:09.575  | DB_PUT           | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:09.575  | DB_PUT           | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:09.575  | DB_PUT           | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:36:09.575  | DB_PUT           | mapr  | 5000  | 10.10.75.98   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:37:26.937  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:37:26.937  | DB_TABLEINFO     | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:37:26.947  | DB_CFSCAN        | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:37:27.194  | DB_INDEXADD      | mapr  | 5000  | 10.10.75.81   | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
| 2018-11-29 08:37:27.194  | DB_REGIONLOOKUP  | mapr  | 5000  | 10.10.75.127  | enable_audit  | 27878493  | /enable_audit/set_audit/db/test  |
...
(省略)
```

このように、Auditログの中ではDB_PUTやDB_INDEXADDなどDB操作のメタ情報が記録されていますが、CDCのように具体的な値については捕捉していません。
一方でどのユーザがどのVolumeのどのテーブルにアクセスしたか、といったCDCでは取得できない情報を包括的に取得することができます。
このようにCDCが具体的なデータ更新分の解析や活用を主眼としている一方で、Auditログがデータアクセス分析やコンプライアンス実現のための機能として向いていると言うことができます。
dataレベルのAudit機能が具体的にどのようなデータ操作を記録できるかについては、[こちらのページ](https://mapr.com/docs/home/SecurityGuide/Auditing-FilesystemTableOperations.html)にまとめられております。
また、上記ページの表の**Operation Name to use for Selective Auditing**カラムが**Y**のオペレーションに関しては、監視対象とするかどうかを制御することが可能です。
制御の際にはVolumeの`-dataauditops`オプションの設定により選択可能となり、この結果は`volume info`の`enableddataauditoperations`,`disableddataauditoperations`に反映されます。

```bash
$ maprcli volume info -name enable_audit -json
{
        "timestamp":1544623211387,
...
                        "coalesceInterval":1,
                        "enableddataauditoperations":"setattr,chown,chperm,chgrp,getxattr,listxattr,setxattr,removexattr,read,write,create,delete,mkdir,readdir,rmdir,createsym,lookup,rename,createdev,truncate,tablecfcreate,tablecfdelete,tablecfmodify,tablecfScan,tableget,tableput,tablescan,tablecreate,tableinfo,tablemodify,getperm,getpathforfid,hardlink",
                        "disableddataauditoperations":"getattr",
}
```

ここで例えば`getattr`を監視対象に入れ、`tableinfo`, `getperm`を監視対象から外すには以下のようにコマンドを実行します。

```bash
$ maprcli volume modify -name enable_audit -dataauditops +getattr,-tableinfo,-getperm
$ maprcli volume info -name enable_audit -json
{
...
                        "enableddataauditoperations":"getattr,setattr,chown,chperm,chgrp,getxattr,listxattr,setxattr,removexattr,read,write,create,delete,mkdir,readdir,rmdir,createsym,lookup,rename,createdev,truncate,tablecfcreate,tablecfdelete,tablecfmodify,tablecfScan,tableget,tableput,tablescan,tablecreate,tablemodify,getpathforfid,hardlink",
                        "disableddataauditoperations":"tableinfo,getperm",
...
```

変更されていますね。
さて、ここまで紹介してきたCDCとAuditの比較結果をまとめてみると、以下の様になりました。

|        |       CDC |    Audit with expandaudit    |
|:-----------------|------------------:|:------------------:|
| リアルタイム性             |              ○ |        ☓(Audit Streamについては後編)        |
| データ           |            実データ |       メタデータ       |
| gateway           |              必要 |        必要なし        |
| データ形式               |                CDC |         json(Audit Streamでは[ConsumeRecords](https://mapr.com/docs/apidocs/v5.2.0/mapr-streams-kafka/org/apache/kafka/clients/consumer/ConsumerRecords.html))         |
| 解析プログラム             |             CDC APIを利用したアプリケーション |       Drillなど       |
| 蓄積場所          |           gatewayで指定したクラスタのストリーム |      同一クラスタ上のMFS       |
| 制御単位 | テーブル | Volume, ディレクトリ, ファイル, DB, ES　|

# まとめ

本編ではAuditログのidの複合から、MapR-DBのAudit機能とCDCとの比較を行いました。
次回のAudit機能シリーズの最終編としては、リアルタイムでのAuditログの解析を可能とする、Audit stream機能について紹介します。