SNS ファンアウト — 1 つの S3 イベントを 2 つの SQS キューとメールへ
コンソールでイベント駆動の経路を構築します。S3 が ObjectCreated:Put を SNS topic に publish し、topic が 2 つの SQS キューと 1 つのメールへファンアウト。全体が動くか静かに失敗するかを決める 3 つの最小権限リソースポリシー付き。
Lab Overview and Learning Objectives
はじめる前に
このラボでは AWS コンソールだけでイベント駆動の経路を一通り構築します。S3 にオブジェクトが PUT されるたびにバケットが SNS topic へメッセージを publish し、topic がそれを同時に 3 か所へ複製します — 処理システム用の SQS キュー 2 つと、担当者用のメール 1 つ。これが典型的なファンアウトです。S3 は宛先を 1 つだけ知っていればよく、consumer が何個あるかは SNS の問題になります。リソースはすべて us-east-1 に作り、ラボ規模なら Free Tier の範囲内です。
- Amazon SNS、Amazon SQS、Amazon S3 を操作できる権限を持つ AWS アカウント。
- すぐ開けるメールアドレス 1 つ — 受信箱の確認リンクをクリックする手順があります。
- Account ID を手元にメモ: このラボの ARN はすべて必要とします。
- 3 つのサービスすべてで同一リージョンを使うこと。本ラボは us-east-1。
- トリガー用の小さいファイルを 1 つ用意(数 KB の .json など)。
1. ファンアウト構成と構築順序
図が経路全体を示しています。S3 が producer、SNS topic が broker、SQS キュー 2 つとメール 1 つが subscriber です。要点は SNS がメッセージを保存しないこと — 即座に配信するので、その瞬間に受け手がいなければメッセージは失われます。だから間に SQS を置きます。キューはメッセージを保持して consumer が後で取りに来られるようにし、メールは人間が状況を知るためだけに存在します。構築順序は入れ替えられません。subscription は Topic ARN を必要とするので topic が先。S3 の event notification は topic が存在し、かつ S3 の publish が許可済みであることを要求するので、バケットとポリシーはイベント作成より先に終わらせます。
- 手順 2–6: SNS topic を作成し、Topic ARN をコピー。
- 手順 7–14: SQS キューを 2 つ作成し、それぞれ topic からの送信を許可。
- 手順 15–21: subscription を 3 つ登録(キュー 2 + メール 1)し、メールを確認。
- 手順 22–27: バケット作成 → topic への publish 許可 → event notification 作成。
- 手順 28–35: ファイルを 1 つアップロードし、同じイベントを 3 つの subscriber で追跡。
- 手順 36–38: consumer 側で JSON を展開し、障害を切り分け、後片付け。
2. Amazon SNS コンソールを開く
コンソール上部の検索欄に「SNS」と入力します。Services の中に「Simple Notification Service」が「SNS managed message topics for Pub/Sub」という説明付きで出るので、それを選びます。この時点で右上のリージョンが US East (N. Virginia) us-east-1 であることを確認してください。SNS、SQS、S3 event notification は同一リージョンでないと接続できませんが、コンソールは別リージョンで作っても警告してくれません。
- AWS Management Console にサインイン。
- 右上のリージョンが US East (N. Virginia) us-east-1 であることを確認。
- SNS で検索し、Simple Notification Service を選択。

3. Topics から Create topic を押す
左メニューで Topics を選びます。新規アカウントでは「No topics — To get started, create a topic」と空のテーブルが出ます。Create topic はテーブル右上と空白領域の中央の 2 か所にあり、どちらも同じフォームを開きます。左メニューには Subscriptions もあり、これは全 topic の subscription を一覧する画面で、手順 19 で使います。
- 左メニューで Topics を選択。
- Create topic をクリック。

4. Type は Standard、topic に名前を付ける
Type は作成後に変更できず、このラボでは Standard 必須です。理由は明快で、FIFO topic は protocol が SQS の 1 種類しか使えないため、FIFO を選ぶと手順 18 のメール subscription が作れません。代償として Standard は best-effort ordering と at-least-once delivery しか保証しません — 順序が入れ替わることも、2 回届くこともあるので、consumer は冪等に作る必要があります。Name に demo-s3-alerts-topic を入力。Display name はメールや SMS で送信者として表示される名前なので、同じ値を入れて送信元が分かるようにします。
- Type で Standard を選択。
- Name に demo-s3-alerts-topic を入力。
- Display name に demo-s3-alerts-topic を入力。
- Encryption、Access policy、Delivery policy、Delivery status logging は既定のまま — access policy は Bucket ARN が揃う手順 23 で編集します。

