本記事はVuls Advent Calendar 2017 18日目の記事です。
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を公開していますので、これで環境構築します。
サンプル用VPC、EC2インスタンスの構築
まずは、スキャン対象のサーバ環境を構築します。
CloudFormationのスタック作成画面で sample_vpc.yml
を選択し、S3にアップロードします。
スタック名(何でも良い)、キーペア(デフォルトのEC2インスタンスで必要)、Vulsスキャンに使用するSSH公開鍵を入力します。
「次へ」を押していき、CloudFormationスタックを作成します。 無事作成が完了すると、「出力」タブに生成されたイベントソースが表示されます。 これらの値は次のCloudFormationで使うのでメモしておきます。
Serverless Vuls環境
CloudFormationスタック作成画面で、serverless_vuls.yml
を選択し、S3にアップロードします。
必要なパラメータを入力します。サブネットID、セキュリティグループID、KMSのIDなどは先ほどメモしたパラメータをコピペします。
スタックの作成が無事完了すると、「出力」タブにスキャンレポートが保存されるS3バケット名が表示されています。
go-cve-dictionary の実行
スキャン前に脆弱性情報をDBに貯めておきます。
Step Functionsに飛んで、FetchVulnerabilityDataFromN-xxxxx
を選択し、「新しい実行」をクリックします。完了までに約1時間かかるので気長に待ちましょう。
(goval-dictionaryはまだ未対応で今後対応していきます)
検証
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のチューニングを行って、さらに限界まで挑みたいと思います。