こんにちは。もうすっかり老害になったインフラエンジニアの渡邉です。
ようやく朝方涼しくなってきましたね。犬の散歩が捗ります。
突然ですが、みなさん脆弱性対応ってしてますか?
今に始まったことではないですが、特にインフラエンジニアにとっては脆弱性対応はとても面倒で手間がかかる頭の痛いタスクになっています。
というわけで今回は、弊社のraksul.com/hacobell.com環境に巷で話題の脆弱性スキャナ「vuls」を導入した話をしたいと思います。
経緯
日を追うごとに管理するEC2インスタンス数や導入しているpackageが増えてきたこともあり、それぞれのCVEを追いかけるのが辛くなってきました。
エンジニアにとっては非常に面倒な監査用のレポーティングもそろそろ必要だろうという機運が
高まってきたところで、ちょうどとある勉強会でvulsのことを知ったので、とりあえずこのビッグウェーブに乗ってやろうと思ったのが発端です。
特にv0.4.0へのupdate後は非常に運用が捗るようになりました。
弊社環境
去年ご紹介の通り、サービスインフラはすべてaws上に展開しています。
オトナの事情もあり、以下のOSが混在しております。
- amazon linux
- ubuntu 16.04
- CentOS 7.3
また、環境構築の再現性を維持するため、それぞれpackageはversionlockを施しています。
vulsもamazon linux上で動かしています。
インストールと設定
repoを見るとわかりますが、vulsは非常に細かくかつ日本語でreadmeが書かれていますので、この通りに実施すればまずハマることはないと思います。
v0.3系まではamazon linux上でも全く問題なく導入ができました。
v0.4.0からgolangのrequire versionが1.8.3以上になったので、amazonのyum repositoryからinstallした1.7系のgoではmakeが通りませんのでご注意を。
弊社では1.9のgolangをrpmbuildして自前yum repositoryにupして使っています。
文末に弊社で使っているchefのrecipeを掲載しますので、よろしければご活用ください。
運用
versionlockをかけている環境ではscan時にversionlockを外さないとpackage差分が取れず
scanが意味をなしません。
そのため弊社ではjenkinsのpipelineを使ってdatabaseのupdateからversionlockのoff/on、reportingまでを行っています。
また増設などによってscan対象が日々変化するため、config.tomlの生成も自動化しています。
フローとしては上記の画像のとおりですが、簡単に説明します。
- まずnvd(jvn)とovalのdatabaseを更新する
- scan対象のversionlockをoffにする
- /etc/yum/plugin.d/versionlock.listを一旦退避します
- 同時にscan対象の一覧を更新します
- config.tomlにscan対象をひたすら追記しています
- vuls scanを実行します
- scanの成功/失敗を問わずversionlockを元に戻します
- 同時にvuls reportでreportingを行います
- 生成されたjsonをサービスごとのresult directoryに移動させます
これをdailyで回して、チーム定例mtgのときにvulsrepoでチェックしています。
slack通知もできるのですが、対象ホストごとにmessageが来るので弊社では通知はせずに能動的に見るようにしています。
一括対応した翌日とかに増えていると、(´;ω;`)ウッ…となります。。。
弊社ではさらにchefのテストで、github上のvuls自体に更新が入れば通知が来るようにしています。
v0.4.0でよくなったところ
※ あくまで弊社運用上の主観です。
- OVALにも対応し、CVSS detailがさらに見やすくなった
- NewPackageVerが出るようになった
- これまではversionlockをとりあえず外してupdateしてからlistを作っていましたが、このおかげで先にversionlockを更新してから安全にupdateができています
- NotFixedYetが出るようになった
- 表示されるpackage versionまで上げたとして、該当のCVEがfixされるのかどうか、がわかるようになりました
- vulsrepoで大量のhostを選択してもきちんと表示されるようになった
- 前のバージョンのときは100台超えるとエラーになってしまってました
おまけ
vulsとvulsrepoをsetupするためのchef recipeです。
golangの導入部分や、pathやuserなどを適宜書き換えてお使いください。
config.tomlの設置、vulsrepo-serverの起動及びリバプロ設定などは別途行ってください。
%w[ golang sqlite ].each do |pkg| package pkg do options '--enablerepo=xxx' end end # https://docs.chef.io/resources.html#recursive-directories %w[ /path/to /path/to/go /path/to/go/src /path/to/go/src/github.com /path/to/go/src/github.com/future-architect /var/log/vuls ].each do |d| directory d do owner 'foo' group 'bar' mode '2775' end end go_home = '/path/to/go' cve_home = "#{go_home}/src/github.com/go-cve-dictionary" git cve_home do repository 'git://github.com/kotakanbe/go-cve-dictionary.git' revision 'master' action :sync user 'foo' group 'bar' notifies :run, 'execute[make-go-cve-dictionary]', :immediately notifies :run, 'execute[get-cve-info]', :immediately notifies :run, 'execute[get-cve-info-ja]', :immediately end execute 'make-go-cve-dictionary' do command 'make install' cwd cve_home user 'foo' environment( 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end execute 'get-cve-info' do command 'for i in `seq 2002 $(date +"%Y")`; do go-cve-dictionary fetchnvd -years $i; done' cwd '/path/to/go' user 'foo' environment( 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end execute 'get-cve-info-ja' do command 'for i in `seq 1998 $(date +"%Y")`; do go-cve-dictionary fetchjvn -years $i; done' cwd '/path/to/go' user 'foo' environment( 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end goval_home = "#{go_home}/src/github.com/goval-dictionary" git goval_home do repository 'git://github.com/kotakanbe/goval-dictionary.git' revision 'master' action :sync user 'foo' group 'bar' notifies :run, 'execute[make-goval-dictionary]', :immediately notifies :run, 'execute[get-redhat-goval-info]', :immediately notifies :run, 'execute[get-ubuntu-goval-info]', :immediately end execute 'make-goval-dictionary' do command 'make install' cwd goval_home user 'foo' environment( 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end execute 'get-redhat-goval-info' do command 'goval-dictionary fetch-redhat 6 7' user 'foo' environment( 'PWD' => '/path/to/go', 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end execute 'get-ubuntu-goval-info' do command 'goval-dictionary fetch-ubuntu 16' user 'foo' environment( 'PWD' => '/path/to/go', 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end vuls_home = "#{go_home}/src/github.com/future-architect/vuls" git vuls_home do repository 'git://github.com/future-architect/vuls.git' revision 'master' action :sync user 'foo' group 'bar' notifies :run, 'execute[make-vuls]', :immediately end execute 'make-vuls' do command 'make install' cwd vuls_home user 'foo' environment( 'GOPATH' => go_home, 'PATH' => "#{ENV['PATH']}:#{go_home}/bin", ) action :nothing end template '/etc/profile.d/goenv.sh' do source 'goenv.sh.erb' owner 'foo' group 'bar' mode '0755' end # setup vulsrepo vulsrepo_home = '/path/to/go/src/github.com/vulsrepo' git vulsrepo_home do repository 'git://github.com/usiusi360/vulsrepo.git' revision 'master' action :sync user 'foo' group 'bar' end template "#{vulsrepo_home}/server/vulsrepo-config.toml" do source 'vulsrepo-config.toml.erb' owner 'foo' group 'bar' mode '0644' variables( :vulsrepo_home => vulsrepo_home, :go_home => go_home ) only_if { Dir.exist?(vulsrepo_home) } end
最後に
導入も簡単で可視化もできてウケもいいので、みなさんぜひ使ってみましょう。
SaaS版の展開もあるようなので、そちらの機能にも期待大ですね。
詰まったら slack の初心者用チャンネルで質問してみましょう。
みんな優しく教えて下さいます。
そして、しょうもない質問にも快く答えてくださったvuls作者の @kotakanbe さん、ありがとうございました!