3

在我的 GCP 项目中,我有一个在 docker 容器中运行的 python API(使用连接)。我想使用 API Gateway 公开 API(使用 API 密钥)。

当我使用 部署 docker 容器时--ingress internal,我会Access is forbidden.通过网关进行 API 调用。因此 API 网关无法访问 Google Run 容器。当我使用 时--ingress all,一切都按预期工作,但是我的内部 API 可以从 Web 访问,这不是我想要的。

我为此创建了一个服务帐户:

gcloud iam service-accounts create $SERVICE_ACCOUNT_ID \
#  --description="the api gateway user" \
#  --display-name="api gateway user"

...给了帐户run.invoker权限:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --role=roles/run.invoker --member \
  serviceAccount:$SERVICE_ACCOUNT_EMAIL

...并使用服务帐户创建 API 配置:

gcloud api-gateway api-configs create $CONFIG_ID \
  --api=$API_ID --openapi-spec=$API_DEFINITION \
  --project=$PROJECT_ID --backend-auth-service-account=$SERVICE_ACCOUNT_EMAIL

但我无法从 API Gateway 访问 docker API。我在这里想念什么?如何保护我的 API,以便 API 网关可以在内部连接。

Update1:​​还将角色应用于我的运行服务:

gcloud run services add-iam-policy-binding $SERVICE_ID \
  --region $REGION --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
  --role="roles/run.invoker"

Update2:John Hanley 要求的一些额外信息:

我的网关 yml 如下所示:

swagger: '2.0'

info:
  title: "title"
  description: "description"
  version: "0.1"

schemes:
- https

x-google-backend:
  address: <CLOUD_RUN_SERVICE_URL>

paths:
  /api:
    post:
      operationId: api
      consumes:
        - application/json
      produces:
        - application/json
      security:
        - api_key: []
      parameters:
        - in: body
          name: request
          description: request
          required: true
          schema:
            $ref: '#/definitions/Request'
      responses:
        200:
          description: "success"
        400:
          description: "bad data"
        503:
          description: "internal error"

definitions:
  Request:
    properties:
      parameter1:
        type: string
      parameter1:
        type: string
    required:  
      - parameter1

securityDefinitions:
  api_key:
    type: "apiKey"
    name: "key"
    in: "query"
gcloud api-gateway api-configs describe api-config --api api-api
createTime: '2021-06-12T15:02:27.382098034Z'
displayName: api-config
gatewayServiceAccount: projects/-/serviceAccounts/apigatewayuser@projectid.iam.gserviceaccount.com
name: projects/722514052893/locations/global/apis/api-api/configs/api-config
serviceConfigId: api-config-3hytlxf4gfvzj
state: ACTIVE
updateTime: '2021-06-12T15:05:09.778404414Z'
gcloud api-gateway gateways describe api-gateway --location europe-west1
apiConfig: projects/722514052893/locations/global/apis/api-api/configs/api-config
createTime: '2021-06-12T15:06:03.383002459Z'
defaultHostname: api-gateway-97x27n6l.ew.gateway.dev
displayName: api-gateway
name: projects/projectid/locations/europe-west1/gateways/api-gateway
state: ACTIVE
updateTime: '2021-06-12T15:07:37.590520122Z'
gcloud run services describe api --region europe-west1
✔ Service api in region europe-west1
 
URL:     https://api-o3rf5h4boa-ew.a.run.app
Ingress: internal
Traffic:
  100% LATEST (currently api-00010-lig)
 
Last updated on 2021-06-12T17:42:49.913232Z by myemail@gmail.com:
  Revision api-00010-lig
  Image:         gcr.io/projectid/api
  Port:          8080
  Memory:        512Mi
  CPU:           1000m
  Concurrency:   80
  Max Instances: 100
  Timeout:       300s

尝试直接在 Cloud Run 上调试:

gcloud iam service-accounts keys create $KEY_FILE --iam-account=$SERVICE_ACCOUNT_EMAIL
gcloud auth activate-service-account $SERVICE_ACCOUNT_EMAIL --key-file $KEY_FILE
BEARER=$(gcloud auth print-identity-token $SERVICE_ACCOUNT_EMAIL)


curl --header "Content-Type: application/json" \
  --header "Authorization: bearer $BEARER" \
  --request POST \
  --data '{"parameter1":"somedata"}' \
  $SERVICE_URL/api

结果仍然是 Forbidden:

<!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 403 (Forbidden)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){#logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>403.</b> <ins>That’s an error.</ins>
  <p>Access is forbidden.  <ins>That’s all we know.</ins>

所以问题在于服务帐户无法访问 Cloud Run 应用程序。我不确定为什么这不起作用,因为该run.invoker角色已添加到 Run 服务中。

4

1 回答 1

7

Ingress internal 表示“仅接受来自项目的 VPC 或 VPC SC 边界的请求”。

当您使用 API Gateway 时,您不在您的 VPC 中,它是无服务器的,它在 Google Cloud 托管的 VPC 中。因此,您的查询是被禁止的。

由于 API 网关(目前)无法插入 VPC 连接器,因此无法将请求路由到您的 VPC,因此您无法使用此 ingress=internal 模式。


因此,解决方案是为所有人设置一个入口,这不是问题,您只授权合法帐户访问它。

为此,请检查 Cloud Run 服务是否在您的项目中授予 allUsers 角色/run.invoker。

  • 如果是,请将其删除

然后,创建一个服务帐户并授予它 Cloud Run 服务上的角色/run.invoker。

遵循本文档

  • 第 4 步:更新 OpenAPI 规范文件中的 x-google-backend 以在调用 Cloud Run 时添加正确的身份验证受众(它是基本服务 URL)
  • 第五步:用后端服务账号创建网关;设置您之前创建的服务帐户

最后,只有经过身份验证和授权的帐户才能访问您的 Cloud Run 服务

所有未经授权的访问都会被 Google 前端过滤并在到达您的服务之前被丢弃。因此,您的服务不会被免费调用,因此您无需支付任何费用!

只有 API Gateway(以及您在 Cloud Run 服务上允许的其他潜在帐户)可以调用 Cloud Run 服务。

所以,好的,您的 URL 是公开的,可以从狂野的 Internet 访问,但受到 Google 前端和 IAM 的保护。

于 2021-06-13T12:12:17.397 回答