Managing IAM permissions across multiple Workspaces in TFE

What is the correct way to handle resources that sit in a different terraform space? I know this isn’t something Terraform is typically designed for but I am finding due to the constraints of enterprise this is needed.

I am working on curating a self serve Google Cloud Run module in Terraform Cloud. I need to update roles in a project managed by a different workspace, yet whenever that workspace is redeployed it deletes the roles.

The resources involved are split across three projects, each which have their own TFE workspace.

  • Service project: Where the consumer deploys Cloud Run.
  • Host project: Where the VPC and Subnet is hosted and shared to the Service Project.
  • Registry project: Where the container images are built and stored in Artifact Registry.

As these required resources are split across different projects, the cloud run service agent (service-PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com) doesn’t get permissions out of the box. So I have created the following resources, to deploy the required roles within the module:

resource "google_project_service_identity" "cloud_run_service_agent" {
  provider = google-beta
  project  = var.project_id
  service  = "run.googleapis.com"
}

resource "google_project_iam_member" "gar_read_access" {
  project = split("/", var.image)[1]
  role    = "roles/artifactregistry.reader"
  member  = resource.google_project_service_identity.cloud_run_service_agent.member
}

resource "google_project_iam_member" "hst_subnet_access" {
  project = var.hst_project_id
  role    = "roles/compute.networkUser"
  member  = resource.google_project_service_identity.cloud_run_service_agent.member
}

However, this means the service project workspace is creating roles in a project that in scope for the host and registry projects. So whenever the Host or Registry are redeployed the roles are destroyed.

Does anyone have any good solutions to this? I want my module to have a good user experience and the deployment to just be a single step, no changes in other repositories needed by the module consumers. However, I’m really struggling to find a suitable way to do this. I’ve looked at lifecycle rules, tfe outputs data source, remote state etc. All don’t seem quite right.

Found the solution.

The answer is to make sure you are only using bindings or members, not policy, when multiple workspaces are changing permissions in a single project.

Yes, using non-authoritative is one option – though do keep in mind that it’s still easy to accidentally create situations where terraform is fighting over those bindings or where you have the same bindings declared in two different places.

I think using authoritative management is a good practice when it’s possible – in either case, for a situation like the one you’ve described, I’ve also created a “meta” or “common” state to handle at least the shared / central project level permissions… and then still handle some resource-level IAM permissions in the same state as the resources they relate to (generally non-authoritatively)

Another thing to watch out for when managing resources authoritatively is to make sure you don’t inadvertently wipe out default permissions that are needed (e.g., any project editor / viewer / etc. grants)

When you say “workspace” here, are you talking about different states and / or terraform cloud workspaces? Or terraform “workspaces” (i.e., using the same code / state with multiple “workspaces”)?