5. Name タグを付けて Create topic
下へスクロールして Tags ブロックを開き、Key = Name、Value = demo-s3-alerts-topic を追加します。Name タグはコンソールが読みやすいラベルとして使い、Cost Explorer と Resource Groups はタグでリソースをグループ化します。ラボでは単なる規律ですが、その規律のおかげで手順 38 で全部を探して消せます。オレンジ色の Create topic ボタンは画面右下です。
- Tags - optional ブロックを開く。
- Add new tag をクリックし、Key = Name、Value = demo-s3-alerts-topic を入力。
- Active tracing (AWS X-Ray) はスキップ — 追加課金があり、ラボには不要。
- Create topic をクリック。

6. Topic ARN をコピーする
topic 詳細画面の Details ブロックには Name、ARN、Display name、Type の 4 項目が並びます。ARN の横のコピーアイコンを押すと「ARN copied」というチップが出ます。ARN は arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic の形で、手順 16・17・18(各 subscription の Topic ARN)と手順 9・12(queue policy の aws:SourceArn 条件)で貼り付けます。5 回も戻ってこないよう、テキストファイルに控えておいてください。下の Subscriptions タブは「Subscriptions (0)」— 現時点では想定どおりです。
- Details ブロックの ARN 横のコピーアイコンをクリック。
- ARN を Account ID と一緒に作業用テキストへ貼る。
- Subscriptions タブが Subscriptions (0) であることを確認。

7. Amazon SQS コンソールを開く
Amazon SQS に移ります。「SQS」で検索するか、上部のピン留めサービスバーを使います。左メニューは Queues の 1 項目だけです。新規アカウントでは「No queues — No queues available」と表示されます。Messages available と Messages in flight の列に注目 — この 2 つの数値は手順 33 で検証に使います。
- SQS で検索し、Simple Queue Service を選択。
- リージョンが us-east-1 のままであることを確認。
- 左メニューで Queues を選び、Create queue をクリック。

8. キュー demo-sqs-worker-1 を作成
Standard topic に合わせて Standard を選びます。コンソールも「You can't change the queue type after you create a queue」と注意してくれます。Name は demo-sqs-worker-1。Configuration の 4 つの値はラボでは既定でよいのですが、障害時の挙動を決めるので意味は押さえておく価値があります。Visibility timeout 30 秒は、受信後にそのメッセージが他の consumer から隠れる時間で、30 秒以内に削除しきれなければメッセージが再出現し二重処理されます。Message retention period 4 日は誰も取らないメッセージを保持する期間。Maximum message size 1024 KiB は S3 イベントが 1–2 KB なので十分。Receive message wait time 0 秒は short polling を意味します。
- Type で Standard を選択。
- Name に demo-sqs-worker-1 を入力。
- Visibility timeout は 30 Seconds、Message retention period は 4 Days のまま。
- Delivery delay 0、Maximum message size 1024 KiB、Receive message wait time 0 Seconds のまま。
- まだ Create queue は押さず、Encryption と Access policy までスクロール。

9. キュー 1 の Encryption と access policy
ここが SNS からメッセージを受け取れるかどうかを決める手順です。Encryption は Server-side encryption = Enabled、Encryption key type = Amazon SQS key (SSE-SQS) のまま。SSE-SQS のキューには SNS が追加設定なしで配信できます。SSE-KMS のカスタマー管理キーに変えると、KMS キーポリシーで sns.amazonaws.com に kms:GenerateDataKey と kms:Decrypt を許可するまでメッセージが静かに消えます — SNS→SQS パターンで最も時間を溶かす罠です。Access policy は Advanced を選び、JSON を直接編集して topic からの送信を許可する statement を追加します。
- Server-side encryption = Enabled、Encryption key type = Amazon SQS key (SSE-SQS) を維持。
- Access policy で Advanced を選択。
- AWS が生成した __owner_statement はそのまま残す — 消すと自分の管理権限を失う。
- 下の JSON の AllowSnsTopicToSendMessage statement を追加し、<account-id> を自分の Account ID に置換。
- Resource が arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-1 を指していることを確認。
{
"Version": "2012-10-17",
"Id": "demo-sqs-worker-1-policy",
"Statement": [
{
"Sid": "__owner_statement",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::<account-id>:root" },
"Action": "SQS:*",
"Resource": "arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-1"
},
{
"Sid": "AllowSnsTopicToSendMessage",
"Effect": "Allow",
"Principal": { "Service": "sns.amazonaws.com" },
"Action": "sqs:SendMessage",
"Resource": "arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-1",
"Condition": {
"ArnEquals": {
"aws:SourceArn": "arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic"
}
}
}
]
}
10. Redrive・DLQ・タグを設定して Create queue
残る 3 ブロックは既定のままです。Redrive allow policy = Disabled、Dead-letter queue = Disabled で十分です。DLQ は consumer が規定回数を超えて処理失敗したメッセージを受け止める場所で、本番では不可欠ですが、失敗する consumer がまだ居ないここでは意味がありません。Key = Name、Value = demo-sqs-worker-1 のタグを付け、右下の Create queue を押します。
- Redrive allow policy = Disabled のまま。
- Dead-letter queue = Disabled のまま。
- タグ Name = demo-sqs-worker-1 を追加。
- Create queue をクリック。

