INFRA

SNS Topic Policy にカスタム statement を足すとデフォルトのアカウント所有者アクセスが消える

CloudWatch アラームから SNS への publish が失敗するようになっていた。SNS Topic Policy にカスタム statement を1つでも足すと、デフォルトのアカウント所有者アクセスが上書きされる。

CloudWatch アラーム → SNS → AWS Chatbot → Slack の構成で、Slack に通知が来なくて詰まった。

原因は SNS Topic Policy。EventBridge から publish できるように statement を1つ足したら、デフォルトのアカウント所有者フルアクセスが上書きされて消えた。CloudWatch アラームから SNS への publish も拒否されるようになっていた。

describe-alarm-history で確認すると Failed to execute action arn:aws:sns:... と出る。これが出たらまず SNS Topic Policy を疑う。

修正は、デフォルトを明示的に復元する statement を追加する:

infra/sns_policy.tf
data "aws_caller_identity" "current" {}
resource "aws_sns_topic_policy" "alarms" {
arn = aws_sns_topic.alarms.arn
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
# デフォルト復元:これを忘れると自アカウントの publish も全部弾かれる
Sid = "DefaultAccountAccess"
Effect = "Allow"
Principal = { AWS = "*" }
Action = [
"SNS:GetTopicAttributes",
"SNS:SetTopicAttributes",
"SNS:AddPermission",
"SNS:RemovePermission",
"SNS:DeleteTopic",
"SNS:Subscribe",
"SNS:ListSubscriptionsByTopic",
"SNS:Publish",
]
Resource = aws_sns_topic.alarms.arn
Condition = {
StringEquals = { "AWS:SourceOwner" = data.aws_caller_identity.current.account_id }
}
},
# 追加したかった statement はその下に積む
{
Sid = "AllowEventBridgePublish"
Effect = "Allow"
Principal = { Service = "events.amazonaws.com" }
Action = "sns:Publish"
Resource = aws_sns_topic.alarms.arn
},
]
})
}

Action = "SNS:*" のワイルドカードは SNS が受け付けず Invalid parameter: Policy statement action out of service scope! で apply エラーになるので、明示リストにする必要がある。