1
votes

I am receiving a 401 error when calling a static HTML page hosted on Cloud Storage bucket.

The Cloud Storage bucket is configured as Public.

The call is done from my Cloud Endpoint, as shown below:

/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 

Cloud Run Log:

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"  
}

Any ideas?

3
Did you deploy ESP in Cloud Run with flag --allow-unauthenticated ? - Wayne Zhang

3 Answers

0
votes

What is happening here is that the x-google-backend is attempting to authenticate to Storage by creating a service account identity token.

On the other hand, Storage accepts only OAuth or no authorization at all. The token it gets from ESP is simply ignored and treated as garbage.

You can even use curl -H 'Authorization: Bearer garbage' https://storage.googleapis.com/bucket/buildings.jpg and still get the exact same error.

For the time being, there is no way of turning off the authorization in this feature, so it won't be working with googleapis.

An alternative would be modifying the ESP image so that it adds a custom location to nginx config by adding file /var/lib/nginx/extra/hello.conf and modifying gcloud_build_image to include this config.

This way it will skip the endpoints altogether, so it can be removed from openapi-run.yaml. You can check both files here.

Let me know if this solves your issue.

0
votes

As you are doing a request to the Cloud Storage API with the usage of endpoints, I believe that you should use the following address instead:

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

As the endpoint is most probably doing a JSON request to the API, this link from the documentation will be useful for you.

EDIT:

I finally managed to make it work with your same settings using the following endpoints configuration:

/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

The thing with this setting is that the file will be served from the storage.cloud.google.com instead and therefore the user will be redirected to apidata.googleusercontent.com instead. I believe that it's not working with the googleapis.com because Endpoints it's not meant to call other APIs, then calling the storage.google.com URL will work instead.

0
votes

This is a bug in ESP, it always send ID token to the backend. Since your GCS bucket is public, the request to the storage API should work if it doesn't have any JWT token. But if it has any JWT token, the call fail.

We are working on a fix. But due to holiday release frozen, the fix will be available next year.

There is a hack to work around it.

1) deploy your OpenAPi spec by:

gcloud endpoints deploy you_open_api.json

2) download its compiled config file from Google service management service

gcloud endpoints configs describe ... > tmp.xml

3) remove the lines with "jwt_audience" in the "Backend" section in the tmp.xml The idea is: if jwt_audience field is empty, ESP will not generate ID token. But in the x-google-backend OpenApi spec, even you did not specify jwt_audience, the compiler will automatically assign "address" field to the "jwt_audience" field.

4) redeploy the tmp.xml to google service managment by:

gcloud endpoints deploy tmp.xml

With this change, ESP will not generate ID token when calling storage API.