本日も乙

ただの自己満足な備忘録。

Serverless Vuls(AWS Lambda)でスキャンできる台数の上限を調べてみた

本記事はVuls Advent Calendar 2017 18日目の記事です。

qiita.com

Vuls祭り #3でAWS Lambdaを使ったVulsスキャン(Serverless Vuls)についてのLTをしたところ、「何台までのサーバ台数ならスキャンできますか?」という質問をTwitterでもらいました。 台数の上限に関するテストをしていなかったので、この機会(?)にサーバ台数の上限にチャレンジしてみました。

環境

  • Vuls v0.4.2
  • AWS Lambda 3008MB、最大5分
  • スキャン対象
    • Amazon Linux 2015.09 (ami-383c1956)
    • インスタンスタイプ: t1.micro, t2.nano, t2.micro, t2.small, t2.medium, m3.medium
    • EC2起動数の上限(オンデマンド:20, スポットインスタンス: 50)があるため、インスタンスタイプをばらしてスキャンしました。

実行内容

Lambda関数内で以下のことを行います。

1. ec2-vuls-config

EC2タグからスキャン対象を選定し、コンフィグファイルに書き出します。

$ ./ec2-vuls-config --config ./config.toml --out /tmp/config.toml

2. vuls configtest

コンフィグチェックします。

$ ./vuls configtest \
-config=/tmp/config.toml \
-log-dir=/tmp/vuls \
-ssh-native-insecure

3. vuls scan

メインです。

$ ./vuls scan \
-config=/tmp/config.toml \
-results-dir=/tmp/results \
-log-dir=/tmp/vuls \
-ssh-native-insecure

4. vuls report -format-one-line-text

ヒットした脆弱件数を出力します。

$ ./vuls report \
-lang=ja \
-config=/tmp/config.toml \
-results-dir=/tmp/results \
-log-dir=/tmp/vuls \
-format-one-line-text \
-cvedb-type=mysql \
-cvedb-url=hogehoge \
-refresh-cve

5. vuls report -to-s3

スキャン結果をS3に保存します。

$ ./vuls report \
-lang=ja \
-config=/tmp/config.toml \
-results-dir=/tmp/results \
-log-dir=/tmp/vuls \
-to-localfile \
-format-json \
-to-s3 \
-aws-region=ap-northeast-1 \
-aws-s3-bucket=S3_BUCKET \
-cvedb-type=mysql \
-cvedb-url=hogehoge \
-refresh-cve

準備

スキャンするためのサーバ環境や、Vulsスキャンのセットアップを行う必要がありますが、CloudFormationを公開していますので、これで環境構築します。

github.com

サンプル用VPC、EC2インスタンスの構築

まずは、スキャン対象のサーバ環境を構築します。
CloudFormationのスタック作成画面で sample_vpc.yml を選択し、S3にアップロードします。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-1.png

スタック名(何でも良い)、キーペア(デフォルトのEC2インスタンスで必要)、Vulsスキャンに使用するSSH公開鍵を入力します。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-2.png

「次へ」を押していき、CloudFormationスタックを作成します。 無事作成が完了すると、「出力」タブに生成されたイベントソースが表示されます。 これらの値は次のCloudFormationで使うのでメモしておきます。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-3.png

Serverless Vuls環境

CloudFormationスタック作成画面で、serverless_vuls.ymlを選択し、S3にアップロードします。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-4.png

必要なパラメータを入力します。サブネットID、セキュリティグループID、KMSのIDなどは先ほどメモしたパラメータをコピペします。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-5.png

スタックの作成が無事完了すると、「出力」タブにスキャンレポートが保存されるS3バケット名が表示されています。

https://contents.blog.jicoman.info/2017/12/serverless-vuls-7.png

go-cve-dictionary の実行

スキャン前に脆弱性情報をDBに貯めておきます。 Step Functionsに飛んで、FetchVulnerabilityDataFromN-xxxxxを選択し、「新しい実行」をクリックします。完了までに約1時間かかるので気長に待ちましょう。
(goval-dictionaryはまだ未対応で今後対応していきます)

https://contents.blog.jicoman.info/2017/12/serverless-vuls-8.png

検証

1台

まずは1台だけスキャンしました。 結果はGistにアップロードしています。

lambda_vuls_scan_1_server.log · GitHub

スキャンは1秒で終わっています。激速。vuls report -format-one-line-textも数秒で終わっています。vuls report -to-s3 はS3にアップロードするのが遅いのか、約3分もかかっており、5分というタイムリミットに対して意外とギリギリで終わりました。

30台

30台でやってみました。

lambda_vuls_scan_1_server.log · GitHub

スキャン成功です。
スキャン完了まで3秒と超速です。一部のサーバでエラーが出てますが、恐らく設定ミスだと思われるので無視。
すべて同じAMIで生成したのに、検知した件数と [Reboot Required] が付いているサーバが異なるのは不思議ですね。

70台

一気に70台までやってみます。本当は100台までいきたかったのですが、AWSの制限により、オンデマンド20台、スポットインスタンス50台の計70台が限界でした。今回の件と関係ありませんが、複数インスタンスを一気に起動できるSpot FleetとEC2 Template機能が便利ですね。

lambda_vuls_scan_1_server.log · GitHub

スキャンが失敗しました。
Too many connectionsで落ちており、vuls report するためにDB接続数が単純に増加していったのだと思います。RDS(MySQL)は db.t2.micro でかなり小さいインスタンスなので、デフォルトで設定されているMax Connectionの値が小さかったのだと思います。 コネクションエラーもありますが、レポート出力する途中で時間切れになってしまったのが最大の要因でした。
スキャンスピードは変わらず3秒程度で完了していました。

結論

今回は時間がなく、中途半端な検証になってしまいましたが、以下のような結論になりました。

  • 30台までは確実にスキャン&レポート出力できる。それ以上はレポート出力がボトルネックになる
  • レポート出力はスキャン対象一台ずつに対してDB接続しているため、Max Connectionのパラメータを上げることで上限を引き上げることができるが限界がある
  • スキャン自体のスピードはとても早く数百台であっても問題ない

次回機会があれば、EC2インスタンスの上限緩和とRDSのチューニングを行って、さらに限界まで挑みたいと思います。