Access secret manager from cloud function in GCP. What IAM settings to use?

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.

Upvotes: 2

Views: 2830

Answers (1)

guillaume blaquiere
guillaume blaquiere

Reputation: 75715

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.

Upvotes: 8

Related Questions