Unable to perform Cloud Function trigger a HTTP triggered Cloud Function that doesn't allow unauthenticated invocations?

↘锁芯ラ 提交于 2020-04-16 05:48:13

问题


I have a situation where I am trying to create two Cloud Functions namely CF1 & CF2 and I have one Cloud Scheduler. Both cloud functions are having authenticated invocation enabled. My flow is Cloud Scheduler will trigger CF1. On completion of CF1, the CF1 will trigger CF2 as a http call. I have referred Cannot invoke Google Cloud Function from GCP Scheduler to access authenticated CF1 from Cloud Scheduler and able to access CF1. But I am getting problem when accessing CF2 from CF1. The CF1 does not trigger CF2 and also not giving any error message. Do we need to follow any other technique when accessing authenticated Cloud Function from another authenticated Cloud Function.

CF1 code:

import json
import logging
from requests_futures.sessions import FuturesSession


def main(request):
    # To read parameter values from request (url arguments or Json body).
    raw_request_data = request.data
    string_request_data = raw_request_data.decode("utf-8")
    request_json: dict = json.loads(string_request_data)

    request_args = request.args

    if request_json and 'cf2_endpoint' in request_json:
        cf2_endpoint = request_json['cf2_endpoint']
    elif request_args and 'cf2_endpoint' in request_args:
        cf2_endpoint = request_args['cf2_endpoint']
    else:
        cf2_endpoint = 'Invalid endpoint for CF2'

    logger = logging.getLogger('test')
    try:
        session = FuturesSession()
        session.get("{}".format(cf2_endpoint))
        logger.info("First cloud function executed successfully.")

    except RuntimeError:
        logger.error("Exception occurred {}".format(RuntimeError))

CF2 code:

import logging

def main(request):
    logger = logging.getLogger('test')
    logger.info("second cloud function executed successfully.")

Current output logs:

First cloud function executed successfully.

Expected output logs:

First cloud function executed successfully.
second cloud function executed successfully.

Note: Same flow is working if I use unauthenticated access to the both cloud functions.


回答1:


Two things are happening here:

  1. You're not using request-futures entirely correctly. Since the request is made asynchronously, you need to block on the result before the function implicitly returns, otherwise it might return before your HTTP request completes (although it probably is in this example):
session = FuturesSession()
future = session.get("{}".format(cf2_endpoint))
resp = future.result()  # Block on the request completing
  1. The request you're making to the second function is not actually an authenticated request. Outbound requests from a Cloud Function are not authenticated by default. If you looked at what the actual response is above, you would see:
>>> resp.status_code
403
>>> resp.content
b'\n<html><head>\n<meta http-equiv="content-type" content="text/html;charset=utf-8">\n<title>403 Forbidden</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Forbidden</h1>\n<h2>Your client does not have permission to get URL <code>/function_two</code> from this server.</h2>\n<h2></h2>\n</body></html>\n'

You could jump through a lot of hoops to properly authenticate this request, as detailed in the docs: https://cloud.google.com/functions/docs/securing/authenticating#function-to-function

However, a better alternative would be to make your second function a "background" function and invoke it via a PubSub message published from the first function instead:

from google.cloud import pubsub

publisher = pubsub.PublisherClient()
topic_name = 'projects/{project_id}/topics/{topic}'.format(
    project_id=<your project id>,
    topic='MY_TOPIC_NAME',  # Set this to something appropriate.
)

def function_one(request):
    message = b'My first message!'
    publisher.publish(topic_name, message)

def function_two(event, context):
    message = event['data'].decode('utf-8')
    print(message)

As long as your functions have the permissions to publish PubSub messages, this avoids the need to add authorization to the HTTP requests, and also ensures at-least-once delivery.



来源:https://stackoverflow.com/questions/61055972/unable-to-perform-cloud-function-trigger-a-http-triggered-cloud-function-that-do

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!