What is the equivalent of this gcloud add-iam-policy-binding in terraform?

36 Views Asked by At

Trying to translate cert-manager, CloudDNS sample code into terraform but I haven't been able to make this snippet work with workload identity:

gcloud iam service-accounts add-iam-policy-binding \
    --role roles/iam.workloadIdentityUser \
    --member "serviceAccount:$PROJECT_ID.svc.id.goog[cert-manager/cert-manager]" \
    dns01-solver@$PROJECT_ID.iam.gserviceaccount.com

I have tried:

resource "google_service_account_iam_binding" "dns01_solver_binding" {
  service_account_id = google_service_account.dns01_solver.name
  role               = "roles/iam.workloadIdentityUser"

  members = [
    "serviceAccount:${var.project_id}.svc.id.goog[cert-manager/cert-manager]/dns01-solver@${var.project_id}.iam.gserviceaccount.com",
  ]
}

and

resource "google_project_iam_member" "main" {
  project = var.project_id
  role    = "roles/iam.workloadIdentityUser"
  member  = "serviceAccount:${var.project_id}.svc.id.goog[cert-manager/cert-manager]/dns01-solver@${var.project_id}.iam.gserviceaccount.com"
}

Keep getting error:

│ Error: Error applying IAM policy for service account 'projects/my-project.iam/serviceAccounts/[email protected]': 
Error setting IAM policy for service account 'projects/my-project.iam/serviceAccounts/[email protected]': 
googleapi: Error 400: Invalid service account (my-project.iam.svc.id.goog[cert-manager/cert-manager]/[email protected])., badRequest

│ 
│   with google_service_account_iam_binding.dns01_solver_binding,
│   on cert-manager.tf line 47, in resource "google_service_account_iam_binding" "dns01_solver_binding":
│   47: resource "google_service_account_iam_binding" "dns01_solver_binding" {

But if I check my service account tab it is actually there: enter image description here

Also the service account needed exists in cert-manager kubernetes namespace as well:

enter image description here

2

There are 2 best solutions below

0
Lorenzo Felletti On

I think the error is caused by the member being "serviceAccount:${var.project_id}.svc.id.goog[cert-manager/cert-manager]/dns01-solver@${var.project_id}.iam.gserviceaccount.com" while it should be just "serviceAccount:$PROJECT_ID.svc.id.goog[cert-manager/cert-manager]". Docs here for more information. Also worth considering if you want an authorative or not-authorative kind of policy, that's also explained in the docs.

resource "google_service_account_iam_binding" "dns01_solver_binding" {
  service_account_id = google_service_account.dns01_solver.name
  role               = "roles/iam.workloadIdentityUser"

  members = [
    "serviceAccount:${var.project_id}.svc.id.goog[cert-manager/cert-manager]",
  ]
}
0
CommonSenseCode On

so I got the cert-manager dns01-solver code working with terraform with following code:


# this is a "Split DNS" setup
resource "google_dns_managed_zone" "public_dns_zone_example" {
  name       = "public-${var.region}-${var.env}-example-com"
  dns_name   = "example.com."
  visibility = "public"

  description = "Public DNS zone needed for cert-manager certificates" # https://cert-manager.io/docs/configuration/acme/dns01/google/

  depends_on = [google_project_iam_member.dns_admin]
}

resource "google_service_account" "dns01_solver" {
  project      = var.project_id
  account_id   = "dns01-solver"
  display_name = "dns01-solver"
}

resource "google_project_iam_member" "dns01_solver" {
  project = var.project_id
  role    = "roles/dns.admin"
  member  = "serviceAccount:${google_service_account.dns01_solver.email}"
}

locals {
  cert_manager_k8s_service_account = "serviceAccount:${var.project_id}.svc.id.goog[cert-manager/cert-manager]"
}

resource "google_project_iam_member" "workload_identity_role" {
  project = var.project_id
  role    = "roles/iam.workloadIdentityUser"
  member  = local.cert_manager_k8s_service_account
}

resource "google_project_iam_member" "dns_admin_cert_manager_sa" {
  project = var.project_id
  role    = "roles/dns.admin"
  member  = local.cert_manager_k8s_service_account
}

And then in the helm package for cert-manager in values.yaml I added this annotation:

serviceAccount
  create: true
  annotations: {
    iam.gke.io/gcp-service-account: [email protected]
  } 

Basically above adds annotation to service account "cert-manager" in k8s namespace "cert-manager"

That will be enough to give permissions to serv.account dns01-solver