GuardDuty が検出した脅威をいい感じに Slack へ通知する

Posted on

AWS re:Invent 2017 で発表された脅威検出サービスの GuardDuty はもう試されましたか? 発表されたその日に有効化してみましたが、さっそく意図せずオープンになっていたポートへの攻撃が検出されました。幸いポートスキャンされただけで実害はありませんでしたが、GuardDuty で検出されなかったら気づくことはなかったと思います。

ところで、GuardDuty が検出した脅威は AWS Management Console で確認できますが、メールや Slack でプロアクティブに通知する機能はありません。 AWS あるあるですが、通知したければ自分で仕組みを作る必要があります。

いつも参考にさせてもらっている Developers.IO の「GuardDuty を設定してメンバーアカウントを招待してみた」にもこんな感想がありました。

いまの状態だと、毎日 GuardDuty のコンソール画面を見に行かなければならないので、たとえば「重要度 High の検知は即時通知、Medium は 1 日 1 回検知数を通知」などしたいですね。メールでなくチャット通知がうれしいです。

この記事では、GuardDuty が検出した脅威をいい感じに Slack へ通知する仕組みをご紹介します。

GuardDuty から Slack への通知の流れ

GuardDuty で脅威が検出されると、5 分間隔に CloudWatch Events に通知されます。この通知を Lambda で処理して Slack の Webhook を叩きます。

GuardDuty から Slack への通知の流れ

GuardDuty の通知には検出した脅威の重要度(0 〜 10.0 の小数)が含まれているので、その値に応じて通知の色とメンションするかどうかを変えています。実際の通知はこんな感じです(通知の中身はサンプルです)。

Slack に通知された GuardDuty の結果

たとえば 9.0 の場合は Critical に位置付けられており、優先事項として直ちに修正することが勧められています。この脅威はすぐに気づく必要があるので @channel でメンションを飛ばしています。逆に 0 の場合は Information レベルに留まるのでメンションは飛ばしていません。

Lambda ファンクションの Python コード

今回は Python 3.6 で Lambda ファンクションを書いてみました。 WEBHOOK_URL は Lambda の環境変数で定義しています。

get_severity_level という関数で脅威のスコアから通知の色とメンションを定義して、その情報をもとに JSON を組み立てて Slack の Webhook へ POST しています。 IAM Role は CloudWatch Logs に書き込める権限があれば OK です。

CloudWatch Events の設定

Lambda ファンクションが準備できれば、あとは CloudWatch Events の設定をすれば完了です。

まずは CloudWatch Events のルールを作って、先ほど作成した Lambda ファンクションをアタッチします。 RegionAccount ID の部分は適宜読み替えてください。

$ aws events put-rule --name guardduty_finding --description 'Notify the GuardDuty Finding.' --event-pattern '{"source":["aws.guardduty"],"detail-type":["GuardDuty Finding"]}'

$ aws events put-targets --rule guardduty_finding --targets 'Id=1,Arn=arn:aws:lambda:<Region>:<Account ID>:function:guardduty_finding'

次にターゲットを呼び出す上で必要なアクセス許可を追加します。

$ aws lambda add-permission --function-name guardduty_finding --statement-id 1 --action 'lambda:InvokeFunction' --principal events.amazonaws.com

通知のテスト

GuardDuty には "Generate sample findings" というサンプルの結果を生成する機能があります。 GuardDuty の設定画面からも操作できますが、API が用意されているので AWS CLI からワンライナーで実行できます。

$ aws guardduty create-sample-findings --detector-id $(aws guardduty list-detectors --query 'DetectorIds' --output text)

実行すると "SAMPLE" から始まる脅威が 20 個ほど生成されるので、うまく連携できていれば数分以内に Slack へ通知されます。

Slack に通知された GuardDuty の結果

まとめ

GuardDuty が検出した脅威は JSON で詳細に取得できるので、ちょっと工夫するだけでいい感じに Slack へ通知できました。

ほかにもアイデア次第で、

  • GuardDuty が検知した攻撃者の IP アドレスを AWS WAF に登録して自動的に遮断する
  • Critical の脅威が見つかったら Twilio 経由で SRE に電話をかける
  • SSH や RDP のポートが全開になっていたら自動的に塞ぐ

など、いろいろ自動化できそうですね。