vulsでRPM以外も脆弱性検知(grasys)

こんにちワン!grasys長谷川です。

今日は脆弱性スキャナのvulsのgrasysでの利用方法ネタを書きます。

vuls


vuls
簡単な構成図はOfficialにあります。

grasysではvulsを工夫して使っているので今回はその部分をご紹介します。

grasysでの構成例

grasysではopsというオーケストレーションしたりするオペレーション用のインスタンスを生成しており、そこからvuls scanを発行しています。

vuls architecutre

grasysだとそのままで使えない理由

grasysではサーバの構成をそれなりにカスタマイズしているのでvulsそのままでは使いにくい点があったりします。

検知対象がRPM Packageのみだったりするので
SourceからBuildするような形だと対象外になってしまいます。

RPMだけで構成してる方はここでブラウザをおもむろに閉じてくださいw


簡単にgrasysの基本的なアーキテクチャを説明

grasysでは言語系のコンポーネントにRPMを極力利用しないようにしています。

目的としては単純に以下です。

  • 長期間の運用考慮
  • 言語のUpdateを止めたままその他のLibなど更新しやすくしたい(お客様の事情で言語のVersion上げられないこともあるので

OSのVersionが上がっても動く環境を再現しやすくするためにやっています。(ちょっと変わってるのかもしれないけどw

言語管理系

Lang Environment Tool
php phpenv
python pyenv
ruby rbenv
perl plenv
java jenv
erlang kerl
node.js nodebrew -> nodenvに移行中

かなりXXenvを多様していますw
大好きXXenv!
anyenvは自動管理するに少しやりにくいところがあったのでうちでは使ってません
開発環境とかだと自分で常にいじったりしてるだろうからいいんだろうけどね〜
上記以外で言語系ではないですがautoenvなども便利なので使ってます!

上記以外のgrasysの必須コンポーネント


RPM以外をどうやって検知対象に入れているか

/usr/local配下

以下あるインスタンスの/usr/localの状態です。

$ tree -L 1 /usr/local/
/usr/local/
├── bin
├── etc
├── games
├── hiredis -> /usr/local/hiredis-0.10.1
├── hiredis-0.10.1
├── include
├── lib
├── lib64
├── libexec
├── nginx -> nginx-1.10.1
├── nginx-1.10.1
├── plenv
├── pyenv
├── sbin
├── share
├── src
└── var

以下ができるような簡単なscriptを用意しています。

  1. /usr/local配下でsymlinkになっているものをreadlink
  2. 実態のbasenameを取得
  3. [Middleware Name], [Version], [Patch Version]にsplit
  4. JSONにする
  5. consul kvにsetする

以下のような情報が入ります。

$ consul-cli kv read vuls/[instance name] | jq .
{
  "host": {
    "node_name": "[instance name]",
    "tags": {
      "machine-type": "n1-standard-2",
      "numeric-project-id": xxxxxxxxxxxxxx,
      "zone": "asia-east1-a",
      "ip": "10.240.x.x",
      "project-id": "xxxxxx-xxxxxx-xxxxxx",
      "external-ip": "xxx.xxx.xxx.xxx",
      "servertype": "[tag]",
      "tags": [
        "[tag]"
      ]
    }
  },
  "middleware": [
    {
      "name": "python",
      "version": "2.7.11"
    },
    {
      "version": "5.20.1",
      "name": "perl"
    },
    {
      "version": "2.69",
      "name": "autoconf"
    },
    {
      "version": "1.15",
      "name": "automake"
    },
    {
      "version": "2.4",
      "name": "chrony"
    },
    {
      "name": "daemon",
      "version": "0.6.4"
    },
    {
      "name": "git",
      "version": "2.8.1"
    },
    {
      "name": "hiredis",
      "version": "0.10.1"
    },
    {
      "version": "3.0.7",
      "name": "redis"
    },
    {
      "version": "6.0",
      "name": "texinfo"
    },
    {
      "name": "consul",
      "version": "0.6.4"
    },
    {
      "version": "0.7.0",
      "name": "serf"
    },
    {
      "version": "0.7.3",
      "name": "dkron"
    },
    {
      "name": "inotifywait",
      "version": "3.13"
    },
    {
      "name": "sshguard",
      "version": "1.6.4"
    },
    {
      "version": "2.4.5",
      "name": "snoopy"
    }
  ],
  "update_time": "2016-08-12 18:58:53"
}

ここではpatch versionが含まれているMiddlewareがありませんが
存在すれば抽出するようにごにょごにょしていますw

こんなのを適当にcronで毎日回しています。

vulsのtomlを自動生成

grasysでは簡単なtemplate engineを利用してvulsのconfigを自動生成しています。

consul kvに入っているJSONはvulsのconfigのcpeNamesを自動設定するために利用しています。

vuls config生成

vuls configのserversセクション抜粋)

[servers]

[servers.[instance name]]
host = "[instance name]"

cpeNames = [
  "cpe:/a:xxxxxxx:[product]:[version]:[update]"
]

上記のcpeNamesの自動生成を取得するためにcve.sqlite3に発行するSQLのSampleです)

sqlite3 [cve.sqlite3]

SELECT
  cpe_name
FROM cpes 
WHERE product = "[product]"
AND version = "[version]"
[ AND update = "[update]" ]

上記をvuls scanするまえに自動生成し定時実行しています。

これでphpenvpyenvといった言語コンポーネントの脆弱性も検知できるようにしています。
通知系はvulsのslack機能は使わずにgrasysの監視ツールに渡してslack通知しています。(slackの通知多くなっちゃうから・・・

InitScript

いろいろサブコマンドとか覚えれられないので独自のInitScriptを用意して運用の軽減をしています。

/etc/init.d/vuls

/etc/init.d/vuls: vuls init script
help:

example:
  /etc/init.d/vuls [sub command]

sub command:
  start:                start server
  stop:                 stop server
  restart               restart server
  status                server status

  1st_setup             setup, update_week, reconfig, prepare, start
  full_setup            setup, update_full, reconfig, prepare, start

  reconfig:             make config
  setup:                setup cve/nve database
  prepare:              prepare instance

  scan:                 scan
  history:              scan history
  report:               for consul service report
  tui:                  Terminal User Interface

update cve database
  update_entire:        dictionary entire update
  update_month:         dictionary month update
  update_week:          dictionary week update
  update_full:          dictionary full update

ちょっと残念なとこ・・・

各言語のversionによる脆弱性やMiddlewareの脆弱性は検知できるけども!

Web Application Frameworkのversionまで自動で集めることができずwww

上記の対応については
Instance Tagに紐づくyamlファイルを拡張で持つことができるようにしてあり
そこに苦肉の策としてごにょごにょ書くことで対応するようにしてます・・・

example)

-
  name: django
  version: 1.6

pip freezeとかしちゃうと他の言語も全部するはめに・・・
だからやらない!