【Lambda不要】EventBridge + SNSでメール件名と本文を自由にカスタマイズする方法(Step Functions活用)

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

はじめに

こんにちは!アプリケーションサービス部エデュケーショナルサービス課(以下ES課)の 三角(みすみ)です。
AWS運用において、リソースの状態変化やセキュリティアラートをEventBridgeで検知し、Amazon SNS経由でメール通知する構成は定番です。
しかし、そのままEventBridgeからSNSへデータを渡すと、メールの件名が一律で 「AWS Notification Message」 という味気ないものになり、本文も読みづらいJSONの羅列になってしまいます。

これを解決するために間にAWS Lambdaを挟むのが一般的ですが、「通知のルーティングのためだけにLambdaのコードを書き、
ランタイム(Node.jsやPythonなど)のバージョン管理をしたくない」という方も多いのではないでしょうか。

本記事では、Step Functions と EventBridgeの入力トランスフォーマー を活用し、Lambdaを一切使わずにメールの件名と本文を綺麗にカスタマイズする方法を解説します。

アーキテクチャの概要

構成は非常にシンプルです。

[Amazon Inspector] → [EventBridge] → [Step Functions] → [Amazon SNS] → [Email]

ポイントは、EventBridgeの「入力トランスフォーマー」機能を使って抽出・整形したJSONデータ(件名と本文)をStep Functionsに渡し、
Step FunctionsがSNSの Subject パラメータと Message パラメータに動的に割り当てて送信(Publish)する点です。

構築手順

事前に通知先の「Amazon SNS トピック」を作成し、ご自身のメールアドレスをサブスクライブ(登録)しておいてください。

Step 1: Step Functions ステートマシンの作成

EventBridgeから「件名」と「本文」を受け取り、SNSに送信するだけのシンプルなステートマシンを作成します。

  1. Step Functionsのコンソールから「ステートマシンの作成」を選択(空白のテンプレートを選択)。
  2. 以下の定義(Amazon States Language)をコードエディタに貼り付けます。 ※ TopicArn は事前に作成したSNSトピックのARNに変更してください。
{
  "Comment": "Inspectorの検知結果をSNSへ送信するステートマシン",
  "StartAt": "PublishToSNS",
  "States": {
    "PublishToSNS": {
      "Type": "Task",
      "Resource": "arn:aws:states:::sns:publish",
      "Parameters": {
        "TopicArn": "arn:aws:sns:ap-northeast-1:123456789012:YourSNSTopicName",
        "Subject.$": "$.CustomSubject",
        "Message.$": "$.CustomMessage"
      },
      "End": true
    }
  }
}

Step 2: EventBridge ルールの作成(イベントパターン)

inspectorが新しい脆弱性(ACTIVE)を検知した際に起動するルールを作ります。今回は重要度が「HIGH」または「CRITICAL」のものだけに絞り込みます。

  • ルールタイプ: イベントパターンを持つルール
  • イベントパターン:
{
  "source": ["aws.inspector2"],
  "detail-type": ["Inspector2 Finding"],
  "detail": {
    "status": ["ACTIVE"],
    "severity": ["HIGH", "CRITICAL"]
  }
}

Step 3: EventBridge ターゲットと入力トランスフォーマーの設定

ターゲットに先ほど作成した「Step Functions ステートマシン」を指定し、追加設定から 「入力トランスフォーマー」 を選択します。
ここで件名と本文のテンプレートを作成します。

① 入力パス (Input Path)
イベントから必要な値を変数として抽出します。

{
  "awsAccountId": "$.detail.awsAccountId",
  "cveId": "$.detail.packageVulnerabilityDetails.vulnerabilityId",
  "findingArn": "$.detail.findingArn",
  "fixedVersion": "$.detail.packageVulnerabilityDetails.vulnerablePackages[0].fixedInVersion",
  "inspectorScore": "$.detail.inspectorScore",
  "installedVersion": "$.detail.packageVulnerabilityDetails.vulnerablePackages[0].version",
  "nameTag": "$.detail.resources[0].tags.Name",
  "packageName": "$.detail.packageVulnerabilityDetails.vulnerablePackages[0].name",
  "region": "$.region",
  "remediation": "$.detail.remediation.recommendation.text",
  "resourceId": "$.detail.resources[0].id",
  "severity": "$.detail.severity",
  "title": "$.detail.title",
  "updatedAt": "$.detail.updatedAt"
}

② 入力テンプレート (Input Template)
抽出した変数を当てはめ、Step Functionsへ渡す「件名(CustomSubject)」と「本文(CustomMessage)」を定義します。改行は \n でエスケープします。

