【问题标题】:GCP API Gateway authentication between services without using service account private key服务之间的 GCP API Gateway 身份验证,无需使用服务帐户私钥
【发布时间】:2021-02-25 04:15:49
【问题描述】:

如何设置 API 网关以在不使用服务帐户私钥文件的情况下对服务进行身份验证?

服务 A,例如云功能,服务帐户 A 想要在不使用服务帐户私钥文件的情况下对 API 网关进行 API 调用。我想知道服务 A 是否有可能使用其凭据进行 API 调用,API 网关可以在其中对请求进行身份验证?

能够执行上述操作,API 网关可以配置为允许不同服务帐户的各种路径。

更新

这是客户端代码的示例

def make_jwt_request(signed_jwt, url):
    """Makes an authorized request to the endpoint"""
    headers = {
        'Authorization': 'Bearer {}'.format(signed_jwt),
        'content-type': 'application/json'
    }
    response = requests.get(url, headers=headers)

此外,API 网关定义类似于

swagger: '2.0'
info:
  title: API_ID optional-string
  description: Sample API on API Gateway with a Google Cloud Functions backend
  version: 1.0.0
schemes:
  - https
produces:
  - application/json
securityDefinitions:
  google:
    authorizationUrl: ""
    flow: "implicit"
    type: "oauth2"
    x-google-issuer: "service-b@example-project.iam.gserviceaccount.com"
    x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-b@example-project.iam.gserviceaccount.com"
paths:
  /helloworld:
    get:
      summary: Hello World
      operationId: hello
      x-google-backend:
        address: https://us-central1-example-project.cloudfunctions.net/function-b
      security:
        - google: []
      responses:
        '200':
          description: A successful response
          schema:
            type: string

【问题讨论】:

  • 只是为了澄清。您想调用一个 API 网关来检查授权标头(使用由服务帐户密钥文件生成的令牌)但您不希望在服务 A 中有服务帐户密钥文件,因为它是一个秘密并且您有困难安全地处理它。对吗?
  • @guillaumeblaquiere 完全正确。 GCP 允许类似于我在云函数中寻找的函数调用 cloud.google.com/functions/docs/securing/authenticating
  • 是的,可以使用函数A的凭证。你能分享一下你调用API网关的代码吗?
  • @guillaumeblaquiere 我更新了最初的帖子以包含示例代码
  • 你是如何创建签名 JWT 的?如果您想问,我如何在没有 JSON 私钥的情况下签署 JWT,那么您可以使用 IAM SignBlob API。当您使用服务元数据中的凭据时,私钥不可用。 Google 提供了一个 API 来为您签署数据。此链接底部是大多数语言的示例:cloud.google.com/iam/docs/reference/rest/v1/…

标签: google-cloud-platform service-accounts google-cloud-api-gateway


【解决方案1】:

您可以使用 sign_jwtiamcredentials 端点在没有私钥的情况下签署 jwt。

现在假设以下安全定义,您可以使用以下 python 代码生成签名的 jwt。

   {
        "securityDefinitions": {
            "SERVICE_ACCOUNT_NAME": {
                "authorizationUrl": "",
                "flow": "implicit",
                "type": "oauth2",
                "x-google-audiences": "SERVICE_ACCOUNT_EMAIL",
                "x-google-issuer": "SERVICE_ACCOUNT_EMAIL",
                "x-google-jwks_uri": "https://www.googleapis.com/service_accounts/v1/metadata/x509/SERVICE_ACCOUNT_EMAIL"
            }
        }
    }

python 脚本

import time
import json 
import urllib.parse
import requests
from oauth2client.client import GoogleCredentials
from googleapiclient import discovery

def generate_jwt_payload(service_account_email):
    """Generates jwt payload"""
    now = int(time.time())
    payload = {
        'iat': now,
        "exp": now + 3600,
        'iss': service_account_email,
        'aud':  service_account_email,
        'sub': service_account_email,
        'email': service_account_email
    }
    return payload

def get_jwt(service_account_email):
    """Generate a signed JSON Web Token using a Google API Service Account."""

    credentials = GoogleCredentials.get_application_default()
    service = discovery.build('iamcredentials', 'v1', credentials=credentials)
    body = {
        "payload": json.dumps(generate_jwt_payload(service_account_email))
    }
    encoded_sa = urllib.parse.quote_plus(service_account_email)
    resp = service.projects().serviceAccounts().signJwt(name=f"projects/-/serviceAccounts/{encoded_sa}", body=body).execute()
    return resp["signedJwt"]


def make_jwt_request(service_account_email, url):
    """Makes an authorized request to the endpoint"""
    signed_jwt = get_jwt(service_account_email)
    headers = {
        'Authorization': 'Bearer {}'.format(signed_jwt),
        'content-type': 'application/json'
    }
    response = requests.get(url, headers=headers)
    return response


if __name__ == '__main__':
    print(make_jwt_request(SERVICE_ACCOUNT_EMAIL,GATEWAY_URL).text)

【讨论】:

    猜你喜欢
    • 2021-04-27
    • 2020-04-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-25
    • 1970-01-01
    • 2019-04-14
    相关资源
    最近更新 更多