EventBridge+SNSで、EC2インスタンスの再起動を検知し、通知メールをカスタマイズする方法

EventBridge+SNSで、EC2インスタンスの再起動を検知し、通知メールをカスタマイズする方法

AWS EventBridgeを使用して、EC2インスタンスの再起動イベントをリアルタイムで監視し、SNSを通じてカスタマイズされた詳細な通知メールを送信する方法をご紹介します。以前書いた「EventBridgeとLambdaを使ってEC2の再起動を検知してメールで通知してみた」というブログの応用編です。
Clock Icon2025.02.19

どうもさいちゃんです。今回は、EventBridge で EC2 の再起動を検知した後、EventBridge の入力トランスフォーマーを使って SNS 通知の内容をカスタムする方法をご紹介します。

はじめに

前回 EventBridge と Lambda を使って EC2 再起動を検知し、SNS 通知を行う方法をご紹介したんですが、さらに通知内容をカスタマイズしたい、もっと簡単に通知内容をカスタマイズしたい、といった方向けに通知内容のカスタマイズ例を 2 つご紹介しようと思います!
https://dev.classmethod.jp/articles/saichan-rebootInstance-monitoring-20250120/

もっと簡単に実装したい:EventBridge の入力トランスフォーマーを使用する

まずはもっと簡単に実装したいという方向けです。コードの記述にあまり慣れていない方や Lambda の管理に手間をかけたくないといった方は EventBridge の入力トランスフォーマーを使用して通知メールのカスタマイズをするのがおすすめです。
前回の構成図を比較してみましょう。

  • 前回の構成図
    構成図1.png

  • 今回の構成図
    構成図2.png

この方法を使えば Lambda が必要なくなるので、より低コストで SNS 通知を行うことができそうです。

やってみた

EventBridge で EC2 の再起動を検知する方法については、上記でご紹介した前回のブログをご確認ください。

ではさっそく前回作ったルールを選択し、詳細ページのターゲットタブからターゲットを編集していきます。

EventBridge2-1.png

ターゲットを Lambda 関数から SNS トピックに変更して、該当の SNS トピックを選択します。

EventBridge2-2.png

追加設定を開き、ターゲット入力を設定の欄を 入力トランスフォーマーに設定すると、設定ボタンが出てくるのでクリックします。

EventBridge2-3.png

設定画面を開くと様々なサンプルイベントが用意されていますが、今回はこのサンプルイベントは使いません。

入力トランスフォーマーを使用するには、 入力パステンプレートを定義する必要があります。
入力パスは、変数を定義するためのものです。
テンプレートでは、実際にターゲットに渡すテンプレートを定義できます。

入力トランスフォーマーの設定画面では入力パスやテンプレートをどの様に定義すれば、出力としてどのようなメッセージが出るのかの例も用意されています。

EventBridge2-5.png

おかげで途中で例を確認したくなった場合でも、コンソールとドキュメントを行ったり来たりする面倒な作業がなくなるのでうれしいですね。

試しに入力パスとテンプレートを以下のように設定してみます。

  • 入力パス
{
  "account": "$.account",
  "instanceId": "$.detail.requestParameters.instancesSet.items[0].instanceId",
  "time": "$.time"
}

CloudTrail で記録された再起動イベントを元に、アカウント ID とインスタンス ID、再起動時刻を変数として定義します。

  • テンプレート

"EC2インスタンスの再起動を検知しました。詳細情報を確認の上、適切に対処してください。"
"【詳細情報】"
"AWSアカウント:<account>"
"インスタンスID:<instanceId>"
"再起動時刻:<time>"

設定を確認して問題なければ、ルールを更新しましょう。

早速 EC2 インスタンスを再起動してみます。

EventBridge2-6.png

Lambda なしでも、メール本文をカスタマイズして通知を送ることができました!

入力トランスフォーマーを使用するメリットとデメリットを以下にまとめました。

  • メリット
    • 設定がシンプルで実装が簡単
    • Lambda の実行コストが発生しないため、より低コストで実現可能
  • デメリット
    • 複雑なメッセージのカスタマイズはできない

