はじめに
こんにちは、MSPの田所です。
我々の住む情報社会では、もっと情報を絞りたい、もっと情報を見やすくしたい、というのは普遍的な悩みかと思います。
そんな時は、不要な情報を遮断し、必要な情報を最適化したいものです。
今回は Trend Micro Cloud One – Workload Security (C1WS) の情報をフィルター、加工した話です。
Amazon SNS と AWS Lambda を使用するよくあるユースケースになるかと思います。
どうぞお付き合いください。
C1WS メールインテグレーションの悩み
C1WS には、サーバーに対する攻撃や変更のイベントを検知し、メール通知する機能があります。
その際に、イベントの種類を限定してアラートを作成することはできるのですが、その条件を細かくフィルターすることはできません。
侵入防御や変更監視などの指定はできますが、ルール番号や重要度などによるフィルターはできません。
そのため以下のような悩みが生じます。
1. 情報過多
全てのアラートが上がってくるため、見る必要がないと分かっているものも含まれてしまいます。
10件のアラートが上がっているのに、本当に見るべきは1件、のような状況が起こりえます。
その1件だけにフィルターしたいですね。
2. 情報不足
通知されたアラートメールには基本的な情報が記載されますが、載っていない情報は C1WS コンソールに入って確認する必要があります。
イベントに対して設定した処理内容やインスタンスのOS情報など、その情報さえあれば対応判断ができるのに、、!
という状況が起こりえます。
必要な情報をカスタマイズして記載したいですね。
解決のステップ
フィルターと加工を実装して悩みを解決します。
1. フィルター
C1WS にはメールインテグレーションの他に、Amazon SNS に通知することができます。
その時に JSON 形式のフィルターを設定することができます。
そこではイベントの種類をはじめ、ルール番号や重要度など細かい条件のフィルターを作成可能です。
今回は重要度が「重大」に設定された侵入防御イベントのみを検知するよう設定します。
Amazon SNS と PagerDuty を連携する
PagerDuty サービスの Integration Email を控えます。
SNS トピックを作成し、プロトコル E メールで控えたメールエンドポイントを入力してサブスクリプションを作成します。
PagerDuty 側で “Subscription Confirmation” を検知するのでサブスクリプションの確認を行います。
Confirm subscription のアドレスをコピーして、AWS コンソール側で確認することをおすすめします。
C1WS と Amazon SNS を連携する
AWS の IAM からユーザー作成を行い、sns:Publish の権限を付与します。
アクセスキーを作成してダウンロードします。
ちなみに IAM ロールでの権限付与はできないようです。
C1WS にログイン > 管理 > システム設定 > イベントの転送
から「Amazon Simple Notification Serviceにイベントを公開」にチェックを入れ、アクセスキーと秘密鍵の情報を入力します。
JSON SNS設定の編集… から以下 JSON フィルターを入力します。
重要度が「重大」に設定された侵入防御イベントのみを、指定の SNS トピックに通知する設定です。
応用すれば、特定のルール番号、文字列、アラートの種類などを AND/OR 条件でフィルターする、柔軟な設定が可能です。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 | { "Version" : "2014-09-24" , "Statement" : [ { "Topic" : "arn:aws:sns:ap-northeast-1:123456789012:tadokoro-c1ws-sns-pd-topic" , "Condition" : { "StringEquals" : { "EventType" : "PayloadLog" , "SeverityString" : "Critical" } } } ] } |
メールインテグレーションから侵入防御アラートを除外する
管理 > システム設定 > アラート > [アラートの設定]
から「侵入防御ルールアラート」のアラートをオフにします。
これにより、侵入防御イベントの発生時にメール通知が飛ばなくなります。
結果、侵入防御イベントは SNS 経由でのみ通知されることになります。
そしてそこでは、重要度が「重大」のものが通知され、「重大」以外のものはフィルターされます。
アラートを発報する
サーバーへの攻撃を再現することになるためここでは省略しますが、SNS 経由のアラートを発報するとこのようになります。
“AWS Notification Message” というなかなかに質素なタイトル。
そして目視で確認するには無理がある雑多な本文です。
2. 加工
C1WS から Amazon SNS に連携すると、タイトルは “AWS Notification Message” となり、本文は JSON オブジェクトを [ ] で囲んだ配列形式のデータとなることが分かりました。
ここから必要な情報を抜き出して整えます。
SNS トピック2 と PagerDuty を連携する
2つ目の SNS トピックを作成し、PagerDuty の Integration Email をサブスクライブします。
先程作成した SNS トピック (tadokoro-c1ws-sns-pd-topic) と同じ状態です。
Lambda 関数を作成する
Lambda 関数を作成します。
Python コードの例は以下のようになります。
メッセージの情報からタイトルや本文を加工した上で、SNS トピック2に渡します。
関数の設定から環境変数 “DESTINATION_TOPIC_ARN” に SNS トピック2のARNを登録します。
また実行ロールには SNS トピック2 への sns:Publish 権限をつけておきます。
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | import json import boto3 import os def lambda_handler(event, context): sns_client = boto3.client( 'sns' ) destination_topic_arn = os.environ[ 'DESTINATION_TOPIC_ARN' ] # 環境変数からARNを取得 # SNSイベントからメッセージを取得 message = event[ 'Records' ][0][ 'Sns' ][ 'Message' ] data_list = json.loads(message) # 配列全体を取得 # 件名を生成(配列内の最初のJSONオブジェクトを使って件名を作成) subject = f "侵入防御ルール {data_list[0]['Reason']} のアラートが発生しました" # 件名が100文字を超えている場合、100文字以内に切り詰める if len(subject) > 100: subject = subject[:100] formatted_messages = [] for data in data_list: reason = data.get( 'Reason' , '不明' ) log_date = data.get( 'LogDate' , '不明' ) severity = data.get( 'SeverityString' , '不明' ) host_id = data.get( 'HostID' , '不明' ) hostname = data.get( 'Hostname' , '不明' ) host_os = data.get( 'HostOS' , '不明' ) action = data.get( 'ActionString' , '不明' ) formatted_message = ( f "アラート:{reason}\n" f "時刻:{log_date}\n" f "重要度:{severity}\n" f "インスタンスID:{host_id}\n" f "インスタンス名:{hostname}\n" f "ホストOS:{host_os}\n" f "処理:{action}" ) formatted_messages.append(formatted_message) # 各メッセージ間に改行を挿入して結合 final_message = "\n\n" . join (formatted_messages) # SNSメッセージを送信 sns_client.publish( TopicArn=destination_topic_arn, Message=final_message, Subject=subject ) return { 'statusCode' : 200, 'body' : json.dumps( 'Message processed and sent to SNS' ) } |
SNS トピック1 と Lambda を連携する
Lambda を SNS トピック1にサブスクライブします。
先程作成した SNS トピック1をそのまま使います。
PagerDuty に直接通知するサブスクリプションは削除しておきます。
C1WS と SNS トピック1 を連携する
C1WS 側で SNS トピック1 への通知やフィルターの設定を行います。
今回は先程の設定を使い回すので省略します。
アラートを発報する
この設定でアラートを発報すると PagerDuty では以下のように検知します。
Lambda なしの時と比べるとずいぶん見やすくなりましたね。
これで必要なアラートを必要な情報と共に検知することができるようになりました。
これなら対応不要のアラートに埋もれることも、情報が足りなくてもどかしい思いをすることもありません。
おわりに
SNS と Lambda を使って、C1WS のアラートをフィルター、加工した上で PagerDuty に検出する方法を見てきました。
ここに Terraform や CloudFormation で構築を自動化したり、Lambda のエラー監視を入れることで、より盤石な構築、運用体制を築いていけそうです。
情報であれ、物であれ、何にせよ整理整頓してすっきりとした生活を送りたいものですね。
おしまい