Невозможно выполнить облачную функцию, запустить HTTP-функцию облачной функции, которая не допускает неаутентифицированные вызовы? - PullRequest
1 голос
/ 06 апреля 2020

У меня есть ситуация, когда я пытаюсь создать две облачные функции, а именно CF1 и CF2, и у меня есть один облачный планировщик. Обе облачные функции имеют активированный вызов аутентификации. Мой поток Cloud Scheduler будет запускать CF1. По завершении CF1 CF1 запустит CF2 как вызов http. Я упомянул Невозможно вызвать Google Cloud Function из планировщика GCP для доступа к аутентифицированному CF1 из Cloud Scheduler и возможности доступа к CF1. Но я получаю проблемы при доступе к CF2 из CF1. CF1 не запускает CF2 и также не выдает никаких сообщений об ошибках. Нужно ли следовать какой-либо другой методике при доступе к проверенной функции облака из другой проверенной функции облака.

Код 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:

import logging

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

Текущий выходные журналы:

First cloud function executed successfully.

ожидаемые выходные журналы:

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

Примечание: тот же поток работает, если я использую неаутентифицированный доступ к обеим облачным функциям.

1 Ответ

0 голосов
/ 07 апреля 2020

Здесь происходят две вещи:

  1. Вы не используете request-futures полностью правильно. Поскольку запрос выполняется асинхронно, необходимо заблокировать результат до того, как функция неявно вернется, иначе он может вернуться до завершения HTTP-запроса (хотя, вероятно, в этом примере):
session = FuturesSession()
future = session.get("{}".format(cf2_endpoint))
resp = future.result()  # Block on the request completing
Запрос, который вы делаете для второй функции, на самом деле не является аутентифицированным запросом. Исходящие запросы от облачной функции не проходят проверку подлинности по умолчанию. Если вы посмотрите на фактический ответ выше, вы увидите:
>>> 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'

Вы можете перепрыгнуть через множество обручей для правильной аутентификации этого запроса, как подробно описано в документации: https://cloud.google.com/functions/docs/securing/authenticating#function -to-function

Однако, лучшей альтернативой было бы сделать вашу вторую функцию "фоновой" функцией и вызывать ее через сообщение 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)

Пока ваши функции имеют разрешения на публикацию сообщений sh PubSub, это избавляет от необходимости добавлять авторизацию к HTTP-запросам, а также обеспечивает доставку по крайней мере один раз.

...