1

When using Google Cloud's workstation for multi-service development, I ran into a CORs issue due to multiple cloud workstation redirects being generated.

When I try to make an external REQUEST from an a client: Example: Service 2 to Service 1, or Local desktop to Service 1, I am returned multiple redirects that never reach the service.

Testing scenarios:

  1. Service 2 (webapp) on Cloud Workstation calling Service 1(REST API) on Cloud workstation.
  2. cURL to service 1(REST API) from local laptop.

Note: These services work in production, across different subdomains with CORs today, it also works locally on my personal laptop with CORs support, just not on cloud workstation since the headers are not present on the redirect.

Requested Site with parameters:

https://2143-${workstation}.cluster-${cluster}.cloudworkstations.dev/sessionToken

Cloud Workstation URI template

https://${port}-${workstation}.cluster-${cluster}.cloudworkstations.dev/${service_route}

Redirect 1:

HTTP/1.1 302 Found
Content-Type: text/html; charset=utf-8
Location: https://ssh.cloud.google.com/devshell/gateway/oauth?state=${token}
Date: Tue, 09 May 2023 08:05:26 GMT

Redirect 2:

HTTP/2 302
content-type: application/binary
location: https://accounts.google.com/ServiceLogin?passive=1209600&osid=1&continue=https://ssh.cloud.google.com/devshell/gateway/oauth?state${state}
content-security-policy: ${policy}
cross-origin-opener-policy: same-origin-allow-popups
date: Tue, 09 May 2023 08:05:26 GMT
server: ESF
content-length: 0
x-xss-protection: 0
x-frame-options: SAMEORIGIN
x-content-type-options: nosniff
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

Redirect 3:

HTTP/2 302
set-cookie: ${cookie}
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Tue, 09 May 2023 08:05:27 GMT
location: https://accounts.google.com/InteractiveLogin?continue=https://ssh.cloud.google.com/devshell/gateway/oauth?state${state}
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: ${policy}
content-security-policy: require-trusted-types-for 'script';report-uri /_/AccountsSigninPassiveLoginHttp/cspreport
content-security-policy: require-trusted-types-for 'script';report-uri /cspreport
accept-ch: ${ch}
cross-origin-opener-policy: unsafe-none
cross-origin-resource-policy: cross-origin
permissions-policy: ${policy}
content-type: application/binary
report-to: ${report}
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
server: GSE
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

Redirect 4:

HTTP/2 302
content-type: text/html; charset=UTF-8
set-cookie: ${cookie}
x-frame-options: DENY
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Tue, 09 May 2023 08:05:27 GMT
location: https://accounts.google.com/v3/signin/identifier?dsh=${dsh}&continue=${continue}
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: ${policy}
content-security-policy: require-trusted-types-for 'script';report-uri /cspreport
cross-origin-opener-policy-report-only: same-origin; report-to="coop_gse_qebhlk"
report-to: ${report}
content-length: 1655
x-content-type-options: nosniff
x-xss-protection: 1; mode=block
server: GSE
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

Redirect 5:

HTTP/2 200
content-type: text/html; charset=utf-8
x-frame-options: DENY
set-cookie: ${cookie}
x-auto-login: realm=com.google&args=continue%3Dhttps://ssh.cloud.google.com/devshell/gateway/oauth?state${state}
x-ua-compatible: IE=edge
cache-control: no-cache, no-store, max-age=0, must-revalidate
pragma: no-cache
expires: Mon, 01 Jan 1990 00:00:00 GMT
date: Tue, 09 May 2023 08:05:27 GMT
strict-transport-security: max-age=31536000; includeSubDomains
content-security-policy: ${policy}
content-security-policy: require-trusted-types-for 'script';report-uri /v3/signin/_/AccountsSignInUi/cspreport
cross-origin-resource-policy: same-site
report-to: ${report}
permissions-policy: ${policy}
cross-origin-opener-policy-report-only: same-origin; report-to="AccountsSignInUi"
accept-ch: ${ch}
server: ESF
x-xss-protection: 0
x-content-type-options: nosniff
alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
accept-ranges: none
vary: Sec-Fetch-Dest, Sec-Fetch-Mode, Sec-Fetch-Site,Accept-Encoding

https://accounts.google.com/v3/signin/identifier?${dsh}

Outcome:

The original request never reached my Google Cloud workstation instance.

  • I can make a cURL request locally on the google cloud workstation, so I can confirm the service is running and capable of receiving traffic.

Update 5/21/23: After further investigation, Google is setting a cookie they use to authenticate the workstation request.

Sequence:

  1. Service 2 (webapp) on Cloud Workstation. Google sets an HTTPOnly Secure cookie on service 2 domain.

    Name: WorkstationJwt; value: encodedJWT

  2. Service 2 calls Service 1(REST API) on Cloud workstation.

  3. Google proxy captures requests, looking for WorkstationJwt cookie before forwarding request, if cookie is NOT present, request to Service 1 (API) on cloud workstation fails and never receives the original request.

  • You left out what is making the request. That software must support handling multiple redirects. In your case at least 5 redirects. – John Hanley May 09 '23 at 16:36
  • Use cases making the request: 1. Service 2 on Cloud Workstation calling Service 1 on Cloud workstation 2. cURL to service 1 from local laptop. I should also note that this service works in production, across different subdomains with CORs today, it also works locally on my personal laptop with CORs support, just not on cloud workstation since the headers are not present on the redirect. – Andrew Maxwell May 10 '23 at 03:19
  • What is `use cases`? Edit your post with details. – John Hanley May 10 '23 at 03:21
  • @JohnHanley Out of curiosity, could you give a bit more information about the multi-service use case? Workstations generally encourages a single developer per workstation, in which a developer might e.g. spin up the entire service stack for development. In the use case you have described, are you using a workstation per service? How are the workstations assigned to developers? – hexacyanide May 14 '23 at 02:02
  • @hexacyanide - did you mean your comment for me? – John Hanley May 14 '23 at 02:11
  • @AndrewMaxwell I understand you discovered that this is due to an authentication cookie related issue. Did you ever find a solution for your project/workflow? I am running into a similar issue. The underlying server never receives the request and cannot present the CORS headers because of this. Any information would be helpful. Thanks. – Tidal5 Aug 04 '23 at 08:47

0 Answers0