Light Dark Auto

Configure Routing

Configure routing and rewrite rules

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

AttributeTypeDefaultDescription
shared_rules.default

JSON map of constraintType : constraint

{}

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

string

""

The pathname for a given route, which the request must match.

route.prefix_rewrite

string

""

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 for
  • match.from.value set to value to compare to the value of the header in the request with key match.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

Note: if the match.from.value is a valid regex, regex matching will be used. Otherwise, it will be exact 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 for
  • match.from.value set to the value to compare to the value of the cookie in the request with key match.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

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 for
  • match.from.value set to the value to compare to the value of the query parameter in the request with key match.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

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:

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.