We have a terraform configuration that deploys resources to GCP so we are using the GCP provider. This terraform configuration creates GCP projects and within those projects it creates many Identity & Access management (IAM) resources such as role grants.
We’ve witnessed some strange behaviour that we can’t wrap our heads around, it may take me a moment to explain.
Here’s the terraform code that creates the projects
locals {
# the logic to derive the project_ids is actually a lot more complicated than this
# but for demo purposes it doesn't really matter
project_ids = toset([project1, project2, project3])
}
resource "google_project" "project" {
# what's important here is that this resource is using a for_each
for_each = local.project_ids
project_id = each.key
name = each.key
folder_id = local.data_science_folder_id
auto_create_network = false
billing_account = local.billing_account_id
}
We then have terraform code which deploys IAM resources within those project. e.g.:
resource "google_service_account_iam_member" "deployer_service_account_token_creator_test" {
for_each = local.deployer_test_access_users
service_account_id = data.google_service_account.deployer_test.name
role = "roles/iam.serviceAccountTokenCreator"
member = each.value
}
Notice that it refers to a google_service_account data source. We think that is significant.
Which causes these changes at apply time
# module.admin-data-eng.google_service_account_iam_member.deployer_service_account_token_creator_test["user:name@example.com"] must be replaced
-/+ resource "google_service_account_iam_member" "deployer_service_account_token_creator_test" {
~ etag = "BwXblGITbpw=" -> (known after apply)
~ id = "projects/project3/serviceAccounts/deployer-test@project1.iam.gserviceaccount.com/roles/iam.serviceAccountTokenCreator/user:name@example.com" -> (known after apply)
~ service_account_id = "projects/project3/serviceAccounts/deployer-test@project1.iam.gserviceaccount.com" -> (known after apply) # forces replacement
# (2 unchanged attributes hidden)
}
This is irritating because terraform is destroying and recreating resources that don’t need to be destroyed and recreated. Even worse, by replacing IAM resources there will be a very very short period of time where the IAM grant is not in place and thus there is the potential for something failing in production while that IAM grant is being created (this hasn’t happened yet but we assume it is a matter of time).
What I’m failing to understand is why terraform is determining that the service_account_id is being changed. It isn’t being changed, that is a service account that already exists so why is terraform determining that the value will be (known after apply)
?
Some other significant information:
- This only seems to occur when we add new projects to the
local.project_ids
(i.e. when we’re creating new projects). Any other time we apply this configuration terraform does not determine that these objects need to be replaced - There are many many IAM resources in the configuration for which this is happening. I’ve picked out one as an example.
- To reiterate if it isn’t clear from above… this only seems to happen when resources depend upon a google_service_account data source.
If anyone can shed any light on why this is happening we’d be very grateful because we are nonplussed.