0

How can I setup an API Gateway to authenticate services without using service account private key file?

Service A, for instance a cloud function, with service account A wants to make API calls to an API gateway without using service account private key file. I am wondering if it is possible that service A uses its credentials to make an API call where the API Gateway can authenticate the request?

Being able to do the above, the API gateway can be configured to allow various paths to different service accounts.

Updated

This is an example of what a client code could be

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)

Also, the API Gateway definition would be something like

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
4

1 回答 1

1

您可以使用sign_jwt iamcredentials 端点在没有私钥的情况下对 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"
            }
        }
    }

蟒蛇脚本

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-12-17T15:26:11.503 回答