从 Cloud Function 到 App Engine 的请求返回错误 401

Posted

技术标签:

【中文标题】从 Cloud Function 到 App Engine 的请求返回错误 401【英文标题】:Requests from Cloud Function to App Engine returns error 401 【发布时间】:2021-12-06 07:31:33 【问题描述】:

我正在尝试从 Cloud Function 向部署在默认 GAE 服务上的多个 App Engine 端点发送请求。我的代码很简单:

云功能

main.py

import logging
import requests

def main(event, context):
    bucketname = event['bucket']
    filename = event['name']
    endpoint = # Some logic extracting the endpoint to be used
    url = 'https://myproject.ew.r.appspot.com/'.format(endpoint)
    data = 
        'bucketname': bucketname,
        'filename': filename
    
    r = requests.post(url, json=data)
    logging.info(r)
    return str(r)

云函数的部署方式:

gcloud functions deploy storage_to_gae --runtime python37 --trigger-resource $BUCKETNAME --trigger-event google.storage.object.finalize --region $REGION --source gcf/ --entry-point main --service-account cf-sa@myproject.iam.gserviceaccount.com

Fuction 使用的服务帐户已授予服务帐户用户 (roles/iam.serviceAccountUser) 角色。

应用引擎

app.yml

runtime: python37
service: default

但是,请求不会到达 App Engine,因为 GAE 服务上没有显示任何日志。请求返回 <Response [401]> 错误代码,因此 CF 似乎无法访问 App Engine 服务。

我还需要哪些额外的角色来提供我的cf-sa@myproject.iam.gserviceaccount.com 服务帐户?我在客户端环境中进行部署,因此我的权限有限,我必须询问所需的确切角色。

【问题讨论】:

您是否在 App Engine 之上使用 IAP? 你是对的,我问了客户 GCP 团队,他们正在使用 IAP 来管理访问。我将结束这个问题,因为它与公司相关,而不是通用问题。 @guillaumeblaquiere 您可以对受 IAP 保护的 App Engine 服务执行 Cloud Functions 调用。没有问题。为什么要结束这个问题? 你能检查一下客户ID是否正确吗?客户端 ID 应该是目标应用引擎的项目 ID。 与我的客户端 GCP​​ 团队的通信很慢,所以我不知道客户端启用了 IAP。当他们告诉我时,我要求项目的正确权限和 IAP 客户端 ID,我能够成功调用 GAE 端点。如果需要,您可以发布一个答案,解释如何调用 IAP 安全 GAE 服务执行请求,我会将其标记为正确。否则,我可以发布用于我的用例的解决方案。 @guillaumeblaquiere 【参考方案1】:

在询问了我客户的 GCP 团队后,他们使用 IAP 来管理访问权限。

我按照this 文档中的说明进行操作,并且能够向 GAE 端点发送请求。

这是我的最终代码:

import requests
from google.oauth2 import id_token
from google.auth.transport.requests import Request

def make_iap_request(url, client_id, method='POST', **kwargs):
    """Makes a request to an application protected by Identity-Aware Proxy.

    Args:
        url: The Identity-Aware Proxy-protected URL to fetch.
        client_id: The client ID used by Identity-Aware Proxy.
        method: The request method to use
                    ('GET', 'OPTIONS', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE')
        **kwargs: Any of the parameters defined for the request function:
                        https://github.com/requests/requests/blob/master/requests/api.py
                        If no timeout is provided, it is set to 90 by default.

    Returns:
      The page body, or raises an exception if the page couldn't be retrieved.
    """
    # Set the default timeout, if missing
    if 'timeout' not in kwargs:
        kwargs['timeout'] = 90

    # Obtain an OpenID Connect (OIDC) token from metadata server or using service
    # account.
    open_id_connect_token = id_token.fetch_id_token(Request(), client_id)

    # Fetch the Identity-Aware Proxy-protected URL, including an
    # Authorization header containing "Bearer " followed by a
    # Google-issued OpenID Connect token for the service account.
    resp = requests.request(
        method, url,
        headers='Authorization': 'Bearer '.format(
            open_id_connect_token), **kwargs)
            
    return resp.text

def main(event, context):
    bucketname = event['bucket']
    filename = event['name']

    endpoint = # Some logic extracting the endpoint to be used
    url = 'https://myproject.ew.r.appspot.com/'.format(endpoint)
    data = 
        'bucketname': bucketname,
        'filename': filename
    
    client_id = 'myclientid'

    r = make_iap_request(url, client_id, 'POST', json=data)
    logging.info(r)
    return str(r)

【讨论】:

以上是关于从 Cloud Function 到 App Engine 的请求返回错误 401的主要内容,如果未能解决你的问题,请参考以下文章

从 App Engine 运行时 Python 3.7 调用 Cloud Function [重复]

从 Cloud Function 本身获取 Cloud Function 名称

从 Cloud Function (python) 写入 Google Cloud Storage

从请求中获取用户信息到 Firebase 中的 Cloud Function

从 Cloud Function 发布到 GCP PubSub 的正确方法是啥?

无法从 GCP 调度程序调用 Google Cloud Function