EventBridgeからSNSに通知ができなくてハマった話

EventBridgeからSNSに通知できないとき、もしかしたらアクセスポリシーが原因かもしれません。
2021.02.05

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちはコンサルティング部の鈴木(純)です。

SDKでEventBridgeからSNSを通知させるコードを書いた時に見事に落とし穴にハマって、解決までに時間がかかったので、みなさんお気をつけくださいというお話です。

SDKやCLIでリソースを作成した時に、EventBridgeからSNS通知ができない…となっている人は同じ原因かもしれません。

設定した内容

GuardDutyのfindingsを通知をさせたいと思ってSDK(Python)でこんな感じのリソースを作成しました。(コードは長くなるので省略)

SNSからはサブスクリプションにEメールを指定していて承認済みです。

EventBridge側のルールではDefaultのイベントバスを使用していて、イベントパターンはGuardDutyのFindingsを取得するようになっています。

ターゲットには先ほどのサブスクリプションが設定されているターゲットが指定されているのを確認しました。

これで準備が完了したと判断して、実際にGuardDutyのサンプルイベントを発行してみたところ残念ながら通知が届きませんでした。

確認した部分

EventBridgeのルール

とりあえず、Eventルールのイベントパターンが合っているかどうかを確認しました。

ルールのメトリクスを確認すると、以下のようなFailledInvocationsが出力されていたので、失敗はしているけどイベントは検知されているので、どうやらイベントパターンの部分は合っていることがわかりました。

これだけではなぜ失敗しているのかわからなかったので、とりあえずEventルールをコンソールの編集画面から確認。

パターン定義は想定している内容で設定していて、実際にトリガーはされているので問題ないと判断。

ターゲットを確認すると指定したトピックが設定されていることが確認できたので、こちらも問題ないと判断して、特に設定内容は変更せずに更新をしました。

もう一度サンプルイベントを発行してみる

原因がわからずに悩んでいる中でもう一度GuardDutyのサンプルイベントを発行したところ、なぜか検知内容のメールが飛んできました。なんでや…

何が原因だったのか

結論からいうと、SNSトピックのアクセスポリシーでEventBridgeからのsns:Publishが許可されていなかったことが原因でした。

もう一度サンプルイベントを発行して問題なく通知されたのは、「コンソール上からEventルールを更新を行った時に、裏でSNSトピックのアクセスポリシーが自動で追加されていたから」。

  • 確認のために編集画面を開いて更新した時 → 通知される
  • SDKで展開しただけの時 → 通知されない

変更せずに更新したときだけ通知がくることに数時間頭を抱えてました。コンソールから設定した時にはアクセスポリシー追加されているなんて全くわからんかった…

対応

SDK(python)でSNSトピックに対してアクセスポリシーを追加してあげます。アクセスポリシーの追加はset_topic_attributesを使います。

responce=client.set_topic_attributes(
            TopicArn=topic_arn,
            AttributeName='Policy',
            AttributeValue=json.dumps(
            {
            "Version": "2008-10-17",
            "Id": "__default_policy_ID",
            "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",
                    "SNS:Receive"
                ],
                "Resource": {topic_arn},
                "Condition": {
                    "StringEquals": {
                    "AWS:SourceOwner": {AWS_Account_id}
                    }
                }
                },
                {
                "Sid": "AWSEvents_Allow",
                "Effect": "Allow",
                "Principal": {
                    "Service": "events.amazonaws.com"
                },
                "Action": "sns:Publish",
                "Resource": topic_arn
                }
            ]
            })
        )

"Sid": "__default_statement_ID",のステートメントはデフォルトでも追加されるものですが、大事なのは"Sid": "AWSEvents_Allow"の方のステートメントです。これを追加することで、EventBridgeからのPublishが可能になります。

CLIで実行する場合には、以下のドキュメントにポリシーの追加方法が載ってますので参考にしてみてください。

最後に

コンソールからは自動でやってくれるシリーズに久々にハマりました。SDKやCLIからリソースを作成した時には気付きにくいポイントだと思うので、どうか私と同じようにハマる人が少しでも少なくなってくれれば嬉しいです。特にリソースベースポリシー忘れがちなので、うまくいかないなって時には疑うようにしましょう!