I am using terraform to create an SNS Queue. I am also creating my own SNS policy file.
variables.tf
variable "awsAccId" {
default = "111222433"
}
variable "region" {
default = "ca-central-1"
}
locals.tf
sns_topic_name = "fail-notification"
fail_noti_topic_arn = "arn:aws:sns:${var.region}:${var.awsAccId}:${local.sns_topic_name}"
resource "aws_sns_topic" "fail-noti-topic" {
name = "${local.sns_topic_name }"
}
resource "aws_sns_topic_policy" "fail-noti-topic-policy" {
arn = aws_sns_topic.fail-noti-topic.arn
policy = file("policy/sns-policy.json")
}
resource "aws_sns_topic_subscription" "fail-noti-topic" {
...
...
}
Inside policy(folder) -> sns-policy.json (file)
{
"Version": "2012-10-17",
"Id": "${local.sns_topic_name}_policy_ID",
"Statement": [
{
"Sid": "${local.sns_topic_name}_statement_ID",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SNS:Publish",
"SNS:RemovePermission",
"SNS:SetTopicAttributes",
"SNS:DeleteTopic",
"SNS:ListSubscriptionsByTopic",
"SNS:GetTopicAttributes",
"SNS:AddPermission",
"SNS:Subscribe"
],
"Resource": "${local.fail_noti_topic_arn}",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "{var.awsAccId}"
}
}
}
]
}
I was expecting that the variables in the json would resolve and I would get the exact values as described in the locals.tf
and variables.tf
file.
Instead, the access policy, as shown in the AWS console is
I tried using policy = jsonencode(file("policy/sns-policy.json"))
, but I am getting another error , while terraform apply
that (something like this)
policyerror Attribute is not valid
.
This error is not there during the planning phase.
I also tried something like
resource "aws_sns_topic_policy" "fail-noti-topic-policy" {
arn = aws_sns_topic.fail-noti-topic.arn
policy = <<POLICY
{
"Version": "2012-10-17",
"Id": "${local.sns_topic_name }_policy_ID",
"Statement": [
{
"Sid": "${local.sns_topic_name}_statement_ID",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
......
POLICY
But, this too does not resolve the variables with their corresponding values.
What should I do, to resolve the variables in the policy JSON files, so that I get their actual values, instead of the variables themselves?
What I usually do is use the data source available for creating the policies, because it is the easiest to get the interpolation right with. In this case, that would look something like the following:
data "aws_iam_policy_document" "sns_topic_policy" {
statement {
sid = "${local.sns_topic_name }_policy_ID"
effect = "Allow"
actions = [
"SNS:Publish",
"SNS:RemovePermission",
"SNS:SetTopicAttributes",
"SNS:DeleteTopic",
"SNS:ListSubscriptionsByTopic",
"SNS:GetTopicAttributes",
"SNS:AddPermission",
"SNS:Subscribe"
]
condition {
test = "StringEquals"
variable = "aws:SourceOwner"
values = [
var.awsAccId
]
}
resources = [
local.fail_noti_topic_arn
]
principals {
type = "AWS"
identifiers = [
"*"
]
}
}
}
You would then reference it like the following:
resource "aws_sns_topic_policy" "fail-noti-topic-policy" {
arn = aws_sns_topic.fail-noti-topic.arn
policy = data.aws_iam_policy_document.sns_topic_policy.json
}
Alternatively, you could use the built-in templatefile
function (instead of file
) which allows providing the input values. In that case, you would do something like the following:
resource "aws_sns_topic_policy" "fail-noti-topic-policy" {
arn = aws_sns_topic.fail-noti-topic.arn
policy = templatefile("${path.root}/policy/sns-policy.json", {
id = "${local.sns_topic_name }_policy_ID"
sid = "${local.sns_topic_name}_statement_ID"
resource = local.fail_noti_topic_arn
account_id = var.awsAccId
})
}
For this to work, you would have to make the changes in the templated JSON file as well:
{
"Version": "2012-10-17",
"Id": "${id}",
"Statement": [
{
"Sid": "${sid}",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"SNS:Publish",
"SNS:RemovePermission",
"SNS:SetTopicAttributes",
"SNS:DeleteTopic",
"SNS:ListSubscriptionsByTopic",
"SNS:GetTopicAttributes",
"SNS:AddPermission",
"SNS:Subscribe"
],
"Resource": "${resource}",
"Condition": {
"StringEquals": {
"AWS:SourceOwner": "${account_id}"
}
}
}
]
}