11. キュー demo-sqs-worker-2 を作成
Queues に戻り、もう一度 Create queue を押します。2 つ目のキューはファンアウトの本質を示すために存在します — topic に publish された 1 通のメッセージが subscriber ごとに独立したコピーになり、片方のキューが遅くても壊れても他方には影響しません。設定は名前以外キュー 1 と同一です。
- Create queue をクリック。
- Type で Standard を選択。
- Name に demo-sqs-worker-2 を入力。
- Configuration ブロックはキュー 1 と同じままにする。

12. キュー 2 の access policy
手順 9 をこのキューで繰り返しますが、1 点だけ注意深く読んでください。Resource は ...:demo-sqs-worker-2 でなければならず、worker-1 ではありません。これはラボ中で最も多いコピペミスであり、しかも最も気づきにくい形で壊れます — subscription は作成でき、状態も Confirmed のまま、エラーもどこにも出ず、ただキュー 2 にメッセージが永遠に来ないだけ。SQS のポリシーはリソースポリシーなので、Resource の ARN が違えばその statement は編集中のキューに適用されません。
- Encryption はキュー 1 と同じ SSE-SQS を維持。
- Access policy で Advanced を選択。
- 手順 9 の JSON を貼り、Id と Resource の両方を demo-sqs-worker-2 に変更。
- aws:SourceArn 条件は同じ demo-s3-alerts-topic を指したまま。
- スクロールする前に Resource をもう一度読み直す。

13. タグを付けてキュー 2 を作成
手順 10 と同じです。Redrive allow policy と Dead-letter queue は Disabled、Key = Name、Value = demo-sqs-worker-2 のタグを付けて Create queue を押します。
- Redrive allow policy と Dead-letter queue は Disabled のまま。
- タグ Name = demo-sqs-worker-2 を追加。
- Create queue をクリック。

14. 2 つのキューが揃ったことを確認
Queues 画面が「Queues (2)」になります。次へ進む前に 4 列を確認してください。Name が正確に demo-sqs-worker-1 と demo-sqs-worker-2(小文字に注意)、Type が両方 Standard、Encryption が Amazon SQS key (SSE-SQS)、そして Messages available が 0 — これが基準値で、手順 33 では 1 か 2 に変わっている必要があります。
- テーブルが Queues (2) になっていることを確認。
- 両キューの名前、Type = Standard、Encryption = Amazon SQS key (SSE-SQS) を照合。
- 両方の Messages available が 0 であることを記録。

15. topic に戻って Create subscription
Amazon SNS → Topics → demo-s3-alerts-topic に戻ります。Subscriptions タブはまだ「Subscriptions (0)」で「You don't have any subscriptions to this topic」と出ています。Create subscription は先ほどと同じ 2 か所にあります。隣の 3 つのボタンも覚えておく価値があります。Request confirmation は保留中のメール subscription へ確認メールを再送、Confirm subscription は確認トークンを手貼りする画面、ページ上部の Publish message は S3 を介さずテストメッセージを送る手段で、手順 37 の切り分けに使います。
- Amazon SNS → Topics → demo-s3-alerts-topic を開く。
- Subscriptions タブで Create subscription をクリック。

16. キュー 1 を topic に subscribe
フォームは 3 項目です。topic ページから来た場合 Topic ARN は入力済みですが、念のため照合してください。Protocol は Amazon SQS を選びます。選んだ瞬間に Endpoint の説明が「Only Amazon SQS standard queues will be listed」に変わります — これは topic が Standard であることの直接の帰結です。Endpoint はキューの ARN なので arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-1 を貼ります。「Enable raw message delivery」を未チェックのままにするのは意図的です。ON にすると SQS は S3 が送った内容そのものを受け取り、OFF なら SNS が MessageId・Timestamp・Signature・UnsubscribeURL を持つ封筒で包みます — 手順 35 でその封筒を解剖して違いを可視化します。
- Topic ARN が arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic であることを確認。
- Protocol で Amazon SQS を選択。
- Endpoint に arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-1 を貼る。
- Enable raw message delivery は未チェックのまま。
- Subscription filter policy と Redrive policy はスキップし、Create subscription をクリック。

17. キュー 2 を topic に subscribe
手順 16 を Endpoint だけ demo-sqs-worker-2 に変えて繰り返します。この 2 つの subscription は完全に独立で、それぞれ固有の SubscriptionArn、filter policy、配信状態を持ちます。これがファンアウトの利点です — 3 つ目、4 つ目の subscriber を足しても S3 側は一切変更不要です。
- もう一度 Create subscription をクリック。
- Protocol は Amazon SQS のまま。
- Endpoint に arn:aws:sqs:us-east-1:<account-id>:demo-sqs-worker-2 を貼る。
- Create subscription をクリック。

