简体   繁体   English

无法执行 Cloud Function 触发 HTTP 触发 Cloud Function 不允许未经身份验证的调用?

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

I have a situation where I am trying to create two Cloud Functions namely CF1 & CF2 and I have one Cloud Scheduler.我有一种情况,我正在尝试创建两个云功能,即 CF1 和 CF2,并且我有一个云调度程序。 Both cloud functions are having authenticated invocation enabled.两个云功能都启用了经过身份验证的调用。 My flow is Cloud Scheduler will trigger CF1.我的流程是 Cloud Scheduler 将触发 CF1。 On completion of CF1, the CF1 will trigger CF2 as a http call. CF1 完成后,CF1 将作为 http 调用触发 CF2。 I have referred Cannot invoke Google Cloud Function from GCP Scheduler to access authenticated CF1 from Cloud Scheduler and able to access CF1.我已经提到无法从 GCP Scheduler 调用 Google Cloud Function 从Cloud Scheduler 访问经过身份验证的 CF1 并能够访问 CF1。 But I am getting problem when accessing CF2 from CF1.但是从 CF1 访问 CF2 时出现问题。 The CF1 does not trigger CF2 and also not giving any error message. CF1 不会触发 CF2,也不会给出任何错误消息。 Do we need to follow any other technique when accessing authenticated Cloud Function from another authenticated Cloud Function.从另一个经过身份验证的云 Function 访问经过身份验证的云 Function 时,我们是否需要遵循任何其他技术。

CF1 code: CF1 代码:

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: CF2 代码:

import logging

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

Current output logs:当前 output 日志:

First cloud function executed successfully.

Expected output logs:预期的 output 日志:

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.注意:如果我对这两个云功能使用未经身份验证的访问,则相同的流程正在工作。

Two things are happening here:这里发生了两件事:

  1. You're not using request-futures entirely correctly.您没有完全正确地使用request-futures 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):由于请求是异步发出的,因此您需要在 function 隐式返回之前阻止结果,否则它可能会在您的 HTTP 请求完成之前返回(尽管它可能在此示例中):
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.您向第二个 function 发出的请求实际上并不是经过身份验证的请求。 Outbound requests from a Cloud Function are not authenticated by default.默认情况下,来自云 Function 的出站请求未经过身份验证。 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您可以跳过很多麻烦来正确验证此请求,如文档中所述: 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:但是,更好的选择是将您的第二个 function 设置为“背景” function 并通过从第一个 ZC1C425268E68385D1AB5074C17A94F14 发布的 PubSub 消息调用它:

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.只要您的函数具有发布 PubSub 消息的权限,这就避免了对 HTTP 请求添加授权的需要,并且还确保了至少一次交付。

Google Cloud Function provide REST API interface what include call method that can be used in another Cloud Function HTTP invokation. Google Cloud Function provide REST API interface what include call method that can be used in another Cloud Function HTTP invokation. Although the documentation mention using Google-provided client libraries there is still non one for Cloud Function on Python.尽管文档 提到使用 Google 提供的客户端库,但 Python 上的 Cloud Function 仍然没有一个。

And instead you need to use general Google API Client Libraries.相反,您需要使用通用的 Google API 客户端库。 [This is the python one]. [这是 python 之一]。 3 3

Probably, the main difficulties while using this approach is an understanding of authentification process.使用这种方法的主要困难可能是对身份验证过程的理解。 Generally you need provide two things to build a client service: credentials ans scopes .通常,您需要提供两件事来构建客户端服务:凭据范围

The simpliest way to get credentials is relay on Application Default Credentials (ADC) library.获取凭据的最简单方法是在应用程序默认凭据 (ADC) 库上进行中继。 The rigth documentation about that are:关于此的正确文档是:

  1. https://cloud.google.com/docs/authentication/production https://cloud.google.com/docs/authentication/production
  2. https://github.com/googleapis/google-api-python-client/blob/master/docs/auth.md https://github.com/googleapis/google-api-python-client/blob/master/docs/auth.md

