从 Cloud Endpoint 调用托管在 Cloud Storage 上的静态 Html 时出现错误 401

Error 401 calling static Html hosted on Cloud Storage from Cloud Endpoint

我在调用 Cloud Storage 存储桶上托管的静态 HTML 页面时收到 401 错误。

Cloud Storage 存储桶配置为 Public。

调用是从我的 Cloud Endpoint 完成的,如下所示:

/my-web-page:
      get:
        summary: call my web page
        operationId: my-web-page
        x-google-allow: all
        x-google-backend:
          address: https://storage.googleapis.com/MY-PROJECT/[MY-BUCKET]/[MY-OBJECT]
        responses:
          '200':
            description: A successful response
            schema:
              type: string 

云运行日志:

XX.XXX.XXX.XXX - "GET https://[MY-CLOUD-ENDPOINT-SERVICE].a.run.app/my-web-page" **401** 804 "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"
Expand all | Collapse all{
 httpRequest: {
  latency: "2.377394394s"   
  protocol: "HTTP/1.1"   
  remoteIp: "XXXXX"   
  requestMethod: "GET"   
  requestSize: "693"   
  requestUrl: "https://[MY-CLOUD-ENDPOINT-SERVICE].a.run.app/storage"   
  responseSize: "804"   
  serverIp: "XXXXXXX"   
  status: 401   
  userAgent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/18.17763"   
 }
 insertId: "5ddef2f900077a8473972018"  
 labels: {…}  
 logName: "projects/[MY-GCP-PROJECT]/logs/run.googleapis.com%2Frequests"  
 receiveTimestamp: "2019-11-27T22:04:41.498296805Z"  
 resource: {
  labels: {
   configuration_name: "XXXXX"    
   location: "us-central1"    
   project_id: "XXXXX"    
   revision_name: "XXXX"    
   service_name: "XXXX"    
  }
  type: "cloud_run_revision"   
 }
 severity: "WARNING"  
 timestamp: "2019-11-27T22:04:41.490116Z"  
 trace: "projects/XXXXXX/traces/aed367cb2b64bf00c215f8b19dff446b"  
}

有什么想法吗?

当您使用端点向云存储 API 发出请求时,我认为您应该改用以下地址:

https://storage.googleapis.com/storage/v1/[PATH_TO_RESOURCE]

由于端点很可能正在向 API 发出 JSON 请求,文档中的 link 将对您有用。

编辑:

我终于设法使用以下端点配置使其与您的相同设置一起工作:

/hello:
  get:
    summary: hello
    operationId: GetImage
    x-google-backend:
      #address: https://storage.googleapis.com/[MY-BUCKET]/[MY-OBJECT]
      address: https://storage.cloud.google.com/[MY-BUCKET]/[MY-OBJECT]
    responses:
      '200':
        description: hello
        schema:
          type: object

此设置的问题是文件将从 storage.cloud.google.com 提供,因此用户将被重定向到 apidata.googleusercontent.com。我相信它不适用于 googleapis.com,因为端点并不意味着调用其他 API,然后调用 storage.google.com URL 将起作用。

这里发生的事情是 x-google-backend 正在尝试通过创建服务帐户身份令牌对存储进行身份验证。

另一方面,Storage 只接受 OAuth 或根本不接受授权。它从 ESP 获得的令牌被简单地忽略并被视为垃圾。

您甚至可以使用 curl -H 'Authorization: Bearer garbage' https://storage.googleapis.com/bucket/buildings.jpg 并仍然得到完全相同的错误。

暂时无法关闭此功能的授权,因此不会与 googleapis 一起使用。

另一种方法是修改 ESP 映像,以便它通过添加文件 /var/lib/nginx/extra/hello.conf 并修改 gcloud_build_image 以包含此配置来向 nginx 配置添加自定义位置。

这样它将完全跳过端点,因此它可以从 openapi-run.yaml 中删除。您可以检查两个文件 here.

如果这能解决您的问题,请告诉我。

这是 ESP 中的一个错误,它总是向后端发送 ID 令牌。由于您的 GCS 存储桶是 public,如果它没有任何 JWT 令牌,对存储 API 的请求应该有效。但是如果它有任何 JWT 令牌,调用就会失败。

我们正在努力修复。但由于假日发布冻结,该修复程序将于明年推出。

有一个 hack 可以解决它。

1) 通过以下方式部署您的 OpenAPI 规范:

gcloud endpoints deploy you_open_api.json

2) 从Google 服务管理服务

下载编译后的配置文件
gcloud endpoints configs describe ... > tmp.xml

3) 删除 tmp.xml 中 "Backend" 部分带有 "jwt_audience" 的行 这个想法是:如果 jwt_audience 字段为空,ESP 将不会生成 ID 令牌。但是在 x-google-backend OpenApi 规范中,即使你没有指定 jwt_audience,编译器也会自动将 "address" 字段分配给 "jwt_audience" 字段。

4) 通过以下方式将 tmp.xml 重新部署到 google 服务管理:

gcloud endpoints deploy tmp.xml

进行此更改后,ESP 将不会在调用存储时生成 ID 令牌 API。