Hello I am using google provider to create projects
Runtime Input for project creation is like -
project_attributes = {
"project_3" = {
"cos" = "dev"
"region" = ["us-central1","asia-south1"]
"billing_account" = 1234
"org_id" = 123
}
"project_4" = {
"cos" = "dev"
"region" = ["us-central1","europe-west1"]
"billing_account" = 1234
"org_id" = 123
}
}
Another variable map is for cmek_keys based on cos and region passed in project_attributes it will return the key to use.
cmek_keys = {
"prod" = {
"us-central1" = "key_prod_us-central1",
"asia-south1" = "key_prod_asia-south1",
}
"dev" = {
"us-central1" = "key_dev_us-central1",
"asia-south1" = "key_dev_asia-south1",
"europe-west2" = "key_dev_europe-west2",
}
}
Problem is region in project_attributes i want to be as a list , i want to make sure this resource below runs for all regions, giving acccess to keys in all different regions.
I am able to run this resource below when region is just a string
resource "google_kms_crypto_key_iam_member" "cmek_auth_permissions" {
for_each = var.project_attributes
crypto_key_id = var.cmek_keys[each.value["cos"]][each.value["region"]]
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${google_project.project[each.key].number}@compute-system.iam.gserviceaccount.com"
}
What would be the best to do this , making sure my input given is concise .
Hi @riteshnanda09!
A good building block for this sort of situation is to use the flatten
function to reduce your nested structure into a flat structure so that each element corresponds to one instance of google_kms_crypto_key_iam_member.cmek_auth_permissions
.
I usually do this in two steps, doing the flattening first as a named local value:
local {
project_regions = toset(flatten([
for n, p in var.project_attributes : [
for r in p.region : {
project = n
region = r
cos = p.cos
key_id = var.cmek_keys[p.cos][p.region]
}
]
]))
}
The nested for
expressions produce a list of lists of objects, and then flatten
reduces that into a single list of objects. Then I used toset
just to be explicit that the ordering of this result isn’t significant and so it isn’t meaningful to use it as a list.
for_each
requires a map where each object has a unique key though, so we’ll need to do one more transform in the for_each
argument to meet that requirement:
resource "google_kms_crypto_key_iam_member" "cmek_auth_permissions" {
for_each = {
for pr in local.project_regions : "${pr.project}.${pr.region}" => pr
}
crypto_key_id = each.value.key_id
role = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
member = "serviceAccount:service-${google_project.project[each.value.project].number}@compute-system.iam.gserviceaccount.com"
}
This will produce instances with addresses like google_kms_crypto_key_iam_member.cmek_auth_permissions["project_3.us-central1"]
, so Terraform can track which instance belongs to each pairing of project and region.
Perfect @apparentlymart works like a charm .
@apparentlymart
I tested with the above solution you provided, however I am not sure if this works var.cmek_keys[p.cos][p.region]
?
locals {
project_attributes = {
"project_3" = {
"cos" = "dev"
"region" = ["us-central1","asia-south1"]
"billing_account" = 1234
"org_id" = 123
}
"project_4" = {
"cos" = "dev"
"region" = ["us-central1","europe-west1"]
"billing_account" = 1234
"org_id" = 123
}
}
cmek_keys = {
"prod" = {
"us-central1" = "key_prod_us-central1",
"asia-south1" = "key_prod_asia-south1",
}
"dev" = {
"us-central1" = "key_dev_us-central1",
"asia-south1" = "key_dev_asia-south1",
"europe-west2" = "key_dev_europe-west2",
}
}
project_regions = toset(flatten([
for n, p in local.project_attributes : [
for r in p.region : {
project = n
region = r
cos = p.cos
key_id = local.cmek_keys[p.cos][p.region] # --> lookup(local.cmek_keys[p.cos], r)
}
]
]))
}
output "out" {
value = local.project_regions
}
36: key_id = local.cmek_keys[p.cos][p.region]
|----------------
| local.cmek_keys is object with 2 attributes
| p.cos is "dev"
| p.region is tuple with 2 elements
The given key does not identify an element in this collection value: string
required.
Error: Invalid index
on tets.tf line 36, in locals:
36: key_id = local.cmek_keys[p.cos][p.region]
|----------------
| local.cmek_keys is object with 2 attributes
| p.cos is "dev"
| p.region is tuple with 2 elements
The given key does not identify an element in this collection value: string
required.```
Also as per doc this may not be the right syntax, please correct me if I am mistaken here .
Hi @smitjainsj,
Sorry, it looks like I made an error. I intended to write var.cmek_keys[p.cos][r]
, where r
is a single region. p.region
is the collection of all regions, and so isn’t valid as a map key.