EventBridgeのルールからAmazon SNSのトピックへイベントを届ける構成は、権限の付け方を間違えると「ルールは一致しているのに通知が来ない」状態になります。本記事で扱うのは、2025年3月以降に推奨された実行ロールと従来のトピックポリシーの2方式、KMSで暗号化したトピックの条件、CLIでの組み立てとテスト送信、SNS側のフィルターで宛先を分けるファンアウト、届かないときの切り分けまでの手順です。最後に、SNSを挟むべきか、ルールのターゲットへ直接つなぐかの判断基準を示します。EventBridgeそのものの仕組みはAmazon EventBridgeとはで解説しています。
まとめ:権限は実行ロールで付け、SNSは購読者が多いときだけ挟む
新しく組むなら、ターゲットにRoleArnを指定し、sns:Publishだけを許したIAMロールで発行させます。トピックポリシーへの追記は、別アカウントのトピックへ送る場合か、既存の構成を変えたくない場合に限ります。KMSで暗号化したトピックは、カスタマー管理キーのキーポリシーにevents.amazonaws.comを加えないと発行が失敗し、再試行もされません。
SNSを間に置く価値があるのは、宛先が6つ以上になる、メールやSMSで人に届ける、購読者を別チームが自分で増減させる、のいずれかに当てはまるときです。宛先が5つ以内のシステム間連携なら、ルールのターゲットへ直接つなぐほうが部品も料金も少なく済みます。
EventBridgeからSNSへ届く経路|ターゲットの置き方と本文の形
ルールのターゲットにSNSトピックを置く構成と1ルール5ターゲットの上限
EventBridgeのルールは、イベントパターンに一致したイベントを登録済みのターゲットへ配ります。SNSトピックはそのターゲットの1種類で、追加に必要なのは、ターゲットとして指定するARNです。1つのルールに付けられるターゲットは最大5つで、クォータ表では引き上げ不可と明記されています。
ここがSNSを挟む理由の出発点です。SNSの標準トピックは1トピックあたり1,250万件の購読を持てるため、ルールの5つの枠のうち1つをSNSに渡せば、その先の宛先数の制約はほぼ消えます。なお、ターゲットを追加した直後に一致したイベントは、新しいターゲットへすぐには届かないことがあると公式に書かれています。設定直後のテストで1件目が来なくても、少し時間を置いて再送してから判断してください。
届く本文はイベントJSONそのまま、メール購読者には生のJSONが届く
入力の変換を何も設定しない場合、SNSへの発行メッセージの本文はEventBridgeのイベント全体のJSONです。version、id、detail-type、source、account、time、region、resources、detailがそのまま入ります。SQSやLambdaの購読者にとっては扱いやすい形です。
困るのはメールの購読者です。件名は既定の文言になり、本文には1行に詰まったJSONがそのまま届きます。運用担当者が読む通知にするなら、ターゲットに入力トランスフォーマーを設定して、必要な項目だけを文章に組み直す設定が必要です。書き方と引用符の規則はEventBridge 入力トランスフォーマーの使い方で扱っています。ただし変換で本文をJSON以外にすると、後述するSNSの本文フィルターが使えなくなる点に注意が必要です。
発行の権限は2方式|実行ロールとトピックポリシーの用途別の選び分け
2025年3月から実行ロールが推奨、コンソールはポリシーを書き換えない
以前のEventBridgeは、SQS・SNS・Lambdaのターゲットに実行ロールを使えず、トピック側のリソースベースポリシーでevents.amazonaws.comからの発行を許す必要がありました。現在のターゲット用IAMロールのページは、この3種類について「IAM実行ロールとリソースベースポリシーの両方に対応」と書いています。リソースベースポリシーのページには、RoleArnを指定しなければトピック側のポリシーが使われる、という優先順位も明記されています。
この変更はクラスメソッドの2025年3月12日の記事でも報告されています。2026年4月の同社記事によれば、コンソールは「実行ロールを使用」が既定で有効なため、トピックポリシーには何も追記されません。「自動で許可が付くはず」という古い説明を前提にポリシーを探しても見つからないのは、この挙動が理由です。新規の構成では実行ロールを選び、許可する操作は対象トピックへのsns:Publishだけに絞ります。
aws iam create-role --role-name eb-to-sns-orders \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"events.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam put-role-policy --role-name eb-to-sns-orders \
--policy-name publish-orders-topic \
--policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"sns:Publish","Resource":"arn:aws:sns:ap-northeast-1:123456789012:orders-events"}]}'
ロールはターゲットごとに別のものを指定できます。1つのルールでSNSとSQSの両方へ送る場合も、宛先ごとに権限を分けておくと、片方の設定変更がもう片方に波及しません。
トピックポリシーで許すときはaws:SourceArnでルールを絞る書き方
実行ロールを使わない、または使えない場面も対象です。代表は別アカウントのトピックへ送る構成で、前掲のクラスメソッドの記事は、クロスアカウントでは引き続きリソースベースポリシーで認可すると説明しています。その場合はトピック側に次の文を加えます。
{
"Sid": "AllowOrdersRule",
"Effect": "Allow",
"Principal": {"Service": "events.amazonaws.com"},
"Action": "sns:Publish",
"Resource": "arn:aws:sns:ap-northeast-1:123456789012:orders-events",
"Condition": {
"ArnEquals": {"aws:SourceArn": "arn:aws:events:ap-northeast-1:123456789012:rule/orders-failed-to-sns"}
}
}
公式のSNSの例には条件がありませんが、同じページのSQSやLambdaの例と同様にaws:SourceArnでルールを限定すると、同じアカウントの別のルールから勝手に発行される余地をなくせます。落とし穴はset-topic-attributesの動き方です。Policy属性は丸ごと置き換わるため、公式手順のとおりget-topic-attributesで既存のポリシーを取り出し、Statementの配列に追記してから設定し直します。新しい文だけを渡すと、既定の__default_statement_IDが消え、購読の操作まで拒否される原因になるため注意が必要です。別アカウントのバスや宛先へ送る経路そのものはEventBridge イベントバスの使い分けで解説しています。
KMS暗号化トピックはカスタマー管理キーとキーポリシーの追記が要る
トピックにサーバー側暗号化を掛けている場合、発行する側にKMSキーを使う権限が要ります。SNSの暗号化キーのページは、AWSサービスのイベントソースと暗号化トピックを組み合わせる手順として、カスタマー管理キーを使うことと、キーポリシーに次の文を入れることを挙げています。
{
"Sid": "AllowEventBridgeToUseKey",
"Effect": "Allow",
"Principal": {"Service": "events.amazonaws.com"},
"Action": ["kms:GenerateDataKey*", "kms:Decrypt"],
"Resource": "*"
}
同じページの別の文には、混乱した代理対策としてaws:SourceAccountやaws:SourceArnを付ける例があります。ところが、EventBridgeから暗号化トピックへの経路ではこれらの条件キーに対応していない、というのが、重要の注記に書かれた制約です。他サービス向けのキーポリシーを流用して条件付きで書くと、発行だけが黙って失敗します。実行ロール方式を使う場合は、ロールのポリシーにも同じ2つのKMS操作を対象キーのARNで加えておくと確実です。AWSマネージドキーaws/snsはキーポリシーを編集できないため、この経路には使えません。
CLIでSNS連携を組む手順|トピック作成からテスト送信まで
create-topicとsubscribeでメールとSQSの購読者を用意する
ここからは、注文処理の失敗イベントを運用チームのメールと監査用のSQSキューへ同報する例で組みます。最初の作業は、トピックの作成と2種類の購読の追加です。メールアドレスはコードに直接書かず、環境変数で渡しています。
aws sns create-topic --name orders-events
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:orders-events \
--protocol email --notification-endpoint "$ALERT_EMAIL"
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:orders-events \
--protocol sqs \
--notification-endpoint arn:aws:sqs:ap-northeast-1:123456789012:orders-audit \
--attributes RawMessageDelivery=true
メールの購読は、届いた確認メールのリンクを開くまで保留のままです。保留の購読は1アカウントで5,000件までと上限があり、確認を忘れると配信されません。SQSの購読は、キュー側のアクセスポリシーでsns.amazonaws.comからのsqs:SendMessageを許可しておく必要があります。
put-ruleとput-targetsで実行ロール付きのターゲットを登録する
次にルールを作り、ターゲットにトピックを登録します。RoleArnには前の章で作ったロールを指定し、配信に失敗したイベントの退避先として標準キューのDLQも付けます。
aws events put-rule --name orders-failed-to-sns \
--event-pattern '{"source":["com.example.orders"],"detail-type":["OrderFailed"]}'
aws events put-targets --rule orders-failed-to-sns --targets '[{
"Id": "orders-topic",
"Arn": "arn:aws:sns:ap-northeast-1:123456789012:orders-events",
"RoleArn": "arn:aws:iam::123456789012:role/eb-to-sns-orders",
"DeadLetterConfig": {"Arn": "arn:aws:sqs:ap-northeast-1:123456789012:eb-orders-dlq"},
"RetryPolicy": {"MaximumRetryAttempts": 185, "MaximumEventAgeInSeconds": 86400}
}]'
RetryPolicyの値は再試行の上限そのもので、最大24時間・185回まで粘ります。通知の鮮度が意味を持つ用途なら、MaximumEventAgeInSecondsを3600程度に縮め、古くなった通知はDLQへ落とすほうが運用者を混乱させません。
put-eventsでテストイベントを送り届いたかを確かめる
パターンに一致するカスタムイベントを手で送り、メールとキューの両方に届くかを確かめます。
aws events put-events --entries '[{
"Source": "com.example.orders",
"DetailType": "OrderFailed",
"Detail": "{\"orderId\":\"A-1001\",\"reason\":\"PAYMENT_DECLINED\",\"amount\":12800}"
}]'
aws sqs receive-message \
--queue-url https://sqs.ap-northeast-1.amazonaws.com/123456789012/orders-audit
応答のFailedEntryCountが0なのは、バスがイベントを受け付けたという意味にすぎません。SNSまで届いたかは、ルールのメトリクスInvocationsとFailedInvocations、トピックのNumberOfMessagesPublishedで確認します。Raw配信を有効にしたキューには、SNSの包みを外したイベントJSONがそのまま入ります。
SNSで宛先を分けるファンアウト|本文フィルターとRaw配信
SNSの購読者側の設計はAmazon SNSとはで全体を扱っています。ここではEventBridgeから届くイベントを前提にした2つの設定に絞ります。
MessageBody指定でdetailの値に応じて購読者を分ける
SNSのフィルターポリシーが既定で見る対象は、メッセージ属性です。EventBridgeから届くメッセージで振り分けの材料になるのは本文のイベントJSONで、sourceやdetailの値は属性ではなく本文の中にあります。FilterPolicyScopeをMessageBodyにすると、本文のJSONに対してフィルターが掛かり、detailの中の値で購読者を振り分けられます。
aws sns subscribe \
--topic-arn arn:aws:sns:ap-northeast-1:123456789012:orders-events \
--protocol sqs \
--notification-endpoint arn:aws:sqs:ap-northeast-1:123456789012:payment-retry \
--attributes '{"RawMessageDelivery":"true","FilterPolicyScope":"MessageBody","FilterPolicy":"{\"detail\":{\"reason\":[\"PAYMENT_DECLINED\"]}}"}'
購読の作成時に3つの属性をまとめて渡すと、範囲とポリシーの不整合が起きる隙間を作りません。本文用のフィルターは整形式のJSONを前提としているため、入力トランスフォーマーで本文を文章にしたターゲットとは両立しません。料金面では、属性によるフィルターは無料ですが、本文によるフィルターは走査したデータ量で課金され、東京では1GBあたり0.13ドル、1メッセージ最低1KBで数えます。1トピックに付けられるフィルターポリシーは200個までです。
SQS購読はRawMessageDeliveryでSNSの封筒を外してイベントを受ける
Raw配信を無効のままSQSで受けると、キューのメッセージはType、MessageId、TopicArn、Message、Signatureなどを持つSNSの封筒になり、イベントはMessageの中に文字列として入ります。受信側は2回JSONを解析することになります。
Raw配信を有効にすると、SNSのメタデータが取り除かれ、EventBridgeのイベントJSONがそのままキューに入ります。SQS・HTTP/S・Firehoseの購読で使え、メールには使えません。受信側のLambdaでdetailを直接読めるので、EventBridgeからSQSへ直接つないだ場合と同じコードを流用できます。購読ごとの設定なので、署名を検証したいHTTP/Sの購読だけ無効のまま残す、といった使い分けも可能です。
届かないときの切り分け|EventBridgeとSNSの2層で失敗を探す
FailedInvocationsとDLQ、SNS側の失敗メトリクスで区間を見分ける
EventBridgeからSNSの購読者までは2つの区間があり、失敗の記録場所も別です。ルールからトピックへの発行が失敗すると、ルールのFailedInvocationsが増え、ターゲットのDLQにイベントが入ります。DLQのページによれば、権限の不足やトピックの削除が原因のときは再試行されずにそのままDLQへ送られ、メッセージ属性ERROR_CODEにNO_PERMISSIONSやNO_RESOURCEが入ります。DLQは同じリージョンの標準キューに限られ、put-targetsで指定したときはキューのポリシーを手で付けなければなりません。
発行は成功しているのに届かないなら、問題はSNSから先です。トピックのNumberOfNotificationsFailedとNumberOfNotificationsFilteredOutを見て、配信の失敗か、フィルターで落ちたかを分けます。購読ごとの配信失敗を退避するには、SNSの購読にも別のDLQを付けます。メール購読は1購読あたり毎秒10件が引き上げ不可の上限なので、大量のイベントをそのままメールへ流す設計は避けてください。ルールそのものが発火しない場合の調べ方はEventBridge ログの調べ方にまとめています。
SNSを挟むかルール直結にするか|宛先数と受け手で決める判断基準
SNSを挟むのは宛先が6つ以上かメール・SMSで人に届けるとき
SNSを間に置くと、部品が1つ増え、料金も1段増えます。それでも挟む価値があるのは次の場面です。
- 同じイベントの宛先が6つ以上あり、ルールの5ターゲットに収まらない
- メール、SMS、モバイルプッシュで人に届ける
- 購読者を受け手のチームが自分で追加・削除し、ルールの所有者を介さずに済ませたい
- 既存のSNSトピックに他のシステムからも発行しており、宛先の管理を1か所にまとめたい
3つ目は見落とされがちです。ルールのターゲットを増やすにはルールの所有者の作業が要りますが、SNSの購読はトピックのポリシーで許せば受け手側が自分で付けられます。複数チームでイベントを共有する組織では、この運用上の差が決め手になります。どのサービスを組み合わせるかの基本はAWS SQS・SNS・SESの違いと使い分けも参照してください。イベント駆動の構成を自社のAWS環境にどう組み込むかの設計から相談したい場合は、インフラ構築(AWS・Google Cloud・Azure)で承っています。
宛先5つ以内のシステム連携はターゲット直結、単純な同報はSNSへ直接発行
逆に、宛先がSQSやLambdaなど5つ以内のシステムだけなら、SNSを挟まずルールのターゲットに直接並べます。EventBridge側のDLQと再試行がターゲットごとに効き、障害の追跡も1層で済みます。
もう1つの見直し点は、自社アプリが出すイベントをただ同報したいだけの構成です。この場合はEventBridgeを通さず、アプリから直接SNSへ発行するほうが安くなります。東京リージョンで月500万件を2つのSQSへ配る例で比べると、EventBridge経由はカスタムイベントの取り込み5.00ドルとSNSのAPIリクエスト2.00ドル(月100万件の無料分を除く)で7.00ドル、SNSへの直接発行は2.00ドルです(SQSとLambdaへの配信は無料、2026年9月版のPrice List APIで取得)。内容による振り分け、アーカイブと再生、AWSサービスのイベントを受ける必要がないなら、EventBridgeは挟みません。
順序が要る処理はSNSのFIFOトピックでなくSQSのFIFOキューへ送る
注文の状態遷移のように順序を守りたいイベントを、SNSのFIFOトピック経由で配りたいという相談はよくあります。ところが、Targetの項目一覧にはSNS用のパラメータがなく、メッセージグループIDを渡す手段はSqsParametersしかありません。ターゲットの説明でも、FIFOとメッセージグループの指定方法が書かれているのはSQSのfairキューとFIFOキューだけです。
順序が要るなら、ルールのターゲットにSQSのFIFOキューを置き、SqsParametersでグループIDを指定します。キューにはコンテンツベースの重複排除を有効にしておくことが条件です。SNSのFIFOトピックは購読者が1トピック100件までで、標準トピックの1,250万件とは桁が違います。順序と大規模な同報を1つのトピックで両立させようとせず、順序が必要な処理系だけをFIFOキューへ切り出す設計にします。
よくある質問
EventBridgeとSNSを組み合わせるときによく出る疑問に、公式ドキュメントの記載をもとに答えます。
EventBridgeからSNSへ送ると料金はどこにかかりますか?
EventBridge側は、AWSサービスが出す管理イベントの取り込みが無料で、自社アプリのカスタムイベントは東京で100万件あたり1.00ドルです。同じアカウント内のターゲットへの配信に追加料金はありません。SNS側は発行が1回のAPIリクエストとして数えられ、月100万件を超えると100万件あたり0.50ドルです。メールは月1,000件を超えると10万件あたり2.00ドルかかります。いずれも件数の計算単位は64KBごとに1件です。EventBridgeの課金の全体像はAmazon EventBridgeの料金で整理しています。
SNSからEventBridgeへ逆向きにイベントを流せますか?
SNSの購読の種類にEventBridgeのバスはありません。SNSに届いたメッセージをEventBridgeへ渡したい場合は、Lambdaを購読者にしてPutEventsを呼ぶか、SQSに受けてEventBridge Pipesでバスへ流します。後者はコードを書かずに済み、Pipes側でフィルターと変換も掛けられる構成です。そもそも送り手を変えられるなら、送り手から直接EventBridgeへ発行するほうが経路は短くなります。
新しいCustom Event Busでも同じ設定でSNSへ送れますか?
本記事の手順はルールとターゲットで配る従来のバス(Custom Event Bus – Classic)の書き方です。2026年に追加された新しいCustom Event Busでは、ターゲットはルールではなくsubscriberに属し、1つのsubscriberがちょうど1つのターゲットへ配ります。ルールあたり5ターゲットという枠の考え方が変わるため、設計を移すときは公式のターゲットのページにある新バスの注記と、subscriberの設定方法を確認してください。
TerraformでEventBridgeとSNSの連携を書けますか?
Terraformで連携を記述することは可能です。ルールはaws_cloudwatch_event_rule、ターゲットはaws_cloudwatch_event_targetで、ターゲットのrole_arnに実行ロールを渡します。トピックポリシー方式ならaws_sns_topic_policyでトピックのポリシー全体を宣言するため、CLIで追記するときのような既定文の消失が起きにくい書き方です。HCLの具体例はTerraform EventBridgeの実装手順にあります。
AWSサービスのイベントをSNSで通知する具体例はありますか?
GuardDutyの検出結果を重大度で絞り、SNSのメールとSlackへ届ける構成をGuardDuty EventBridge連携の実装で解説しています。AWSサービスのイベントはデフォルトバスに無料で届くため、本記事のテスト用カスタムイベントの部分をサービスのイベントパターンへ置き換えれば、同じ権限設定のまま使えます。
関連記事
- Amazon EventBridgeとは?仕組み・料金とCLI・Pythonでの実装手順、新Custom Event Busとの違いを解説【2026年版】:バス・ルール・ターゲットの全体像と最小構成。
- Amazon SNSとは|Pub/Sub通知の仕組み・配信先・FIFO/フィルタリングと採用判断を実装者目線で解説:トピックと購読の設計、FIFOと料金の基本。
- EventBridge 入力トランスフォーマーの使い方:InputTemplateでSNS・Slack通知を整形する:メールに届く本文を読める文章に組み直す方法。
- EventBridge イベントバスの使い分け:クロスアカウント・リージョン送信のポリシー設定:別アカウントのトピックへ送るときの経路と許可。
- EventBridge ログの調べ方:ルールが発火しない原因をメトリクス・バスログ・DLQで特定する:ルールが一致しないときの調査手順。