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:
- Service 2 (webapp) on Cloud Workstation calling Service 1(REST API) on Cloud workstation.
- 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:
Service 2 (webapp) on Cloud Workstation. Google sets an HTTPOnly Secure cookie on service 2 domain.
Name: WorkstationJwt; value: encodedJWT
Service 2 calls Service 1(REST API) on Cloud workstation.
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.