The place where to get scopes is the each REST API function documentation page.获取范围的地方是每个 REST API function 文档页面。 Like, OAuth scope: https://www.googleapis.com/auth/cloud-platform像, OAuth scope:https://www.googleapis.com/auth/cloud-platform

The complete code example of calling 'hello-world' clound fucntion is below.调用“hello-world”云函数的完整代码示例如下。 Before run:运行前:

  1. Create default Cloud Function on GCP in your project.在项目的 GCP 上创建默认 Cloud Function。
  • Keep and notice the default service account to use保留并注意要使用的默认服务帐户
  • Keep the default body.保留默认正文。
  1. Notice the project_id , function name , location where you deploy function.注意project_idfunction name ,部署 function 的位置
  2. If you will call function outside Cloud Function environment (locally for instance) setup the environment variable GOOGLE_APPLICATION_CREDENTIALS according the doc mentioned above如果您要在 Cloud Function 环境(例如本地)之外调用 function,请根据上述文档设置环境变量 GOOGLE_APPLICATION_CREDENTIALS
  3. If you will call actualy from another Cloud Function you don't need to configure credentials at all.如果您实际上是从另一个 Cloud Function 调用,则根本不需要配置凭据。
from googleapiclient.discovery import build
from googleapiclient.discovery_cache.base import Cache
import google.auth

import pprint as pp

def get_cloud_function_api_service():
    class MemoryCache(Cache):
        _CACHE = {}

        def get(self, url):
            return MemoryCache._CACHE.get(url)

        def set(self, url, content):
            MemoryCache._CACHE[url] = content

    scopes = ['https://www.googleapis.com/auth/cloud-platform']

    # If the environment variable GOOGLE_APPLICATION_CREDENTIALS is set,
    # ADC uses the service account file that the variable points to.
    #
    # If the environment variable GOOGLE_APPLICATION_CREDENTIALS isn't set,
    # ADC uses the default service account that Compute Engine, Google Kubernetes Engine, App Engine, Cloud Run,
    # and Cloud Functions provide
    #
    # see more on https://cloud.google.com/docs/authentication/production
    credentials, project_id = google.auth.default(scopes)

    service = build('cloudfunctions', 'v1', credentials=credentials, cache=MemoryCache())
    return service


google_api_service = get_cloud_function_api_service()
name = 'projects/{project_id}/locations/us-central1/functions/function-1'
body = {
    'data': '{ "message": "It is awesome, you are develop on Stack Overflow language!"}' # json passed as a string
}
result_call = google_api_service.projects().locations().functions().call(name=name, body=body).execute()
pp.pprint(result_call)
# expected out out is:
# {'executionId': '3h4c8cb1kwe2', 'result': 'It is awesome, you are develop on Stack Overflow language!'}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Google Cloud Functions 部署“允许未经身份验证的调用...” - Google Cloud Functions Deploy "allow unauthenticated invocations..." 谷歌云部署 function 在 python 中“允许未经身份验证” - Google cloud deploy function with “allow unauthenticated” in python 如何禁用现有 gcp 云 function 的“--allow-unauthenticated”标志? - How to disable “--allow-unauthenticated” flag of existing gcp cloud function? 使用 Google Cloud Function 触发 HTTP 出现问题 - Problem with HTTP trigger with Google Cloud Function HTTP 触发云 Function 在 Flutter web - HTTP trigger Cloud Function in Flutter web GCP Cloud Function HTTP 触发器“没有'Access-Control-Allow-Origin' header 存在于请求的资源上。” 错误 - GCP Cloud Function HTTP trigger “No 'Access-Control-Allow-Origin' header is present on the requested resource.” error 哪个 IP 地址触发了我的 HTTP 云功能? - Which ip address triggered my HTTP Cloud Function? Google Cloud Functions - Python - 没有函数名称的 HTTP 触发器 URL - Google Cloud Functions - Python - HTTP Trigger URL Without Function Name 使用 Google Cloud 函数触发 Cloud Composer - Trigger Cloud Composer Using Google Cloud Function 使用 Cloud Scheduler 触发 HTTP 云功能 - HTTP Triggering Cloud Function with Cloud Scheduler
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM