Search code examples
python-3.xgoogle-cloud-platformgoogle-cloud-functionsserverlessgoogle-vpc

Problem invoking a Cloud Function with "Allow internal traffic only" flag from another Cloud Function


I have 2 Google Cloud Function 1 gen, R and C, on the same GCP project.

R is a private function with the "Allow internal traffic only" flag set to true. In the permission tab I give to the Service Account SA the invoker role.

C is a public function that has ALL the egress traffic redirected to a Serverless VCP Connector.

As expected, If I try to call R from the browser, I receive a 404 not found error.

In his code, C uses the SA json key (saved on the secret manager) to get an auth token and then make an HTTP request to R, setting the Authentication header with the Bearer token retrieved.

Here the R code:

def hello_world(request):
  return f'Hello World!'

Here the C code:

import requests
import functions_framework
import google.auth
import google.auth.transport.requests
from flask import Request
from typing import Tuple

from google.oauth2 import service_account
import os, json


def get_token() -> str:
    service_account_key = json.loads(os.getenv('SA'))
    credentials = service_account.Credentials.from_service_account_info(
        service_account_key,  
        scopes=['https://www.googleapis.com/auth/cloud-platform']  
    )
    auth_req = google.auth.transport.requests.Request()
    credentials.refresh(auth_req)
    return credentials.token


@functions_framework.http
def test(req: Request) -> Tuple[str, int]:
    url = "..."
    headers = {
        "Authentication": f"Bearer {get_token()}"
    }
    response = requests.get(url, headers=headers)
    return response.text, response.status_code

I expect that C can call R, but I receive a 403 Forbidden error.

The only way C can call R is making R public (I have tried it and it works).

This is the excepted behavior? I'm missing something?


Solution

  • You must invoke the Cloud Functions with an Identity token and not an access Token. You're making use of the latter.

    In addition, do not use a service account key file, even stored in secret manager, it's totally useless and you increase your security risk.


    Here a code sample to generate an identity token

    import google.oauth2.id_token
    import google.auth.transport.requests
    
    request = google.auth.transport.requests.Request()
    target_audience = "my_cloud_function_url"
    
    id_token = google.oauth2.id_token.fetch_id_token(request, target_audience)
    print(id_token)