GuardDutyをGoogle Hangouts Chatで通知する

GuardDutyの通知をAWS Lambdaを使って、Google Hangouts Chatに通知してみました。 コードや手順をシェアします。

チャットルームの作成

チャットルームとWebhookを作成します。 https://chat.google.com/に接続し、左メニューからチャットルームを作成します。 今回はGuardDuty通知という部屋にしました。

チャットルームにWebhookを設定します。

名前を入力すると、URLが発行されます。

URLは後ほど使うので控えておきます。

チャットに連携するLambdaの作成

macOSで試した手順を共有します。 lambda_hangoutschatディレクトリを作成します。 WebHookを呼び出すためのrequestsモジュールを、インストールします。

$ mkdir lambda_hangoutschat
$ virtualenv lambda_hangoutschat/
$ source lambda_hangoutschat/bin/activate
$ pip3 install requests  

関数を作成します。 lambda_function.pyは後述の内容をコピーペーストします。

$ cd lambda_hangoutschat
$ vi lambda_function.py

zipファイルを作成します。

$ zip -r9 ../lambda_hangoutschat.zip .
$ cd ..

Lambda関数を作成します。今回はAWS CLIを使いますが、AWSコンソールでも可能です。 --roleは、Lambdaを実行するIAMロールのarnを指定します。IAMロールにIAMポリシーは不要です。 HANGOUT_WEBHOOK_URLはHangouts ChatのWeb HookのURLを指定します。

$ aws lambda create-function \
--region ap-northeast-1 \
--function-name lambda_hangoutschat \
--zip-file fileb://lambda_hangoutschat.zip \
--role arn:aws:iam::aws-account-id:role/AWSLambdaExecute \
--handler lambda_function.lambda_handler \
--runtime python3.7 \
--timeout 10 \
--memory-size 128 \
--environment Variables={HANGOUT_WEBHOOK_URL="WebHook URL"}  

lambda_function.py

Lambda関数のコードです。Python3.7で動作確認しました。 GuardDuty の CloudWatch イベントの形式や、レスポンスの構文を参考にし、特に重要な情報だけ通知しました。 また、イベントによって項目が異なるため、event変数に項目が存在するか確認します。

from json import dumps, loads
import logging
import os
from botocore.vendored import requests

def lambda_handler(event, context):
    URL = os.environ['HANGOUT_WEBHOOK_URL']

    body = "version:" + str(event['version']) + '\n'

    messages_keys = ["account","time","region","detail-type"]
    for key in messages_keys:
        body += key + ":" + str(event[key]) + '\n'

    messages_detail_keys = ["accountId","type","title","desctiption","account","region","createdAt","updatedAt"]
    for key in messages_detail_keys:
        if 'detail' in event:
            if key in event['detail']:
                body += key + ":" + str(event['detail'][key]) + '\n'

    bot_message = {
        'text' : body}

    message_headers = { 'Content-Type': 'application/json; charset=UTF-8'}

    response = requests.post(
        URL,
        headers=message_headers,
        data=dumps(bot_message),
    )

    return loads(response.text)

CloudWatch EventsとLambdaの紐付け

GuardDutyで検知すると、CloudWatch Eventsが発生します。 イベントとLambdaを紐付けます。 イベントパターンにGuardDutyを指定し、ルールを作成します。

aws events put-rule --name lambda_hangoutschat --event-pattern "{\"source\":[\"aws.guardduty\"]}"

ルールとLambda関数を紐付けます。

aws events put-targets --rule lambda_hangoutschat --targets Id=1,Arn=arn:aws:lambda:ap-northeast-1:aws-account-id:function:<your_function>

CloudWatchイベントがLambda関数を呼び出せるアクセス許可を追加します。

aws lambda add-permission --statement-id "TrustCWEToInvokeMyLambdaFunction" \
--action "lambda:InvokeFunction" \
--principal "events.amazonaws.com" \
--function-name "arn:aws:lambda:region:account-id:function:lambda_hangoutschat" \
--source-arn "arn:aws:events:region:account-id:rule/lambda_hangoutschat"

結果サンプルを発生させ、通知できるかテスト

GuardDutyの設定画面から、サンプルイベントを作成します。

以下のように通知できれば完了です。 まず、サンプルイベント作成のイベントが通知されます。

まもなく、サンプルイベントも通知されます。

スレッドに返信していく形で使うと便利です。 心当たりがある担当者はスレッドに反応し、問題のある内容かシェアします。

おわりに

GuardDutyの通知をAWS Lambdaを使って、Google Hangouts Chatに通知しました。 GuardDutyでイベントを検知したら、そのイベントが問題があるものかないものか切り分ける必要があります。 Hangouts Chatに通知すれば、スレッド形式で担当者間でやり取りができるため、切り分けに役立てられます。

参考