Lambda 応用編:件名やメッセージをもっとカスタムしたい

上記の方法でもうまくいったんですが、

Lambda だとメールの件名も変更できたよな・・入力トランスフォーマではできないのかな?
インスタンス ID だけでなくインスタンスの名なども通知したいな・・

と、いくつか課題が出てきたので、Lambda でメッセージや件名をカスタマイズしたバージョンについてもご紹介したいと思います。

サンプル Lambda 関数

今回は以下のような Lambda 関数を作成してみました。

const { EC2Client, DescribeInstancesCommand } = require("@aws-sdk/client-ec2");
const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");

const ec2Client = new EC2Client();
const snsClient = new SNSClient();

exports.handler = async (event) => {
  try {
    console.log("Received event:", JSON.stringify(event, null, 2));

    // CloudTrailイベントからインスタンスIDを抽出
    const instanceIds =
      event.detail.requestParameters?.instancesSet?.items?.map(
        (item) => item.instanceId
      );

    if (!instanceIds || instanceIds.length === 0) {
      throw new Error("No instance IDs found in the event");
    }

    // 最初のインスタンスIDを使用
    const instanceId = instanceIds[0];

    // インスタンスの詳細情報を取得
    const describeParams = {
      InstanceIds: [instanceId],
    };
    const describeCommand = new DescribeInstancesCommand(describeParams);
    const describeResponse = await ec2Client.send(describeCommand);

    // インスタンス名(Nameタグ)を取得
    const instanceName =
      describeResponse.Reservations[0].Instances[0].Tags.find(
        (tag) => tag.Key === "Name"
      )?.Value || "N/A";

    // 現在の日時を取得
    const currentDateTime = new Date().toLocaleString("ja-JP", {
      year: "numeric",
      month: "2-digit",
      day: "2-digit",
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit",
      timeZone: "Asia/Tokyo",
    });

    // カスタマイズした件名とメッセージ
    const subject = `[AWS通知] インスタンス再起動のお知らせ - ${instanceName}/${instanceId}`;
    const message = `AWSインスタンス ${instanceName}/${instanceId} の再起動が予定されています。
    インスタンス名/ID: ${instanceName}/${instanceId}
    再起動予定日時: ${currentDateTime}
    以上`;

    // SNSトピックのARN(環境変数から取得)
    const topicArn = process.env.SNS_TOPIC_ARN;

    // SNSメッセージ送信
    const publishParams = {
      Message: message,
      Subject: subject,
      TopicArn: topicArn,
    };
    const publishCommand = new PublishCommand(publishParams);
    const response = await snsClient.send(publishCommand);

    console.log("SNS通知送信成功:", response);
    return response;
  } catch (error) {
    console.error("エラーが発生しました:", error);
    throw error;
  }
};

SNS トピックの ARN は環境変数として設定しています。

これでインスタンス ID だけでなく、インスタンス名も取得し、件名までカスタマイズされたメールを送ることが可能になったはずです。
この Lambda を EventBriodge ルールのターゲットとして選んであげるとこんなメールが飛んできます。

EventBridge2-10.png

Lambda 関数を使用した場合のメリットとデメリットは下記の通りです。

  • メリット
    • より柔軟なメッセージのカスタマイズが可能
    • API の呼び出しや追加のデータ取得が可能
  • デメリット
    • Lambda 関数の実行コストがかかる
    • 慣れていない場合、実装や管理が難しく手間がかかる

最後に

今回は EventBridge ルールを使用して検知したインスタンスの再起動を SNS 通知する場合のメールのカスタマイズ方法を 2 つご紹介しました。それぞれメリットとデメリットをまとめてみると、以下のように使い分けるのがよさそうです。

  • Lambda 関数の作成に慣れていない場合、通知したい内容が単純な場合:入力トランスフォーマー
  • Lambda 関数の作成に慣れている場合、よりカスタマイズされたメールを受け取りたい場合:Lambda 関数

SNS 通知のカスタマイズに悩んでいる方はぜひ本記事を参考にしてみてください。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.