Home > Back-end >  How to add multiple policy using loop in terraform
How to add multiple policy using loop in terraform

Time:08-27

I am trying to create multiple SNS topic subscription in the SQS. I do have the config file like below in json format

"snsSubscriptionArns": [
        "arn:aws:sns:<region>:<accountno>:test1",
        "arn:aws:sns:<region>:<accountno>:test2",
        "arn:aws:sns:<region>:<accountno>:test3"
        ]

Above mentioned Arns will be based on the requirement. It's dynamic. It can be 0, can be 5.. I am trying to create policy using the below

locals {
  # Load all of the data from json
  config = jsondecode(file("testsqs.json"))
}

data "aws_iam_policy_document" "sns_policy" {
  for_each = lookup(local.config, "snsSubscriptionArns", null) == null ? toset([]) : [ for i in local.config.snsSubscriptionArns : i ]
      statement {
      sid     = "topic-subscription-${each.key}"
      effect  = "Allow"
      actions = [
        "sqs:SendMessage"
      ]
      resources = [
        "test-arn"
      ]
      condition {
        test     = "ArnLike"
        variable = "aws:SourceArn"
        values = [
          "${each.key}"
        ]
      }
    }
  policy = data.aws_iam_policy_document.sns_policy[each.key].json
  }

I need to collect all the policies and then I will use resource block to create SQS with above policy like below

resource "aws_sqs_queue_policy" "sqs_queue_policy" {
  queue_url = aws_sqs_queue.queue.id
  policy = data.aws_iam_policy_document.sns_policy.json
}

But I am getting the below error msg.

Error: Unsupported argument

  on main.tf line 36, in data "aws_iam_policy_document" "sns_policy":  
  36:   policy = data.aws_iam_policy_document.sns_policy[each.key].json

An argument named "policy" is not expected here.

It looks my approach is wrong in terraform. Could someone please guide me to achieve? Thanks in advance.

CodePudding user response:

policy is not a valid attribute for iam_policy_document data source see : https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document

It is expected on aws_iam_policy data source, you must create aws_iam_policy resources with a foreach loop

CodePudding user response:

As you can see from the docs for data source aws_iam_policy_document, there is no policy attribute. I believe either of these two options should work. You are very close.

Given the source json file testsqs.json:

{
  "snsSubscriptionArns": [
    "arn:aws:sns:<region>:<accountno>:test1",
    "arn:aws:sns:<region>:<accountno>:test2",
    "arn:aws:sns:<region>:<accountno>:test3"
  ]
}

and main.tf:

locals {
  config = jsondecode(file("testsqs.json"))
  arns   = lookup(local.config, "snsSubscriptionArns", [])
}

data "aws_iam_policy_document" "sns_policy_one_statement" {
  statement {
    actions   = ["sqs:SendMessage"]
    resources = ["test-arn"]
    condition {
      test     = "ArnLike"
      variable = "aws:SourceArn"
      values   = local.arns
    }
  }
}

data "aws_iam_policy_document" "sns_policy_many_statements" {
  dynamic "statement" {
    for_each = local.arns

    content {
      sid       = "topic-subscription-${statement.key}"
      actions   = ["sqs:SendMessage"]
      resources = ["test-arn"]
      condition {
        test     = "ArnLike"
        variable = "aws:SourceArn"
        values   = [statement.value]
      }
    }
  }
}

output "sns_policy_one_statement" {
  value = data.aws_iam_policy_document.sns_policy_one_statement.json
}

output "sns_policy_many_statements" {
  value = data.aws_iam_policy_document.sns_policy_many_statements.json
}

You get outputs like:

Changes to Outputs:
    sns_policy_many_statements = jsonencode(
        {
            Statement = [
                {
                    Action    = "sqs:SendMessage"
                    Condition = {
                        ArnLike = {
                            "aws:SourceArn" = "arn:aws:sns:<region>:<accountno>:test1"
                        }
                    }
                    Effect    = "Allow"
                    Resource  = "test-arn"
                    Sid       = "topic-subscription-0"
                },
                {
                    Action    = "sqs:SendMessage"
                    Condition = {
                        ArnLike = {
                            "aws:SourceArn" = "arn:aws:sns:<region>:<accountno>:test2"
                        }
                    }
                    Effect    = "Allow"
                    Resource  = "test-arn"
                    Sid       = "topic-subscription-1"
                },
                {
                    Action    = "sqs:SendMessage"
                    Condition = {
                        ArnLike = {
                            "aws:SourceArn" = "arn:aws:sns:<region>:<accountno>:test3"
                        }
                    }
                    Effect    = "Allow"
                    Resource  = "test-arn"
                    Sid       = "topic-subscription-2"
                },
            ]
            Version   = "2012-10-17"
        }
    )
    sns_policy_one_statement   = jsonencode(
        {
            Statement = [
                {
                    Action    = "sqs:SendMessage"
                    Condition = {
                        ArnLike = {
                            "aws:SourceArn" = [
                                "arn:aws:sns:<region>:<accountno>:test1",
                                "arn:aws:sns:<region>:<accountno>:test2",
                                "arn:aws:sns:<region>:<accountno>:test3",
                            ]
                        }
                    }
                    Effect    = "Allow"
                    Resource  = "test-arn"
                    Sid       = ""
                },
            ]
            Version   = "2012-10-17"
        }
    )

You only need for_each at the resource level if you want to create multiple of that resource. In your case, I think you only need one policy. You can decide which works for aws_sqs_queue_policy. This uses the dynamic block.

  • Related