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 Cloud Partner Top Engineer 2025、2024 AWS All Cert、ビール検定1冠
Recommends
こちらもおすすめ
-
AWS Chatbotを使って、Slack通知をカスタマイズする
2024.2.15
-
Terraform を運用するについて考える ~第2回 Terraformを始める~
2022.10.26
-
Terraform で Amazon EC2 を複数台作成する
2022.4.7
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28

AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16