{
  "CustomSubject": "[<severity>] <resourceId> (<nameTag>) に脆弱性を検知: <cveId>",
  "CustomMessage": "Amazon Inspectorにより、以下のリソースでセキュリティ上の懸念が検出されました。内容を確認し、修正対応をお願いします。\n\n■ 概要\n--------------------------------------------------\n重要度   : <severity> (Score: <inspectorScore>)\nCVE ID   : <cveId>\nタイトル  : <title>\n検出日時  : <updatedAt>\n--------------------------------------------------\n■ 対象リソース\n--------------------------------------------------\nリソースID : <resourceId>\nサーバー名 : <nameTag>\nAWSアカウント: <awsAccountId>\nリージョン : <region>\n--------------------------------------------------\n■ 検出詳細と修正方法\n--------------------------------------------------\n対象パッケージ: <packageName>\n現在のバージョン: <installedVersion>\n修正バージョン : <fixedVersion>\n\n【推奨アクション】\n<remediation>\n--------------------------------------------------\n■ 詳細リンク\nhttps://<region>.console.aws.amazon.com/inspector/v2/home?region=<region>#/findings/details?findingArn=<findingArn>"
}

これで構築は完了です!

テスト手順(超重要:NotAuthorizedForSourceException の回避)

設定が完了したら、EventBridgeのコンソールからテスト用のJSONデータを送信して動作確認を行います。

しかしここで一つ罠があります。イベントソースに aws.inspector2 を指定して手動でイベントを送信しようとすると、NotAuthorizedForSourceException という権限エラーで弾かれます。
(※ aws. で始まるソース名はAWSサービス専用として予約されており、ユーザーがなりすまして送信できない仕様になっているためです。)

この制限を回避し、安全にテストを通すための手順を解説します。

フェーズ1:ルールのイベントパターンを一時変更(テストモード化)

テスト用の擬似イベントを受け入れるように、EventBridgeルールを一時的に変更します。

ルールの「イベントパターン」を編集し、source の配列にテスト用の名前(例:test.inspector2)を追記して保存します。

{
  "source": ["aws.inspector2", "test.inspector2"],
  "detail-type": ["Inspector2 Finding"],
  "detail": {
    "status": ["ACTIVE"],
    "severity": ["HIGH", "CRITICAL"]
  }
}

フェーズ2:テストイベントの送信

EventBridgeコンソールの左側メニューから 「イベントバス」 を選択し、右上の 「イベントの送信」 をクリックします。
以下の通りに入力します。

* イベントバス: default * イベントソース: test.inspector2 (※フェーズ1で追記したテスト用の名前) * 詳細タイプ: Inspector2 Finding * イベント詳細: 以下のダミーJSONを貼り付けます。

{
  "awsAccountId": "123456789012",
  "findingArn": "arn:aws:inspector2:ap-northeast-1:123456789012:finding/00000000-0000-0000-0000-000000000000",
  "inspectorScore": 8.8,
  "severity": "HIGH",
  "status": "ACTIVE",
  "title": "CVE-2024-0001 - dummy-package",
  "updatedAt": "2026-03-15T12:00:00Z",
  "packageVulnerabilityDetails": {
    "vulnerabilityId": "CVE-2024-0001",
    "vulnerablePackages": [
      {
        "name": "dummy-package",
        "version": "1.0.0-1.el8",
        "fixedInVersion": "1.0.1-1.el8"
      }
    ]
  },
  "remediation": {
    "recommendation": {
      "text": "dummy-packageをバージョン1.0.1-1.el8以上にアップデートしてください。"
    }
  },
  "resources": [
    {
      "id": "i-0123456789abcdef0",
      "tags": {
        "Name": "test-web-server-01"
      }
    }
  ]
}

入力したら、右下の 「送信」 をクリックします。

フェーズ3:動作確認

送信が成功したら、以下の2点を確認します。

  1. メールの受信: 指定したメールアドレスに、件名が [HIGH] i-0123456789abcdef0 (test-web-server-01) に脆弱性を検知: CVE-2024-0001 となっているメールが届いているか確認します。
  2. Step Functionsの履歴: もしメールが届かない場合は、Step Functionsのコンソールを開き、対象ステートマシンの「実行 (Executions)」タブからエラーが出ていないか(権限不足などがないか)を確認します。

フェーズ4:ルールの復元(後片付け)※超重要

テストが完了したら、不正なイベントを受け付けないように必ず本番用の設定に戻します。
EventBridgeルールのイベントパターンから "test.inspector2" を削除し、元の状態に戻して保存してください。

{
  "source": ["aws.inspector2"],
  "detail-type": ["Inspector2 Finding"],
  "detail": {
    "status": ["ACTIVE"],
    "severity": ["HIGH", "CRITICAL"]
  }
}

まとめ

Lambdaを使わずに、EventBridgeの入力トランスフォーマーとStep Functionsを組み合わせることで、ノーコード(ローコード)で柔軟なアラートメール環境を構築できました。
ランタイムの保守運用から解放されるため、インフラ運用において非常に強力なパターンです。ぜひ試してみてください!

三角悠生(執筆記事の一覧)

CI2部2課

2022年9月入社。バイクが好き。主に初心者向けの記事を書いていきます。