【AWS】各サービスを触ってみる EventBridge①(EC2の状態変更を検知して通知を行う)
はじめに
ご覧いただきありがとうございます。阿河です。
当ブログでもEventBridgeを扱うことが多いですが、改めてサービスの中身を掘り下げてみようと思います。
第一弾として「EC2が特定の状態になったことをEventBridgeで自動検知」を行い「LambdaでSlack通知を実行」させます。
対象者
- AWSを運用中
- 運用を自動化したい
- AWSとSlackの連携方法について知りたい
概要
- Lambda関数の作成
- EventBridgeルールの作成
今回やりたいことは以下の通りです。
- EC2インスタンスが「stopped」「terminate」「shutting-down」いずれかの状態となったことをEvnetBridgeが検知。
- 上記を検知した場合、Lambdaを経由してSlackに通知を飛ばす
EventBridgeは、サーバレスのイベントバスサービスです。
イベント駆動アーキテクチャを用意に構築でき、イベントの送信元/送信先がお互いの実装を意識する必要が無くなります。
今回は下記①~④のフローで処理が流れていきます。
①イベントソースである「AWSサービス」からイベントが送信される
②イベントバス(default)がイベントを受けつける
③イベントバスに紐づけたルールが後続処理に送信するイベントを選択
④後続処理を行うターゲット(今回はLambda)にイベントが送信され、イベントが処理されます。
EventBridgeの詳細はBlackBeltを参照頂ければと思います。
事前準備
- AWSアカウント作成
- AdministratorAccessを付与したIAMユーザーの作成
- EC2を2台作成して「running」の状態としておく
1. Lambda関数の作成
EventBridgeのサンプルイベントを確認する
イベントとは「状態の変化」を表します。
今回はEC2インスタンスが特定の状態に移行した場合に、EvnetBridgeで検知できるようにします。
AWSマネジメントコンソールのEventBridgeのページで、ルール作成を行う過程で、サンプルイベントを確認できる箇所があります。
こちらでサンプルイベントの構造を手っ取り早く確認できます。
複数のAWSサービスのサンプルイベントが確認できますが、今回はEC2の状態変更に関わる「EC2 Instance State-change Notification」を選択します。
{
"version": "0",
"id": "651d5f8b-947c-4c0f-acb7-5ac4e41a1b8a",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "123456789012",
"time": "2015-11-11T21:33:19Z",
"region": "us-east-1",
"resources": ["arn:aws:ec2:us-east-1:123456789012:instance/i-abcd3333"],
"detail": {
"instance-id": "i-abcd3333",
"state": "stopped"
}
}
sourceは「イベントの送信元」を表します。AWSサービスのイベントの場合は、aws.ec2のようなサービス名が入ります。
detail-typeは「イベントの種類」を表します。
detailは「イベントの内容」を表し、sourceとdetail-typeの組み合わせによりスキーマが決まります。
上記のイベントサンプルをもとに、必要な設定を進めていきます。
Lambda用のIAMロールを作成
- 信頼されるエンティティ: Lambda
- ポリシー: (AWSLambdaBasicExecutionRole)
Lambda関数を作成
- オプション: 一から作成
- ランタイム: Python3.8
- アーキテクチャ: x86_64
- ロール: 作成したロール
Lambdaコードを記述
import boto3
def lambda_handler(event, context):
time = event["time"]
instance_id = event["detail"]["instance-id"]
state = event["detail"]["state"]
message = f"該当EC2インスタンスの状態変化を検知しました。問題がないか確認お願いします\n発生日時: {time}\nインスタンス: {instance_id}\n状態: {state}"
print(message)
return True
先程確認したサンプルイベントを参考に、イベントから必要なデータを取り出すようにコードを記述します。
今回必要なのは、「時間」「インスタンスID」「インスタンスの状態」です。
CloudWatch Logsでテスト結果を確認するため、Printをします。
Lambda関数のテストを実施
Lambdaでテストイベントを作成して、作成したLambda関数が正常に実行されるかを確認します。
テストイベントのJSONには、先ほどEventBridgeの画面で確認したサンプルイベントを貼ります。
ではLambda関数をテストしてみましょう。
テストボタンクリック後に、CloudWatch Logsを確認します。
CloudWatchのページで、ロググループ(※今回作成したLambdaの名前のロググループが作成されています)⇒ログストリーム(※最新のログストリーム)⇒ログイベントを確認します。
サンプルイベントから正常にデータを取り出すことができました。
2. EventBridgeルールの作成
EventBridgeのルールを作成します。
ルールとは、イベントバスで受信したイベントのうち「どのイベントをターゲットに送信するかを定義する」規則です。
-
名前: ※任意の名前
-
イベントバス: default
-
ルールタイプ: イベントパターンを持つルールタイプ
-
イベントソース: AWS イベントまたは EventBridge パートナーイベント
-
イベントパターン: イベントパターンのフォーム
フォームに従って入力を行います。
イベントタイプ:EC2 Instance State-change Notification
特定の状態: "shutting-down","terminated","stopped"
インスタンスID: ※事前に立ち上げたEC2のうち、1台のインスタンスのIDを指定
フォームに入力を行うと、自動でJSONが作成されます。
{
"source": ["aws.ec2"],
"detail-type": ["EC2 Instance State-change Notification"],
"detail": {
"state": ["shutting-down", "terminated", "stopped"],
"instance-id": ["xxxxxxxxxxxxxxxxxx"]
}
}
入力が終わったら、次の画面へ進みます。
- ターゲットタイプ: AWSのサービス
- ターゲットを選択: Lambda関数
- 機能: ※作成したLambda関数
ターゲットは、イベントの送信先となり、イベントを処理するものです。今回はLambda関数を指定しています。
以上の設定でEventBridgeルールを作成します。
EC2をダウンさせる
事前に起動させていたEC2インスタンスを2台停止します。
インスタンス2台が停止したことを確認したら、CloudWatch Logsを確認します。
Lambdaが実行されたことが分かります。
EventBridgeでEC2インスタンスの状態変更を検知できています。
3. Slackで自動通知を行う
Webhook URLを取得
Lambda関数の処理結果を、Slackのチャンネルに通知します。
Slack側の設定方法は、以前に書いた「GuardDutyの検知結果をSlackに自動通知する」を参照ください。
2の「Slack通知を実装」と同じ方法で、Webhook URLを取得します。
Lambdaコードを変更
import urllib3
import json
import boto3
http = urllib3.PoolManager()
def lambda_handler(event, context):
time = event["time"]
instance_id = event["detail"]["instance-id"]
state = event["detail"]["state"]
url = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
message = f"該当EC2インスタンスの状態変化を検知しました。問題がないか確認お願いします\n発生日時: {time}\nインスタンス: {instance_id}\n状態: {state}"
msg = {
"channel": "#xxxxxxxxxxxxxxxxx",
"username": "",
"text": message,
"icon_emoji": ""
}
encoded_msg = json.dumps(msg).encode('utf-8')
resp = http.request('POST',url, body=encoded_msg)
return True
Webhook URLとSlackチャンネル名は、自身の環境のものに置き換えます。
EC2をダウンさせる
検証のため、EC2 2台を起動状態にします。
準備ができたら、EC2を停止させましょう。
すぐにSlackに通知が届きました。
さいごに
このようにイベントの自動検知/他のAWSサービスとの連携が簡単にできました。
また今後の記事でEventBridgeについて掘り下げていければと思います。
御覧いただき ありがとうございました!
Discussion