18. メールアドレスを topic に subscribe
3 つ目の subscription は Email protocol を使います — 手順 4 で Standard topic を選んだ理由がこれです。Endpoint に自分のメールアドレスを入力します。SQS との重要な違いは、メール subscription は自動確認されないこと。AWS がそのアドレスへ確認メールを送り、誰かがリンクを押すまで subscription は Pending confirmation のままで、その間は何も受信しません。確認リンクは 3 日で失効し、その後は Request confirmation ボタンで再送する必要があります。
- もう一度 Create subscription をクリック。
- Protocol で Email を選択。
- Endpoint にすぐ開けるメールアドレスを入力。
- Create subscription をクリック。

19. Subscriptions 一覧を読む: Confirmed と Pending
左メニューの Subscriptions を開くと全 topic の subscription が並ぶので、demo-s3-alerts-topic で絞り込みます。読むべきは Status 列です。SQS の 2 行は緑のチェック付きで Confirmed、EMAIL の行は時計アイコン付きで Pending confirmation、しかも ID 列が SubscriptionArn ではなく「Pending confirmation」という文字列になっています。subscriber が何も受け取らないときは必ずこの画面に戻ってください — 保留状態が原因の第 1 位です。
- 左メニューで Subscriptions を選択。
- Search 欄に demo-s3-alerts-topic を入力して絞り込む。
- Protocol 列を確認: SQS が 2 行、EMAIL が 1 行。
- Status 列を確認: SQS = Confirmed、EMAIL = Pending confirmation。

20. メールを開いて Confirm subscription を押す
受信箱で no-reply@sns.amazonaws.com からの「AWS Notification - Subscription Confirmation」を探します。本文には subscribe した topic ARN と Confirm subscription リンクが書かれています。押す前にメール内の ARN が本当に demo-s3-alerts-topic かを確認してください — SNS の確認メールはフィッシングの定番の題材であり、このリンクを押す行為そのものが「自分のアドレスへの送信を許可する」という意思表示です。メールが見つからないときは、まず迷惑メールを確認し、それでも無ければコンソールの Request confirmation を使います。
- subscribe したアドレスの受信箱を開く。
- AWS Notification - Subscription Confirmation メールを探す。
- メール内の Topic ARN が自分の topic と一致することを確認。
- Confirm subscription リンクをクリック。

21. Subscription confirmed ページ
「Subscription confirmed! You have successfully subscribed」という緑のパネルと、発行された SubscriptionArn、unsubscribe リンクが表示されます。コンソールに戻って Subscriptions を再読み込みすると、EMAIL 行が Confirmed になり、ID 列が Pending confirmation の文字列から実際の SubscriptionArn に変わっています。
- 確認ページの Subscription confirmed! を読む。
- SNS コンソールに戻り Subscriptions を再読み込み。
- 3 行すべてが Confirmed であることを確認。

22. バケット demo-source-data-test を作成
Amazon S3 → Buckets → Create bucket に移ります。Bucket type は General purpose、Bucket namespace は Global namespace のまま。Bucket name に demo-source-data-test を入力します。バケット名はグローバルに一意なので、埋まっていたら自分用の接尾辞を足し、実際に使った名前を必ず控えてください(以降の手順すべてがそれを参照します)。Object Ownership は ACLs disabled (recommended) のまま — これが正しい既定で、アクセス制御は ACL ではなく bucket policy で行います。残り(Block Public Access は ON、Versioning は OFF、SSE-S3 暗号化)は既定のまま Create bucket を押します。
- Amazon S3 → Buckets → Create bucket を開く。
- Bucket type = General purpose、Bucket namespace = Global namespace のまま。
- Bucket name に demo-source-data-test を入力。
- Object Ownership = ACLs disabled (recommended) のまま。
- Block all public access は有効のまま Create bucket をクリック。

