Open iamlohit opened 1 year ago
Note: We should use -log-http
with gcloud to determine the underlying API call. Is it possible this is done using a Cloud Run IAM resource?
I can confirm it does use Cloud run.
I believe this should get around the issue.
resource "google_cloud_run_v2_service_iam_policy" "invoker" {
location = google_cloudfunctions2_function.function.location
name = google_cloudfunctions2_function.function.name
policy_data = data.google_iam_policy.invoker.policy_data
}
Greetings! This issue renders google_cloudfunctions2_function completely unusable when you need permission management. @tweakster the google_cloud_run_v2_service_iam_policy workaround does not solve the problem anymore as the command throws
Resource 'functionName' of kind 'SERVICE' in region 'us-central1' in project 'projectName' does not exist.
Hopefully someone will pick up this issue as soon as possible, because without being able to set up policies, cloud functions v2 are completely unusable.
@EduardJoy It still works for me. Are you sure you you have all the details correct?
Attaching the code here. If I am not missing something I think indeed that the issue is still active @tweakster
data "google_iam_policy" "public_policy" {
binding {
role = "roles/run.invoker"
members = [
"allUsers",
]
}
}
resource "google_cloud_run_v2_service_iam_policy" "public_policy_beforecreate" {
location = google_cloudfunctions2_function.beforeCreateFunction.location
name = google_cloudfunctions2_function.beforeCreateFunction.name
policy_data = data.google_iam_policy.public_policy.policy_data
}
Just upgraded to version 5.1.0 and the issue is still active.
I'm run into a similar issue: i have defined a bunch of Cloud Functions 2nd gen invoked by Google Workflow, using the google_cloudfunctions2_function_iam
resource i received the same error showed in the first post.
The official documentation is not very clear about how set this type of permission, relying on the statement "from gcloud use the add-invoker-policy-binding
command for 2nd gen Cloud Functions".
I've looked a bit into that gcloud command behaviour, in the end it's just a wrapper for this sequence of operations:
So it is correct to use the google_cloud_run_service_iam (i've used the google_cloud_run_service_iam_member
flavour, in my case, with success)
See also this example: https://registry.terraform.io/providers/hashicorp/google/latest/docs/resources/cloudfunctions2_function#example-usage---cloudfunctions2-scheduler-auth
(it also defines the google_cloudfunctions2_function_iam_member
resource but i think it isn't necessary)
Sadly, as previously mention this did not work for me. I will try to include both of them to see if there is any change but I think this behaviour should be covered by the GCP provider.
Same problem here. Trying to use either
resource "google_cloudfunctions2_function_iam_member" "run_invoker" {
project = google_cloudfunctions2_function.function.project
location = google_cloudfunctions2_function.function.location
cloud_function = google_cloudfunctions2_function.function.name
role = "roles/run.invoker"
member = "allUsers"
}
or
data "google_iam_policy" "admin" {
binding {
role = "roles/run.invoker"
members = [
"allUsers"
]
}
}
resource "google_cloudfunctions2_function_iam_policy" "policy" {
project = google_cloudfunctions2_function.function.project
location = google_cloudfunctions2_function.function.location
cloud_function = google_cloudfunctions2_function.function.name
policy_data = data.google_iam_policy.admin.policy_data
}
But both are resulting in "Error setting IAM policy".
Error is still present in the latest version. Is there any update about possible progress in this issue? I believe having this functionality is critical to being able to deploy and manage cloud functions with the help of terraform. Kindest regards
There is a way to solve this, when deploying cloud functions gen2 with terraform, the cloud run service is auto-generated with the same name as the cloud function as long the name is in kebab-case.
Have a look at the comment in the code sample here which mentions "name should use kebab-case so generated Cloud Run service name will be the same"
So you can just define a cloud run IAM binding with the same name:
resource "google_cloudfunctions2_function" "test_function" {
name = "gcf-function" # name should use kebab-case so generated Cloud Run service name will be the same
location = "us-central1"
description = "a new function"
build_config {
runtime = "nodejs16"
entry_point = "helloHttp" # Set the entry point
source {
storage_source {
bucket = google_storage_bucket.bucket.name
object = google_storage_bucket_object.object.name
}
}
}
service_config {
min_instance_count = 1
available_memory = "256M"
timeout_seconds = 60
service_account_email = google_service_account.account.email
}
}
# IAM Binding for the generated cloud run service
resource "google_cloud_run_service_iam_binding" "binding" {
location = google_cloudfunctions2_function.test_function.location
project = google_cloudfunctions2_function.test_function.project
service = google_cloudfunctions2_function.test_function.name
role = "roles/run.invoker"
members = [
"allUsers",
]
}
Worked for me!
@nikhil-g777 I will try your method tomorrow and tell you the result. However I have tried this previously but it still did not work as expected. However the "google_cloudfunctions2_function_iam_policy" resources should have done exactly this. And as such I still consider it a bug.
Thank you @nikhil-g777! Making sure I follow kebab-case is what fixed it for me. I keep my names snakecase typically, so I just `replace(..., "", "-")inside the
google_cloud_run_service_iam_binding` block.
I can confirm as well: when strictly using kebab case for the Cloud Function name, the google_cloud_run_service_iam_binding
will work.
@EduardJoy yes this is a workaround but it is mentioned in the example in the docs that the cloud run service name will be the same as long as its in kebab-case. The ideal solution would be to provide the name of the auto-created cloud run service as an attribute (output) for the google_cloudfunctions2_function resource.
Then cloud run service name can be used to configure IAM policy bindings, etc.
Been three months and this issue sadly still persists.
I have managed to make it work by emploting
# IAM Binding for the generated cloud run service
resource "google_cloud_run_service_iam_binding" "public_binding" {
project = google_cloudfunctions2_function.link_analytics_log_function.project
location = google_cloudfunctions2_function.link_analytics_log_function.location
service = google_cloudfunctions2_function.link_analytics_log_function.name
role = "roles/run.invoker"
members = [
"allUsers",
]
depends_on = [ google_cloudfunctions2_function.link_analytics_log_function ]
}
However I do feel like this is a pretty big caveat?
An issue which I discovered is that for update of the cloud functio, you will need to redo the service_iam_binding because the cloud run service gets recreated (and implicitly all IAM bindings are deleted).
to fix this you can do
# IAM Binding for the generated cloud run service
resource "google_cloud_run_service_iam_binding" "public_binding" {
project = google_cloudfunctions2_function.link_analytics_log_function.project
location = google_cloudfunctions2_function.link_analytics_log_function.location
service = google_cloudfunctions2_function.link_analytics_log_function.name
role = "roles/run.invoker"
members = [
"allUsers",
]
depends_on = [ google_cloudfunctions2_function.link_analytics_log_function ]
lifecycle {
replace_triggered_by = [ google_cloudfunctions2_function.link_analytics_log_function ]
}
}
Lifecycle should handle it.
I have managed to get it work without any manipulations with function name - the "google_cloudfunctions2_function" resource outputs the service name after creation. So the policy looks like this:
resource "google_cloud_run_service_iam_member" "member" {
location = google_cloudfunctions2_function.default.location
service = google_cloudfunctions2_function.default.service_config[0].service
project = var.project_id
for_each = toset(setunion(var.admins, var.public ? ["allUsers"] : []))
role = "roles/run.invoker"
member = each.key
}
Community Note
Description
Google Cloud recently introduced second generation Cloud Functions, which are built on the same underlying infrastructure as Cloud Run. This change has implications for setting the invoker role, which allows a function to receive HTTP requests. Currently, setting the role
roles/cloudfunctions.invoker
with the Terraform Google provider doesn't suffice for second generation Cloud Functions, as they require the roleroles/run.invoker
to be set through Cloud Run. As a workaround, one needs to manually run the followinggcloud
command, which is not scalable:However, if we try to set
roles/run.invoker
using thegoogle_cloudfunctions2_function_iam_policy
resource, we encounter the following error:Error: Error setting IAM policy for cloudfunctions2 function "projects/project-id/locations/region-name/functions/function-name": googleapi: Error 400: Invalid argument: 'An invalid argument was specified. Please check the fields and try again.'
This feature request is to enhance the
google_cloudfunctions2_function_iam_policy
resource to support setting theroles/run.invoker
IAM role for second generation Cloud Functions, eliminating the need for the manualgcloud
command and resolving the error.New or Affected Resource(s)
Potential Terraform Configuration
References
Terraform Documentation: google_cloudfunctions2_function_iam Version 4.74.0 Latest