I have this root module which calls the child module to create a GCP project and create IAM role bindings.
module "test_project" {
source = "terraform.dev.mydomain.com/Dev/sbxprjmodule/google"
version = "1.0.3"
short_name = "looker-nwtest"
owner_bindings = ["group:npe-cloud-platformeng-contractors@c.mydomain.com", "group:npe-sbox-rw-tfetraining@c.mydomain.com"]
}
variable "owner_bindings" {
type = list(string)
default = null
}
This is the child module which does the assignments
resource "google_project_iam_binding" "g-sbox-iam-owner" {
count = var.owner_bindings == null ? 0 : length(var.owner_bindings)
project = "${var.project_id}-${var.short_name}"
role = "roles/owner"
members = [var.owner_bindings[count.index]]
}
variable "owner_bindings" {
type = list(string)
default = null
}
/*
When I do a terraform plan and apply, it creates both the bindings properly, looping through twice. Then when I run a terraform plan again and apply, it shows this change below.
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner[0] will be updated in-place
~ resource "google_project_iam_binding" "g-sbox-iam-owner" {
id = "g-prj-npe-sbox-looker-nwtest/roles/owner"
~ members = [
+ "group:npe-cloud-platformeng-contractors@c.mydomain.com",
- "group:npe-sbox-rw-tfetraining@c.mydomain.com",
]
# (3 unchanged attributes hidden)
}
Next time I do a terraform plan and apply, it shows the below. It then alternates between the two of the groups on each subsequent plan and apply.
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner[1] will be updated in-place
~ resource "google_project_iam_binding" "g-sbox-iam-owner" {
id = "g-prj-npe-sbox-looker-nwtest/roles/owner"
~ members = [
- "group:npe-cloud-platformeng-contractors@c.relayhealth.com",
+ "group:npe-sbox-rw-tfetraining@c.relayhealth.com",
]
# (3 unchanged attributes hidden)
}
Tried to change the data structure from list to set and had the same issue. The groups are not inherited and are applied only at the project level too. So not sure what I'm doing wrong here.
Instead of count
you can use a for_each
the change is simple...
the resource in your child module will look something like this:
resource "google_project_iam_binding" "g-sbox-iam-owner" {
for_each = var.owner_bindings == null ? toset([]) : toset(var.owner_bindings)
project = "${var.project_id}-${var.short_name}"
role = "roles/owner"
members = [each.value]
}
The count changes for_each and in the members we use the each.value
With a for_each
the state changes, you will no longer see the numeric array:
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner[0]
...
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner[1]
instead it will have the names, something like:
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner["abc"]
...
# module.lookernwtest_project.google_project_iam_binding.g-sbox-iam-owner["def"]
After looking at this for a while; I'm questioning why do we need individual iam_binding if they all will have the same role, if all members have the same "roles/owner" we could just do:
resource "google_project_iam_binding" "g-sbox-iam-owner" {
project = "${var.project_id}-${var.short_name}"
role = "roles/owner"
members = [var.owner_bindings]
}