23. Bucket ARN をコピーし、S3 に publish を許可する
バケット → Properties タブ → Bucket overview で、Amazon Resource Name (ARN) 横のコピーアイコンを押して arn:aws:s3:::demo-source-data-test を取得します。バケット ARN にリージョンとアカウントの区画が無いのは、バケット名がすでにグローバルに一意だからです。この ARN はラボで最も重要な手順に今すぐ必要です。SNS topic は既定でアカウント所有者の publish しか許可しないため、S3 には現時点で送信権限がありません。Amazon SNS → demo-s3-alerts-topic → Edit → Access policy で、既存の __default_statement_ID を残したまま下の AllowS3BucketToPublish statement を追加します。
- バケットの Properties タブで Bucket ARN をコピー。
- Amazon SNS → Topics → demo-s3-alerts-topic → Edit を開く。
- Access policy ブロックを開き、下の AllowS3BucketToPublish statement を追加。
- <account-id> を自分の Account ID に置換し、aws:SourceArn がコピーした Bucket ARN と一致することを確認。
- Save changes をクリック。
{
"Version": "2012-10-17",
"Id": "demo-s3-alerts-topic-policy",
"Statement": [
{
"Sid": "__default_statement_ID",
"Effect": "Allow",
"Principal": { "AWS": "*" },
"Action": [
"SNS:GetTopicAttributes", "SNS:SetTopicAttributes",
"SNS:AddPermission", "SNS:RemovePermission", "SNS:DeleteTopic",
"SNS:Subscribe", "SNS:ListSubscriptionsByTopic", "SNS:Publish"
],
"Resource": "arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic",
"Condition": {
"StringEquals": { "AWS:SourceOwner": "<account-id>" }
}
},
{
"Sid": "AllowS3BucketToPublish",
"Effect": "Allow",
"Principal": { "Service": "s3.amazonaws.com" },
"Action": "sns:Publish",
"Resource": "arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic",
"Condition": {
"StringEquals": { "aws:SourceAccount": "<account-id>" },
"ArnLike": { "aws:SourceArn": "arn:aws:s3:::demo-source-data-test" }
}
}
]
}
24. Properties → Event notifications → Create
バケットの Properties タブで AWS CloudTrail data events を通り過ぎ、Event notifications ブロックまでスクロールします。今は「Event notifications (0)」「No event notifications」です。Create event notification をクリック。すぐ下の Amazon EventBridge ブロックが Off になっていることにも注目 — これが代替ルートです。EventBridge を有効にするとバケットの全イベントがそちらへ流れ、宛先を個別に固定する代わりに rule と pattern でルーティングできます。このラボ程度の単純なファンアウトなら SNS 直結のほうが素直です。
- Properties タブで Event notifications ブロックまでスクロール。
- Create event notification をクリック。

25. イベント名・prefix/suffix・event type を設定
Event name に Test-notify-sns-handle-ups3 を入力(スクリーンショットに合わせます)。Prefix と Suffix はこのラボでは空のままですが、意味は知る価値があります。prefix に images/ を入れればそのフォルダ配下のオブジェクトだけ、suffix に .jpg を入れれば画像だけを捕まえられます — SNS のメッセージを 1 通消費する前に S3 自身でフィルタする唯一の方法です。Event types では「Put — s3:ObjectCreated:Put」だけにチェックを入れます。「All object create events」(s3:ObjectCreated:*) は選ばないこと。Post・Copy・CompleteMultipartUpload まで一括で含むため、ログを読んだときにオブジェクトの出自が判別できなくなり、大きいファイルの multipart upload 1 回が予想と全く違うイベントを生みます。
- Event name に Test-notify-sns-handle-ups3 を入力。
- Prefix と Suffix は空のまま。
- Object creation で Put (s3:ObjectCreated:Put) にチェック。
- All object create events にはチェックせず、Object removal・Restore・Replication・Intelligent-Tiering・Annotation の各グループはスキップ。

26. destination に SNS topic を選ぶ
Destination ブロックまでスクロールします。選択肢は Lambda function、SNS topic、SQS queue の 3 つ — SNS topic を選びます。S3 に宛先を 1 つだけ知らせたまま、多数の consumer が同じイベントを共有できるようにするのがこれです。Specify SNS topic では「Choose from your SNS topics」を選び、ドロップダウンで demo-s3-alerts-topic を指定します。「Enter SNS topic ARN」は別アカウントの topic 用です。ブロック先頭の青い情報パネルは手順 23 でやったことをそのまま述べています — 先に S3 principal へ権限を与える必要がある、と。Save changes をクリック。
- Destination で SNS topic を選択。
- Choose from your SNS topics を選択。
- SNS topic ドロップダウンで demo-s3-alerts-topic を選択。
- Save changes をクリック。

27. event notification が作成されたことを確認
緑のバナー「Successfully created event notification "Test-notify-sns-handle-ups3"」が出て、テーブルが「Event notifications (1)」になります。4 列を読んで設定を確定させましょう。Name は Test-notify-sns-handle-ups3、Event types は Put、Filters はダッシュ(prefix/suffix フィルタなし)、Destination type は SNS topic、Destination は demo-s3-alerts-topic へのリンクです。配線はここで完成、まだテストはしていません。
- 作成成功の緑バナーを読む。
- Event notifications (1) テーブルの Event types = Put を確認。
- Destination 列が demo-s3-alerts-topic を指していることを確認。

28. Objects タブを開いて Upload
バケットの Objects タブに戻ります。テーブルは「Objects (0)」「You don't have any objects in this bucket」です。Upload をクリック。この瞬間から、アップロードはすべて本物のテストになります — 受信箱にメールが飛び、両方のキューにメッセージが入るので、検証中に大量アップロードはしないでください。
- demo-source-data-test の Objects タブを選択。
- テーブルが Objects (0) であることを確認。
- Upload をクリック。

