resource "aws_iam_role" "this" {
name = var.role_name
assume_role_policy = data.aws_iam_policy_document.AWSGlueTrustPolicy.json
description = "The Glue role for APC project"
}
resource "aws_iam_role_policy_attachment" "this" {
depends_on = [aws_iam_policy.ESource_S3_Trove_LADWP, aws_iam_policy.esource_s3_int_esource_client_apc, aws_iam_policy.ESource_S3_Glue_Delete]
role = aws_iam_role.this.name
for_each = toset([ data.aws_iam_policy.AWSGlueRole.arn,
aws_iam_policy.ESource_S3_Trove_LADWP.arn,
aws_iam_policy.esource_s3_int_esource_client_apc.arn,
aws_iam_policy.ESource_S3_Glue_Delete.arn
])
policy_arn = each.key
}
during
terraform plan
causes
Error: Invalid for_each argument
│
│ on role.tf line 57, in resource "aws_iam_role_policy_attachment" "this":
│ 57: for_each = toset([ data.aws_iam_policy.AWSGlueRole.arn,
│ 58: aws_iam_policy.ESource_S3_Trove_LADWP.arn,
│ 59: aws_iam_policy.esource_s3_int_esource_client_apc.arn,
│ 60: aws_iam_policy.ESource_S3_Glue_Delete.arn
│ 61: ])
│ ├────────────────
│ │ aws_iam_policy.ESource_S3_Glue_Delete.arn is "arn:aws:iam::994851769564:policy/ESource_S3_Glue_Delete"
│ │ aws_iam_policy.ESource_S3_Trove_LADWP.arn is a string, known only after apply
│ │ aws_iam_policy.esource_s3_int_esource_client_apc.arn is a string, known only after apply
│ │ data.aws_iam_policy.AWSGlueRole.arn is "arn:aws:iam::aws:policy/service-role/AWSGlueServiceRole"
│
│ The "for_each" value depends on resource attributes that cannot be determined until apply, so Terraform cannot predict how many instances will
│ be created. To work around this, use the -target argument to first apply only the resources that the for_each depends on.
╵
The only way around is to disable the policy attachment. Get the policies created and then run with the policy attachment.
@tbugfinder :
the original code version did not have depends_on. I added it in an attempt to resolve the problem. Adding depends_on makes no difference.
I found quite a few references to this seemingly widespread issue with for_each. Here user Mariux suggests breaking up the code into separate stacks. That is essentially what I resorted to doing, granted in a brutal way of commenting out the policy_attachement and then re-running the code with the code been present…
What the error message is trying to say here is that the the values are unknown at planning time, and therefore can’t be used to address the resource instances. Part of the requirements of the for_each value is is that the keys must be known.
Since the values are hard-coded in this configuration, you could create a map rather than a set of values here
The difference is that the key values for the map are known, so Terraform can properly plan each resource instance. For example, the value aws_iam_policy.esource_s3_int_esource_client_apc.arn cannot be known until after that resource has been created, so we can’t use that value to name a aws_iam_role_policy_attachment instance. We can however name that instance aws_iam_role_policy_attachment["client"], and use the arn only for the policy_arn attribute.
ah , i see
aws_iam_group_policy_attachment.grp_policy_att[" DS.arn:aws:iam::aws:policy/IAMUserChangePassword "] was before and now
aws_iam_policy.ESource_S3_Trove_LADWP
Yes, the trick here is that assigning a set to for_each is really just a shortcut for writing out a map with the same keys as values…
for_each = toset(["a", "b"])
…is the same as…
for_each = {
"a" = "a"
"b" = "b"
}
That convenience comes at a cost, though: it means that all of the values must be known and non-sensitive, so that they can be used as map keys.
The advantage of writing it out in full, as a real map, is that you can choose different keys than values, and therefore it’s fine for the values to be unknown or sensitive, as long as the keys still meet the constraints to allow Terraform to use them as stable identifiers between runs.
FWIW, we recently merged a change to this error message which has an additional suggestion to use a map with known keys, since the current error message you saw here does have the drawback that it only presents a workaround and not an actual solution. It’s not really practical to get into all of the underlying details and reasoning in a concise error message, but from the next minor release of Terraform it will at least still prompt to think about using a map instead.