Lambda + SNS でSecurity Hubの検出結果をメール通知する

記事タイトルとURLをコピーする

CI2部 技術2課の山﨑です。

EventBridgeを利用してメール通知設定を行うには大きく以下の2つの方法があります。

  • EventBridgeの入力トランスフォーマー + SNSで実装する
  • Lambda + SNSで実装する

1つ目の方法については過去にブログを執筆しましたので、今回は2つ目の方法「 Lambda + SNS」を使ったSecurity Hubの通知を実装してみました

blog.serverworks.co.jp

事前準備

  • SNSトピックの作成およびサブスクリプションの追加

Lambda

実行環境

  • ランタイム:python3.8

Execution role

以下のIAM PolicyをアタッチしたIAM RoleをLambda関数に関連付け

  • AWSLambdaBasicExecutionRole(AWS管理ポリシー)
  • SNSPublish(カスタマー管理ポリシー)

以下、SNSPublishのポリシーステートメント

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "sns:Publish"
            ],
            "Resource": "*",
            "Effect": "Allow"
        }
    ]
}

環境変数(Environment variables )

  • sns_topic : 事前準備で作成したSNSトピックのARN

関数

  • 関数名:SecurityHub-Notification

ソースコードは以下を使用

import logging
import os
 
import boto3
 
 
logger = logging.getLogger()
logger.setLevel(logging.INFO)
 
def lambda_handler(event, context):
    try:
        messages = parse_event(event)
        sns_publish(messages)

        return {
            'statusCode': 200,
            'body': 'Success Sending Message'
        }
    except Exception as e:
        logger.exception(e)
        raise e
 
# SNSでメッセージを送信
def sns_publish(messages):
    client = boto3.client('sns')
    topic_arn = os.environ['sns_topic']
 
    for message in messages:
        client.publish(
            TopicArn = topic_arn,
            Subject = message[0],
            Message = message[1]
        )
    return
 
### イベント情報からSNSの件名とメッセージを整形
def parse_event(event):
    messages = []
 
    time = event['time']
    region = event['region']
    # Security Hub以外のサービスのFindingsでもひと目で分かるようにイベント情報からsourceを取得
    source = event['source']
    source = source.split('.')
 
    for index, finding in enumerate(event['detail']['findings']):
        message_list = []
 
        account = finding['AwsAccountId']
        description = finding['Description']
        title = finding['Title']
        findings_id = finding['Id']
        label = finding['Severity']['Label']
 
        subject = f'【{source[1]}が重要度{label}の異常を検知しました】'    
        message = f"""
        【検出結果 {index + 1} つ目】

        <基本情報>
        ▼Account ID : {account}
        ▼検知時刻 : {time}
        ▼リージョン: {region}
    
        <詳細情報>
        ▼検出項目: {title}
        ▼検出内容 : {description}
        ▼検索ID : {findings_id}

        <ネクストアクション>
        ▼Security Hubのコンソール画面の左メニュータグより「検出結果」を選択
        ▼次に検索ウィンドウで「フィルターの追加」で「ID」選択
        ▼「ID」に検索IDの値を入力して検索を実行。
        ▼ヒットした検出結果の「タイトル」列のリンクを開いて詳細情報を確認してください    
        """
        message.strip()
         
        message_list.extend([subject, message])
        messages.append(message_list)
        logger.info('Success Creating SNS Messages')
 
    return messages

EventBridge

イベントパターン

イベントパターンは以下を利用

{
  "source": [
    "aws.securityhub"
  ],
  "detail-type": [
    "Security Hub Findings - Imported"
  ],
  "detail": {
    "findings": {
      "Severity": {
        "Label": [
          "CRITICAL",
          "HIGH"
        ]
      }
    }
  }
}

ターゲット

  • Lambda function
    • functionには作成したLambda関数(SecurityHub-Notification)を指定

通知内容

通知結果は以下のようになりました

f:id:swx-yamasaki:20220226102231p:plain
メール通知内容

まとめ

EventBridgeを利用してメール通知設定を行う2つの方法を実装してみましたが、それぞれ使い所は以下かなと思いました。

  • EventBridgeの入力トランスフォーマー + SNSで実装する
    • メール通知のメッセージをサクッとカスタマイズしたい
  • Lambda + SNSで実装する
    • メール通知のメッセージだけでなく、件名もカスタマイズしたい
    • イベント情報に対して何らかの処理を実行した上で、メッセージをカスタマイズしたい

山﨑 翔平 (Shohei Yamasaki) 記事一覧はコチラ

2019/12〜2023/2までクラウドインテグレーション部でお客様のAWS導入支援を行っていました。現在はIE(インターナルエデュケーション)課にて採用周りのお手伝いや新卒/中途オンボーディングの業務をしています。2023 Japan AWS Top Engineers/2023 Japan AWS Ambassadors