0

I have a task to refactor current usual IAM module to IAM module with option to send 1 or more policy as input from Terragrunt. I am trying to use latest resources from aws: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role.html

variable "policy" {
  type    = list(string)
  default = null
}

data "aws_iam_policy_document" "instance_assume_role_policy" {
  statement {
    actions = ["sts:AssumeRole"]

    principals {
      type        = "Service"
      identifiers = var.aws_assume_identifiers
    }
  }
}

resource "aws_iam_role" "role" {
  count              = var.create_role ? 1 : 0
  name                = var.role_name
  assume_role_policy  = data.aws_iam_policy_document.instance_assume_role_policy.json # (not shown)
  managed_policy_arns = [aws_iam_policy.policy[0].arn]
}

resource "aws_iam_policy" "policy" {
  name = "policy"
  for_each = toset(var.policy)
  policy = each.value
}

The problem is inside sending policy, what type of variable it should, how it should be divided etc. If I send policy as array with "" I get this:

  policy = [ <<POLICY
    "{ # POLICY 1
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Sid" : "",
          "Effect" : "Allow",
          "Action" : [
            "s3:Get*",
            "s3:List*"
          ]
          "Resource" : "*"
        }
      ]
    }",
    "{ # POLICY 2
      "Version" : "2012-10-17",
      "Statement" : [
        {
          "Sid" : "",
          "Effect" : "Allow",
          "Action" : [
            "ec2:Get*",
            "ec2:List*"
          ]
          "Resource" : "*"
        }
      ]
    }"
POLICY      
  ]
Planning failed. Terraform encountered an error while generating this plan.

╷
│ Error: "policy" contains an invalid JSON policy: leading space characters are not allowed
│ 
│   with aws_iam_policy.policy["  \"{\n      \"Version\" : \"2012-10-17\",\n      \"Statement\" : [\n        {\n          \"Sid\" : \"\",\n          \"Effect\" : \"Allow\",\n          \"Action\" : [\n            \"s3:Get*\",\n            \"s3:List*\"\n          ]\n          \"Resource\" : \"*\"\n        }\n      ]\n    }\",\n    \"{\n      \"Version\" : \"2012-10-17\",\n      \"Statement\" : [\n        {\n          \"Sid\" : \"\",\n          \"Effect\" : \"Allow\",\n          \"Action\" : [\n            \"ec2:Get*\",\n            \"ec2:List*\"\n          ]\n          \"Resource\" : \"*\"\n        }\n      ]\n    }\"   \n"],
│   on main.tf line 38, in resource "aws_iam_policy" "policy":
│   38:   policy = (each.value) #var.policy[0] #jsonencode(var.policy[0])

1 IAM role with attached 1, 2 or 10 IAM policy passed as input

I have updated code.

Oleksadr S
  • 13
  • 4
  • 2
    Your variable value is a list (array), and your variable definition is a map(string), change the map to list(string) and that should solve your problem. – victor m Jul 27 '23 at 14:25
  • Thanks, if I change to list(string), then I get: │ Error: Invalid for_each argument │ 36: for_each = var.policy │ │ var.policy is list of string with 1 element │ The given "for_each" argument value is unsuitable: the "for_each" argument │ must be a map, or set of strings, and you have provided a value of type │ list of string. – Oleksadr S Jul 27 '23 at 15:22
  • You can use a local variable to change the list into a map. Or you change your loop to iterate over a set. Use the toset() function. – victor m Jul 29 '23 at 18:02

0 Answers0