UPDATE
Actual issue described here:
https://github.com/terraform-providers/terraform-provider-google/issues/5889#issuecomment-611714012
modular-magician user, it is either in the process of being autogenerated, or is planned to be autogenerated soon. If an issue is assigned to a user, that user is claiming responsibility for the issue. If an issue is assigned to hashibot, a community member has claimed the issue already.0.12.13
provider version 3.16
resource "google_cloudfunctions_function" "function" {
project = "${var.project}"
name = "${var.name}"
description = "${var.description}"
runtime = "${var.runtime}"
timeout = "${var.timeout}"
available_memory_mb = "${var.memory}"
entry_point = "${var.entry_point}"
source_archive_bucket = "${var.source_bucket}"
source_archive_object = "${var.source_object}"
trigger_http = "${var.function_trigger_http}"
event_trigger {
event_type = "${var.event_trigger.event_type}"
resource = "${var.event_trigger.resource}"
}
environment_variables = "${var.env}"
service_account_email = "${var.service_account}"
}
When updating an existing terraform managed cloud function, service account email should not be affected (unless that is the argument being updated).
When updating any argument of the cloud function, the service account email assigned when the cloud function was created is removed (and the default app engine service account is assigned).
I believe this is because the service_account_email property is simply omitted from the update function for the cloudfunction_function resource
@chriswacker I have followed the steps you provided and saw NO change in the field of the custom service account email. Could you please post the full debug logs of the executions before and after you apply the change in the environment field? Thank you
I'm sorry I haven't had time to come up with more detailed steps or the information you asked for. I looked at the code, and although I am very inexperienced with this code base, I spotted what might be the issue (although I am not sure how to fix it):
"service_account_email" shows up in:
https://github.com/terraform-providers/terraform-provider-google/blob/e820eaf01aafd5e3a55315372037b3f424b6732e/google/resource_cloudfunctions_function.go#L295
and
https://github.com/terraform-providers/terraform-provider-google/blob/e820eaf01aafd5e3a55315372037b3f424b6732e/google/resource_cloudfunctions_function.go#L402
but is no where in
https://github.com/terraform-providers/terraform-provider-google/blob/e820eaf01aafd5e3a55315372037b3f424b6732e/google/resource_cloudfunctions_function.go#L459'
@edwardmedia does that seem odd to you?
@chriswacker I am using below HCL to test your issue. But I see the service_account_email remain unchange after I updated value for MY_ENV_VAR. Please provide the your details so I can see your issue. Thanks
resource "google_cloudfunctions_function" "function" {
name = "function-test"
description = "My function"
runtime = "nodejs10"
available_memory_mb = 128
source_archive_bucket = "cloud-function-5889"
source_archive_object = "helloworld.zip"
trigger_http = true
timeout = 60
entry_point = "helloGET"
labels = {
my-label = "my-label-value"
}
environment_variables = {
MY_ENV_VAR = "my-env-var-value-2" # changed from "my-env-var-value"
}
service_account_email = "[email protected]"
}
After looking more closely, it turns out the problem only occurs when the service account that terraform is using does not have roles/iam.serviceAccountUser on the default service account: [email protected], even when that shouldn't be required.
Steps to reproduce:
roles/cloudfunctions.developer on the project level, androles/iam.serviceAccountUser on 'function-agent' created in step 1 (not on project level).terraform plan -out plan && terraform apply plan, providing the tfvars:provider "google" {
project = "${var.project}"
region = "${var.region}"
credentials = "${file(var.terraform_agent_key_file)}" # JSON key for terraform-agent
}
resource "google_cloudfunctions_function" "function" {
name = "function-test"
description = "My function"
runtime = "python37"
available_memory_mb = 128
source_archive_bucket = "${var.source_bucket}"
source_archive_object = "${var.source_object}"
trigger_http = true
entry_point = "hello"
environment_variables = {
TEST = "ENV"
}
service_account_email = "function-agent@${var.project}.iam.gserviceaccount.com"
}
terraform plan -out plan && terraform apply plan.The output I receive from step 6 is:
Error: Error while updating cloudfunction configuration: googleapi: Error 403: Missing necessary permission iam.serviceAccounts.actAs for on the service account [email protected].
Ensure that service account [email protected] is a member of the project myproject, and then grant the roles/iam.serviceAccountUser role.
You can do that by running 'gcloud iam service-accounts add-iam-policy-binding [email protected] --member= --role=roles/iam.serviceAccountUser'
In case the member is a service account please use the prefix 'serviceAccount:' instead of 'user:'., forbidden
I believe this is erroneous because iam.serviceAccounts.actAs should only be required for 'function-agent' since that is the service account we've assigned to the function. After all, I was able to create it without that permission, I just can't update it.
In our use case, this is an issue because we are practicing least privilege, and do not what to grant roles/iam.serviceAccountUser on the default service account when it is not necessary.
@chriswacker It looks like the account the Terraform uses must have the iam.serviceAccounts.actAs. It is by design. The error you received is from API and there is nothing to do with Terraform provider. Below is what the cloud function doc says https://cloud.google.com/functions/docs/securing/function-identity#permissions_required_to_use_non-default_identities. Please let me know if this makes sense to you.
Permissions required to use non-default identities
In order to deploy a function with a non-default service account, the deployer must have the iam.serviceAccounts.actAs permission on the service account being deployed.
@edwardmedia the documentation you linked states:
In order to deploy a function with a non-default service account, the deployer must have the iam.serviceAccounts.actAs permission on the service account being deployed.
In my case, the service account being deployed is function-agent which terraform-agent _does_ have the iam.serviceAccounts.actAs permission for. This is why I was able to create the function. When trying to update, the error says it needs iam.serviceAccounts.actAs on the default app engine service account, which is not the service account being deployed. I'd like to stress that _I was able to create the function_ and the error only occurs on update. Why would I have permission to create but not update? This is definitely a bug, are you saying it's a bug with Google's API?
@chriswacker I can repro it now. We will take a closer look. Thank you for filing this issue.
Terraform is sending a correct request to the API, it's getting misinterpreted upstream. I filed a bug against Cloud Functions, I'll update this issue when I get a response. In the meantime, I'm marking it upstream and unassigning myself to mark that there's no action to be taken.
Internal Reference: b/154019086
Hi all, I was taking a look at this https://cloud.google.com/functions/docs/reference/rest/v1/projects.locations.functions#CloudFunction It looks like that is expected behavior from the CFs perspective because is documented, but anyway that involves active AppEngine API that a bit tricky, not always is necessary it. Using gcloud command to deploy a CF, as part of the parameters is the SA to use, that works because is a parameter passed in the REST API and there is con confusion there. My question, it is possible to enable a parameter in the terraform CF resource to enforce always the usage of the SA passed to deploy? Avoiding the possible usage of the default account provided by the GCP project
Is there a reasonable workaround? (I don't consider terraform taint before apply a really good one and giving the deployer SA iam.serviceAccount.actAs to the appspot account did not work for me)
Most helpful comment
Terraform is sending a correct request to the API, it's getting misinterpreted upstream. I filed a bug against Cloud Functions, I'll update this issue when I get a response. In the meantime, I'm marking it
upstreamand unassigning myself to mark that there's no action to be taken.Internal Reference: b/154019086