Kong Gateway supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols.
Each of these protocols accept a different set of routing attributes:
-
http
: methods
, hosts
, headers
, paths
(and snis
, if https
)
-
tcp
: sources
, destinations
(and snis
, if tls
)
-
grpc
: hosts
, headers
, paths
(and snis
, if grpcs
)
Note that all of these fields are optional, but at least one of them
must be specified.
For a request to match a route:
- The request must include all of the configured fields
- The values of the fields in the request must match at least one of the
configured values. While the field configurations accept one or more values,
a request needs only one of the values to be considered a match.
Let’s go through a few examples. Consider a route configured like the following:
{
"hosts": ["example.com", "foo-service.com"],
"paths": ["/foo", "/bar"],
"methods": ["GET"]
}
Some of the possible requests matching this route would look like the following:
GET /foo HTTP/1.1
Host: example.com
GET /bar HTTP/1.1
Host: foo-service.com
GET /foo/hello/world HTTP/1.1
Host: example.com
All three of these requests satisfy all the conditions set in the route
definition.
However, the following requests would not match the configured conditions:
GET / HTTP/1.1
Host: example.com
POST /foo HTTP/1.1
Host: example.com
GET /foo HTTP/1.1
Host: foo.com
All three of these requests satisfy only two of configured conditions. The
first request’s path is not a match for any of the configured paths
, same for
the second request’s HTTP method, and the third request’s Host header.
Now that we understand how the routing properties work together, let’s explore
each property individually.
Kong Gateway supports routing by arbitrary HTTP headers. A special case of this
feature is routing by the Host header.
Routing a request based on its Host header is the most straightforward way to
proxy traffic through Kong Gateway, especially since this is the intended usage of the
HTTP Host header. Kong Gateway makes it easy to do via the hosts
field of the route
entity.
hosts
accepts multiple values, which must be comma-separated when specifying
them via the Admin API:
curl -i -X POST http://localhost:8001/routes/ \
--header 'Content-Type: application/json' \
--data '{"hosts":["example.com", "foo-service.com"]}'
To satisfy the hosts
condition of this route, any incoming request from a
client must now have its Host header set to one of:
or:
Similarly, any other header can be used for routing:
curl -i -X POST http://localhost:8001/routes/ \
--data 'headers.region=north'
Incoming requests containing a Region
header set to North
are routed to
said route.
To provide flexibility, Kong Gateway allows you to specify hostnames with wildcards in
the hosts
field. Wildcard hostnames allow any matching Host header to satisfy
the condition, and thus match a given Route.
Wildcard hostnames must contain only one asterisk at the leftmost
or rightmost label of the domain. For example:
-
*.example.com
would allow Host values such as a.example.com
and
x.y.example.com
to match.
-
example.*
would allow Host values such as example.com
and example.org
to match.
A complete example would look like this:
{
"hosts": ["*.example.com", "service.com"]
}
Which would allow the following requests to match this route:
GET / HTTP/1.1
Host: an.example.com
GET / HTTP/1.1
Host: service.com
It’s possible to route requests by other headers besides Host
.
To do this, use the headers
property in your route:
{
"headers": { "version": ["v1", "v2"] },
"service": {
"id": "..."
}
}
Given a request with a header such as:
GET / HTTP/1.1
version: v1
This request will be routed through to the Service. The same happens with this one:
GET / HTTP/1.1
version: v2
This request isn’t routed to the Service:
GET / HTTP/1.1
version: v3
Note: The headers
keys are a logical AND
and their values a logical OR
.
Another way for a route to be matched is via request paths. To satisfy this
routing condition, a client request’s normalized path must be prefixed with one of the
values of the paths
attribute.
For example, with a route configured like so:
{
"paths": ["/service", "/hello/world"]
}
The following requests would be matched:
GET /service HTTP/1.1
Host: example.com
GET /service/resource?param=value HTTP/1.1
Host: example.com
GET /hello/world/resource HTTP/1.1
Host: anything.com
For each of these requests, Kong Gateway detects that their normalized URL path is prefixed with
one of the routes’ paths
values. By default, Kong Gateway would then proxy the
request upstream without changing the URL path.
When proxying with path prefixes, the longest paths get evaluated first.
This allows you to define two routes with two paths, such as /service
and
/service/resource
, and ensure that the former doesn’t overshadow the latter.
For a path to be considered a regular expression, it must be prefixed with a ~
:
Any path that isn’t prefixed with a ~
is considered plain text:
"paths": ["/users/\d+/profile", "/following"]
For more information about how the router processes regular expressions, see the routing performance considerations.
The router evaluates routes using the regex_priority
field of the
Route
where a route is configured. Higher regex_priority
values
mean higher priority.
[
{
"paths": ["~/status/d+"],
"regex_priority": 0
},
{
"paths": ["~/version/d+/status/d+"],
"regex_priority": 6
},
{
"paths": ["/version"]
},
{
"paths": ["~/version/any/"]
}
]
In this scenario, Kong Gateway evaluates incoming requests against the following
defined URIs, in this order:
/version/\d+/status/\d+
/status/\d+
/version/any/
/version
Routers with a large number of regexes can consume traffic intended for other rules.
Regular expressions are much more expensive to build and execute and can’t be optimized easily.
You can avoid creating complex regular expressions using the Router Expressions language.
If you see unexpected behavior, use the Kong debug header to help track down the source:
- In
kong.conf
, set allow_debug_header=on
.
- Send
Kong-Debug: 1
in your request headers to indicate the matched route ID in the response headers for
troubleshooting purposes.
As usual, a request must still match a Route’s hosts
and methods
properties
as well, and Kong Gateway traverses your Routes until it finds one that matches
the most rules.
Capture groups are also supported, and the matched group will be extracted
from the path and available for plugins consumption. Consider the
following regex:
/version/(?<version>\d+)/users/(?<user>\S+)
And the following request path:
Kong Gateway considers the request path a match, and if the overall Route is
matched (considering other routing attributes), the extracted capture groups
will be available from the plugins in the ngx.ctx
variable:
local router_matches = ngx.ctx.router_matches
-- router_matches.uri_captures is:
-- { "1", "john", version = "1", user = "john" }
Keep the following path matching criteria in mind when configuring paths:
-
Regex in paths: For a path to be considered a regular expression, it must be prefixed with a
~
.
You can avoid creating complex regular expressions using the Router Expressions language.
-
Capture groups: Regex capture groups are also supported, and the matched group is extracted from the path and available for plugin consumption.
-
Escaping special characters: When configuring Routes with regex paths via the Admin API, be sure to URL encode your payload if necessary according to RFC 3986.
-
Normalization behavior: To prevent Route match bypasses, the incoming request URI from the client is always normalized according to RFC 3986 before router matching occurs.
To prevent trivial route match bypass, the incoming request URI from the client
is always normalized according to RFC 3986
before router matching occurs. Specifically, the following normalization techniques are
used for incoming request URIs, which are selected because they generally don’t change
semantics of the request URI:
- Percent-encoded triplets are converted to uppercase. For example:
/foo%3a
becomes /foo%3A
.
- Percent-encoded triplets of unreserved characters are decoded. For example:
/fo%6F
becomes /foo
.
- Dot segments are removed as necessary. For example:
/foo/./bar/../baz
becomes /foo/baz
.
- Duplicate slashes are merged. For example:
/foo//bar
becomes /foo/bar
.
The values in the paths
attribute of the Route object are also normalized. This is achieved by first determining
if the path is a plain text or regex path. Based on the result, different normalization techniques
are used:
- Plain text route path: Uses the same normalization technique as above, that is, methods 1 through 4.
- Regex route path: Only uses methods 1 and 2. In addition, if the decoded character becomes a regex
meta character, it will be escaped with a backslash.
Kong Gateway normalizes any incoming request URI before performing router
matches. As a result, any request URI sent over to the upstream services will also
be in normalized form, which preserves the original URI semantics.
The methods
field allows matching the requests depending on their HTTP
method. It accepts multiple values. Its default value is empty, where the HTTP
method is not used for routing.
The following route allows routing via GET
and HEAD
:
{
"methods": ["GET", "HEAD"],
"service": {
"id": "..."
}
}
This route would be matched with the following requests:
HEAD /resource HTTP/1.1
Host: ...
This route wouldn’t match a POST
or DELETE
request. This allows for much more
granularity when configuring plugins on Routes. For example, you might have two routes pointing to the same service:
one with unlimited unauthenticated GET
requests, and a second one allowing only authenticated and rate-limited
POST
requests (by applying the authentication and rate limiting plugins to
those requests).
Note: This section only applies to TCP and TLS routes.
The sources
routing attribute allows
matching a route by a list of incoming connection IP and/or port sources.
The following route allows routing via a list of source IP/ports:
{
"protocols": ["tcp", "tls"],
"sources": [
{ "ip": "10.1.0.0/16", "port": 1234 },
{ "ip": "10.2.2.2" },
{ "port": 9123 }
],
"id": "..."
}
TCP or TLS connections originating from IPs in CIDR range “10.1.0.0/16” or IP
address “10.2.2.2” or Port “9123” would match such route.
Note: This section only applies to TCP and TLS routes.
The destinations
attribute, similarly to sources
,
allows matching a route by a list of incoming connection IP and/or port, but
uses the destination of the TCP/TLS connection as routing attribute.
When using secure protocols (https
, grpcs
, or tls
), a
Server Name Indication can be used as a routing attribute.
The following route allows routing via SNIs:
{
"snis": ["foo.test", "example.com"],
"id": "..."
}
Incoming requests with a matching hostname set in the TLS connection’s SNI
extension would be routed to this route.
SNI routing also applies to other protocols carried over TLS, such as HTTPS.
If multiple SNIs are specified in the route, any of them can match the incoming request’s SNI.
The SNI is indicated at TLS handshake time and can’t be modified after the TLS connection has
been established. This means, for example, that multiple requests reusing the same keepalive connection
will have the same SNI hostname while performing router matches, regardless of the value in the Host
header.