GCP - 从 API 网关访问 Google 云 运行 后端
GCP - access from API Gateway to Google Cloud Run backend
在我的 GCP 项目中,我在 docker 容器中有一个 python API 运行ning(使用连接)。我想使用 API 网关公开 API(使用 API 密钥)。
当我使用 --ingress internal
部署 docker 容器时,我在通过网关的 API 调用中得到 Access is forbidden.
。所以API网关无法访问Google运行容器。
当我使用 --ingress all
时,一切都按预期工作,但是我的内部 API 可以从网络访问,这不是我想要的。
我为此创建了一个服务帐户:
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 网关访问 docker API。我在这里错过了什么?如何保护我的 API,以便 API 网关可以在内部连接。
更新1:
还将角色应用到我的 运行 服务:
gcloud run services add-iam-policy-binding $SERVICE_ID \
--region $REGION --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
--role="roles/run.invoker"
更新2:
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
尝试直接在云上调试 运行:
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>
所以问题出在服务帐户无法访问云 运行 应用程序。我不确定为什么这不起作用,因为 run.invoker
角色已添加到 运行 服务。
Ingress internal 表示“仅接受来自项目的 VPC 或 VPC SC 边界的请求”。
当您使用 API 网关时,您不在 VPC 中,它是无服务器的,它在 Google 云托管 VPC 中。因此,您的查询被禁止。
并且由于 API 网关无法插入 VPC 连接器(目前),因此无法将请求路由到您的 VPC,因此您不能使用此 ingress=internal 模式。
因此,解决方案是为所有人设置一个入口,这不是问题,因为您只授权合法帐户访问它。
为此,请检查 Cloud 运行 服务是否已在您的项目中向所有用户授予 roles/run.invoker。
- 如果是,删除它
然后,创建一个服务帐户并授予它 roles/run.invoker on the Cloud 运行 服务。
关注这个documentation
- 第 4 步:更新您的 OpenAPI 规范文件中的 x-google-后端,以便在您调用 Cloud 运行(这是基本服务)时添加正确的身份验证受众URL)
- 第 5 步:使用后端服务帐户创建网关;设置您之前创建的服务帐户
最后,只有经过身份验证和授权的帐户才能访问您的云 运行 服务
所有未经授权的访问都被 Google 前端过滤并在到达您的服务之前被丢弃。因此,您的服务不会被无偿调用,因此您无需支付任何费用!
只有 API 网关(以及您在云 运行 服务上允许的潜在其他帐户)可以调用云 运行 服务。
那么,好吧,你的 URL 是 public,可以从野外互联网访问,但受到 Google 前端和 IAM 的保护。
在我的 GCP 项目中,我在 docker 容器中有一个 python API 运行ning(使用连接)。我想使用 API 网关公开 API(使用 API 密钥)。
当我使用 --ingress internal
部署 docker 容器时,我在通过网关的 API 调用中得到 Access is forbidden.
。所以API网关无法访问Google运行容器。
当我使用 --ingress all
时,一切都按预期工作,但是我的内部 API 可以从网络访问,这不是我想要的。
我为此创建了一个服务帐户:
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 网关访问 docker API。我在这里错过了什么?如何保护我的 API,以便 API 网关可以在内部连接。
更新1: 还将角色应用到我的 运行 服务:
gcloud run services add-iam-policy-binding $SERVICE_ID \
--region $REGION --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
--role="roles/run.invoker"
更新2: 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
尝试直接在云上调试 运行:
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>
所以问题出在服务帐户无法访问云 运行 应用程序。我不确定为什么这不起作用,因为 run.invoker
角色已添加到 运行 服务。
Ingress internal 表示“仅接受来自项目的 VPC 或 VPC SC 边界的请求”。
当您使用 API 网关时,您不在 VPC 中,它是无服务器的,它在 Google 云托管 VPC 中。因此,您的查询被禁止。
并且由于 API 网关无法插入 VPC 连接器(目前),因此无法将请求路由到您的 VPC,因此您不能使用此 ingress=internal 模式。
因此,解决方案是为所有人设置一个入口,这不是问题,因为您只授权合法帐户访问它。
为此,请检查 Cloud 运行 服务是否已在您的项目中向所有用户授予 roles/run.invoker。
- 如果是,删除它
然后,创建一个服务帐户并授予它 roles/run.invoker on the Cloud 运行 服务。
关注这个documentation
- 第 4 步:更新您的 OpenAPI 规范文件中的 x-google-后端,以便在您调用 Cloud 运行(这是基本服务)时添加正确的身份验证受众URL)
- 第 5 步:使用后端服务帐户创建网关;设置您之前创建的服务帐户
最后,只有经过身份验证和授权的帐户才能访问您的云 运行 服务
所有未经授权的访问都被 Google 前端过滤并在到达您的服务之前被丢弃。因此,您的服务不会被无偿调用,因此您无需支付任何费用!
只有 API 网关(以及您在云 运行 服务上允许的潜在其他帐户)可以调用云 运行 服务。
那么,好吧,你的 URL 是 public,可以从野外互联网访问,但受到 Google 前端和 IAM 的保护。