1
votes

I have no ideas what to set here. The whole policy, binding and member stuff is very confusing IMHO. Are any of these roles? Anyway...

Trying to access the secret manager from a cloud function. The cloud function is setup using Terraform:

module "mds_reporting_cloud_function" {
  source                         = "terraform-google-modules/scheduled-function/google"
  version                        = "2.0.0"
  project_id                     = var.function_gcp_project
  job_name                       = var.function_name
  job_description                = var.function_description
  job_schedule                   = var.function_cron_schedule
  function_entry_point           = "main"
  function_source_directory      = "${path.module}/../../../../src"
  function_name                  = var.function_name
  region                         = var.function_gcp_region
  bucket_name                    = var.function_name
  function_description           = var.function_description
  function_environment_variables = var.function_environment_variables
  function_runtime               = "python38"
  topic_name                     = var.function_name
}

resource "google_cloudfunctions_function_iam_binding" "binding" {
  project        = var.function_gcp_project
  region         = var.function_gcp_region
  cloud_function = var.function_name
  role           = "roles/secretmanager.secretAccessor"
  members = [
    "serviceAccount:${var.function_gcp_project}@appspot.gserviceaccount.com"
  ]
}

My understanding is, that if no service account for the cloud function is specified it will use the default App Engine service account.

The binding should 'bind' the role to the existing IAM policy of the App Engine service account.

However, it throws this error:

Error: 
Error applying IAM policy for cloudfunctions cloudfunction "projects/alpine-proton-280612/locations/europe-west3/functions/mds-reporting-cloud-function":
Error setting IAM policy for cloudfunctions cloudfunction "projects/alpine-proton-280612/locations/europe-west3/functions/mds-reporting-cloud-function": 
googleapi: Error 400: Role roles/secretmanager.secretAccessor is not supported for this resource.

Not sure what do.

1
You have the role assignment backwards. You are trying to grant the service account secretAccessor to the function. Functions do not provide the secret service. If you are trying to modify a service account and grant it an additional role, grant the permission to the project resource, not the function resource.John Hanley
Tip: be careful modifying the project resource using Terraform. It is possible to lock yourself out of your project by overwriting (removing) existing roles. Create a throw away test project.John Hanley
Review @guillaume's answer. His approach is better granting secretAccessor on the Secret Manager resource.John Hanley
@John Hanley, thanks so much for thr explanation!Moritz Schmitz v. Hülst

1 Answers

3
votes

The best solution is to grant, only on the secret, the permission for the Cloud Functions service account to access the secret. For that use the Secret Manager IAM terraform resource

resource "google_secret_manager_secret_iam_binding" "binding" {
  project = var.function_gcp_project
  secret_id = google_secret_manager_secret.your-secret.secret_id
# If your secret is not created by terraform, use this format for the id projects/{{project}}/secrets/{{secret_id}}
  role = "roles/secretmanager.secretAccessor"
  members = [
    "serviceAccount:${var.function_gcp_project}@appspot.gserviceaccount.com"
  ]
}

Important note:

  • You can also grant this role at the project level, but it's less secure because the function will have access to all the secrets of the project
  • You use the App Engine (and cloud function) default service account. It's also not so secure. Indeed, any App Engine service, and Cloud Functions with custom service account will use by default this service account, and thus will be able to access the secrets. Prefer a custom service account for your Cloud Functions
  • The second comment of John is very important. Terraform have several level of write-and-replace of IAM roles. Keep in mind (work for all IAM_XXX terraform module)
    • Policy replace all the accounts of all the possible roles of the whole resource (on a project, it could be dramatic!)
    • Binding replace all the accounts of a specific role
    • Member only add an account on a specific role. Delete nothing.