Apigee To Cloud function Auth

We have an apigeeX proxy calling cloud function. Apigee proxy is deployed using service account X and this service account has appropriate role to invoke the cloud function. I am wondering if by default apigee passes service account credentials when it calls cloud function or we need to configure our proxy to obtain the credentials and pass it to CF through proxy code

Client (User Auth)=> Apigee => (Service Auth??) Cloud Function

 
3 3 470
3 REPLIES 3

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

 

Hi @dchiesa1 ,

So we have created the Service Account in ApigeeX Project and then we have cloud functions generation 2 on another project and we are using PSC .

Just want to understand more,

1. Do we need the cloud function project to provide access to our created service account ?

2. If no, how does the GoogleIdToken in Apigee works ? Does that mean we can create a single Service Account to call any cloud functions backend just give it a correct Audience ? Please correct me if I am missing something or my understanding is incorrect.

Thank you.

Do we need the cloud function project to provide access to our created service account ?

yes. Specifically, Grant the permission to invoke the function, to the Service Account . The service account exists in the Apigee X project.

This gcloud command should do it:

 

gcloud functions add-invoker-policy-binding "$CLOUD_FUNCTION_NAME" \
  --member="serviceAccount:${SA_EMAIL}" \
  --region="$CLOUD_FUNCTIONS_REGION" \
  --project="$CLOUD_FUNCTIONS_PROJECT"

You may need to wait a bit here, perhaps 30 seconds, for that change to take effect. Updating IAM policy is an "eventually consistent" operation. After the permissions get propagated, you can invoke the proxy and it should have access to the cloud function.