29. ファイルを選んで Upload
Add files を押して小さいファイルを選びます — スクリーンショットは約 11.2 KB の ModelOrchConfig.json です。Files and folders テーブルにこれから上げるファイルの名前・Type・Size が並び、Destination ブロックが s3://demo-source-data-test を示します。このアップロード経路は PutObject を使うので、手順 25 で選んだ event type と一致します。注意: おおよそ 16 MB を超えるファイルはコンソールが multipart upload に切り替えるため、発生するイベントは s3:ObjectCreated:CompleteMultipartUpload になり、このラボの notification では捕まえられません。小さいファイルを使ってください。
- Add files をクリックし、数 KB の .json など小さいファイルを選択。
- Destination が s3://demo-source-data-test であることを確認。
- Permissions と Properties はスキップ。
- Upload をクリック。

30. Upload succeeded
Upload: status 画面に緑の「Upload succeeded」バナーと Summary(Succeeded 1 file (100.00%)、Failed 0 files)が出ます。Files and folders テーブルではそのファイルの Status が Succeeded です。この時刻を覚えておいてください — S3 イベントはまさに今 publish されており、手順 31 のメールの Timestamp、手順 34 のキュー到着時刻と突き合わせられます。
- Upload succeeded バナーと Summary を読む。
- ファイルの Status 列が Succeeded であることを確認。
- 後で照合するためにアップロード時刻を記録。

31. メールで Amazon S3 Notification を確認
受信箱を開きます。新着メールの件名は「Amazon S3 Notification」、送信者は demo-s3-alerts-topic と表示されます — 手順 4 で設定した Display name がここで効きます。本文は S3 イベントの生 JSON で、eventName は ObjectCreated:Put、awsRegion は us-east-1、bucket.name は demo-source-data-test、object.key はアップロードしたファイル名で size と eTag も付きます。通常は数秒で届きます。届かないときは迷惑メールを確認してください。
- 手順 21 で確認したアドレスの受信箱を開く。
- demo-s3-alerts-topic からの件名 Amazon S3 Notification を探す。
- eventName が ObjectCreated:Put、object.key がアップロードしたファイルであることを確認。

