24

Here is the terraform code I have used to create a service account and bind a role to it:

resource "google_service_account" "sa-name" {
  account_id = "sa-name"
  display_name = "SA"
}

resource "google_project_iam_binding" "firestore_owner_binding" {
  role               = "roles/datastore.owner"
  members = [
    "serviceAccount:sa-name@${var.project}.iam.gserviceaccount.com",
  ]
  depends_on = [google_service_account.sa-name]
}

Above code worked great... except it removed the datastore.owner from any other service account in the project that this role was previously assigned to. We have a single project that many teams use and there are service accounts managed by different teams. My terraform code would only have our team's service accounts and we could end up breaking other teams service accounts.

Is there another way to do this in terraform?

This of course can be done via GCP UI or gcloud cli without any issue or affecting other SAs.

kxasha
  • 293
  • 1
  • 4
  • 12
  • Do the other services are created with terraform too? What is the result of the command `terraform plan` ? – guillaume blaquiere Apr 03 '20 at 09:44
  • a lot of them are manually created and there is no control over what other teams are doing. Plan or apply never showed any destruction. – kxasha Apr 03 '20 at 15:14

2 Answers2

52

From terraform docs, "google_project_iam_binding" is Authoritative. Sets the IAM policy for the project and replaces any existing policy already attached. That means that it replaces completely members for a given role inside it.

To just add a role to a new service account, without editing everybody else from that role, you should use the resource "google_project_iam_member":

resource "google_service_account" "sa-name" {
  account_id = "sa-name"
  display_name = "SA"
}

resource "google_project_iam_member" "firestore_owner_binding" {
  project = <your_gcp_project_id_here>
  role    = "roles/datastore.owner"
  member  = "serviceAccount:${google_service_account.sa-name.email}"
}

Extra change from your sample: the use of service account resource email generated attribute to remove the explicit depends_on. You don't need the depends_on if you do it like this and you avoid errors with bad configuration.

Terraform can infer the dependency from the use of a variable from another resource. Check the docs here to understand this behavior better.

  • from the document, Other roles with tha IAM policy for the project are pereserved. google_project_iam_binding: Authoritative for a given role. Updates the IAM policy to grant a role to a list of members. Other roles within the IAM policy for the project are preserved. – Richard D Feb 16 '21 at 00:03
  • Thanks Marcos it helped me in my issue – Nitin G Jul 13 '22 at 06:03
5

It's an usual problem with Terraform. Either you do all with it, or nothing. If you are between, unexpected things can happen!!

If you want to use terraform, you have to import the existing into the tfstate. Here the doc for the bindind, and, of course, you have to add all the account in the Terraform file. If not, the binding will be removed, but this time, you will see the deletion in the tf plan.

guillaume blaquiere
  • 66,369
  • 2
  • 47
  • 76