標的型攻撃に対するJPCERT/CCのおすすめログ設定をElasticsearchで構築してみる（メールサーバ編）

# はじめに

「標的型攻撃に対するJPCERT/CCのおすすめログ設定を[Elasticsearch](https://www.elastic.co/jp/products/elasticsearch)で構築してみる」のメールサーバ編です。メールサーバとして([Postfix](http://www.postfix.org/))を利用します。

（これまでの記事）
* [「準備編」](https://qiita.com/rhpenguin/items/f68bdfdf726cb44c26e7)
* [「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)


※本記事で作成する[Filebeat](https://www.elastic.co/jp/products/beats/filebeat)モジュールやPostfixの設定例は[こちら](https://github.com/rhpenguin/Filebeat-module-for-Postfix)へ仮置きしておきます（今後、もう少しわかりやすい配置にする予定です）。

※Ubuntu18.04上で構築（FilebeatはDEBパッケージでインストール）しますので他のディストリビューションやFilebeatインストール方法の場合にはファイルの配置場所などを読みかえてください。

※実際の環境で運用するには、ネットワーク設定、個々のソフトウェアのインストール/初期設定や認証/通信の暗号、冗長構成や負荷分散などで相応の設定が必要となります。それぞれ個別のドキュメントをご参照ください。本記事ではログ設定に関係する基本的なコンフィグレーションにフォーカスして記載します。

#利用するソフトウェア
- OS: Ubuntu 18.04
- メールサーバ: Postfix (3.3.0) / Dovecot (2.2.33.2)
- DNSサーバ: Dnsmasq (2.79)
- Elasticsearch (6.6.0) 
- Kibana (6.6.0)
- Filebeat (6.6.0)
- VMware Workstation Player等のVMソフトウェア
- Windows 10 (クライアントPC)

#ネットワーク構成例
ここでは「[準備編](https://qiita.com/rhpenguin/items/f68bdfdf726cb44c26e7)」で説明した以下のようなシンプルなネットワーク構成を想定。
![log_network_postfix.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362125/ac91bb02-d68b-5ad8-1c74-9434b6f49929.png)


|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|メール|Windows 10クライアントPC上のメールクライアントはdmz.example.comで動作するメールサーバ(Postfix)へアクセス|
ログ|dmz.example.com上で動作するメールサーバのログをFilebeatがElasticsearch(log.example.com)へ転送|

#作業内容
1. ネットワーク構築および各ソフトウェアのインストールと設定
2. Postfixログ設定およびフォーマット追加
3. Postfix用のFilebeatモジュール作成
4. Postfix用のFilebeatモジュールをdmz.example.comに配置し設定
5. Kibanaで確認

#JPCERT/CCのおすすめログ設定
[「高度サイバー攻撃への対処におけるログの活用と分析方法」](https://www.jpcert.or.jp/research/apt-loganalysis.html)をもとに以下の情報を出力するように設定します。

* メールヘッダのFromに含まれる情報
* MIMEヘッダ（Content-Type/Content-Disposition）の添付ファイル名

![smtp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362125/669d14e9-cfb3-726d-d857-d74f72ad1bce.png)
**Alice(alice\@example.com)からBob(bob\@example.com)へメール送信した例 (SMTP)**


これらの情報より以下の攻撃を検出できる可能性があります。

* 送信元を偽装したメールを送り付けて、その添付ファイルを開かせる、またはメッセージ中のURLをクリックさせる
* マルウエアである実行ファイルを添付したメールを送り付ける

（JPCERT/CCの同資料より抜粋）

これらのログを利用した分析手法の詳細についても[同資料](https://www.jpcert.or.jp/research/apt-loganalysis.html)に説明されていますのでぜひご参照ください。

またメールに添付されるファイルを利用した典型的な攻撃例（例えばMicrosoft Officeドキュメント(.docx, .xlsx)やWindowsショートカットファイル(.lnk)が添付される場合など）では、そのファイル開封後にマルウェアの実体がダウンロードされる処理が続けて実行される場合があります。その際にはHTTP/HTTPSトラフィックを偽装またはそれらをトランスポートにすることも多く、[前回の記事](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)で扱ったプロキシサーバログとの照合が重要になるかもしれません。
参考:
* [IQYファイル(※)を悪用する攻撃手に関する注意点 （第二版）](https://www.ipa.go.jp/files/000068065.pdf) [IPA 2018/08]
* [IQYファイルを利用するマルウェアスパム、日本のみを標的に 50 万通拡散](https://blog.trendmicro.co.jp/archives/19506) [Trend Micro 2018/09]

このような疑わしい添付ファイルも既知のものはvirustotalなどで無償でチェックできますが、ファイルハッシュで照合するのではなく、ファイルを検体としてアップロードする場合には情報漏洩につながらないように**十分に**ご注意ください。
参考: [ウイルスチェックのつもりで情報漏えい？　VirusTotalの使い方に注意]
(https://www.itmedia.co.jp/enterprise/articles/1603/14/news104.html) [ITmediaエンタープライズ 2016/3/14]

#メールサーバ(Postfix)のログ設定とフォーマット追加

###Fromヘッダ情報の採取
送信元を偽装したメールを検出するためにメールヘッダのFromフィールドの**display name**と実際のメールアドレスの情報を採取します。以下のように設定ファイルを変更します。

```text:/etc/postfix/main.cf
header_checks = regexp:/etc/postfix/header_checks
```

次にファイル**header_checks**を作成し実際にログ採取するメールヘッダのフィールドパターンを指定します。

```
cd /etc/postfix
touch header_checks
nano header_checks
```
Fromヘッダのパターンを設定します。

```text:/etc/postfix/header_checks
/^From:/ WARN
```
この設定により以下のようなPostfixログが採取されます。

```text:/var/log/mail.log
Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header From: alice <alice@example.com> from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>
```

```text:メールヘッダの情報
header From: alice <alice@example.com>
```

```text:エンビロープの情報
from=<alice@example.com> to=<bob@example.com>
```

###MIMEヘッダ情報の採取
以下のMIMEヘッダ情報を採取します。
* Content-Type
* Content-Disposition

```text:/etc/postfix/main.cf
mime_header_checks = regexp:/etc/postfix/mime_header_checks
```

ファイル**mime_header_checks**を作成し実際にログ採取するメールヘッダのフィールドパターンを指定します。

```
cd /etc/postfix
touch mime_header_checks
nano mime_header_checks
```
MIMEヘッダのパターンを設定します。

```text:/etc/postfix/mime_header_checks
/^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+)"?\s*$/ WARN
```
この設定により以下のようなPostfixログが採取されます。

```text:/var/log/mail.log
Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header Content-Type: image/png;? name="Test.png" from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>
Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header Content-Disposition: attachment;? filename="Test.png" from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>
```
**Test.png**というファイル名を採取。この値はBase64エンコードされている場合があります。

#PostfixログメッセージのJSON変換
[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)と同様にPostfixログメッセージはFilebeatによりJSON形式へ変換されてElasticsearchへ転送されます。

```text:/var/log/mail.log（処理前）
Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header Content-Type: image/png;? name="Test.png" from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>
```
このログメッセージはFilebeatにより以下のようにJSON形式へ変換されます。

```json-doc:Filebeatによる変換処理後
{
  "_index": "filebeat-6.6.0-2019.xx.xx",
  "_type": "doc",
  "_id": "ge2SdmoBsFF1POM-ajN-",
  "_version": 1,
  "_score": null,
  "_source": {
    "offset": 23700,
    "log": {
      "file": {
        "path": "/var/log/mail.log"
      }
    },
    "prospector": {
      "type": "log"
    },
    "source": "/var/log/mail.log",
    "fileset": {
      "module": "postfix",
      "name": "mail"
    },
    "message" : "Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header Content-Type: image/png;? name=\"Test.png\" from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>",
    "input": {
      "type": "log"
    },
    "@timestamp": "2019-04-20T23:01:31.000Z",
    "beat": {
      "hostname": "dmz_server",
      "name": "dmz_server",
      "version": "6.6.0"
    },
    "host": {
      "os": {
        "codename": "bionic",
        "name": "Ubuntu",
        "family": "debian",
        "version": "18.04.1 LTS (Bionic Beaver)",
        "platform": "ubuntu"
      },
      "containerized": false,
      "name": "dmz_server",
      "id": "39557a23335243cb9d4740a1a210ae3d",
      "architecture": "x86_64"
    },
    "event": {
      "dataset": "postfix.mail"
    }
  },
  "fields": {
    "@timestamp": [
      "2019-04-20T23:01:31.000Z"
    ]
  },
  "sort": [
    1556767467095
  ]
}
```
その後Elasticsearch/Ingestノードにより_source.messageフィールドがパーシングおよびパイプライン処理され以下のように変換されます（詳細は後述）。

```json-doc:Elasticsearc/Ingestノードによる変換処理後
{
  "_index": "filebeat-6.6.0-2019.xx.xx",
  "_type": "doc",
  "_id": "ge2SdmoBsFF1POM-ajN-",
  "_version": 1,
  "_score": null,
  "_source": {
    "offset": 23700,
    "log": {
      "file": {
        "path": "/var/log/mail.log"
      }
    },
    "prospector": {
      "type": "log"
    },
    "source": "/var/log/mail.log",
    "fileset": {
      "module": "postfix",
      "name": "mail"
    },
    "input": {
      "type": "log"
    },
    "@timestamp": "2019-04-20T23:01:31.000Z",
    "beat": {
      "hostname": "dmz_server",
      "name": "dmz_server",
      "version": "6.6.0"
    },
    "host": {
      "os": {
        "codename": "bionic",
        "name": "Ubuntu",
        "family": "debian",
        "version": "18.04.1 LTS (Bionic Beaver)",
        "platform": "ubuntu"
      },
      "containerized": false,
      "name": "dmz_server",
      "id": "39557a23335243cb9d4740a1a210ae3d",
      "architecture": "x86_64"
    },
    "postfix": {
      "mail": {
        "process": "cleanup",
        "to_email": "bob@example.com",
        "remote_ip": "192.168.0.xx",
        "from_email": "alice@example.com",
        "mime_type": "image/png",
        "header": "Content-Type",
        "pid": "2368",
        "mime_name": "Test.png",
        "time": "2019-04-20T23:01:14.000Z",
        "mail_server": "dmz_server",
        "queue_id": "304A6101243",
        "remote_host": "unknown"
      }
    },
    "event": {
      "dataset": "postfix.mail"
    }
  },
  "fields": {
    "@timestamp": [
      "2019-04-20T23:01:31.000Z"
    ]
  },
  "sort": [
    1556767467095
  ]
}
```
ご覧の通り_soruce/messageフィールドが_source.postfixフィールドへオブジェクトとして展開されています。こうすることでKibanaで各情報単位で検索や集計したり、自作ツール等で扱いやすくなります。

#Postfix用Filebeatモジュールの作成
（現状）FilebeatのパッケージにはPostfix用モジュールが含まれていないようです。そのためPostfixログ用のモジュールを作成します。

Filebeatのモジュール作成方法は[こちらの公式サイト](https://www.elastic.co/guide/en/beats/devguide/current/filebeat-modules-devguide.html)で解説されていますが（テンプレートファイルを生成するMakeファイルも用意されています）、前回同様にFilebeatのパッケージに同梱されているApache用のモジュールを雛形にして作成してみます。

基本的な作業は前回の[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)とほぼ同様ですので詳細についてはあわせて参照してください。

```
Apache用モジュールをコピー
cd /usr/share/filebeat/module
cp -r ./apache2 ./postfix

error.log用の設定は必要ないので削除する
cd postfix
rm -rf error

（logファイル名による）ディレクトリ名を変更する
mv access mail
```

### Postfix用モジュールのファイル構成
「[準備編](https://qiita.com/rhpenguin/items/f68bdfdf726cb44c26e7)」にて説明しました通り以下のような構成でモジュールのファイルを配置します。

```
/usr/share/filebeat/
   `- module/
        `- postfix/
             |- module.yml
             `- mail/
                  |- manifest.yml
                  |- config/
                  |    `- mail.yml
                  `- ingest/
                       `- default.json 
```

|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|manifest.yml|モジュール関連のファイルパスつまりingest/default.jsonなどの設定を記述します|
|config/mail.yml|Filebeatへの入力ファイル設定（Postfixのログファイルパス）を生成するテンプレートを記述。Filebeatの開発言語であるGOの[テンプレート機能](https://golang.org/pkg/text/template/)を利用します。**今回は特に変更しません**|
|module.yml|ダッシュボード（Kibana）の設定を記述するファイルですが今回はダッシュボードは扱わないのでフィールドの名前だけ変更します|
|ingest/default.json|Elasticsearch/[Ingestノード](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest.html)へ注入するPipeline設定（[プロセッサ](https://www.elastic.co/guide/en/elasticsearch/reference/current/ingest-processors.html)の設定）を記述します。PostfixモジュールではGrok、Date、Remove、Dropプロセッサを利用しますのでその設定を行います|

##manifest.ymlの設定
```yml:manifest.yml
module_version: 1.0

var:
  - name: paths
    default:
      # Postfixのログファイルパス（FilebeatへのInputソース）
      - /var/log/mail.log*

# Ingestノードのパイプライン設定ファイルパス
ingest_pipeline: ingest/default.json

# 入力ソースの設定ファイルパス
input: config/mail.yml

requires.processors:
```

##config/mail.ymlの設定
Apache用モジュールからコピーしたまま変更しません。

```yml:config/mail.yml
type: log
paths:
{{ range $i, $path := .paths }}
 - {{$path}}
{{ end }}
exclude_files: [".gz$"]
```

##module.yml
ID値だけ変更しておきます。

```yml:module.yml
dashboards:
- id: Filebeat-Postfix-Dashboard
```

##ingest/default.json
Ingestノードに注入するPipeline設定を記述します。

###Ingestノードのパイプライン（プロセッサ）の設定

Postfix用のログメッセージをパーシングしてJSON形式へ変換します。以下のプロセッサを利用します。
![filebeat_json5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362125/2fc3ce13-ff72-6d14-1483-412c280470e4.png)


|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|[Grokプロセッサ](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html)|ログメッセージのテキストデータをパーシングしてJSON形式へ変換するプロセッサ。<br>パース形式を正規表現を組み合わせたパターンで記述するだけでOKです|
|<nobr>[Dateプロセッサ](https://www.elastic.co/guide/en/elasticsearch/reference/current/date-processor.html)</nobr>|PostfixログのSyslog形式タイムスタンプからISO8601形式へ変換します|
|[Removeプロセッサ](https://www.elastic.co/guide/en/elasticsearch/reference/current/remove-processor.html)  |不要な情報を削除。<br>Grokによってパーシングされた後で不要なログメッセージ情報をElasticsearchへ保存する前に削除します|
|[Dropプロセッサ](https://www.elastic.co/guide/en/elasticsearch/reference/current/drop-processor.html)  |採取対象外のログをElasticsearchへ保存する前に削除します|

設定の全体は以下の通りとなります。それぞれのプロセッサ設定について説明していきます。

```json-doc:ingest/default.json
{
  "description": "Pipeline for parsing postfix mail.log.",
  "processors": [{
    "grok": {
      "field": "message",
      "patterns":[
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.header_display_name} <%{DATA:postfix.mail.header_from_email}> from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>",
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* name=\"%{DATA:postfix.mail.mime_name}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>",
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* filename=\"%{DATA:postfix.mail.mime_filename}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>"
        ],
      "ignore_missing": false,
      "ignore_failure": false
    }
  }, {
      "date": {
        "field": "postfix.mail.time",
        "target_field": "postfix.mail.time",
        "formats": [
            "MMM  d HH:mm:ss",
            "MMM dd HH:mm:ss"
        ],
        "ignore_failure": true
      }
  }, {
      "remove": {
        "field": "message",
        "ignore_missing": true,
        "ignore_failure": true
      }
  }],
  "on_failure" : [{
    "drop" : {
      "ignore_failure" : true
    }
  }]
}
```

###GrokプロセッサによるログメッセージのJSON変換
GrokプロセッサによりFilebeatから転送された(b)JSONドキュメント内の**_source.message**フィールドのログメッセージは、(c)JSONドキュメントのようにパーシングされ**_source.postfix**のJSONオブジェクト形式へ変換されます。

```json-doc:(b)JSON（変換処理前）
{
  "_index" : "filebeat-6.6.0-2019.xx.xx",
  "_type" : "doc",
  "_id" : "SKMrAmoB5yTtiEEfLG6k",
  "_score" : 1.0,
  "_source" : {
  ......
    "message" : "Apr  21 08:01:14 dmz_server postfix/cleanup[6615]: 4B19A1000EB: warning: header Content-Type: image/png;? name=\"Test.png\" from unknown[192.168.0.xx]; from=<alice@example.com> to=<bob@example.com> proto=ESMTP helo=<[192.168.0.xx]>",
  ......
  }
}
```

```json-doc:(c)JSON（変換処理後）
{
  "_index" : "filebeat-6.6.0-2019.xx.xx",
  "_type" : "doc",
  "_id" : "SKMrAmoB5yTtiEEfLG6k",
  "_score" : 1.0,
  "_source" : {
  ......
    "postfix": {
      "mail": {
        "process": "cleanup",
        "to_email": "bob@example.com",
        "remote_ip": "192.168.0.xx",
        "from_email": "alice@example.com",
        "mime_type": "image/png",
        "header": "Content-Type",
        "pid": "2368",
        "mime_name": "Test.png",
        "time": "2019-04-20T23:01:14.000Z",
        "mail_server": "dmz_server",
        "queue_id": "304A6101243",
        "remote_host": "unknown"
      }
    },
  ......
  }
}
```

###変換先のテンプレート定義
まずGrokプロセッサがインデクスへ格納するログ情報のJSON形式（**_source.postfix**オブジェクト）を定義します。

テンプレートはデフォルトでは**/etc/filebeat/fields.yml**に定義されています。このファイルを**my_fields.yml**としてコピーしPostfixモジュール用の定義を追加します(前回Squidモジュールの作業を行っている場合には同じファイルを利用してください)。

```
cd /etc/filebeat
cp fields.yml my_fields.yml
```

モジュール本体と同様にここでもApache用のテンプレート定義(- key: apache2)を雛形にして作業します。詳細については前回の[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)に説明していますのであわせて参照してください。


###Postfix用モジュールのテンプレート定義
Postfix用モジュールの定義を**/etc/filebeat/my_fields.yml**へ追加します。

```/etc/filebeat/my_fields.yml
- key: postfix
  title: "postfix"
  description: >
    Postfix Module
  short_config: true
  fields:
    - name: postfix
      type: group
      description: >
        Postfix fields.
      fields:
        - name: mail
          type: group
          description: >
            Contains fields for the Postfix mail log.
          fields:
            - name: time
              type: keyword
              description: >
                log_time.
            - name: mail_server
              type: text
              description: >
                mail_server.
            - name: process
              type: keyword
              description: >
                process.
            - name: pid
              type: long
              description: >
                PID.
            - name: queue_id
              type: keyword
              description: >
                queue_id.
            - name: header
              type: keyword
              description: >
                header.
            - name: header_display_name
              type: text
              description: >
                header_display_name.
            - name: header_from_email
              type: text
              description: >
                header_from_email.
            - name: remote_host
              type: text
              description: >
                remote_host.
            - name: remote_ip
              type: keyword
              description: >
                remote_ip.
            - name: from_email
              type: text
              description: >
                from_email.
            - name: to_email
              type: text
              description: >
                to_email.
            - name: mime_type
              type: text
              description: >
                mime_type.
            - name: mime_name
              type: text
              description: >
                mime_name.
            - name: mime_filename
              type: text
              description: >
                mime_filename.
```

###Grokプロセッサの詳細
Grokプロセッサによるログメッセージのパーシング結果を変換するJSON形式を定義できました。次にプロセッサの設定を以下の通り行います。

```json-doc:ingest/default.json
{
  "description": "Pipeline for parsing postfix mail.log.",
  "processors": [{
    "grok": {
      "field": "message",
      "patterns":[
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.header_display_name} <%{DATA:postfix.mail.header_from_email}> from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>",
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* name=\"%{DATA:postfix.mail.mime_name}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>",
        "%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* filename=\"%{DATA:postfix.mail.mime_filename}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>"
        ],
      "ignore_missing": false,
      "ignore_failure": false
    }
  ......
}
```
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|field: message|Grokプロセッサが処理するフィールド名。ログメッセージが設定されている(b)JSONドキュメントの**message**フィールドを指定します|
|patterns:[...]|fieldで指定されたフィールド値のパーシング規則を正規表現を利用して記述します（詳細については前回の[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)を参照）|
|ignore_missing: false|フィールドが存在しない場合にはログ採取の対象外としてDropプロセッサへ渡します|
|ignore_failure: false|パーシング等に失敗した場合にはログ採取の対象外としてDropプロセッサへ渡します|

設定の詳細については[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/grok-processor.html)を参照。

####Grok patterns（パターン）の説明
Grokプロセッサの詳細については前回の[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)に説明していますので参照してください。

####Postfixログパーシング用のGrok patterns(パターン)
Squidモジュールと同様にKibanaのGrok Debuggerを利用して作成したパターンが以下です。

```text
%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.header_display_name} <%{DATA:postfix.mail.header_from_email}> from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>
%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* name=\"%{DATA:postfix.mail.mime_name}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>
%{SYSLOGTIMESTAMP:postfix.mail.time} %{DATA:postfix.mail.mail_server} postfix/%{DATA:postfix.mail.process}\\[%{NUMBER:postfix.mail.pid}\\]: %{BASE16NUM:postfix.mail.queue_id}: %{LOGLEVEL}: header %{DATA:postfix.mail.header}: %{DATA:postfix.mail.mime_type};(\\?)* filename=\"%{DATA:postfix.mail.mime_filename}\" from %{DATA:postfix.mail.remote_host}\\[%{IP:postfix.mail.remote_ip}\\]; from=<%{DATA:postfix.mail.from_email}> to=<%{DATA:postfix.mail.to_email}>
```
* '['および']'は'\'でエスケープします。
* **ingest/default.json**の**grok/patterns**は配列型ですので複数パターンを同時に記述できます。
* フィールド名は前回[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)のテンプレート定義で説明した通り、階層（ネスト）構造で指定します。
* **ingest/default.json**へ設定する場合には'"'および'\'をさらに'\'でエスケープします。

###DateプロセッサによるISO8601形式タイムスタンプの追加
Postfixのログで記録されるSyslog形式のタイムスタンプからISO8601形式タイムスタンプを生成し追加します。

```json-doc
{
  "description": "Pipeline for parsing postfix mail.log.",
  "processors": [{
  ......
  }, {
      "date": {
        "field": "postfix.mail.time",
        "target_field": "postfix.mail.time",
        "formats": [
            "MMM  d HH:mm:ss",
            "MMM dd HH:mm:ss"
        ],
        "ignore_failure": true
      }
  ......
  }],
  ......
}
```
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|field|Syslogタイムスタンプのフィールド名を指定します|
|target_field|変換結果を書き込むフィールド名を指定します|
|formats|変換元のSyslog形式フォーマットを指定します|
|ignore_failure: true|パーシング等でエラーが発生した場合に処理をスキップします|

###Removeプロセッサによる不要な情報の削除
不要または冗長な情報を削除します。
####Removeプロセッサの設定
パーシングしたmessageフィールドは不要なため削除します。

```json-doc:ingest/default.json
{
  "description": "Pipeline for parsing postfix mail.log.",
  "processors": [{
  ......
  }, {
    "remove": {
      "field": "message",
      "ignore_missing": true,
      "ignore_failure": true
    }
  ......
  }],
  ......
}
```
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|field|削除するフィールド名を指定します|
|ignore_missing: true|フィールド値が見つからない場合に処理をスキップします|
|ignore_failure: true|エラーが発生した場合に処理をスキップします|

詳細については[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/remove-processor.html)を参照。

###Dropプロセッサによって採取対象外のログメッセージを削除
本記事の設定例では採取対象外のログメッセージを削除します。
####Dropプロセッサの設定

```json-doc:ingest/default.json
{
  "description": "Pipeline for parsing postfix mail.log.",
  "processors": [{
  ......
  ......
  }],
  "on_failure" : [{
    "drop" : {
      "ignore_failure" : true
    }
  }]
}
```
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|ignore_failure: true|エラーが発生した場合に処理をスキップします|

詳細については[こちら](https://www.elastic.co/guide/en/elasticsearch/reference/current/drop-processor.html)を参照。

#Filebeatモジュールの設定手順
Postfix用のモジュールが完成しましたのでそれをdmz.example.comへデプロイします。

###モジュールの設定ファイル作成
```
/etc/filebeat/
   `- modules.d/
       `- postfix.yml.disabled
```
こちらもApache用の設定ファイルを雛形にして多少変更するだけです。

```text
cd /etc/filebeat/modules.d
cp apache2.yml.disabled postfix.yml.disabled
```

```yml:/etc/modules.d/postfix.yml.disabled
- module: postfix
  # Access logs
  mail:
    enabled: true

    # Set custom paths for the log files. If left empty,
    # Filebeat will choose the paths depending on your OS.
    #var.paths:
```

###モジュールのテンプレート設定を追加
前回[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)で設定している場合には必要ありません。

```
/etc/filebeat/
   `- my_fields.yml
```
さきほど作成したmy_fields.ymlのパスをFilebeatの設定ファイル(**/etc/filebeat/filebeat.yml**)で変更します。以下の**setup.template.fields**で説明します。

### Filebeatの設定ファイルを修正
こちらも前回[「プロキシサーバ編」](https://qiita.com/rhpenguin/items/7ec7ddf562906257e297)で設定している場合には必要ありません。

```
/etc/filebeat/
   `- filebeat.yml
```
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|説明|
|---|---|
|hosts: ["log.example.com:9200"]|Elasticsearchが動作するホストアドレスとポート番号を指定|
|filebeat.overwrite_pipelines: true|Elasticsearchへの接続毎にIngestノードのパイプライン設定を注入（デバッグ用）|
|setup.template.enabled: true|テンプレート設定の注入を有効化|
|setup.template.fields: "/etc/filebeat/my_fields.yml"|テンプレート設定ファイルの場所を変更|
|setup.template.overwrite: true|既存のテンプレート設定を更新|

詳細は**/etc/filebeat/filebeat.reference.yml**を参照してください。

```yml:/etc/filebeat/filebeat.yml
hosts: ["log.example.com:9200"]

#運用時にはコメントアウト
filebeat.overwrite_pipelines: true

setup.template.enabled: true
setup.template.fields: "/etc/filebeat/my_fields.yml"
setup.template.overwrite: true
```
Filebeatを再起動します。

```text
systemctl restart filebeat.service
```

###モジュールの有効化 
以上の設定作業が終わったらSquid用のモジュールを有効化します。

```text
filebeat modules enable postfix
```

###モジュールのテンプレート設定をElasticsearchへ注入

```text
filebeat setup --template
```

###モジュールのパイプライン設定をElasticsearchへ注入

```text
filebeat setup --pipelines -modules postfix
```

###補足
```
テンプレートの参照
curl -XGET http://log.example.com:9200/_template/filebeat-*?pretty 

テンプレートの削除
curl -XDELETE http://log.example.com:9200/_template/filebeat-*

パイプライン設定の参照
curl -XGET http://log.example.com:9200/_ingest/pipeline/filebeat-*?pretty 

パイプライン設定の削除
curl -XDELETE http://log.example.com:9200/_ingest/pipeline/filebeat-*

ログの取得
curl -XGET http://log.example.com:9200/filebeat-*/_search?pretty -H 'Content-Type: application/json' -d 
'{
  "query": {
    "match_all":{}
  },
  "size":100
}'

インデクスのリスト
curl http://log.example.com:9200/_cat/indices?v

registryファイルのクリア
rm /var/lib/filebeat/registry
```

#Kibanaでログを確認

* **Management/Create Index Pattern**にて **filebeat-***を指定してインデクスパターンを生成または更新（Refresh field list）。
* **Discover**にて**squid.access.***フィールドへパーシングされたログを確認できます。
![kibana_postfix1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362125/e6cfffdf-e104-8f53-eac4-fa7bd84eb6ae.png)
![kibana_postfix2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/362125/7b29c6b8-cce5-b534-c4e6-922fe6899121.png)


#まとめ
JPCERT/CCによる[「高度サイバー攻撃への対処におけるログの活用と分析方法」](https://www.jpcert.or.jp/research/apt-loganalysis.html)で推奨されるメールサーバのログ設定をもとにPostfixおよびElasticsearchを利用したログ解析基盤を構築してみました。

次回の記事では[Winlogbeat](https://www.elastic.co/products/beats/winlogbeat)を利用してエンドポイントログ採取(Windows 10 PC)のコンフィグレーションを追加していきます。

[「エンドポイントログ編（その１- 概要/Sysmon）」](https://qiita.com/rhpenguin/items/a53484fa76e375f27f24)へ続く