Imran Ismail
Imran Ismail

Reputation: 16

Letting upstream handle cors requests

I'm trying to setup a service that already handles CORS requests and would like to keep it that way instead of handling the CORS request on the Edge Proxy.

Leaving the cors field blank didn't help at all.

Is there anyway to achieve this with Ambassador?

Upvotes: 0

Views: 1831

Answers (1)

Noah Krause
Noah Krause

Reputation: 156

Ambassador will not handle CORS in anyway unless you set the cors parameter in a Mapping or Module config.

Even if that is set, the way Envoy handles CORS seems to be the behavior you are searching for.

Taking a look at the linked comment in this issue https://github.com/envoyproxy/envoy/issues/300#issuecomment-296796675, we can see how Envoy chose to implement it's CORS filter. Specifically:

  1. Assign values to the CORS headers in the repsponse: For each of the headers specified in Table 1 above:

    a. let value be the option for the header config

    b. if value is not defined, continue to the next header

    c. else, write the response header for the specified config option

This means that Envoy will first take the value of the headers set by the upstream service and only write them with the configured values if they are not set in the response.

You can test this by creating a route to the httpbin.org (which handles CORS) and setting cors parameter in the Mapping.

---
apiVersion: getambassador.io/v2
kind: Mapping
metadata:
  name: cors-httpbin
spec:
  prefix: /httpbin/
  service: httpbin.org
  cors:
    origins:
    - http://foo.example
    methods:
    - POST
    - OPTIONS

The Mapping above should configure Envoy to set the access-control-allow-origins and access-control-allow-methods headers to http://foo.example.com and POST respectively. However, after sending a test request to this endpoint, we can see that we are instead getting very different CORS headers back in the response:

curl https://aes.example.com/httpbin/headers -v -H "Origin: http://bar.example.com" -H "Access-Control-Request-Method: GET" -X OPTIONS
*   Trying 34.74.58.157:443...
* Connected to aes.example.com (10.11.12.100) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
* Server certificate: aes.example.com
* Server certificate: Let's Encrypt Authority X3
* Server certificate: DST Root CA X3
> OPTIONS /httpbin/headers HTTP/1.1
> Host: aes.example.com
> User-Agent: curl/7.69.0
> Accept: */*
> Origin: http://bar.example.com
> Access-Control-Request-Method: GET
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< date: Thu, 19 Mar 2020 13:25:48 GMT
< content-type: text/html; charset=utf-8
< content-length: 0
< server: envoy
< allow: HEAD, OPTIONS, GET
< access-control-allow-origin: http://bar.example.com
< access-control-allow-credentials: true
< access-control-allow-methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
< access-control-max-age: 3600
< x-envoy-upstream-service-time: 33
< 
* Connection #0 to host aes.example.com left intact

This is because the httpbin.org upstream is setting these headers in the response and so Envoy is defaulting to using them instead of forcing the CORS configuration we gave it. In this way, Envoy really acts as a default for CORS settings and allows upstreams to set more or less restrictive configurations as they see fit.

This behavior can be confusing and caused me a lot of headaches trying to figure it out. I hope I helped clear it up for you.

Upvotes: 1

Related Questions