You need to use the Authentication element in the TargetEndpoint, and specify a GoogleIDToken.
EDIT - here is a sample that sets up Apigee X to connect to a cloud function.
I just tried this. Here’s how I set it up. In my setup I have 2 GCP projects: one that runs the Cloud Function, and one that is the host for the Apigee X organization. I’ve set up my Cloud Function to use nodejs v18, and to run as the default service account. Like this:
CF_PROJECT=my-cf-project
CF_NAME=dchiesa-cf101
REGION=us-west1
gcloud functions deploy $CF_NAME \
--gen2 \
--project $CF_PROJECT \
--runtime=nodejs18 \
--region=$REGION \
--source=. \
--entry-point=helloGET \
--trigger-http
And it does not permit unauthenticated access. Which means it’s going to require an ID Token , passed as a bearer token. Because I am editor/owner on this project, I have the required permission to invoke this cloud function. Therefore I can test this with an ID token that identifies myself, like this:
curl -i -H "Authorization: Bearer $(gcloud auth print-identity-token)" \
https://us-west1-my-cf-project.cloudfunctions.net/dchiesa-cf101/helloGET
And that works.
But I want (you want) a service account to be able to invoke this function. So I need to add a Service Account that has the appropriate permission to invoke this Cloud Function. I’ve created the Service Account in the Apigee project, which, remember, is a different project than the one that hosts the cloud function.
SA_NAME=cf101-invoker
SA_PROJECT=my-apigee-project
gcloud iam service-accounts create $SA_NAME --project "$SA_PROJECT"
SA_EMAIL=${SA_NAME}@${SA_PROJECT}.iam.gserviceaccount.com
gcloud functions add-invoker-policy-binding $CF_NAME \
--region="$REGION" \
--project="$CF_PROJECT" \
--member="serviceAccount:${SA_EMAIL}"
To test this, I’ll need to have permission to get an Identity token that identifies that service account. So:
gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \
--project $SA_PROJECT \
--member=user:my_user@organization.com \
--role=roles/iam.serviceAccountUser
And having that permission I can request an ID token:
audience="https://${REGION}-${CF_PROJECT}.cloudfunctions.net/${CF_NAME}"
curl -X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{"audience": "'${audience}'", "includeEmail": "true"}' \
"https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/${SA_EMAIL}:generateIdToken"
The result of that is an ID token, which I can pass as a bearer to the cloud function:
SA_IDTOKEN=ey...output-of-the-above
curl -i -H "Authorization: Bearer ${SA_IDTOKEN}" \
https://us-west1-my-cf-project.cloudfunctions.net/dchiesa-cf101/helloGET
And that works. Good.
Now, to tell Apigee to do the authentication magic, using that service account, I use this TargetEndpoint configuration:
<TargetEndpoint name='target-1'>
...
<HTTPTargetConnection>
<Authentication>
<GoogleIDToken>
<!--
This did not work for me
<Audience useTargetUrl="true"/>
-->
<Audience>https://us-west1-my-cf-project.cloudfunctions.net/dchiesa-cf101</Audience>
</GoogleIDToken>
</Authentication>
<SSLInfo>
<Enabled>true</Enabled>
<Enforce>true</Enforce>
</SSLInfo>
<!-- the proxy.pathsuffix will get appended -->
<URL>https://us-west1-my-cf-project.cloudfunctions.net/dchiesa-cf101</URL>
</HTTPTargetConnection>
</TargetEndpoint>
And I must deploy the API Proxy with that service account. And then to invoke that API Proxy, I pass in the /helloGET as the proxy pathsuffix., which gets added to the URL for the target, and the right thing happens. It all works.
Full tutorial for using Apigee X to connect to cloud functions: https://github.com/GoogleCloudPlatform/apigee-samples/tree/main/cloud-functions