terraform-google-service-accounts
terraform-google-service-accounts copied to clipboard
Error: Invalid for_each argument
If you want to create a single service account with the module, a error appears about a for_each:
module "gke_service_account" {
source = "terraform-google-modules/service-accounts/google"
version = "~> 4.0"
project_id = var.project_id
description = "Service Account for Cluster xyz (managed by Terraform)"
names = ["test"]
project_roles = [
"${var.project_id}=>roles/monitoring.viewer",
"${var.project_id}=>roles/monitoring.metricWriter",
"${var.project_id}=>roles/logging.logWriter",
"${var.project_id}=>roles/stackdriver.resourceMetadata.writer",
"${var.project_id}=>roles/artifactregistry.reader",
]
}
The error output is:
╷
│ Error: Invalid for_each argument
│
│ on .terraform/modules/gke_service_account/main.tf line 38, in resource "google_service_account" "service_accounts":
│ 38: for_each = local.names
│ ├────────────────
│ │ local.names is set of string with 1 element
│
│ 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.
╵
I think it worked with v0.15.x but I am not sure.
My Terraform Version is now:
➜ ~ tf -version
Terraform v1.0.0
on darwin_amd64
what was the fix here?
Unfortunately, I have to reopen the issue. This error appears again on following version:
➜ cloud git:(feature/BB-864-production-infrastructure) ✗ terraform version
Terraform v1.0.4
on darwin_amd64
+ provider registry.terraform.io/hashicorp/external v2.1.0
+ provider registry.terraform.io/hashicorp/google v3.78.0
+ provider registry.terraform.io/hashicorp/google-beta v3.79.0
+ provider registry.terraform.io/hashicorp/kubernetes v2.4.1
+ provider registry.terraform.io/hashicorp/null v3.1.0
+ provider registry.terraform.io/hashicorp/random v3.1.0
+ provider registry.terraform.io/hashicorp/time v0.7.2
Just to summarize, this is the issue thrown in the console:
╷
│ Error: Invalid for_each argument
│
│ on .terraform/modules/gke_service_account/main.tf line 38, in resource "google_service_account" "service_accounts":
│ 38: for_each = local.names
│ ├────────────────
│ │ local.names is set of string with 2 elements
│
│ 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 module source code is:
module "gke_service_account" {
source = "terraform-google-modules/service-accounts/google"
version = "~> 4.0"
project_id = var.project_prefix
description = "Service Account for Cluster ${var.cluster_name}-${var.environment} (managed by Terraform)"
prefix = "gke"
names = [
"${var.cluster_name}-${var.environment}-${random_id.gke_suffix.hex}"]
project_roles = [
"${var.project_prefix}=>roles/monitoring.viewer",
"${var.project_prefix}=>roles/monitoring.metricWriter",
"${var.project_prefix}=>roles/logging.logWriter",
"${var.project_prefix}=>roles/stackdriver.resourceMetadata.writer",
"${var.project_prefix}=>roles/artifactregistry.reader",
]
}
The module cannot handle creating a single service account since "name" list has only one element...? @jmymy were you able to fix that somehow?
@floflock The problem is not with the length of your list. It's that you are using random_id.gke_suffix.hex
in the names of the Service Accounts. Terraform does not allow you to use dynamically-computed values in the key of for_each
resources.
You could instead inject the random ID as a prefix using the existing prefix
variable. Alternatively, I'd be happy to review a PR adding a suffix variable as well.
As a workaround, you can also apply your random ID resource terraform apply -target=random_id.gke_suffix
separately before applying your full Terraform config.
@morgante, thanks for the quick response! Will give a try and will also try to fork in order to prepare the PR.
So I had a similar error and am looking for a way to workaround this limitation.
I am using the terraform-google-modules/project-factory/google
module to create a VPC and then create an additional service account at the same time.
module "project" {
source = "terraform-google-modules/project-factory/google"
version = "11.1.1"
name = lower(var.project_name)
random_project_id = true
org_id = var.org_id
folder_id = var.folder_id
billing_account = var.billing_account
activate_apis = concat(var.activate_apis, var.additional_apis)
default_service_account = "disable"
disable_services_on_destroy = false
}
module "terraform_cloud_sa" {
source = "terraform-google-modules/service-accounts/google"
version = "4.0.2"
project_id = module.project.project_id
prefix = "tfc"
names = ["generated-sa"]
project_roles = ["${module.project.project_id}=>roles/owner", "${module.project.project_id}=>roles/serviceusage.serviceUsageAdmin"]
generate_keys = true
}
I can confirm it is the random_project_id
var in the project module as it appends a 2-byte hex to the end of the project name to get the project_id.
I really like this naming/ID feature and would like to keep it. I am also trying to limit the number of things I have to rename every time I want a copy of these 2 blocks. For example, these 2 blocks are part of a standard "module" we use when spinning up new VPCs. Everything used to work fine, and now on version 1.0+ it seems we hit this issue.
I can manually make up a 4 digit ending for the project_id and provide that but seems pointless if I could just use a random_id
automatically.
Outside of basically using a template and generating a new block and committing that, is there any other way I could do this?
the apply -target=
is not feasible as we are using terraform cloud and only allow remote runs via git workflows
ultimately I would just like to instantiate both of those modules like so:
module "new_vpc" {
source = "../modules/vpc"
name = "new-vpc-name
}
I think there's a decent case to be made for us to refactor this module so you don't need to provide the project ID in project_roles
and therefore don't run into that issue.
I think there's a decent case to be made for us to refactor this module so you don't need to provide the project ID in project_roles
I think that would be super helpful
My example is:
provider "google" {
project = var.project_id
region = var.region
}
module "service_accounts" {
for_each = { for sa in var.service_accounts : sa.name => sa }
source = "terraform-google-modules/service-accounts/google"
version = "~> 4.0.3"
project_id = var.project_id
names = [each.key]
description = each.value.description
project_roles = each.value.roles
}
Where var.service_accounts looks like:
service_accounts = [
{ "name": "ci-deploy-user",
"description": "Service account with enough roles to perform deployment operation",
"roles": ["roles/pubsub.editor", "roles/run.invoker", "roles/storage.objectAdmin"]
},
{ "name": "monitoring-example",
"description": "Service account to do some fancy stuff",
"roles": ["roles/monitoring.viewer"]
}
]
My problem here is that I now need to somehow inject project_id mapping into each element of the roles list dynamically and my tiny brain cant compute that :)
This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days
I happen to have the same issue, for the exact reason that I am using a random suffix for the project ID, as @morgante explained.
To make this refactor happen would be awesome. We currently have to use -target
for each run, which is not recommended by Terraform and is slow.
I think there's a decent case to be made for us to refactor this module so you don't need to provide the project ID in
project_roles
and therefore don't run into that issue.
We would be happy to accept a PR with that refactor.
just hit this issue 2 Apr 2022
We tried to setup a project with terraform and using random project_id so that we can recreate this at any given time. We also ran into this issue. From my point of view, this is a design error in this module. I really hope this could be refactored to not use "names" or "project_roles" in any for_each. "names" should also allow dynamic names like suffixes.
See also this stack overflow question / answer: https://stackoverflow.com/questions/70144554/how-to-solve-for-each-terraform-cannot-predict-how-many-instances-will-be-cre
Hit this issue today, as well.
Uggg.... 🤢 Hitting this issue today and banging my head as there is no good way my boss will approve my PR if I'm hardcoding the project id into the module.