32. キューを開いて Send and receive messages
Amazon SQS → Queues → demo-sqs-worker-1 へ。Details ブロックには後で使う 3 つがあります。ARN、Queue URL(https://sqs.us-east-1.amazonaws.com/<account-id>/demo-sqs-worker-1 — SDK が必要とするのは ARN ではなくこちら)、そして Encryption。下のタブ列には SNS subscriptions があり、このキューがどの topic を購読しているか確認できます。右上の Send and receive messages をクリック。
- Amazon SQS → Queues → demo-sqs-worker-1 を開く。
- 手順 36 のコード用に Details の Queue URL をコピー。
- Send and receive messages をクリック。

33. Poll for messages
Receive messages ブロックでは先に 4 つの数値を読みます。Messages available は 2 — バケットがイベントを生んだ回数と一致します(元のスクリーンショットは 2 回アップロードしています)。Polling duration は 30 秒、Maximum message count は 10、Messages (0) はまだ poll していないから。重要なのは、メッセージはこの画面を開いた時ではなくアップロードの時点からキューに入っているということ。SQS は pull 型で、誰も consumer に push しません。consumer 自身が ReceiveMessage を呼ぶ必要があります。Poll for messages をクリック。
- Messages available を読む — 0 より大きいこと。
- Poll for messages をクリック。
- Polling progress が Success になるまで待つ。

34. キューに 2 通のメッセージ
テーブルが「Messages (2)」になり、各メッセージの ID・Sent・Size・Receive count が並びます。サイズ 1.19 KB と 1.78 KB は S3 のペイロード単体よりかなり大きく、各メッセージが SNS の封筒も抱えているためです。Receive count はそのメッセージが何回受信されたかを数えます。削除せず poll するたび増え、実システムではこの数値が dead-letter queue へ送るタイミングを決めます。demo-sqs-worker-2 も同じ件数であることを相互確認してください — それがファンアウトの証拠です。
- Messages テーブルを想定イベント数と照合。
- Size 列を読む — 各メッセージ約 1–2 KB。
- poll ごとに Receive count が増えることに注目。
- demo-sqs-worker-2 を開き、同様に poll して比較。

35. message body を読む: S3 イベントを包む SNS の封筒
メッセージの ID をクリックし Body タブを見ます。ラボで一番じっくり見るべき場所です。consumer が扱う構造がここで分かります。外側は SNS の封筒で、Type・MessageId・TopicArn・Subject・Timestamp・Signature・SigningCertURL・UnsubscribeURL を持ちます。本物の S3 イベントは Message フィールドの中 — しかも入れ子オブジェクトではなく「文字列」なので、コンソールでは \" のエスケープだらけに見えます。その文字列の中にようやく Records があり、eventName ObjectCreated:Put、configurationId Test-notify-sns-handle-ups3、bucket.name、object.key が入っています。手順 16 で raw message delivery を ON にしていればこの封筒は消え、Body が S3 の JSON そのものになります — すっきりしますが、検証に使う Signature と UnsubscribeURL を失います。
- メッセージ ID をクリックし Body タブを開く。
- 外層を特定: Type = Notification、TopicArn、Subject = Amazon S3 Notification。
- Message フィールドを見つけ、エスケープ済み JSON 文字列だと認識する。
- その中を読む: eventName、configurationId、bucket.name、object.key。
- Attributes タブと Details タブで SQS が付けたメタデータも見る。
{
"Type": "Notification",
"MessageId": "f60f601f-c151-429c-9314-63547c38a6c0",
"TopicArn": "arn:aws:sns:us-east-1:<account-id>:demo-s3-alerts-topic",
"Subject": "Amazon S3 Notification",
"Message": "{\"Records\":[{\"eventVersion\":\"2.5\",\"eventSource\":\"aws:s3\",\"awsRegion\":\"us-east-1\",\"eventTime\":\"2026-09-06T14:40:51.153Z\",\"eventName\":\"ObjectCreated:Put\",\"s3\":{\"configurationId\":\"Test-notify-sns-handle-ups3\",\"bucket\":{\"name\":\"demo-source-data-test\",\"arn\":\"arn:aws:s3:::demo-source-data-test\"},\"object\":{\"key\":\"ModelOrchConfig.json\",\"size\":11466,\"eTag\":\"56c3528f3ba14b1fef28f978f7142758\"}}}]}",
"Timestamp": "2026-09-06T14:40:51.814Z",
"SignatureVersion": "1",
"Signature": "UtWyhwoUS4d2Onilzwl+DpUbggV43djhxE07e1WFZ7RPDjVjovpzKHGY0DjTMRNO/...",
"SigningCertURL": "https://sns.us-east-1.amazonaws.com/SimpleNotificationService-....pem",
"UnsubscribeURL": "https://sns.us-east-1.amazonaws.com/?Action=Unsubscribe&SubscriptionArn=..."
}
36. consumer 側で JSON を 2 層剥がす
コンソールからコードへ移ります。下の Python はキューを読み、手順 35 で見えた 3 点を正しく処理します。第 1 に json.loads を 2 回: Body から封筒を得るために 1 回、envelope['Message'] から S3 イベントを得るためにもう 1 回 — 2 回目を省くのが SNS→SQS パターン最大の落とし穴です。第 2 に object.key は URL エンコードされているため「my report.pdf」は「my+report.pdf」で届きます。unquote_plus しないと、今アップロードしたそのファイルに対して GetObject が NoSuchKey を返します。第 3 に処理後は必ず delete_message すること。visibility timeout 30 秒が切れるとメッセージはキューに戻り再処理されますし、Standard キューはそもそも at-least-once なので consumer は冪等でなければなりません。
- boto3 を入れ、sqs:ReceiveMessage と sqs:DeleteMessage 権限のある認証情報を設定。
- QUEUE_URL を手順 32 でコピーした Queue URL に置換。
- コードを実行し、出力を手順 31 のメールの object.key と照合。
- もう一度 poll する: メッセージが消えていれば delete_message が効いた証拠。
import json
from urllib.parse import unquote_plus
import boto3
REGION = "us-east-1"
QUEUE_URL = "https://sqs.us-east-1.amazonaws.com/<account-id>/demo-sqs-worker-1"
sqs = boto3.client("sqs", region_name=REGION)
response = sqs.receive_message(
QueueUrl=QUEUE_URL,
MaxNumberOfMessages=10,
WaitTimeSeconds=20, # long polling: one call instead of 20 empty ones
)
for message in response.get("Messages", []):
# Layer 1: Body is the SNS envelope (Type, TopicArn, Message, Signature...).
envelope = json.loads(message["Body"])
# Layer 2: envelope["Message"] is still A STRING holding the S3 event.
# Skipping this is the most common break when reading SNS -> SQS.
event = json.loads(envelope["Message"])
for record in event["Records"]:
bucket = record["s3"]["bucket"]["name"]
# The key is URL-encoded: "my report.pdf" arrives as "my+report.pdf".
key = unquote_plus(record["s3"]["object"]["key"])
print(record["eventName"], f"s3://{bucket}/{key}", record["s3"]["object"]["size"])
# Without the delete, the message returns after the 30s visibility timeout.
sqs.delete_message(QueueUrl=QUEUE_URL, ReceiptHandle=message["ReceiptHandle"])37. よくある失敗と切り分け方
下の 4 つでこのパターンの故障はほぼ網羅できますが、共通点は「静かに壊れる」ことです。切り分けの原則は、subscriber から producer へ逆向きに辿り、subscriber 間の差分を手がかりに使うこと。メールは届くがキューが空 → 原因は確実に queue policy。どこにも届かない → 原因は topic policy か event notification。片方のキューだけ届く → 原因は届かないキューの Resource フィールド。下の CLI コマンドは、それぞれの問いに推測ではなく実データで答えます。
- どこにも届かず、S3 が「Unable to validate the following destination configurations」と言う — topic policy に s3.amazonaws.com の許可が無い。手順 23 を見直す。
- メールが届かないがキューにはある — メール subscription がまだ Pending confirmation、または確認メールが迷惑メールにある。手順 19・20 を見直す。
- メールは届くが両キューが空 — queue policy が sns.amazonaws.com の sqs:SendMessage を許可していない。手順 9・12 を見直す。
- 片方のキューだけメッセージがある — もう一方の Resource フィールドの ARN が違う。手順 12 を見直す。
- SSE-KMS のカスタマー管理キーで暗号化したキューが空 — キーポリシーが sns.amazonaws.com に kms:GenerateDataKey と kms:Decrypt を許可していない。
- 大きいファイルを上げてもイベントが来ない — コンソールが multipart upload を使ったので、イベントは Put ではなく CompleteMultipartUpload。手順 25・29 を見直す。
REGION=us-east-1
ACCOUNT=<account-id>
TOPIC_ARN=arn:aws:sns:$REGION:$ACCOUNT:demo-s3-alerts-topic
# 1) Which subscriptions are unconfirmed? SubscriptionArn = "PendingConfirmation".
aws sns list-subscriptions-by-topic --region $REGION --topic-arn $TOPIC_ARN \
--query 'Subscriptions[].{Protocol:Protocol,Endpoint:Endpoint,Arn:SubscriptionArn}' \
--output table
# 2) Does the topic let s3.amazonaws.com publish yet?
aws sns get-topic-attributes --region $REGION --topic-arn $TOPIC_ARN \
--query 'Attributes.Policy' --output text
# 3) What is the bucket publishing, and where to?
aws s3api get-bucket-notification-configuration --region $REGION \
--bucket demo-source-data-test
# 4) Is the queue policy blocking SNS, and is anything waiting?
QUEUE_URL=https://sqs.$REGION.amazonaws.com/$ACCOUNT/demo-sqs-worker-1
aws sqs get-queue-attributes --region $REGION --queue-url $QUEUE_URL \
--attribute-names Policy ApproximateNumberOfMessages
# 5) Take S3 out of the picture: publish to the topic by hand.
# Reaches the queue -> the fault is on the S3 side.
# Does not -> the fault is the topic or queue policy.
aws sns publish --region $REGION --topic-arn $TOPIC_ARN \
--subject "manual test" --message "hello from cli"38. リソースの後片付け
ラボ規模のコストはほぼゼロです。SNS は月 100 万リクエストとメール通知 1,000 通、SQS は 100 万リクエストが無料、S3 は数 KB のストレージ課金だけ。それでも片付ける実務的な理由が 2 つあります。event notification が生きている間はこのバケットへの今後のアップロードすべてがメールを飛ばすこと、そして demo-source-data-test という名前はバケットを削除するまでグローバル名前空間に押さえられ続けること。下の順序は意図的です — データを消す前にイベントを止めます。
- バケットの event notification を無効化、または Properties → Event notifications で削除。
- 全オブジェクトを削除してからバケットを削除(バケットは空でないと削除できません)。
- topic demo-s3-alerts-topic を削除 — subscription 3 つも一緒に消えるので個別削除は不要。
- キュー demo-sqs-worker-1 と demo-sqs-worker-2 を削除。
- 最後の 2 コマンドを実行し、ラボのリソースが残っていないことを確認。
REGION=us-east-1
ACCOUNT=<account-id>
BUCKET=demo-source-data-test
TOPIC_ARN=arn:aws:sns:$REGION:$ACCOUNT:demo-s3-alerts-topic
# 1) Switch the event notification off FIRST. Otherwise clearing objects in
# step 2 can still produce notifications and look like leftover config.
aws s3api put-bucket-notification-configuration --region $REGION \
--bucket $BUCKET --notification-configuration '{}'
# 2) A bucket must be empty before it can be deleted.
aws s3 rm s3://$BUCKET --recursive
aws s3api delete-bucket --region $REGION --bucket $BUCKET
# 3) Delete the topic: all of its subscriptions go with it.
aws sns delete-topic --region $REGION --topic-arn $TOPIC_ARN
# 4) Delete both queues. A deleted queue name is reserved for ~60 seconds;
# recreating it immediately returns QueueDeletedRecently.
for q in demo-sqs-worker-1 demo-sqs-worker-2; do
aws sqs delete-queue --region $REGION \
--queue-url https://sqs.$REGION.amazonaws.com/$ACCOUNT/$q
done
# 5) Confirm nothing is left.
aws sns list-topics --region $REGION --query 'Topics[?contains(TopicArn, `demo-s3-alerts`)]'
aws sqs list-queues --region $REGION --queue-name-prefix demo-sqs-worker参考ドキュメント
- Creating an Amazon SNS topic
- Subscribing an Amazon SQS queue to an Amazon SNS topic
- Amazon SNS email notifications
- Enabling and configuring event notifications using the Amazon S3 console
- Granting permissions to publish event notification messages to a destination
- Amazon S3 event notification types and destinations
- Amazon SNS raw message delivery
- Amazon SNS message filtering
- Key management for Amazon SQS server-side encryption
- Amazon SNS pricing