When running terraform plan I get the following error: 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 tuple.
I'm trying to create buckets, but either allow the user to provide a kms key or looking it up for them.
│ Error: Invalid for_each argument
│
│ on ../ec2-pattern/main.tf line 39, in module "s3_bucket":
│ 329: for_each = local.s3_bucket_list
│ ├────────────────
│ │ local.s3_bucket_list is tuple 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 tuple.
dev.tfvars
s3_buckets = {
bucket1 : {
policy_bucket_modify_arns_csv = "s3-policy-arns/s3-policy-modify-arns.csv"
policy_bucket_read_arns_csv = "s3-policy-arns/s3-policy-read-arns.csv"
bucket_suffix = "test"
contains_pci_info = false
}
}
main.tf
locals {
s3_bucket_list = flatten([
for k, v in var.s3_buckets :
merge(v, { kms_master_key_id = lookup(v, "kms_master_key_id", null), kms_master_key_id = module.datasource-module.data.s3_kms.arn_alias })
])
}
module "s3_bucket" {
for_each = local.s3_bucket_list
create_bucket = each.value.create_bucket
policy_bucket_read_arns_csv = each.value.policy_bucket_read_arns_csv
policy_bucket_modify_arns_csv = each.value.policy_bucket_modify_arns_csv
kms_master_key_id = each.value.kms_master_key_id
}
variable "s3_buckets" {
description = "A map of all buckets"
type = any
default = {}
}
The error seems clear:
given "for_each" argument value is unsuitable ... must be a map, or set of strings, and you have provided a value of type tuple...
To troubleshoot something like that you have to output your s3_bucket_list
so you can confirm is the correct type, in your case your output is a list, you are doing flatten([
that only works on a list:
https://developer.hashicorp.com/terraform/language/functions/flatten
Here is how I would change your code:
variable "s3_buckets" {
default = {
bucket1 : {
bucket_suffix = "test"
contains_pci_info = false
}
bucket2 : {
bucket_suffix = "abc"
contains_pci_info = true
kms_master_key_id = "123"
}
}
}
locals {
s3_bucket_list = {
for k, v in var.s3_buckets :
k => merge(v, { kms_master_key_id = lookup(v, "kms_master_key_id", "foo") })
}
}
output "s3_bucket_list" {
value = local.s3_bucket_list
}
If you do a terraform plan on that we get
Changes to Outputs:
+ s3_bucket_list = {
+ bucket1 = {
+ bucket_suffix = "test"
+ contains_pci_info = false
+ kms_master_key_id = "foo"
}
+ bucket2 = {
+ bucket_suffix = "abc"
+ contains_pci_info = true
+ kms_master_key_id = "123"
}
}
that is a proper map that we can use in the for_each
...
things I've changed:
flatten
, your structure is flat, no clue why you needed thatlookup
I changed the null for foo
you can put any default you want there, like what you had module.datasource-module.data.s3_kms.arn_alias
k => ...
that creates the map structure and we are keeping the original key from s3_bucketsLast thought now with this change maybe you should not name it s3_bucket_list
since that is not a list. I hope that is all clear enough.