使用 JWT 触发 Google 云函数

Trigger Google Cloud Function using JWT

我正在尝试使用 HTTP 请求和服务帐户触发 Google 云功能。 我遵循了这些步骤:

  1. 创建服务帐户
  2. 下载JSON密钥文件
  3. 创建一个 Google 需要身份验证的云功能(这是一个测试功能,只是 returns “Hello world!”
  4. 在 Cloud Functions 权限中,我添加了具有 Cloud Functions Invoker 角色的服务帐户

如果我使用此服务帐户 (gcloud auth print-identity-token) 生成身份令牌并使用它来触发我的云功能(headers 中的 Authorization: Bearer $ID_TOKEN),它会按预期工作. 但现在我希望能够在生产中做到这一点。所以我所做的是生成一个 JWT,使用它来获取访问令牌并使用此访问令牌,就像我对身份令牌所做的那样,但我得到 401 未经授权的响应。

这是我的代码 (Python)

import jwt
import time
import requests

# These elements are found in the service account JSON file (step 2)
PRIVATE_KEY_ID_FROM_JSON = "123ab4cdefghi56jk789123456789f123456m7n"
PRIVATE_KEY_FROM_JSON = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
SERVICE_ACCOUNT_EMAIL = "ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com"

# Create JWT
iat = int(time.time())
exp = iat + 3600

payload = {
    'iss': SERVICE_ACCOUNT_EMAIL,
    'sub': SERVICE_ACCOUNT_EMAIL,
    'aud': "https://www.googleapis.com/oauth2/v4/token",
    'target_audience ': 'https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME',
    'iat': iat,
    'exp': exp,
    "scope": "https://www.googleapis.com/auth/cloud-platform"
}
additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}

signed_jwt = jwt.encode(
    payload,
    PRIVATE_KEY_FROM_JSON,
    headers=additional_headers,
    algorithm='RS256'
)

# Use JWT to get access token
resp = requests.post(
    f"https://www.googleapis.com/oauth2/v4/token"
    f"?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={signed_jwt}",
    headers={
        "Authorization": f"Bearer {signed_jwt}",
        "Content-Type": "application/x-www-form-urlencoded"
    }
)

access_token = resp.json()["access_token"]

# Trigger Cloud Function using this access token
resp_cf = requests.post(
    "https://europe-west1-cuure-265415.cloudfunctions.net/Test_service_account",
    headers={
        "Authorization": f"Bearer {access_token}"
    }
)

print(resp_cf.content)

结果如下

b'\n<html><head>\n<meta http-equiv="content-type" content="text/html;charset=utf-8">\n<title>401 Unauthorized</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Unauthorized</h1>\n<h2>Your client does not have permission to the requested URL <code>/CLOUD FUNCTION NAME</code>.</h2>\n<h2></h2>\n</body></html>\n'

我不想使用 Python 库来通过服务帐户验证我的请求,因为我的目标是能够在无代码开发平台 Bubble.io 中重现这一点。

有人知道我做错了什么吗?

Answer所述:

There are three types of OAuth tokens. Refresh Token, Access Token, Identity Token. You are trying to use an OAuth Access Token instead of an OAuth Identity Token. For Authorization, Google Cloud Functions uses an OAuth Identity Token in the authorization: bearer HTTP header.

您还可以参考 documentation and ,其中对将 self-signed JWT 交换为 Google-signed ID 令牌进行了很好的解释。

You can manage access to an HTTP Cloud Function using IAM roles. You will want to assign the roles/cloud functions.invoker role to a service account, and have the caller provide the oauth credentials to the function in the Authorization header.