3
votes

I want to deploy a Google Cloud Function without public access. A service account should be able to invoke the function with least permissive rights - to be used by an external server.

I have created a service account, added bindings and downloaded keys:

gcloud iam service-accounts create <NAME> --project <PROJECT> --description <DESCRIPTION>
gcloud beta functions add-iam-policy-binding <FUNCTION> --region europe-west1 --member serviceAccount:<EMAIL> --role roles/cloudfunctions.invoker
gcloud iam service-accounts keys create --iam-account <EMAIL> <KEYFILE>

When I call the function with the invoker-role, this fails:

gcloud auth activate-service-account <EMAIL> --key-file <KEYFILE>
gcloud beta functions call <FUNCTION> --region=europe-west1 --data '{}'
ERROR: (gcloud.beta.functions.call) ResponseError: status=[403], code=[Forbidden], message=[The caller does not have permission]

However, when I switch to my user, add the roles/cloudfunctions.developer role, switch back to the service account, the above works:

gcloud config set account <USER>
gcloud beta functions add-iam-policy-binding <FUNCTION> --region europe-west1 --member serviceAccount:<EMAIL> --role roles/cloudfunctions.developer
gcloud auth activate-service-account <EMAIL> --key-file <KEYFILE>
gcloud beta functions call <FUNCTION> --region=europe-west1 --data '{}'
Success!
  1. This really surprises me, I thought the invoker role should be sufficient. What am I missing here?

I wanted to use a token to access the function via curl, but this doesn't work at all, neither as invoker nor as developer:

echo $(GOOGLE_APPLICATION_CREDENTIALS=<KEYFILE> gcloud auth application-default print-access-token) > <TOKENFILE>
curl -H "Authorization: Bearer $(cat <TOKENFILE>" <FUNCTIONURL>
→ 401 Unauthorized as HTML page
  1. What's the problem here?

Thanks for any help! Best, Boris

1
FWIW ... I recreated your exact story and am also not understanding why invoker is not sufficient. - Kolban
See below, it seems that gcloud beta functions call ... needs extra permissions. - Boris Lau

1 Answers

4
votes

Google Cloud recommends treating such requests as end-user requests i.e use OAuth2.0 by passing Authorization header(with bearer token) while accessing the Cloud functions with the invoker role. The details are here

Try passing the bearer token by doing the following

gcloud auth activate-service-account <service account> <key file>
gcloud auth print-identity-token <service account>
curl https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME \
    -H "Authorization: bearer $(gcloud auth print-identity-token)"