This post aims to add some missing information to Google’s docs about setting up CI/CD for Cloud Functions with Cloud Build.
Global vs Regional
Cloud Build triggers are global by default. You can create a regional trigger in the Cloud Console by changing the location when editing or creating a trigger. NOTE: I can’t find any way at all to create a regional trigger with Terraform.
However, functions must be regional. The Google docs indicate that you must specify a region in your cloud build config file. If you’re using a global trigger, the
substitution variable is set to $LOCATION
global
, and you’ll get a permission error when trying to deploy to a regional function. There are two options that I know of, and neither is great:
- Hard-code the region of the Cloud Function in your Cloud Build config
- Create a regional trigger in the same region as the function, and use the
$LOCATION
substitution variable in the Cloud Build config
I think the second option is slightly less bad, because it keeps infrastructure specifics out of the Cloud Build config. You can define the Cloud Function as a Terraform resource, and then (ideally) define the Cloud Build trigger in Terraform, using the same region as the Cloud Function. Unfortunately, you apparently can’t create a regional Cloud Build Trigger with Terraform, at this time.
The infamous cloud-functions-mixer permission error
Once you’ve solved the region error, another permissions error appears:
ERROR: (gcloud.functions.deploy) ResponseError: status=[403], code=[Ok], message=[Missing necessary permission iam.serviceAccounts.actAs for cloud-functions-mixer on the service account opentok-webhook@mend-infrastructure.iam.gserviceaccount.com. Grant the role 'roles/iam.serviceAccountUser' to cloud-functions-mixer on the service account opentok-webhook@mend-infrastructure.iam.gserviceaccount.com. You can do that by running 'gcloud iam service-accounts add-iam-policy-binding opentok-webhook@mend-infrastructure.iam.gserviceaccount.com --member=cloud-functions-mixer --role=roles/iam.serviceAccountUser'.
Google’s trying to be helpful here, but their advice is WRONG. There is no such thing as a cloud-functions-mixer
service account. The member should actually be the service account that is deploying the Cloud Function. For example, if you’re using a Cloud Build trigger, the member should be the custom service account for the Cloud Build trigger.
See my stackoverflow response for the full details.