Passing variable to policy_arn

I have defined groups with policies and want to assign all existing policies (statically created) to group, but it doesn`t work:

groups.auto.tfvars

groups = [
  {
    group_name="test_group_1",
    group_desc="test",
    group_policy = [
      "s3-read-write-access",
      #"test_group_2",
    ],
    email="test@example.com",
  },
  {
    group_name="test_group_2",
    group_desc="test",
    group_policy = [
      "s3-read-write-access",
      #"test_group_2",
    ],
    email="test@example.com",
  },
]

policies.tf

locals {
  group_policy_pairs = merge([
    for key in var.groups : {
      for policy in key.group_policy :
          "${key.group_name}-${policy}" => {
          group  = key.group_name
          policy = policy
        }
    }
  ]...)
}

resource "aws_iam_policy" "s3-read-write-access" {
  name        = "s3-read-write-access"
  description = "S3 policy for read/write access"

  policy = jsonencode({
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["*"]
    },
    {
      "Effect": "Allow",
      "Action": [
        "s3:PutObject",
        "s3:GetObject",
        "s3:DeleteObject"
      ],
      "Resource": ["*"]
    }
  ]
})
}

resource "aws_iam_group_policy_attachment" "this" {
  for_each = local.group_policy_pairs
  group      = each.value.group
  policy_arn = aws_iam_policy[each.value.policy].arn
}

error log

Error: Invalid reference
│ 
│   on policies.tf line 41, in resource "aws_iam_group_policy_attachment" "this":
│   41:   policy_arn = aws_iam_policy[each.value.policy].arn
│ 
│ A reference to a resource type must be followed by at least one attribute
│ access, specifying the resource name.

If I use policy_arn = aws_iam_policy.s3-read-write-access.arn it works of course

The Terraform language does not include any way to perform dynamic i.e. data-driven references to resource blocks.

I think this might be as a consequence of how it figures out dependencies between resource blocks by analysing what references what.

In your situation, this leaves two options for a workaround:

1) Define every aws_iam_policy that you want to reference by name using 1 resource block, and for_each

i.e.

resource "aws_iam_policy" "policy" {
  for_each = {
    s3-read-write-access = {
      description = "..."
      policy = ...
    }
  }

  name = each.key
  description = each.value.description
  policy = each.value.policy
}

Now you can reference aws_iam_policy.policy[name_goes_here].

2) Manually maintain a separate lookup table by name

locals {
  policy_lookup = {
    s3-read-write-access = aws_iam_policy.s3-read-write-access
  }
}
1 Like