CORS
Summary
Grey Matter supports the configuration of cross-origin resource sharing on a sidecar. CORS can be configured to allow an application to access resources at a different origin (domain, protocol, or port) than its own.
For more information on CORS, see this CORS reference.
Simple Requests
Simple requests are classified as requests that don't require a CORS preflight check. This distinction is made between requests that might be dangerous (i.e. modifies server resources) and those that are most likely benign. A request is considered simple when all of the following criteria is true:
The method is
GET
,HEAD
, orPOST
Only CORS safe-listed headers are present
The
Content Type
header is set to one ofapplication/x-www-form-urlencoded
ormultipart/form-data
ortext/plain
A more comprehensive list and explanation can be found here.
As an example, say an app running at http://localhost:8080
is trying to call a backend service with a Grey Matter sidecar at http://localhost:10808
. Without a CORS configuration, this request would fail, because the app localhost:8080
is trying to access resources from a server at a different origin, localhost:10808
. To solve this, the following CORS config is set on its domain:
{
"zone_key": "zone-default-zone",
"domain_key": "domain-backend-service",
"name": "*",
"port": 10808,
"cors_config": {
"allowed_origins": [
{ "match_type": "exact", "value": "http://localhost:8080" }
],
"allowed_headers": [],
"allowed_methods": [],
"exposed_headers": [],
"max_age": 60
}
}
With this configuration, if a simple request comes in to the sidecar from the app, it will have an Origin
header value of http://localhost:8080
, and this request will succeed. The server will attach a header Access-Control-Allow-Origin: http://localhost:8080
to the response, which signals to the browser that this request is allowed.
Preflight Requests
Preflight requests are initiated by the browser using the OPTIONS
HTTP method before sending a request in order to determine if the real request is safe to send. The response to this kind of request contains information about what is allowed from a request, and the server determines whether or not to send the actual request based on this information.
This response information is in the form of three HTTP headers, access-control-request-method
, access-control-request-headers
, and the origin
header. These correspond to fields of the cors_config
- thus these configurations can be specified to determine how the Grey Matter sidecar will respond to preflight requests. If a preflight request comes in to the Grey Matter Sidecar that does not meet the specification for one of these configured fields, the sidecar will send back a response to not initiate the request.
Based on the same example from simple requests, say the app running at http://localhost:8080
wants to send requests to the backend service at http://localhost:10808
with a content-type of application/json;charset=UTF-8
. This particular content-type is outside of those allowed by CORS for simple requests, and thus would result in sending a preflight request to determine if the request can be sent. In order for the CORS configuration to indicate that the request can be sent, it would need to allow the content-type
header by configuring the allowed_headers
field:
{
"zone_key": "zone-default-zone",
"domain_key": "domain-backend-service",
"name": "*",
"port": 10808,
"cors_config": {
"allowed_origins": [
{ "match_type": "exact", "value": "http://localhost:8080" }
],
"allowed_headers": ["content-type"],
"allowed_methods": [],
"exposed_headers": [],
"max_age": 60
}
}
In the above configuration, CORS will allow requests with Origin
header value http://localhost:8080
only and indicate that the content-type header can be set according to the request.
Configuration
To set up CORS, set the cors_config
field on a domain object with the desired configuration, see the fields below.
For an existing domain, run
greymatter edit domain <domain-name>
and add the desired cors_config
object.
Example object
"cors_config": {
"allowed_origins": [],
"allowed_headers": [],
"allowed_methods": [],
"exposed_headers": [],
"max_age": 0,
"allow_credentials": true
}
Fields
allowed_origins
allowed_origins
This field specifies an array of string patterns that match allowed origins. The proxy will use these matchers to set the access-control-allow-origin
header. This header will be set on any cross-origin response that matches one of the allowed_origins
.
Available matchers include:
exact
prefix
suffix
regex
Example:
"allowed_origins": [
{ "match_type": "exact", "value": "http://localhost:8080" }
]
A wildcard value *
is allowed except when using the regex
matcher.
allow_credentials
allow_credentials
Specifies the content for the access-control-allow-credentials
header that the proxy will set on any cross-origin request that matches one of the allowed_origins
. This header specifies whether or not the upstream service allows credentials.
exposed_headers
exposed_headers
Specifies the content for the access-control-expose-headers
header that the proxy will set on any cross-origin request that matches one of the allowed_origins
. This header specifies an array of headers that are allowed on the response.
max_age
max_age
Specifies the content for the access-control-max-age
header that the proxy will set on the preflight response. This header is an integer value specifying how long a preflight request can be cached by the browser.
allowed_methods
allowed_methods
Specifies the content for the access-control-allow-methods
header that the proxy will set on the preflight response. This header specifies an array of methods allowed by the upstream service.
allowed_headers
allowed_headers
Specifies the content for the access-control-allow-headers
header that the proxy will set on the preflight response. This header specifies an array of headers allowed by the upstream service.
Notes
By default, the proxy will use the upstream service's CORS policy on the gateway and on the upstream service. The gateway policy is ignored.
Because CORS is a browser construct, curl can always make a request to the server, with or without CORS. However, it can be used to mimic a browser and verify how the proxy will react to CORS requests:
$ curl -v 'http://localhost:9080/services/catalog/latest/' \
-X OPTIONS \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: content-type' \
-H 'Origin: http://localhost:8080'
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 9080 (#0)
> OPTIONS /services/catalog/latest/ HTTP/1.1
> Host: localhost:9080
> User-Agent: curl/7.64.1
> Accept: */*
> Access-Control-Request-Method: POST
> Access-Control-Request-Headers: content-type
> Origin: http://localhost:8080
>
< HTTP/1.1 200 OK
< access-control-allow-origin: http://localhost:8080
< access-control-max-age: 60
< date: Tue, 12 May 2020 20:11:13 GMT
< server: envoy
< content-length: 0
<
* Connection #0 to host localhost left intact
* Closing connection 0
Last updated
Was this helpful?