1
votes

I'm trying to invoke a cloud function (CF2) from another (CF1). However, I keep getting a 403.

My issue is figuring out which service account to be a "cloud function invoker" of CF2.

I assumed that the cloud function service agent of CF1 is the one that's required, but this hasn't been working.

2
You will most likely need to configure your IAM Roles for invoker. Additionally, you can take a look at the following documentation, which explains the service accounts used for Cloud Functions and Troublshooting methods for Cloud Function permission errors. Hope this helps a bit.sllopis
Yeah, this is what I'm going through right now.itsPav
Do you still have issue with this? If yes, what is your latest status?guillaume blaquiere
Yeah, still having issues with it. I've set up the cloud function invoker to be the service account with the proper role. Still throwing 403's. Going to see what else I can do.itsPav
When an unauthenticated caller sends a request to the function, they will see a 401/403 status code response. You should ensure that allUsers has roles/cloudfunctions.invoker role in the function's IAM. You can read more about it here. What I shared with you earlier is a full list of IAM roles and their associated permissions used in Cloud Funtions.sllopis

2 Answers

2
votes

From Documentation:

Receiving Function

First, you'll need to configure the receiving function to accept requests from the calling function:

Grant the Cloud Functions Invoker (roles/cloudfunctions.invoker) role to the calling function identity on the receiving function. By default, this identity is [email protected]

Use the gcloud functions add-iam-policy-binding command:

gcloud functions add-iam-policy-binding RECEIVING_FUNCTION \
  --member='serviceAccount:CALLING_FUNCTION_IDENTITY' \
  --role='roles/cloudfunctions.invoker'

where RECEIVING_FUNCTION is the receiving function, and CALLING_FUNCTION_IDENTITY is the calling function identity.


Calling Function

In the calling function, you'll need to:

  1. Create a Google-signed OAuth ID token with the audience (aud) set to the URL of the receiving function.
  2. Include the ID token in an Authorization: Bearer ID_TOKEN header in the request to the function.
# Requests is already installed, no need to add it to requirements.txt
import requests

def calling_function(request):
  # Make sure to replace variables with appropriate values
  receiving_function_url = 'https://REGION-PROJECT.cloudfunctions.net/RECEIVING_FUNCTION'

  # Set up metadata server request
  # See https://cloud.google.com/compute/docs/instances/verifying-instance-identity#request_signature
  metadata_server_token_url = 'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience='

  token_request_url = metadata_server_token_url + receiving_function_url
  token_request_headers = {'Metadata-Flavor': 'Google'}

  # Fetch the token
  token_response = requests.get(token_request_url, headers=token_request_headers)
  jwt = token_response.content.decode("utf-8")

  # Provide the token in the request to the receiving function
  receiving_function_headers = {'Authorization': f'bearer {jwt}'}
  function_response = requests.get(receiving_function_url, headers=receiving_function_headers)

  return function_response.content

More info can be found here

0
votes

Here are the steps I followed:

  1. I created two services accounts:

    gcloud iam service-accounts create function-one --desplay-name function-one
    gcloud iam service-accounts create function-two --display-name function-two
    
  2. I assigned the necessary roles to my services accounts:

    gcloud projects add-iam-policy-binding my_project --member serviceAccount:function-one@my_project.iam.gserviceaccount.com --role roles/cloudfunctions.serviceAgent
    gcloud projects add-iam-policy-binding my_project --member serviceAccount:function-two@my_project.iam.gserviceaccount.com --role roles/cloudfunctions.serviceAgent
    
  3. I created two cloud functions on the Google Cloud console link. When I created the cloud functions, under "Environment variables, networking, timeouts and more", "Service acoount" I assigned to each cloud function a service account created in step 1.

    def hello_gcs_generic_one(request):
    
         import requests
         print ('Hello from cloud function one')
    
         response = requests.post("https://us-central1-my_project.cloudfunctions.net/function-two")
    
         if response.status_code != 200:
             exit("Could not call function! :(")
    
    
    
    def hello_gcs_generic_two(request):
    
        print ('Hello from cloud function two')
    
  4. I tested calling the function-one "TESTING/TEST THE FUNCTION" :

    Function One Loggs:

        Function execution started
        Hello from cloud function one
        Function execution took 2219 ms, finished with status code: 200
    

    Function Two Loggs:

        Function execution started
        Hello from cloud function two
        Function execution took 18 ms, finished with status code: 200