TerraformでAWS ChatbotとAmazon SNSを設定していて、詰まった話
はじめに
こんにちは、Shunです。
AWS Chatbotをコード化する際に、Amazon SNSで詰まってしまったので、その体験を共有します。
私自身、かなり苦労したため、これが誰かの助けになれば幸いです。
想定読者
- Terraformを使用してAWS Chatbotを作成していて、通知が届かない方
- Amazon SNS関連で問題に直面している方
- リソースをTerraformで管理したいと考えている方
本記事で紹介する内容
- Amazon SNS設定時の注意事項
- Terraform記述時のポイント
本記事で紹介しない内容
- AWS Chatbotの具体的な設定方法
- Amazon SNSなどのサービス詳細
- Terraformの基本記法
実施していたこと
以下の構成をTerraformで記述していました。
エラーは発生せず、環境は正常にapplyされました。
しかし、CloudWatch Alarmの状態を変更してChatbotへの通知を試みたところ、通知が届きませんでした。
以前、コンソールで同様の設定を行った経験があるため、何が間違っているのかがわかりませんでした。。
確認した事項
AWS Chatbotの設定確認
まず、Slackへの通知機能を持つChatbotが正しく機能するかを確認しました。
すぐにSlackへの通知が届き、Chatbotの権限や対象チャネルの設定に問題はないことが分かりました。
Amazon CloudWatch Alarmの設定確認
CloudWatch Alarmの設定を確認しましたが、今回のアラームはEventBridgeのルールによって捉えられるため、設定されていないことが正常です。
Amazon EventBridgeの設定確認
EventBridgeの設定も問題ないことを確認しました。
「イベントパターン」は適切なCloudWatch Alarmを指しており、問題はありませんでした。
「ターゲット」も問題なさそうです。
Amazon SNSの設定確認
SNSについては、コンソールで作成する際には名前の入力のみで済むため、最後に確認しました。
関連する「アクセスポリシー」を見てみると、
以下のような権限が設定されています。
{ "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxx:xxxxxxxxxxx", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxxx" } } } ] }
これとは別に、コンソールから作成したSNSトピックの「アクセスポリシー」も確認してみると、
{ "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxx:xxxxxxxxxxx", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxxx" } } }, { "Sid": "xxxxxxxxxxxxxxxxxxxxxxxxx", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxx:xxxxxxx" } ] }
記憶にない設定が追加されていることが判明しました。具体的には、"events.amazonaws.com"
への"sns:Publish"
権限が新たに付与されていました。
この追加された設定が、Slackへの通知が届かなかった原因であることが明らかになりました。
つまり、
SNSの「アクセスポリシー」内で、EventBridgeからのアクセスに”sns:Publish”の権限を明示的に付与
する必要があったのです。
検証
先述した設定がどのように行われたのか検証を行いました。まず、Terraformを用いて以下の設定を適用しました。
resource "aws_sns_topic" "test" { name = "test" } resource "aws_cloudwatch_event_rule" "test" { event_bus_name = "default" event_pattern = file("alarm_event.json") is_enabled = true name = "test" } resource "aws_cloudwatch_event_target" "test" { arn = aws_sns_topic.test.arn rule = aws_cloudwatch_event_rule.test.id input_transformer { input_paths = { "account" : "$.account", "alarm" : "$.detail.alarmName", "description" : "$.detail.configuration.description", "instance" : "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId", "metrics_name" : "$.detail.configuration.metrics[0].metricStat.metric.name", "state" : "$.detail.state.value", "timestamp" : "$.detail.state.timestamp" } input_template = file("alarm_template.json") } }
やはりこの設定では、SNSの「アクセスポリシー」にEventBridgeからのアクセス権限が自動的に付与されませんでした。
次に、上記の設定をコンソールから実施します。(表示部分以外は、既定値です。)
「アクセスポリシー」を確認します。
{ "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxx:test", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxxxxx" } } }
やはりアクセスポリシーは付与されていません。
続いて、EventBridgeを設定します。Terraformの設定と同様の「イベントパターン」と「ターゲット」を選択し、作成します。
そして、もう一度SNSの「アクセスポリシー」を確認してみると、
{ "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxx:test", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxxxxx" } } }, { "Sid": "xxxxxxxxxxxxxxxxxxxxxxxxx", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxxxxx:xxxxxxx" } ] }
やっぱり増えてるんです。。
このことから、
コンソールから操作を行うと、EventBridgeからのアクセスに対して、自動でSNSのアクセスポリシーに権限が付与
されることが確認できました。
解決策
問題の解決策として、Terraformによる実装でSNSの「アクセスポリシー」にEventBridgeからのアクセスを明示的に付与する必要がありました。
resource "aws_sns_topic" "test" { name = "test" } resource "aws_sns_topic_policy" "test" { arn = aws_sns_topic.test.arn policy = <<POLICY { "Version": "2008-10-17", "Id": "__default_policy_ID", "Statement": [ { "Sid": "__default_statement_ID", "Effect": "Allow", "Principal": { "AWS": "*" }, "Action": [ "SNS:Publish", "SNS:RemovePermission", "SNS:SetTopicAttributes", "SNS:DeleteTopic", "SNS:ListSubscriptionsByTopic", "SNS:GetTopicAttributes", "SNS:AddPermission", "SNS:Subscribe" ], "Resource": "arn:aws:sns:ap-northeast-1:xxxxxxxx:xxxxxxxxx", "Condition": { "StringEquals": { "AWS:SourceOwner": "xxxxxxxxx" } } }, { "Sid": "xxxxxxxxx", "Effect": "Allow", "Principal": { "Service": "events.amazonaws.com" }, "Action": "sns:Publish", "Resource": "arn:aws:sns:ap-northeast-1:xxxxxx:xxxxxxxx" } ] } POLICY } resource "aws_cloudwatch_event_rule" "test" { event_bus_name = "default" event_pattern = file("alarm_event.json") is_enabled = true name = "test" } resource "aws_cloudwatch_event_target" "test" { arn = aws_sns_topic.test.arn rule = aws_cloudwatch_event_rule.test.id input_transformer { input_paths = { "account" : "$.account", "alarm" : "$.detail.alarmName", "description" : "$.detail.configuration.description", "instance" : "$.detail.configuration.metrics[0].metricStat.metric.dimensions.InstanceId", "metrics_name" : "$.detail.configuration.metrics[0].metricStat.metric.name", "state" : "$.detail.state.value", "timestamp" : "$.detail.state.timestamp" } input_template = file("alarm_template.json") } }
このコードを適用した結果、正常にSlackに通知が送信されるようになりました。
まとめ
コンソールからリソースを作成すると、設定値が自動で補完されたり、設定が裏側で追加されるなど、便利な機能が多いことを改めて確認しました。しかし、サービスに対する深い理解を得るためには、コード化による設定も有効な手段だと感じました。
この記事が何らかの形で役立てば幸いです。
最後まで読んでいただきありがとうございました。
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterGoogle Cloud11冠、2024 AWS All Cert、ビール検定1冠
Recommends
こちらもおすすめ
-
【ハンズオン】Amazon EKSをTerraformで構築してみる
2022.10.25
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28
AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16