Zabbixに登録されたホスト情報を脆弱性スキャナVulsへ自動連携する

# 追記
- 2016/7/25
    - 記事のタイトルを修正しました。
- 2016/10/3
    - フロー②③について関連記事を追加

VulsにおけるZabbixを絡めた連携フローは以下のようになります。
> ① Zabbixに登録されているホスト情報を元にVulsの設定ファイル(スキャン対象ホストを記述)を生成する
> ② Vulsでスキャンする（JSONの結果ファイルを出力する）
> ③ JSONの結果ファイルを元にホスト毎の脆弱性の個数と深刻度の最大値をZabbixに送信

本記事では①について記載しています。
②③については、@aomoriringoさんが作られたスクリプトを元に、Zabbixでのグラフ化＆トリガー・アラート条件へ連携することができます。

2016/10/3 別投稿にまとめました。
[脆弱性スキャナVulsのスキャン結果をZabbixへ連携しアラート通知する](http://qiita.com/usiusi360/items/5a9341575d4901598658)


# はじめに
最近話題になっている脆弱性検知ツール「Vuls」を使ってみました。

Github：[Vuls: VULnerability Scanner](https://github.com/future-architect/vuls)
[あなたのサーバは本当に安全ですか？今もっともイケてる脆弱性検知ツールVulsを使ってみた](http://qiita.com/sadayuki-matsuno/items/0bb8bb1689425bb9a21c)

機能や使い方は上記のサイトに詳しく書かれているので省略しますが、使ってみて一点気になったのはスキャン対象のサーバ情報はスキャン実施前に設定ファイルに記述する必要があり、それらの設定管理がちょっと面倒です。
ツール自身にdiscover機能はあるのですが、自動生成された設定ファイルを見るとサーバ名は[servers.IPアドレス]となり、TUI(Terminal-Based User Interface)で見たときに認識しづらく、ホスト名で表示できればと思いました。

![image](https://qiita-image-store.s3.amazonaws.com/0/54952/7aae077f-f48b-37fb-f0c6-22ad269ecf10.png)

```bash:Vulsのdiscover機能で生成された設定ファイル
[servers]
[servers.172-31-4-82]　←←←★ホスト名になって欲しい★
host        = "172.31.4.82"
port        = "22"
user        = "root"
keyPath     = "/home/username/.ssh/id_rsa"
```
またdiscover機能は一回の実行で一つのセグメントしか指定できないようなので、複数セグメントある場合はセグメント毎に実行した結果をくっつけたり、スキャン不要なホストの削除も手動で修正する必要があります。

というわけで、今回はシステム監視に使用しているZabbixからホスト情報をAPIで抜き出して、Vulsの設定情報を自動生成したいと思います。


# サーバ設定情報の生成

※以降、Vulsのホームディレクトリは/opt/vulsにあるものとします。
serversセクション以外の共通設定をconfig.toml.masterに記述しておきます。
後述するスクリプトの中でZabbixから抜き出した情報とくっつけます。


```bash:config.toml.master
$ cd /opt/vuls
$ vi config.toml.master

<<通知が必要な場合は、[slack]または[mail]セクションもここに記述>>

[default]
port        = "22"
user        = "username"
keyPath     = "/home/username/.ssh/id_rsa"

```

今回は手っ取り早くbashスクリプトにしてみました。途中curlとjqコマンドを使っているのでインストールしておく必要があります。また、スクリプト内のZabbixのID、Passwordを環境に合わせて変更しておきます。

以下のスクリプト内では、Zabbix上に登録されているホストの中で、ZabbixAgentのステータスが「正常」、かつホストのステータスが「有効」になっているものをAPIで抽出します。さらにホストの「エージェントのインターフェース」の中から一つ目のIPアドレスだけ抜き出します。

```bash:create_config.sh
#!/bin/bash

ZABBIX_SERVER="zabbix-server"
ZABBIX_USER="Admin"
ZABBIX_PASS="hogehoge"

VULS_HOME=`cd $(dirname $0) && pwd`

###########################

url="http://${ZABBIX_SERVER}/zabbix/api_jsonrpc.php"
curl_comm='curl -s -X POST -H Content-Type:application/json-rpc --data @_tmp_json'

cd ${VULS_HOME}
if [ ! -e config.toml.master ]; then
  echo "Not found [config.toml.master]"
  exit 1
fi

#===== authentication
cat << EOS > _tmp_json
{
    "jsonrpc": "2.0",
    "method": "user.login",
    "params": {
        "user": "${ZABBIX_USER}",
        "password": "${ZABBIX_PASS}"
    },
    "id": 1
}
EOS

session_id=`$curl_comm $url | jq -r '.result'`

if [ "$session_id" == "" ];then
  echo "Authentication fail"
  exit 1
fi

#===== getHostdata
cat << EOS > _tmp_json
{
    "jsonrpc": "2.0",
    "method": "host.get",
    "params": {
        "output": [ "host" , "available" , "status" ],
        "selectInterfaces" : [ "ip" , "type" ],
        "sortfield" : "host",
        "filter" : {
                    "available" : [ "1" ],
                    "status" : [ "0" ]
                   }
    },
    "auth": "$session_id",
    "id": 2
}
EOS

$curl_comm $url | jq -r '.result[] | "\(.interfaces[] | select(.type=="1") | .ip) \(.host)"' | uniq -f 1 > _tmp_serverlist

if [ -e ignore.list ]; then
  while read line; do
    sed -i "/$line/d" _tmp_serverlist
  done < ignore.list
fi

#===== createConfig #####
echo "" > _tmp_config
echo "[servers]" > _tmp_config
while read line; do
    serverIP=`echo "$line" | cut -d " " -f1`
    serverName=`echo "$line" | cut -d " " -f2`
    echo "[servers.$serverName]" >> _tmp_config
    echo "host = \"$serverIP\"" >> _tmp_config
    echo "" >> _tmp_config
done < _tmp_serverlist

cat config.toml.master _tmp_config > config.toml

```

スキャン対象外とするホストをignore.listに記載します（ホスト名かIPアドレス [部分一致可]）。

```bash:ignore.list
（例）
ap001
db
192.168.10
```

最後に作成したスクリプトを実行するとconfig.tomlが作成されます。

```bash
$ chmod 755 create_config.sh
$ ./create_config.sh

$ cat config.toml
[default]
port        = "22"
user        = "username"
keyPath     = "/home/username/.ssh/id_rsa"

[servers]
[servers.web001]　←←←★ホスト名で登録されている★
host        = "192.168.0.1"

[servers.app001]　←←←★ホスト名で登録されている★
host        = "192.168.0.2"
　　　～～～～
```

prepareで対象ホストの動作チェックを行います。

```bash:対象ホストの動作チェック
$ vuls prepare -config /opt/vuls/config.toml

```

# さいごに

Zabbixのホストディスカバリ機能を使って自動でホスト追加を行っていれば、冒頭に書いたとおり
「Vulsコンフィグ作成」⇒「vuls prepare」⇒「vuls scan」⇒「Zabbixへ通知」
をcronで定期実行し、サーバの作成からシステム監視、脆弱性チェックまで一貫して自動化することができます。