3
votes

I will start by saying I am very new to both GCP and Terraform, so I hope there is a simple answer that I have just overlooked.

I am trying to create a GCP cloud function and then make it public using Terraform. I am able to create the function but not make it public, despite closely following the documentation's example: https://www.terraform.io/docs/providers/google/r/cloudfunctions_function.html

I receive the error "googleapi: Error 403: Permission 'cloudfunctions.functions.setIamPolicy' denied on resource ... (or resource may not exist)" when the google_cloudfunctions_function_iam_member resource is reached.

How can I make this function public? Does it have something to do with the account/api key I am using for credentials to create all these resources?

Thanks in advance.

my main.tf file:

provider "google" {
  project     = "my-project"
  credentials = "key.json" #compute engine default service account api key
  region      = "us-central1"
}

terraform {
  backend "gcs" {
    bucket  = "manually-created-bucket"
    prefix  = "terraform/state"
    credentials = "key.json"
  }
}

# create the storage bucket for our scripts
resource "google_storage_bucket" "source_code" {
  name     = "test-bucket-lh05111992"
  location = "us-central1"
  force_destroy = true
}

# zip up function source code
data "archive_file" "my_function_script_zip" {
 type        = "zip"
 source_dir  = "../source/scripts/my-function-script"
 output_path = "../source/scripts/my-function-script.zip"
}

# add function source code to storage
resource "google_storage_bucket_object" "my_function_script_zip" {
 name   = "index.zip"
 bucket = google_storage_bucket.source_code.name
 source = "../source/scripts/my-function-script.zip"
}

#create the cloudfunction 
resource "google_cloudfunctions_function" "function" {
  name        = "send_my_function_script"
  description = "This function is called in GTM. It sends a users' google analytics id to BigQuery."
  runtime     = "nodejs10"

  available_memory_mb   = 128
  source_archive_bucket = google_storage_bucket.source_code.name
  source_archive_object = google_storage_bucket_object.my_function_script_zip.name
  trigger_http          = true
  entry_point           = "handleRequest"
}

# IAM entry for all users to invoke the function 
resource "google_cloudfunctions_function_iam_member" "invoker" {
  project        = google_cloudfunctions_function.function.project
  region         = "us-central1"
  cloud_function = google_cloudfunctions_function.function.name
  
  role = "roles/cloudfunctions.invoker"
  member = "allUsers"
}
2

2 Answers

7
votes

It seems the only problem with that example from the terraform site are the " Cloud Functions IAM resources" which have been modified since Nov 2019. Now you have to specify these resources as explained here. Now for your user case (public cloud function) I'd recommend you to follow this configuration and just change the "members" attribute to "allUsers" so it'd be something like this

resource "google_cloudfunctions_function_iam_binding" "binding" {
  project = google_cloudfunctions_function.function.project
  region = google_cloudfunctions_function.function.region
  cloud_function = google_cloudfunctions_function.function.name
  role = "roles/cloudfunctions.invoker"
  members = [
    "allUsers",
  ]
}

Finally, you can give it a test and modify the functions you've already created here at the #Try this API" right panel and enter the proper resource and request body like this (make sure to enter the "resource" parameter correcly):

{
  "policy": {
    "bindings": [
      {
        "members": [
          "allUsers"
        ],
        "role": "roles/cloudfunctions.invoker"
      }
    ]
  }
}
2
votes

In addition to adjusting the IAM roles how @chinoche suggested, I also discovered that I needed to modify the service account I was using to give it poject owner permissions. (I guess the default one I was using didn't have this). I updated my key.json and it finally worked.