エンジニア

2022.12.20

AWSCloudformationでEventBridgeからSNSを設定したが通知がこないそこのあなたへ【コードあり】

こんにちわ、最近は本格的な冬が訪れ、温かなお布団から出られなくなって来ました。

はじめに

さっそくですが、AWSリソースにおける様々な状態変化等を通知させる仕組みを構築することがよくありませんか? ん?ありますよね? うん、ありますよね(圧

以前弊社ブログにある、AWS Chatbotを使ってSlackに通知をさせてみた結果(導入〜テスト編)を実際に社内勉強会でコード化してみたら見事にハマってしまったので、原因と解決策について執筆してみました。

結論から先に書くと、コンソールからEventBridgeに対して変更をかけるとSNSのアクセスポリシーにEventBridgeからのアクセスに対して、sns:Publishの権限が自動付与されるという【コンソールよしなにしてくれるあるある】です。

NGコード例

先日こんなCloudFormationのymlコードを書いてみました。

一見良さげにみえるんですが、これだと、実はEC2の状態がかわってもメールが届きません。

AWSTemplateFormatVersion: 2010-09-09
Description: EventBridgeRuleSample

Resources:
  SNSTopicSample:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: Sample-Topic
      Subscription:
        - Endpoint: xxxxxxxx@hands-lab.com
          Protocol: email

  EventBridgeRuleSample:
    Type: AWS::Events::Rule
    Properties:
      Name: EventBridgeRuleSample
      EventPattern:
        source:
          - aws.ec2
      Targets:
        - Arn: !Ref SNSTopicSample
          Id: Handslab-no-blog-mitene

※該当のメールにて認証があるのですが、それは今回は割愛します

※弊社ではEメールではなくchatbot → slackを活用しますが割愛します

これをコンソール側で見てみましょう

EventBridge側

↑今回はわかりやすく、EC2の状態が変わったらイベント発火

↑発火したらSNSに通知を飛ばす

SNS側

↑ SNS側の設定はxxx@hand-lab.comにメールをするようにしている

SNSのアクセスポリシー(★なにげにここが今回のポイント)

{
  "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": "arn:aws:sns:ap-xxxxxx:xxxxxxxx:Sample-Topic",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "xxxxxx:xxxxxx@hands-lab.com"
        }
      }
    }
  ]
}

なーんか違和感が全然ないのです。 でもメールはきません。

この時点で頭の中が????状態になります。

試しにコンソールをいじってみる

疑いをもちつつコンソールのEventBridge画面の編集ボタンからもう一度、何もせず更新だけかけてみましょう!

□でくくったターゲットのところを一旦別のサービスに変えてみてください

また今回のことはコンソール上の注意書き(○の箇所)でもかかれておりますが、、、はじめはよくわかりませんでしたw

次へを連打して、更新をかけるとなぜかメールがくるようになるのです。

SNS側のアクセスポリシーを確認してみると、設定がしれっと変わっております。

{
  "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": "arn:aws:sns:ap-xxxxxx:xxxxxxxx:Sample-Topic",
      "Condition": {
        "StringEquals": {
          "AWS:SourceOwner": "xxxxxx:xxxxxx@hands-lab.com"
        }
      }
    },
    {
      "Sid": "AWSEvents_EventBridgeRuleSample_Idxxxxx",
      "Effect": "Allow",
      "Principal": {
        "Service": "events.amazonaws.com"
      },
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:xxxxxx:xxxxx:Sample-Topic"
    }
  ]
}

Oh, my god、、、特にSNSのアクセスポリシーは変えていないのに、なんか下についているんですよね・・・・

そう!!! コンソールから変更するとEventbredgeからのアクセスに対して、sns:Publishの権限が自動で付与されるのです。この権限がないためにメールが飛びませんでした。

OKコード例

なのではじめのコードをこのように変更します。

AWSTemplateFormatVersion: 2010-09-09
Description: EventBridgeRuleSample

Resources:
  SNSTopicSample:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: Sample-Topic
      Subscription:
        - Endpoint: xxxxxxxx@hands-lab.com
          Protocol: email

  TopicPolicySample:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Statement:
          - Sid: AllowServices
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
                - sns:Publish
            Resource:
              - !Ref SNSTopicSample
      Topics:
        - !Ref SNSTopicSample

  EventBridgeRuleSample:
    Type: AWS::Events::Rule
    Properties:
      Name: EventBridgeRuleSample
      EventPattern:
        source:
          - aws.ec2
      Targets:
        - Arn: !Ref SNSTopicSample
          Id: Handslab-no-blog-mitene

これを追加することにより、無事メールが送信されるようになりました。

コンソールで作成してから、cloudformationを作成するとかよくあるのですが、

その際にハマりがちな箇所ですね。

実際に私も結構ハマりました (´•ω•̥`)

コンソールは便利ですが、裏でよしなにやってくれるとコードにしたときにわからなくなるということがよくありますw  本ブログはそんな方の解決策となってくれると嬉しいです。

ハンズラボでは、AWSを使い様々な技術課題を解決していきます。

おもしろいなぁと思っていていただけた方はこちらよりご応募ください☆

一覧に戻る