Routing pertains to the path one request should take to get from a client to a specified endpoint. In greymatter.io, this is configured through Domains and Clusters.
For each greymatter.io domain, a virtual host will be created from a combination of the domain configuration as well as any greymatter.io route object that routes to it. Each route object is also linked to a greymatter.io shared rules object, which determines the default greymatter.io cluster to send the incoming request to.
The link between domain, route, and shared rules is important. A request is sent to a domain based on its Host or :authority header. From there, each route on the virtual host for that domain is checked in order for a match. Once a match is found, the request is forwarded to a cluster. This cluster will be determined either by the shared rules default configuration linked to that route, or by the routing rules constraints
field. See route forwarding for these configuration specifics.
Configuration Reference
Attribute | Type | Default | Description |
---|---|---|---|
shared_rules.default |
|
| Defines the types of traffic the shared rules will serve to the specified upstream clusters. |
shared_rules.rules | Array of rules |
| List of rules applied to to decide to the upstream cluster target. |
route.rules | Array of rules |
| List of rules applied to to decide to the upstream cluster target. |
route.route_match |
|
| The pathname for a given route, which the request must match. |
route.prefix_rewrite |
|
| The updated URL on the outgoing request. |
domain.redirects | Array of redirects |
| .Redirection configuration for routes on the same host |
Example Object
The greymatter.io route object is used to configure Envoy’s HTTP routing for a virtual host. The minimal route object looks something like the following:
{
"route_key": "example-route",
"domain_key": "example-domain",
"zone_key": "zone-default-zone",
"path": "",
"route_match": {
"path": "/services/example/latest/",
"match_type": "prefix"
},
"prefix_rewrite": "/",
"redirects": null,
"shared_rules_key": "example-shared-rules",
"rules": null,
"response_data": {},
"cohort_seed": null,
"retry_policy": null,
"high_priority": false,
}
The domain_key
explicitly links this route to a specific domain, and the shared_rules_key
does the same for shared rules. When a request is sent to the greymatter.io domain matching this domain_key
, the route configured from this object will be on the list of routes to be considered for a match. If a request is matched to this route, the request will be sent to a cluster as determined by the shared rules object given by "shared_rules_key"
unless specified otherwise in the route’s rules .
Path Matching
When a request is sent to a particular domain, each route on the virtual host for that domain is checked in order for a match on its :path header. Once a match is found, the route is used. In order for a request to be considered a “match” for a route, it must meet whatever matching criteria is configured in the route object. In the most basic case, this requires path matching.
Path matching is configured using the route_match
field in the route object. This field takes two values, path
and match_type
. If the :path header on the incoming request matches whatever the route_match.path
is, based on the route_match.match_type
, this path is considered a “match”.
See the routing example .
There are options to create more complex matching criteria, including matching specific headers, cookies, etc. These extra matching rules can be set using routing rules .
Prefix Rewriting
When a route is matched to a request, there is an option to change the value of the :path header on the request before directing the request to the cluster.
Prefix rewriting is configured on a route in the prefix_rewrite
field. When a request is matched to the route, the :path that the request came in on will be rewritten, replacing the matched route_match
value with the string value of prefix_rewrite
.
For example, if the :path header for an incoming request to the example-domain
is "/services/examples/latest/ping"
, the route created by the example object will be considered a match. At this point in time the request :path will altered by replacing the route_match.path
, which is "/services/example/latest/"
, with the prefix_rewrite
value, which is "/"
. Thus, the :path on the request will now be "/ping"
when it is forwarded to the cluster.
This is particularly necessary in a service mesh, where requests are rarely sent directly to their destination service.
Redirect
Redirects are supported on both domain and route objects for convenience. Both have the same syntax: The redirects
top-level key on a domain or route is an array of redirect objects:
"redirects": [
{
"name": ""
"from": "^/services/drive-data/2\\.0\\.0$",
"to": "/services/drive-data/2.0.0/",
"redirect_type": "permanent",
"header_constraints": null
}
]
The new route (implicitly generated from each redirect) will have its path matching specification with match type regex
for the value configured in the redirect.from
field. The route will redirect to the url given by the redirect.to
value, with response code set as either 307
for Temporary Redirect or 308
for Permanent Redirect, as configured with redirect_type
.
For redirects on a route object, the name
field is optional, defaulting to ""
, and collisions cause no trouble due to the parent route scoping. There is also the option to set header matchers on the redirect route. The header_constraints
field takes a list of header constraint objects, and each constraint in this list will be used to configure an Envoy header matcher on the route. This means that, before an incoming request will be considered a match for the route, it also must match each of these header constraints. First, the incoming requests headers will checked for the existence of the header with key equal to the name
field of the header constraint. If the header exists, its value will be regex compared with the value
field of the header constraint. If this value is equal, the header match is considered a match. If and only if the incoming request path matches and route and matches every header constraint set on the route is the request considered a match.
One very common reason for adding a redirect to an existing route is to support paths with and without a trailing slash. The following example creates a route with a trailing slash, and uses redirects
in the same object to add a redirect from the version of the route without the trailing slash to the version with a trailing slash.
{
"route_key": "edge-to-data-route",
"domain_key": "edge",
"zone_key": "zone-default-zone",
"shared_rules_key": "edge-to-data-shared-rules",
"route_match": {
"path": "/services/drive-data/2.0.0/",
"match_type": "prefix"
},
"prefix_rewrite": "/",
"redirects": [
{
"from": "^/services/drive-data/2\\.0\\.0$",
"to": "/services/drive-data/2.0.0/",
"redirect_type": "permanent"
}
]
}
Rules
A rule
set on a route or shared rules can be used to specify the cluster that a route should send requests to. To do this, set the constraints
key in the rules field for the desired cluster as described in route forwarding.
Adding additional, more complex specifications for a route match can also be configured using the methods
and matches
fields of the rules object. These can be used to configure additional constraints to be added to the route that a request must also meet in order to be considered a match.
The methods
field can be used to configure method matching on the route. The matches
field in the rules object allows for the addition of specific header, cookie, or query parameter matchers to the route match. This field takes a list of match
objects to add a series of these constraints.
Additionally, rules can be used to configure metadata matching for using load balancer subsets on the upstream cluster and it’s routes.
Method Match
The methods
field takes a list of values which will be matched against the method of the incoming request. If one value is provided, the match will be an exact match. If more than one is provided, the match will be a regex match to a pipe delimited list of the methods
values. If methods
are configured, the incoming request will be considered a match only if its method matches those configured here.
Header Match
A header matcher rule on the route will look for a specific header on the incoming request and compare it’s value to a configured value. To configure a header match in the matches
field as follows:
match.kind
set to"header"
match.from.key
set to the name of the header to check the incoming request formatch.from.value
set to value to compare to the value of the header in the request with keymatch.from.key
match.to.key
- not currently supported
- if configured, sets up a metadata match for the upstream cluster
- required if
match.to.value
is set
match.to.value
- not currently supported
- see metadata match
Note: if the
match.from.value
is a valid regex, regex matching will be used. Otherwise, it will be exact match.
Cookie Match
To configure a header matcher rule for a cookie on the route, configure a match in the matches
field as follows:
match.kind
set to"cookie"
match.from.key
set to the name of the cookie to check the incoming request’s cookies formatch.from.value
set to the value to compare to the value of the cookie in the request with keymatch.from.key
match.to.key
- not currently supported
- if configured, sets up a metadata match for the upstream cluster
- required if
match.to.value
is set
match.to.value
- not currently supported
- see metadata match
Note: for a cookie match, the match type will always be regex
If match.from.value
is left empty, a wildcard cookie match will be used.
Query Parameter Match
To configure a query parameter matcher on the route, configure a match in the matches
field as follows:
match.kind
set to"query"
match.from.key
set to the name of the query parameter to check the incoming request’s query string formatch.from.value
set to the value to compare to the value of the query parameter in the request with keymatch.from.key
match.to.key
- not currently supported
- if configured, sets up a metadata match for the upstream cluster
- required if
match.to.value
is set
match.to.value
- not currently supported
- see metadata match
Retry Policies
A retry policy can be implemented on a route in the retry_policy
field.
Per Route Filter Configuration
The route object field filter_configs
can be used to set greymatter.io filters on specific routes.
Example:
"filter_configs": {
"gm.observables": {
"emitFullResponse": true
},
"gm.oidc-validation": {
"enforce": true,
"enforceResponseCode": 401
}
}
Filters that currently support per route configurations are:
gm.observables
gm.oidc-validation
gm.metrics
gm.listauth
gm.oauth
envoy.buffer
envoy.ext_authz
envoy.filters.http.rbac
filter-metdata
(deprecated)
Note This method of configuring filters at the route level is deprecated may not be supported in the next major release. Use filter_configs
instead (see above).
The route object field filter_metadata
can be used to set greymatter.io filters on specific routes.
The filter_metadata
takes a map from the name of the filter to configure for the route, and the corresponding key, value pair should indicate the filter configuration field and the value to set it to. Note that the filter being customized has to be active in the listener active filters for the service in order to set per route configurations. The filter_metadata
configuration will look like the following:
"filter_metadata": {
"<filter-name>": [
{
"key": "<filter configuration key to set value for>",
"value": "<desired value of key>"
}
]
}
All filters listed above support this; however, the only values that can be configured are string “key”: “value” pairs.