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を使い様々な技術課題を解決していきます。
おもしろいなぁと思っていていただけた方はこちらよりご応募ください☆