From 2f5f4c0a0e06a92ddd61f9b413100fd5b3526b64 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Tue, 21 Jan 2025 15:42:23 +0000 Subject: [PATCH 01/17] Simplify Service entity --- app/_gateway_entities/service.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/app/_gateway_entities/service.md b/app/_gateway_entities/service.md index 6b9673c52..385eefc36 100644 --- a/app/_gateway_entities/service.md +++ b/app/_gateway_entities/service.md @@ -4,7 +4,7 @@ content_type: reference entities: - service -description: A Gateway Service is an abstraction of an upstream application that services requests. +description: A Gateway Service represents your actual backend API or microservice. related_resources: - text: Routes entity @@ -34,17 +34,13 @@ api_specs: ## What is a Gateway Service? -A Gateway Service is an abstraction of an upstream application that services requests. -Services can store collections of objects like plugin configurations, and policies, and they can be associated with routes. +A Gateway Service represents your actual backend API or microservice. -When defining a Service, the administrator provides a name and the upstream application connection information. -The connection details can be provided in the URL field as a single string, or by providing individual values for protocol, host, port, and path individually. +For simple deployments, the upstream URL can be provided directly in the Service. For so phisticated traffic management needs, a Service can point at an [Upstream](/gateway/entities/upstream/). -Gateway Services have a one-to-many relationship with upstream applications, which allows administrators to create sophisticated traffic management behaviors. +Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}. -Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}. -{{site.base_gateway}} abstracts the service from the clients by using Routes. -Since the client always calls the Route, changes to the Services (like versioning) don't impact how clients make the call. +[Plugins](/gateway/entities/plugin/) can be attached to a Service, and will run against every request that triggers a request to the Service that they're attached to. {% mermaid %} flowchart LR From 1206a7af9756a01e17dc089f730195d885c5c8d5 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Tue, 21 Jan 2025 18:00:29 +0000 Subject: [PATCH 02/17] Service + Routes review --- app/_gateway_entities/route.md | 423 ++++++++++++++++++---- app/gateway/routing/expressions.md | 4 +- app/gateway/routing/traditional.md | 553 +++++++++++++++++++++++++++++ 3 files changed, 902 insertions(+), 78 deletions(-) create mode 100644 app/gateway/routing/traditional.md diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index 69d918e4f..dd714be31 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -12,6 +12,8 @@ related_resources: url: /gateway/entities/service/ - text: Expressions router url: /gateway/routing/expressions/ + - text: Traditional router + url: /gateway/routing/traditional/ - text: Upstream entity url: /gateway/entities/upstream/ @@ -26,79 +28,50 @@ schema: api: gateway/admin-ee path: /schemas/Route -faqs: - - q: How can I divert traffic from an old URL to a new one with {{site.base_gateway}}? - a: Create a new route and point it to the existing Gateway Service. The new route will proxy traffic to the existing service at the new URL. - --- ## What is a Route? -A Route is a path to a resource within an upstream application. In {{site.base_gateway}}, Routes typically map to endpoints exposed through [Gateway Services](/gateway/entities/service/). Routes determine how (and if) requests are sent to their Services after they reach {{site.base_gateway}}. Where a Service represents the backend API, a Route defines what is exposed to clients. +Routes fulfil two responsibilities in {{ site.base_gateway }}: -Routes can also define rules that match requests to associated Services. Because of this, one Route can reference multiple endpoints. Once a Route is matched, {{site.base_gateway}} proxies the request to its associated Service. A basic Route should have a name, path or paths, and reference an existing Service. +1. Match incoming requests and route them to the correct [Gateway Service](/gateway/entities/service/) +2. Use plugins to transform the request/response proxied using this Route -{% mermaid %} -flowchart LR - A(API client) - B("`Route - (/mock)`") - C("`Gateway Service - (example-service)`") - D(Upstream - application) - - A <--requests - responses--> B - subgraph id1 ["` - **KONG GATEWAY**`"] - B <--requests - responses--> C - end - C <--requests - responses--> D - - style id1 rx:10,ry:10 - -{% endmermaid %} +A Route must be attached to a [Service](/gateway/entities/service/), and _may_ have one or more [Plugin](/gateway/entities/plugin/) entities attached. ## Route and Service interaction -Routes, in conjunction with [Services](/gateway/entities/service/), let you expose your Services to applications with {{site.base_gateway}}. {{site.base_gateway}} abstracts the Service from the applications by using Routes. Since the application always uses the Route to make a request, changes to the Services, like versioning, don’t impact how applications make the request. Routes also allow the same Service to be used by multiple applications and apply different policies based on the Route used. +Routes, in conjunction with [Services](/gateway/entities/service/), let you expose your services to applications with {{site.base_gateway}}. Routes also allow the same service to be used by multiple applications and apply different policies based on the route used. For example, say you have an external application and an internal application that need to access the `example_service` Service, but the *external* application should be limited in how often it can query the Service to avoid a denial of service. If you apply a rate limit policy to the Service and the *internal* application calls it, the internal application is also limited. Routes can solve this problem. -In this example, you can create two Routes to handle the two applications, say `/external` and `/internal`, and point both of them to `example_service`. -You can configure a policy to limit how often the `/external` Route is used. -When the external application tries to access the Service via {{site.base_gateway}} using `/external`, it's rate limited. -But when the internal application accesses the Service using {{site.base_gateway}} using `/internal`, the internal application isn't limited. +In this example, you can create two Routes with different hosts to handle the two applications, say `internal.example.com` and `external.example.com`, and point both of them to `example_service`. +You can configure a policy to limit how often the external Route is used. +When the external application tries to access the Service via {{site.base_gateway}} using `external.example.com`, it's rate limited. +But when the internal application accesses the Service using {{site.base_gateway}} using `internal.example.com`, the internal application isn't limited. The following diagram illustrates this example: {% mermaid %} flowchart LR A(External application) - B("`Route (/external)`") - B2(Rate Limiting - plugin) + B("`Route (external.example.com)`") + B2(Rate Limiting plugin) C("`Service (example-service)`") D(Upstream application) E(Internal application) - F("`Route (/internal)`") + F("`Route (internal.example.com)`") A --request--> B E --request--> F subgraph id1 ["` **KONG GATEWAY**`"] - B --> B2 --"10 requests - per minute"--> C + B --> B2 --"10 requests per minute"--> C F ---> C end - C --transformed - and routed - requests--> D + C --> D style id1 rx:10,ry:10 @@ -115,58 +88,354 @@ Common use cases for Routes: | Perform a complex URL rewrite | Use the Routes entity to rewrite a group of paths, such as replacing `/api//old` with `/new/api/`.

[Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) | | Describe paths as patterns using regular expressions | [Expressions router](/gateway/routing/expressions/) | -## How routing works +## Configuration formats -For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. As soon as a Route yields a match, the router stops matching and {{site.base_gateway}} uses the matched Route to [proxy the current request](/gateway/traffic-control/proxying/). +{{site.base_gateway}} provides two methods to define Routes. The traditional JSON format, and a more powerful DSL-based expressions format. The router used is configured via the `router_flavor` property in `kong.conf`. -If multiple Routes match, {{site.base_gateway}} handles routing in the following order: +The router you should use depends on your use case and {{site.base_gateway}} version: +* **[Expressions router](/gateway/routing/expressions/):** The recommended method for anyone running {{site.base_gateway}} 3.4.x or later. Handles complex routing logic efficiently. +* **[Traditional router](/gateway/routing/traditional/):** +The original {{ site.base_gateway }} routing configuration format. Provide your matching criteria in JSON format. -1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. -1. If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their [priority](#priority-matching) and uses the highest priority matching Route to handle a request. +Setting `router_flavor` to `expressions` allows you to configure both expression based and JSON based routing criteria at the same time. If an `expression` route matches, the JSON format router will not run, regardless of the JSON priority set. -{{site.base_gateway}} provides two different routers, enabled via the `router_flavor` property in `kong.conf`. The router you should use depends on your use case and {{site.base_gateway}} version: -* **[Expressions router](/gateway/routing/expressions/):** The recommended method for anyone running {{site.base_gateway}} 3.4.x or later. Can be run in both `traditional_compat` and `expressions` modes. Handles complex routing logic and regex in Routes. -* **Traditional compatibility router:** Only recommended for anyone running {{site.base_gateway}} 2.9.x or earlier. The default routing method for {{site.base_gateway}}. Doesn't handle complex routing logic. +To disble the DSL based format, set `router_flavor` to `traditional_compat`. Only JSON routes will be accepted with this configuration. -### Path matching +## Routing criteria -Keep the following path matching criteria in mind when configuring paths: +You can match incoming requests against the following routing criteria: -* **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](/gateway/routing/expressions/). -* **Capturing groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins 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](https://tools.ietf.org/html/rfc3986). -* **Normalization behavior:** To prevent trivial Route match bypass, the incoming request URI from client -is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) -before router matching occurs. +- Protocols: The protocol used to communicate with the upstream application. +- Hosts: Lists of domains that match a route +- Methods: HTTP methods that match a route +- Headers: Lists of values that are expected in the header of a request +- Port: The request's source/destination port +- SNI: The server name indicated in a TLS request - Regex Route paths only use methods 1 and 2. In addition, if the decoded character becomes a regex meta character, it will be escaped with backslash. +For detailed examples of each, see the dedicated [expressions](/gateway/routing/expressions/#routing-criteria) or [traditional](/gateway/routing/traditional/#routing-criteria) sections. + +## How routing works + +For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. + +{{site.base_gateway}} handles routing in the following order: + +1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. +1. If multiple Routes match, the {{site.base_gateway}} router orders all defined Routes by their [priority](#priority-matching) and uses the highest priority matching Route to handle a request. + +Once all routing rules have been evaluated, {{ site.base_gateway }} uses the matched Route to [proxy the current request](/gateway/traffic-control/proxying/). ### Priority matching If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. How Routes are prioritized depends on the router mode you're using. -#### Traditional compatibility mode +For more information, see the detailed [expressions](/gateway/routing/expressions/#priority-matching) or [traditional](/gateway/routing/traditional/#priority-matching) sections. + +### Route behavior + +The Route entity allows you to configure proxy behaviour on a per route basis by setting the `strip_path`, `preserve_host` and `path_handling` values. + +#### strip_path + +It may be desirable to specify a path prefix to match a route, but not +include it in the upstream request. To do so, use the `strip_path` boolean +property by configuring a route like so: + +```json +{ + "paths": ["/service"], + "strip_path": true, + "service": { + "id": "..." + } +} +``` + +Enabling this flag instructs {{site.base_gateway}} that when matching this route, and proceeding +with the proxying to a service, it should **not** include the matched part of +the URL path in the upstream request's URL. For example, the following +client's request to the above route: + +```http +GET /service/path/to/resource HTTP/1.1 +Host: ... +``` -In `traditional_compat` mode, the priority of a Route is determined as -follows, by the order of descending significance: +This causes {{site.base_gateway}} to send the following upstream request: -1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. -2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. -3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. -4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. -5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. +```http +GET /path/to/resource HTTP/1.1 +Host: ... +``` -When two Routes have the same path, {{site.base_gateway}} uses a tiebreaker. For example, if the rule count for the given request is the same for both Routes `A` and `B`, then the following tiebreaker rules are applied in the order they are listed. Route `A` will be selected over `B` if: - * `A` has only plain Host headers and `B` has one or more wildcard - host headers - * `A` has more non-Host headers than `B` - * `A` has at least one regex path and `B` has only plain paths - * `A`'s longest path is longer than `B`'s longest path - * `A.created_at < B.created_at` +The same way, if a Regex path is defined on a route that has `strip_path` +enabled, the entirety of the request URL matching sequence will be stripped. +For example: -#### Expressions router mode +```json +{ + "paths": ["/version/\d+/service"], + "strip_path": true, + "service": { + "id": "..." + } +} +``` -In [`expressions` mode](/gateway/routing/expressions/), when a request comes in, {{site.base_gateway}} evaluates Routes with a higher `priority` number first. The priority is a positive integer that defines the order of evaluation of the router. The larger the priority integer, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. +The following HTTP request matching the provided Regex path: + +```http +GET /version/1/service/path/to/resource HTTP/1.1 +Host: ... +``` + +Is proxied upstream by {{site.base_gateway}} as: + +```http +GET /path/to/resource HTTP/1.1 +Host: ... +``` + +#### preserve_host + +When proxying, {{site.base_gateway}}'s default behavior is to set the upstream request's Host +header to the hostname specified in the service's `host`. The +`preserve_host` field accepts a boolean flag instructing {{site.base_gateway}} not to do so. + +For example, when the `preserve_host` property is not changed and a route is +configured like so: + +```json +{ + "hosts": ["service.com"], + "service": { + "id": "..." + } +} +``` + +A possible request from a client to {{site.base_gateway}} could be: + +```http +GET / HTTP/1.1 +Host: service.com +``` + +{{site.base_gateway}} would extract the Host header value from the service's `host` property, , +and would send the following upstream request: + +```http +GET / HTTP/1.1 +Host: +``` + +However, by explicitly configuring a route with `preserve_host=true`: + +```json +{ + "hosts": ["service.com"], + "preserve_host": true, + "service": { + "id": "..." + } +} +``` + +And assuming the same request from the client: + +```http +GET / HTTP/1.1 +Host: service.com +``` + +{{site.base_gateway}} would preserve the Host on the client request and would send the following +upstream request instead: + +```http +GET / HTTP/1.1 +Host: service.com +``` + +### path_handling + +The `path_handling` parameter accepts `v0` or `v1`. + +`"v0"` is the behavior used in Kong 0.x, 2.x and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed. + +`"v1"` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`. + +{:.warning} +> `path_handling` v1 is not supported in the `expressions` router and may be removed in a future version of {{ site.base_gateway }}. We **strongly** recommend using `v0`. + +Both versions of the algorithm detect "double slashes" when combining paths, replacing them by single +slashes. + +
+ +Expand to see a table showing detailed v0 and v1 examples + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
service.pathroute.pathrequestroute.strip_pathroute.path_handlingrequest pathupstream path
/s/fv0reqfalsev0/fv0/req/s/fv0/req
/s/fv0blankfalsev0/fv0/s/fv0
/s/fv1reqfalsev1/fv1/req/sfv1/req
/s/fv1blankfalsev1/fv1/sfv1
/s/tv0reqtruev0/tv0/req/s/req
/s/tv0blanktruev0/tv0/s
/s/tv1reqtruev1/tv1/req/s/req
/s/tv1blanktruev1/tv1/s
/s/fv0/reqfalsev0/fv0/req/s/fv0/req
/s/fv0/blankfalsev0/fv0//s/fv01/
/s/fv1/reqfalsev1/fv1/req/sfv1/req
/s/fv1/blankfalsev1/fv1//sfv1/
/s/tv0/reqtruev0/tv0/req/s/req
/s/tv0/blanktruev0/tv0//s/
/s/tv1/reqtruev1/tv1/req/sreq
/s/tv1/blanktruev1/tv1//s
+ +
### Routing performance recommendations diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 9a12216b4..d82983d6d 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -14,6 +14,8 @@ related_resources: url: /gateway/entities/route/ - text: Expressions repository url: https://github.com/Kong/atc-router + - text: Traditional router + url: /gateway/routing/traditional/ min_version: gateway: '3.0' @@ -85,7 +87,7 @@ This section explains how to optimize the expressions you write to get the most ### Number of routes -#### Route matching priority order +#### Priority Matching Expressions routes are always evaluated in the descending `priority` order they were defined. Therefore, it is helpful to put more likely matched routes before (as in, higher priority) diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md new file mode 100644 index 000000000..beef1a77d --- /dev/null +++ b/app/gateway/routing/traditional.md @@ -0,0 +1,553 @@ +--- +title: Traditional router + +description: "The traditional router is a collection of Routes that are all evaluated against incoming requests until a match can be found." + +content_type: reference +layout: reference + +products: + - gateway + +related_resources: + - text: Route entity + url: /gateway/entities/route/ + - text: Expressions router + url: /gateway/routing/expressions/ + +min_version: + gateway: "3.0" + +breadcrumbs: + - /gateway/ + +faqs: + - q: When should I use the traditional router? + a: "@TODO: When using APIOps transforms" +--- + +The traditional router is {{ site.base_gateway }}'s original routing configuration format. It uses JSON to provide a list of routing criteria, including `host`, `path` and `headers`. + +Routing based on JSON configuration is available when `router_flavor` is set to both `traditional_compat` _or_ `expressions` in `kong.conf`. + +## How routing works + +### Priority Matching + +In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: + +1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. +2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. +3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. +4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. +5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. + + +For example, if two routes are configured like so: + +```json +{ + "hosts": ["example.com"], + "service": { + "id": "..." + } +}, +{ + "hosts": ["example.com"], + "methods": ["POST"], + "service": { + "id": "..." + } +} +``` + +The second route has a `hosts` field **and** a `methods` field, so it is +evaluated first by {{site.base_gateway}}. By doing so, we avoid the first route "shadowing" +calls intended for the second one. + +Thus, this request matches the first route: + +```http +GET / HTTP/1.1 +Host: example.com +``` + +And this request matches the second one: + +```http +POST / HTTP/1.1 +Host: example.com +``` + +Following this logic, if a third route was to be configured with a `hosts` +field, a `methods` field, and a `paths` field, it would be evaluated first by +{{site.base_gateway}}. + +If the rule count for the given request is the same in two routes `A` and +`B`, then the following tiebreaker rules will be applied in the order they +are listed. Route `A` will be selected over `B` if: + +- `A` has only plain Host headers and `B` has one or more wildcard + host headers +- `A` has more non-Host headers than `B` +- `A` has at least one regex path and `B` has only plain paths +- `A`'s longest path is longer than `B`'s longest path +- `A.created_at < B.created_at` + +### Path matching + +Keep the following path matching criteria in mind when configuring paths: + +1. **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](/gateway/routing/expressions/). +1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. +1. **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](https://tools.ietf.org/html/rfc3986). +1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. + +### Normalization behavior + +To prevent trivial route match bypass, the incoming request URI from client +is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) +before router matching occurs. Specifically, the following normalization techniques are +used for incoming request URIs, which are selected because they generally do not change +semantics of the request URI: + +1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. +2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. +3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. +4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. + +The `paths` attribute of the Route object are also normalized. It is achieved by first determining +if the path is a plain text or regex path. Based on the result, different normalization techniques +are used. + +For plain text route path: + +Same normalization technique as above is used, that is, methods 1 through 4. + +For regex route path: + +Only methods 1 and 2 are used. In addition, if the decoded character becomes a regex +meta character, it will be escaped with backslash. + +{{site.base_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 that preserves the original URI semantics. + + +## Routing criteria + +{{site.base_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 accepts 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: + +```json +{ + "hosts": ["example.com", "foo-service.com"], + "paths": ["/foo", "/bar"], + "methods": ["GET"] +} +``` + +Some of the possible requests matching this route would look like the following: + +```http +GET /foo HTTP/1.1 +Host: example.com +``` + +```http +GET /bar HTTP/1.1 +Host: foo-service.com +``` + +```http +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: + +```http +GET / HTTP/1.1 +Host: example.com +``` + +```http +POST /foo HTTP/1.1 +Host: example.com +``` + +```http +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. + +### Request header + +{{site.base_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 {{site.base_gateway}}, especially since this is the intended usage of the +HTTP Host header. {{site.base_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: + +```bash +curl -i -X POST http://localhost:8001/routes/ \ + -H 'Content-Type: application/json' \ + -d '{"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: + +``` +Host: example.com +``` + +or: + +``` +Host: foo-service.com +``` + +Similarly, any other header can be used for routing: + +```sh +curl -i -X POST http://localhost:8001/routes/ \ + -d 'headers.region=north' +``` + +Incoming requests containing a `Region` header set to `North` are routed to +said route. + +#### Using wildcard hostnames + +To provide flexibility, {{site.base_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: + +```json +{ + "hosts": ["*.example.com", "service.com"] +} +``` + +Which would allow the following requests to match this route: + +```http +GET / HTTP/1.1 +Host: an.example.com +``` + +```http +GET / HTTP/1.1 +Host: service.com +``` + +### Additional request headers + +It's possible to route requests by other headers besides `Host`. + +To do this, use the `headers` property in your route: + +```json +{ + "headers": { "version": ["v1", "v2"] }, + "service": { + "id": "..." + } +} +``` + +Given a request with a header such as: + +```http +GET / HTTP/1.1 +version: v1 +``` + +This request will be routed through to the service. The same happens with this one: + +```http +GET / HTTP/1.1 +version: v2 +``` + +But this request isn't routed to the service: + +```http +GET / HTTP/1.1 +version: v3 +``` + +**Note**: The `headers` keys are a logical `AND` and their values a logical `OR`. + +### Request path + +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: + +```json +{ + "paths": ["/service", "/hello/world"] +} +``` + +The following requests would be matched: + +```http +GET /service HTTP/1.1 +Host: example.com +``` + +```http +GET /service/resource?param=value HTTP/1.1 +Host: example.com +``` + +```http +GET /hello/world/resource HTTP/1.1 +Host: anything.com +``` + +For each of these requests, {{site.base_gateway}} detects that their normalized URL path is prefixed with +one of the routes' `paths` values. By default, {{site.base_gateway}} would then proxy the +request upstream without changing the URL path. + +When proxying with path prefixes, **the longest paths get evaluated first**. +This allow you to define two routes with two paths: `/service` and +`/service/resource`, and ensure that the former does not "shadow" the latter. + +#### Using Regex in paths + +For a path to be considered a regular expression, it must be prefixed with a `~`: + +``` +paths: ["~/foo/bar$"] +``` + +Any path that isn't prefixed with a `~` will be considered plain text: + +``` +"paths": ["/users/\d+/profile", "/following"] +``` + +For more information about how the router processes regular expressions, see [performance considerations when using Expressions](/gateway/latest/key-concepts/routes/expressions/#performance-considerations-when-using-expressions). + +##### Evaluation order + +The router evaluates routes using the `regex_priority` field of the +`Route` where a route is configured. Higher `regex_priority` values +mean higher priority. + +```json +[ + { + "paths": ["~/status/\d+"], + "regex_priority": 0 + }, + { + "paths": ["~/version/\d+/status/\d+"], + "regex_priority": 6 + }, + { + "paths": /version, + }, + { + "paths": ["~/version/any/"], + } +] +``` + +In this scenario, {{site.base_gateway}} evaluates incoming requests against the following +defined URIs, in this order: + +1. `/version/\d+/status/\d+` +2. `/status/\d+` +3. `/version/any/` +4. `/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](/gateway/latest/reference/router-expressions-language/). + +{% if_version lte:3.1.x %} +If you see unexpected behavior, sending `Kong-Debug: 1` in your +request headers will indicate the matched route ID in the response headers for +{% endif_version %} + +{% if_version gte:3.2.x %} +If you see unexpected behavior, use the Kong debug header to help track down the source: + +1. In `kong.conf`, set [`allow_debug_header: on`](/gateway/{{page.release}}/reference/configuration/#allow_debug_header). +1. Send `Kong-Debug: 1` in your request headers to indicate the matched route ID in the response headers for + troubleshooting purposes. + {% endif_version %} + +As usual, a request must still match a route's `hosts` and `methods` properties +as well, and {{site.base_gateway}} traverses your routes until it finds one that [matches +the most rules](#matching-priorities). + +##### Capturing groups + +Capturing groups are also supported, and the matched group will be extracted +from the path and available for plugins consumption. If we consider the +following regex: + +``` +/version/(?\d+)/users/(?\S+) +``` + +And the following request path: + +``` +/version/1/users/john +``` + +{{site.base_gateway}} considers the request path a match, and if the overall route is +matched (considering other routing attributes), the extracted capturing groups +will be available from the plugins in the `ngx.ctx` variable: + +```lua +local router_matches = ngx.ctx.router_matches + +-- router_matches.uri_captures is: +-- { "1", "john", version = "1", user = "john" } +``` + + +### Request HTTP method + +The `methods` field allows matching the requests depending on their HTTP +method. It accepts multiple values. Its default value is empty (the HTTP +method is not used for routing). + +The following route allows routing via `GET` and `HEAD`: + +```json +{ + "methods": ["GET", "HEAD"], + "service": { + "id": "..." + } +} +``` + +Such a route would be matched with the following requests: + +```http +GET / HTTP/1.1 +Host: ... +``` + +```http +HEAD /resource HTTP/1.1 +Host: ... +``` + +But it would not match a `POST` or `DELETE` request. This allows for much more +granularity when configuring plugins on routes. For example, one could imagine +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 +such requests). + +### Request source + +{:.note} +> **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: + +```json +{ + "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. + +### Request destination + +{:.note} +> **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. + +### Request SNI + +When using secure protocols (`https`, `grpcs`, or `tls`), a [Server +Name Indication][SNI] can be used as a routing attribute. The following route +allows routing via SNIs: + +```json +{ + "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. As mentioned, SNI routing applies not +only to TLS, but also to other protocols carried over TLS - such as HTTPS and +If multiple SNIs are specified in the route, any of them can match with the incoming request's SNI. +with the incoming request (OR relationship between the names). + +The SNI is indicated at TLS handshake time and cannot 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 match, regardless of the `Host` header. +has been established. This means keepalive connections that send multiple requests +will have the same SNI hostnames while performing router match +(regardless of the `Host` header). + +Please note that creating a route with mismatched SNI and `Host` header matcher +is possible, but generally discouraged. From f42c3ed9c7b502065e7e8537c57ffd70674af1be Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 13:15:58 +0000 Subject: [PATCH 03/17] More Route entity updates --- app/_gateway_entities/route.md | 30 +-- app/gateway/routing/expressions.md | 19 +- app/gateway/routing/traditional.md | 286 ++++++++++++++--------------- 3 files changed, 167 insertions(+), 168 deletions(-) diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index dd714be31..f007659a9 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -17,6 +17,12 @@ related_resources: - text: Upstream entity url: /gateway/entities/upstream/ +next_steps: + - text: Learn about the Expressions router + url: /gateway/routing/expressions/ + - text: Learn about the Traditional router + url: /gateway/routing/traditional/ + tools: - admin-api - konnect-api @@ -86,7 +92,6 @@ Common use cases for Routes: | Rate limiting | Use Routes to set different rate limits for clients accessing the upstream application via specific paths, for example `/internal` or `/external`.

[Enable a rate limiting plugin on Routes attached to the Service](/plugins/rate-limiting-advanced/) | | Perform a simple URL rewrite | Use the Routes entity to rename an endpoint. For example, you can rename your legacy `/api/old/` upstream endpoint to a publicly accessible API endpoint named `/new/api`. | | Perform a complex URL rewrite | Use the Routes entity to rewrite a group of paths, such as replacing `/api//old` with `/new/api/`.

[Request Transformer Advanced plugin](/plugins/request-transformer-advanced/) | -| Describe paths as patterns using regular expressions | [Expressions router](/gateway/routing/expressions/) | ## Configuration formats @@ -116,25 +121,22 @@ For detailed examples of each, see the dedicated [expressions](/gateway/routing/ ## How routing works -For each incoming request, {{site.base_gateway}} must determine which Service gets to handle it based on the Routes that are defined. +For each incoming request, {{site.base_gateway}} must determine which Service will handle it based on the Routes that are defined. -{{site.base_gateway}} handles routing in the following order: - -1. {{site.base_gateway}} finds Routes that match the request by comparing the defined routing attributes with the attributes in the request. -1. If multiple Routes match, the {{site.base_gateway}} router orders all defined Routes by their [priority](#priority-matching) and uses the highest priority matching Route to handle a request. - -Once all routing rules have been evaluated, {{ site.base_gateway }} uses the matched Route to [proxy the current request](/gateway/traffic-control/proxying/). +The {{site.base_gateway}} router orders all defined Routes by their [priority](#priority-matching) and uses the highest priority matching Route to [proxy the request](/gateway/traffic-control/proxying/). ### Priority matching -If multiple Routes match, the {{site.base_gateway}} router then orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. How Routes are prioritized depends on the router mode you're using. +To maximise performance, the {{site.base_gateway}} router orders all defined Routes by their priority and uses the highest priority matching Route to handle a request. How Routes are prioritized depends on the router mode you're using. -For more information, see the detailed [expressions](/gateway/routing/expressions/#priority-matching) or [traditional](/gateway/routing/traditional/#priority-matching) sections. +For more information, see the detailed [expressions](/gateway/routing/expressions/#priority-matching) or [traditional](/gateway/routing/traditional/#route-priority) sections. ### Route behavior The Route entity allows you to configure proxy behaviour on a per route basis by setting the `strip_path`, `preserve_host` and `path_handling` values. +In most cases, `strip_path` and `preserve_host` should be `false` (this is the default value), and `path_handling` should be set to `v0`. + #### strip_path It may be desirable to specify a path prefix to match a route, but not @@ -260,9 +262,9 @@ Host: service.com The `path_handling` parameter accepts `v0` or `v1`. -`"v0"` is the behavior used in Kong 0.x, 2.x and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed. +`v0` is the behavior used in Kong 0.x, 2.x and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed. -`"v1"` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`. +`v1` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`. {:.warning} > `path_handling` v1 is not supported in the `expressions` router and may be removed in a future version of {{ site.base_gateway }}. We **strongly** recommend using `v0`. @@ -272,10 +274,10 @@ slashes.
-Expand to see a table showing detailed v0 and v1 examples +Expand this block to see a table showing detailed v0 and v1 examples - +
diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index d82983d6d..d1c986903 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -24,11 +24,15 @@ breadcrumbs: - /gateway/ faqs: - - q: When should I use the expressions router in place of (or alongside) the traditional router? - a: We recommend using the expressions router if you are running {{site.base_gateway}} 3.0.x or later. After enabling expressions, traditional match fields on the Route object (such as `paths` and `methods`) remain configurable. You may specify Expressions in the new `expression` field. However, these cannot be configured simultaneously with traditional match fields. Additionally, a new `priority` field, used in conjunction with the expression field, allows you to specify the order of evaluation for Expression Routes. + - q: Is there a performance difference between the traditional router and expressions? + a: Both Traditional and Expressions use the same routing engine internally. Traditional mode configures routes with JSON, and Expressions uses a DSL. + - q: Why would I choose Expressions over the Traditional router? + a: The Expressions router provides more routing flexibility, including fast exact matching that is not available in the Traditional router. + - q: When should I keep using the traditional router over expressions? + a: If you are working with APIOps pipelines that manipulate the route using `deck file patch`, the JSON format used by the traditional router is recommended --- -The expressions router is a collection of [Routes](/gateway/entities/route/) that are all evaluated against incoming requests until a match can be found. This allows for more complex routing logic than the traditional router and ensures good runtime matching performance. +The expressions router provides a Domain Specific Language (DSL) that allows for complex routing rule definition. The expressions router ensures good runtime matching performance by providing specific routing comparisons such as non-regex equality checks that are not available in the traditional router. You can do the following with the expressions router: * Prefix-based path matching @@ -45,10 +49,9 @@ In your `kong.conf` file, set `router_flavor = expressions` and restart your {{s ## How requests are routed with the expressions router -At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require, -and supplies the value of these fields to the router execution context. -Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is -updated incrementally as configured Routes change. +At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require, and supplies the value of these fields to the router execution context. + +Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is updated incrementally as configured Routes change. As soon as a Route yields a match, the router stops matching and the matched Route is used to process the current request/connection. @@ -168,7 +171,7 @@ http.path == "/foo/bar" || http.path == "/foo/bar/" http.path ~ r#"^/foo/?$"# ``` -## Expressions router reference +## Expressions router reference This reference explains the different configurable entities for the expressions router. diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md index beef1a77d..3440dd739 100644 --- a/app/gateway/routing/traditional.md +++ b/app/gateway/routing/traditional.md @@ -30,110 +30,6 @@ The traditional router is {{ site.base_gateway }}'s original routing configurati Routing based on JSON configuration is available when `router_flavor` is set to both `traditional_compat` _or_ `expressions` in `kong.conf`. -## How routing works - -### Priority Matching - -In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: - -1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. -2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. -3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. -4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. -5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. - - -For example, if two routes are configured like so: - -```json -{ - "hosts": ["example.com"], - "service": { - "id": "..." - } -}, -{ - "hosts": ["example.com"], - "methods": ["POST"], - "service": { - "id": "..." - } -} -``` - -The second route has a `hosts` field **and** a `methods` field, so it is -evaluated first by {{site.base_gateway}}. By doing so, we avoid the first route "shadowing" -calls intended for the second one. - -Thus, this request matches the first route: - -```http -GET / HTTP/1.1 -Host: example.com -``` - -And this request matches the second one: - -```http -POST / HTTP/1.1 -Host: example.com -``` - -Following this logic, if a third route was to be configured with a `hosts` -field, a `methods` field, and a `paths` field, it would be evaluated first by -{{site.base_gateway}}. - -If the rule count for the given request is the same in two routes `A` and -`B`, then the following tiebreaker rules will be applied in the order they -are listed. Route `A` will be selected over `B` if: - -- `A` has only plain Host headers and `B` has one or more wildcard - host headers -- `A` has more non-Host headers than `B` -- `A` has at least one regex path and `B` has only plain paths -- `A`'s longest path is longer than `B`'s longest path -- `A.created_at < B.created_at` - -### Path matching - -Keep the following path matching criteria in mind when configuring paths: - -1. **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](/gateway/routing/expressions/). -1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. -1. **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](https://tools.ietf.org/html/rfc3986). -1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. - -### Normalization behavior - -To prevent trivial route match bypass, the incoming request URI from client -is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) -before router matching occurs. Specifically, the following normalization techniques are -used for incoming request URIs, which are selected because they generally do not change -semantics of the request URI: - -1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. -2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. -3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. -4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. - -The `paths` attribute of the Route object are also normalized. It is achieved by first determining -if the path is a plain text or regex path. Based on the result, different normalization techniques -are used. - -For plain text route path: - -Same normalization technique as above is used, that is, methods 1 through 4. - -For regex route path: - -Only methods 1 and 2 are used. In addition, if the decoded character becomes a regex -meta character, it will be escaped with backslash. - -{{site.base_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 that preserves the original URI semantics. - - ## Routing criteria {{site.base_gateway}} supports native proxying of HTTP/HTTPS, TCP/TLS, and GRPC/GRPCS protocols. @@ -207,7 +103,7 @@ 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. -### Request header +### Host header {{site.base_gateway}} supports routing by arbitrary HTTP headers. A special case of this feature is routing by the Host header. @@ -283,7 +179,7 @@ GET / HTTP/1.1 Host: service.com ``` -### Additional request headers +### Headers It's possible to route requests by other headers besides `Host`. @@ -321,7 +217,7 @@ version: v3 **Note**: The `headers` keys are a logical `AND` and their values a logical `OR`. -### Request path +### Path 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 @@ -376,7 +272,7 @@ Any path that isn't prefixed with a `~` will be considered plain text: For more information about how the router processes regular expressions, see [performance considerations when using Expressions](/gateway/latest/key-concepts/routes/expressions/#performance-considerations-when-using-expressions). -##### Evaluation order +##### Regex evaluation order The router evaluates routes using the `regex_priority` field of the `Route` where a route is configured. Higher `regex_priority` values @@ -384,20 +280,20 @@ mean higher priority. ```json [ - { - "paths": ["~/status/\d+"], - "regex_priority": 0 - }, - { - "paths": ["~/version/\d+/status/\d+"], - "regex_priority": 6 - }, - { - "paths": /version, - }, - { - "paths": ["~/version/any/"], - } + { + "paths": ["~/status/d+"], + "regex_priority": 0 + }, + { + "paths": ["~/version/d+/status/d+"], + "regex_priority": 6 + }, + { + "paths": ["/version"] + }, + { + "paths": ["~/version/any/"] + } ] ``` @@ -410,28 +306,21 @@ defined URIs, in this order: 4. `/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](/gateway/latest/reference/router-expressions-language/). - -{% if_version lte:3.1.x %} -If you see unexpected behavior, sending `Kong-Debug: 1` in your -request headers will indicate the matched route ID in the response headers for -{% endif_version %} +You can avoid creating complex regular expressions using the [Router Expressions language](/gateway/routing/expressions/). -{% if_version gte:3.2.x %} If you see unexpected behavior, use the Kong debug header to help track down the source: -1. In `kong.conf`, set [`allow_debug_header: on`](/gateway/{{page.release}}/reference/configuration/#allow_debug_header). +1. In `kong.conf`, set [`allow_debug_header: on`](/gateway/{{page.release}}/reference/configuration/#allow_debug_header). @TODO: Update URL 1. Send `Kong-Debug: 1` in your request headers to indicate the matched route ID in the response headers for troubleshooting purposes. - {% endif_version %} As usual, a request must still match a route's `hosts` and `methods` properties as well, and {{site.base_gateway}} traverses your routes until it finds one that [matches the most rules](#matching-priorities). -##### Capturing groups +##### Capture groups -Capturing groups are also supported, and the matched group will be extracted +Capture groups are also supported, and the matched group will be extracted from the path and available for plugins consumption. If we consider the following regex: @@ -446,7 +335,7 @@ And the following request path: ``` {{site.base_gateway}} considers the request path a match, and if the overall route is -matched (considering other routing attributes), the extracted capturing groups +matched (considering other routing attributes), the extracted capture groups will be available from the plugins in the `ngx.ctx` variable: ```lua @@ -456,21 +345,59 @@ local router_matches = ngx.ctx.router_matches -- { "1", "john", version = "1", user = "john" } ``` +#### Path matching + +Keep the following path matching criteria in mind when configuring paths: + +1. **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](/gateway/routing/expressions/). +1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. +1. **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](https://tools.ietf.org/html/rfc3986). +1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. + +#### Path normalization + +To prevent trivial route match bypass, the incoming request URI from client +is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) +before router matching occurs. Specifically, the following normalization techniques are +used for incoming request URIs, which are selected because they generally do not change +semantics of the request URI: -### Request HTTP method +1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. +2. Percent-encoded triplets of unreserved characters are decoded. For example: `/fo%6F` becomes `/foo`. +3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. +4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. + +The `paths` attribute of the Route object are also normalized. It is achieved by first determining +if the path is a plain text or regex path. Based on the result, different normalization techniques +are used. + +For plain text route path: + +Same normalization technique as above is used, that is, methods 1 through 4. + +For regex route path: + +Only methods 1 and 2 are used. In addition, if the decoded character becomes a regex +meta character, it will be escaped with backslash. + +{{site.base_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 that preserves the original URI semantics. + +### HTTP method The `methods` field allows matching the requests depending on their HTTP -method. It accepts multiple values. Its default value is empty (the HTTP +method. It accepts multiple values. Its default value is empty (the HTTP method is not used for routing). The following route allows routing via `GET` and `HEAD`: ```json { - "methods": ["GET", "HEAD"], - "service": { - "id": "..." - } + "methods": ["GET", "HEAD"], + "service": { + "id": "..." + } } ``` @@ -493,9 +420,10 @@ two routes pointing to the same service: one with unlimited unauthenticated `POST` requests (by applying the authentication and rate limiting plugins to such requests). -### Request source +### Source {:.note} + > **Note:** This section only applies to TCP and TLS routes. The `sources` routing attribute allows @@ -505,25 +433,30 @@ The following route allows routing via a list of source IP/ports: ```json { - "protocols": ["tcp", "tls"], - "sources": [{"ip":"10.1.0.0/16", "port":1234}, {"ip":"10.2.2.2"}, {"port":9123}], - "id": "...", + "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. -### Request destination +### Destination {:.note} + > **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. -### Request SNI +### SNI When using secure protocols (`https`, `grpcs`, or `tls`), a [Server Name Indication][SNI] can be used as a routing attribute. The following route @@ -551,3 +484,64 @@ will have the same SNI hostnames while performing router match Please note that creating a route with mismatched SNI and `Host` header matcher is possible, but generally discouraged. + +## Route Priority + +In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: + +1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. +2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. +3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. +4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. +5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. + +For example, if two routes are configured like so: + +```json +{ + "hosts": ["example.com"], + "service": { + "id": "..." + } +}, +{ + "hosts": ["example.com"], + "methods": ["POST"], + "service": { + "id": "..." + } +} +``` + +The second route has a `hosts` field **and** a `methods` field, so it is +evaluated first by {{site.base_gateway}}. By doing so, we avoid the first route "shadowing" +calls intended for the second one. + +Thus, this request matches the first route: + +```http +GET / HTTP/1.1 +Host: example.com +``` + +And this request matches the second one: + +```http +POST / HTTP/1.1 +Host: example.com +``` + +Following this logic, if a third route was to be configured with a `hosts` +field, a `methods` field, and a `paths` field, it would be evaluated first by +{{site.base_gateway}}. + +If the rule count for the given request is the same in two routes `A` and +`B`, then the following tiebreaker rules will be applied in the order they +are listed. Route `A` will be selected over `B` if: + +- `A` has only plain Host headers and `B` has one or more wildcard + host headers +- `A` has more non-Host headers than `B` +- `A` has at least one regex path and `B` has only plain paths +- `A`'s longest path is longer than `B`'s longest path +- `A.created_at < B.created_at` From a1add148805aba0b81ee2d80668aacd986cb90ae Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 13:16:10 +0000 Subject: [PATCH 04/17] Update TOC to show h3 --- app/_layouts/with_aside.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/_layouts/with_aside.html b/app/_layouts/with_aside.html index b4cbb6584..9ce5d4a70 100644 --- a/app/_layouts/with_aside.html +++ b/app/_layouts/with_aside.html @@ -24,7 +24,7 @@ {% if page.toc != false %}
- {% include toc.html html=content h_min=2 h_max=2 id='toc' anchor_class='tab-button__vertical scroll-to' class="tabcolumn" %} + {% include toc.html html=content h_min=2 h_max=3 id='toc' anchor_class='tab-button__vertical scroll-to' class="tabcolumn" %}
{% endif %} From 601096664cbee59517cb9e30b326f3862f9fd131 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 13:48:33 +0000 Subject: [PATCH 05/17] Update Consumers page --- app/_gateway_entities/consumer.md | 67 +++++++++++++++---------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/app/_gateway_entities/consumer.md b/app/_gateway_entities/consumer.md index 193da32c3..e31f0a904 100644 --- a/app/_gateway_entities/consumer.md +++ b/app/_gateway_entities/consumer.md @@ -19,45 +19,40 @@ faqs: a: | Credentials are necessary to authenticate Consumers via various authentication mechanisms. The credential type depends on which authentication plugin you want to use. -

+ For example, a Key Authentication plugin requires an API key, and a Basic Authentication plugin requires a username and password pair. - q: What is the difference between Consumers and Applications? a: | - Applications provide developers the ability to get access to APIs managed by {{site.base_gateway}} or {{site.konnect_short_name}} - with no interaction from the Kong admin team to generate the required credentials. -

+ Applications provide developers the ability to get access to APIs managed by {{site.base_gateway}} or {{site.konnect_short_name}} with no interaction from the Kong admin team to generate the required credentials. Applications are managed using the Developer Portal. + With Consumers, the Kong team creates Consumers, generates credentials, and shares them with the developers that need access to the APIs. - You can think of Applications as a type of Consumer in Kong that allows developers to automatically obtain credentials for, and subscribe to the required APIs. - q: What is the difference between Consumers and Developers? a: | - Developers are real users of the Dev Portal, whereas Consumers are abstractions. + A developer is a person that has registered for a Developer Portal. They can create applications and manage credentials themselves. + + Consumers are a part of your {{ site.base_gateway }} configuration and are managed by your administrators. - q: What is the difference between Consumers and RBAC Users? a: | - RBAC Users are users of Kong Manager, whereas Consumers are users (real or abstract) of the Gateway itself. + RBAC Users are users of Kong Manager, whereas Consumers are users of the services proxied by the Gateway itself. - q: Which plugins can be scoped to Consumers? a: | - Certain plugins can be scoped to Consumers (as opposed to Gateway Services, Routes, Consumer Groups, or globally). For example, you might want to - configure the Rate Limiting plugin to rate limit a specific Consumer, or use the Request Transformer plugin to edit requests for that Consumer. + Most plugins can be scoped to Consumers, with the exception of authentication plugins and plugins that control routing. + You can see the full list in the [plugin scopes compatibility reference](/plugins/scopes/). - q: Can you scope authentication plugins to Consumers? a: | - No. You can associate Consumers with an auth plugin by configuring credentials. For example, a Consumer with basic - auth credentials will use the Basic Authentication plugin. - But that plugin must be scoped to either a Route, Service, or globally, so that the Consumer can access it. - + No. Authentication plugins must be scoped to either a Route, Service, or globally - q: Can you manage Consumers with decK? a: | - Yes, you can manage Consumers using decK, but take caution if you have a large number of Consumers. -

- If you have many Consumers in your database, don't export or manage them using decK. - decK is built for managing entity configuration. It is not meant for end user data, - which can easily grow into hundreds of thousands or millions of records. + Yes, you can manage Consumers using decK, but take caution if you have a large number of Consumers as the sync time will be high. + + To manage a large number of consumers using decK, we recommend a federated configuration management approach where consumers are placed in to Consumer Groups and managed separately to the rest of your configuration. tools: - admin-api @@ -78,34 +73,36 @@ schema: ## What is a Consumer? -A Consumer typically refers to an entity that consumes or uses the APIs managed by {{site.base_gateway}}. +A Consumer is an entity that consumes or uses the APIs managed by {{site.base_gateway}}. Consumers can be applications, services, or users who interact with your APIs. Since they are not always human, {{site.base_gateway}} calls them Consumers, because they "consume" the service. {{site.base_gateway}} allows you to define and manage Consumers, apply access control policies, and monitor their API usage. Consumers are essential for controlling access to your APIs, tracking usage, and ensuring security. -They are identified by key authentication, OAuth, or other authentication and authorization mechanisms. +They are identified by key authentication, OAuth, or other authentication and authorization mechanisms. For example, adding a Basic Auth plugin to a Gateway Service or Route allows it to identify a Consumer, or block access if credentials are invalid. -You can choose to use {{site.base_gateway}} as the primary datastore for Consumers, or you can map the Consumer list -to an existing database to keep consistency between {{site.base_gateway}} and your existing primary datastore. - By attaching a plugin directly to a Consumer, you can manage specific controls at the Consumer level, such as rate limits. {% mermaid %} flowchart LR -A(Consumer entity) -B(Auth plugin) -C[Upstream service] - -Client --> A -subgraph id1[{{ site.base_gateway }}] -direction LR -A--Credentials-->B +Consumer(Consumer entity) +Service(Gateway Service) +Auth(Auth plugin) +Upstream[Upstream service] +RL["Per-consumer +Rate Limiting Plugin applied"] + +Client --> Authenticate +subgraph Authenticate ["Consumer Identity Added"] + direction TB + Service --> Auth + Auth-->Consumer end +Authenticate --> RL +RL --> Upstream -B-->C {% endmermaid %} ## Use cases for Consumers @@ -114,9 +111,9 @@ Common use cases for Consumers: |Use case | Description| |---------|------------| -|Authentication | Client authentication is the most common reason for setting up a Consumer. If you're using an authentication plugin, you'll need a Consumer with credentials.| -|Consumer Groups | Group Consumers by sets of criteria and apply certain rules to them.| -|Rate limiting | Rate limit specific Consumers based on tiers.| +| Authentication | Client authentication is the most common reason for setting up a Consumer. If you're using an authentication plugin, you'll need a Consumer with credentials. | +| Rate limiting | Rate limit specific Consumers based on tiers. | +| Transformation | Add or remove values from response bodies based on the Consumer | ## Schema From 2d57cb9e987b326013a1696d148d7f00ebc4aa39 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 13:56:07 +0000 Subject: [PATCH 06/17] Update Consumer Groups --- app/_gateway_entities/consumer-group.md | 29 ++++++++----------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/app/_gateway_entities/consumer-group.md b/app/_gateway_entities/consumer-group.md index 259ab43bc..0d440d1de 100644 --- a/app/_gateway_entities/consumer-group.md +++ b/app/_gateway_entities/consumer-group.md @@ -53,9 +53,6 @@ Consumer Groups enable the organization and categorization of [Consumers](/gatew With Consumer Groups, you can scope plugins to specifically defined Consumer Groups and a new plugin instance will be created for each individual Consumer Group, making configurations and customizations more flexible and convenient. For all plugins available on the consumer groups scope, see the [Plugin Scopes Reference](/plugins/scopes/). -{:.info} -> **Note**: Consumer Groups plugin scoping is a feature that was added in {{site.base_gateway}} version 3.4. Running a mixed-version {{site.base_gateway}} cluster (3.4 control plane, and <=3.3 data planes) is not supported when using plugins scoped to Consumer Groups. - For example, you could define two groups, Gold and Silver, assign different rate limits to them, then process each group using a different plugin: @@ -64,46 +61,38 @@ flowchart LR A((fa:fa-user Consumers 1-5)) B(Consumer Group Gold - 10 requests/second fa:fa-user Consumer 1, fa:fa-user Consumer 2, fa:fa-user Consumer 5 ) C(Consumer Group Silver - 5 requests/minute fa:fa-user Consumer 3, fa:fa-user Consumer 4) - D(Rate Limiting Advanced) - E(Request Transformer Advanced) + D(Rate Limiting Advanced + 10 requests/second) + E(Rate Limiting Advanced + 2 requests/second) F(Gateway Service QR Code Generation) - G(Gateway Service - OCR) H(QR Code Generation service) - I(OCR service) A--> B & C subgraph id1 [Kong Gateway] direction LR B --> D --> F - subgraph id2 [Gold route] - direction LR - D - end - C --> E --> G - subgraph id3 [Silver route] - direction LR - E - end + C --> E --> F end F --> H - G --> I {% endmermaid %} +Without Consumer Groups there are five Rate Limiting Advanced plugins, once for each consumer. Any time you change the rate limit, you need to update every consumer individually. + +Consumer Groups allow you to manage your plugin configuration centrally, and reduce the size of your {{ site.base_gateway }} configuration at the same time. In this example, it's the difference between using two plugins or five plugins. In your production environment, it could be the difference between two plugins and five _million_ plugins. + ## Use cases Common use cases for Consumer Groups: From 72a2952593526748b85b8e2562a850e275df7ed1 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 14:06:18 +0000 Subject: [PATCH 07/17] Update Upstreams with load-balancing info --- app/_gateway_entities/upstream.md | 153 +++++++++++++++++++++++++++--- 1 file changed, 138 insertions(+), 15 deletions(-) diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index 80ce4567e..efb99e5cf 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -34,18 +34,18 @@ schema: ## What is an Upstream? -An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#active-health-checks), [circuit break](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#passive-health-checks-circuit-breakers), and [load balance](https://docs.konghq.com/gateway/latest/how-kong-works/load-balancing/) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. +An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#active-health-checks), [circuit break](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#passive-health-checks-circuit-breakers), and [load balance](#load-balancing-algorithms) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. ## Upstream and Gateway Service interaction -You can configure a Service to point to an Upstream instead of a host. -For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. -The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. +You can configure a Service to point to an Upstream instead of a host. +For example, if you have a Service called `example_service` and an Upstream called `example_upstream`, you can point `example_service` to `example_upstream` instead of specifying a host. +The `example_upstream` Upstream can then point to two different [Targets](/gateway/entities/target/): `httpbin.konghq.com` and `httpbun.com`. In a real environment, the Upstream points to the same Service running on multiple systems. -This setup allows you to load balance between upstream targets. -For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. -If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). +This setup allows you to load balance between upstream targets. +For example, if an application is deployed across two different servers or upstream targets, {{site.base_gateway}} needs to load balance across both servers. +If one of the servers (like `httpbin.konghq.com` in the previous example) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). The following diagram shows how Upstreams interact with other {{site.base_gateway}} entities: @@ -55,11 +55,134 @@ The following diagram shows how Upstreams interact with other {{site.base_gatewa The following are examples of common use cases for Upstreams: -| Use case | Description | -|----------|-------------| -| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic.| -| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. | -| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests.

**Note:** This feature is not supported in hybrid mode. | +| Use case | Description | +| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Load balance | When an Upstream points to multiple upstream targets, you can configure the Upstream entity to load balance traffic between the targets. If you don't need to load balance, we recommend using the `host` header on a [Route](/gateway/entities/route/) as the preferred method for routing a request and proxying traffic. | +| Health check | Configure Upstreams to dynamically mark a target as healthy or unhealthy. This is an active check where a specific HTTP or HTTPS endpoint in the target is periodically requested and the health of the target is determined based on its response. | +| Circuit break | Configure Upstreams to allow {{site.base_gateway}} to passively analyze the ongoing traffic being proxied and determine the health of targets based on their behavior responding to requests.

**Note:** This feature is not supported in hybrid mode. | + +## Load balancing algorithms + +The load balancer supports the following load-balancing algorithms: + +- `round-robin` +- `consistent-hashing` +- `least-connections` +- `latency` + +### Round-Robin + +The round-robin algorithm will be done in a weighted manner. It will be identical +in results to the DNS based load-balancing, but due to it being an `upstream` +the additional features for health-checks and circuit-breakers will be available +in this case. + +When choosing this algorithm, consider the following: + +- good distribution of requests. +- fairly static, as only DNS updates or `target` updates can influence the + distribution of traffic. +- does not improve cache-hit ratios. + +### Consistent-Hashing + +With the consistent-hashing algorithm a configurable client-input will be used to +calculate a hash-value. This hash-value will then be tied to a specific backend +server. + +A common example would be to use the `consumer` as a hash-input. Since this ID is +the same for every request from that user, it will ensure that the same user will +consistently be dealt with by the same backend server. This will allow for cache +optimizations on the backend, since each of the servers only serves a fixed subset +of the users, and hence can improve its cache-hit-ratio for user related data. + +This algorithm implements the [ketama principle](https://github.com/RJ/ketama) to +maximize hashing stability and minimize consistency loss upon changes to the list +of known backends. + +When using the `consistent-hashing` algorithm, the input for the hash can be either +`none`, `consumer`, `ip`, `header`, or `cookie`. When set to `none`, the +`round-robin` scheme will be used, and hashing will be disabled. The `consistent-hashing` +algorithm supports a primary and a fallback hashing attribute; in case the primary +fails (e.g., if the primary is set to `consumer`, but no Consumer is authenticated), +the fallback attribute is used. This maximizes upstream cache hits. + +Supported hashing attributes are: + +- `none`: Do not use `consistent-hashing`; use `round-robin` instead (default). +- `consumer`: Use the Consumer ID as the hash input. If no Consumer ID is available, + it will fall back on the Credential ID (for example, in case of an external authentication mechanism like LDAP). +- `ip`: Use the originating IP address as the hash input. Review the configuration + settings for [determining the real IP][real-ip-config] when using this. +- `header`: Use a specified header as the hash input. The header name is + specified in either `hash_on_header` or `hash_fallback_header`, depending on whether + `header` is a primary or fallback attribute, respectively. +- `cookie`: Use a specified cookie with a specified path as the hash input. + The cookie name is specified in the `hash_on_cookie` field and the path is + specified in the `hash_on_cookie_path` field. If the specified cookie is not + present in the request, it will be set by the response. Hence, the `hash_fallback` + setting is invalid if `cookie` is the primary hashing mechanism. + The generated cookie will have a random UUID value. So the first assignment will + be random, but then sticks because it is preserved in the cookie. + +The consistent-hashing balancer is designed to work both with a single node as well +as in a cluster. + +When choosing this algorithm, consider the following: + +- improves backend cache-hit ratios. +- requires enough cardinality in the hash-inputs to distribute evenly (for example, hashing on + a header that only has 2 possible values does not make sense). +- the cookie based approach will work well for browser based requests, but less so + for machine-2-machine clients which will often omit the cookie. +- avoid using hostnames in the balancer as the + balancers might/will slowly diverge because the DNS ttl has only second precision + and renewal is determined by when a name is actually requested. On top of this is + the issue with some nameservers not returning all entries, which exacerbates + this problem. So when using the hashing approach in a Kong cluster, preferably add + `target` entities by their IP address. This problem can be mitigated by balancer + rebuilds and higher ttl settings. + +### Least-Connections + +This algorithm keeps track of the number of in-flight requests for each backend. +The weights are used to calculate "connection-capacity" of a backend. Requests are +routed towards the backend with the highest spare capacity. + +When choosing this algorithm, consider the following: + +- good distribution of traffic. +- does not improve cache-hit ratio's. +- more dynamic since slower backends will have more connections open, and hence + new requests will be routed to other backends automatically. + +### Latency + +The `latency` algorithm is based on peak EWMA (exponentially weighted moving average), +which ensures that the balancer selects the backend by lowest latency +(`upstream_response_time`). The latency metric used is the full request cycle, from +TCP connect to body response time. Since it is a moving average, the metrics will +"decay" over time. + +Weights will not be taken into account. + +When choosing this algorithm, consider the following: + +- good distribution of traffic provided there is enough base-load to keep the + metrics alive, since they are "decaying". +- not suitable for long-lived connections like websockets or server-sent events (SSE) +- very dynamic since it will constantly optimize. +- ideally, this works best with low variance in latencies. This means mostly similar + shaped traffic and even workloads for the backends. For example, usage + with a GraphQL backend serving small-fast queries as well big-slow ones will result + in high variance in the latency metrics, which will skew the metrics. +- properly set up the backend capacity and ensure proper network latency to prevent + resource starvation. For example, use 2 servers: one a small capacity close by (low + network latency), the other high capacity far away (high latency). Most traffic + will be routed to the small one, until its latency starts going up. The latency + going up however means the small server is most likely suffering from resource + starvation. So, in this case, the algorithm will keep the small server in a constant + state of resource starvation, which is most likely not efficient. ## Schema @@ -70,6 +193,6 @@ The following are examples of common use cases for Upstreams: {% entity_example %} type: upstream data: - name: example-upstream - algorithm: round-robin -{% endentity_example %} \ No newline at end of file + name: example-upstream + algorithm: round-robin +{% endentity_example %} From 9ebbc19390b8288dd0b064366c982647e7d2acf9 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 14:14:20 +0000 Subject: [PATCH 08/17] Update Targets --- app/_gateway_entities/target.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md index ddf3d2f53..693a98de9 100644 --- a/app/_gateway_entities/target.md +++ b/app/_gateway_entities/target.md @@ -28,12 +28,22 @@ schema: ## What is a Target? A Target is an IP address/hostname with a port that identifies an instance of a backend service. -Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing](https://docs.konghq.com/gateway/latest/how-kong-works/load-balancing/). For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). +Each [Upstream](/gateway/entities/upstream/) can have many Targets. Targets are used by Upstreams for [load balancing](/gateway/entities/upstream/#load-balancing-algorithms). For example, if you have an `example_upstream` Upstream, you can point it to two different Targets: `httpbin.konghq.com` and `httpbun.com`. This is so that if one of the servers (like `httpbin.konghq.com`) is unavailable, it automatically detects the problem and routes all traffic to the working server (`httpbun.com`). The following diagram illustrates how Targets are used by Upstreams for load balancing: {% include entities/upstreams-targets-diagram.md %} +## Using hostnames + +A `target` can also have a hostname instead of an IP address. In that case the name will be resolved and all entries found will individually be added to the load balancer, e.g., adding `api.host.com:123` with `weight=100`. + +If the hostname `api.host.com` resolves to an A record with 2 IP addresses, both IP addresses are added as target, each with `weight=100` and port 123. + +If the hostname resolves to an SRV record, then the `port` and `weight` fields from the DNS record are used, and override the port and weight set in the Target. + +The balancer will honor the DNS record's `ttl` setting. Upon expiry it queries the nameserver and updates the balancer. When a DNS record has `ttl=0`, the hostname will be added as a single target, with the specified weight. The nameserver will be queried for every request, adding latency to the request. + ## Schema {% entity_schema %} From 291da1e70896152b737949252694fc0825e10e95 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 14:18:10 +0000 Subject: [PATCH 09/17] Update Certificate entity --- app/_gateway_entities/certificate.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/app/_gateway_entities/certificate.md b/app/_gateway_entities/certificate.md index 5ad1235e0..a13ae09b4 100644 --- a/app/_gateway_entities/certificate.md +++ b/app/_gateway_entities/certificate.md @@ -34,7 +34,7 @@ schema: faqs: - q: What's the difference between the Certificate entity and the CA Certificate entity? - a: Certificates handle [SSL/TLS termination](/kic/tls-termination-passthrough) for encrypted requests and [CA Certificates](/gateway/entities/ca-certificate/) validate client or server certificates. + a: Certificates handle SSL/TLS termination for encrypted requests and [CA Certificates](/gateway/entities/ca-certificate/) validate client or server certificates. - q: Is the Certificate entity used in {{site.konnect_short_name}} for data plane nodes as well? a: No, the data plane nodes use a [different certificate](/api/konnect/control-planes-config/). --- @@ -44,9 +44,8 @@ faqs: A Certificate object represents a public certificate, which is used to validate the sender's authorization and name. It can optionally be paired with the corresponding private key to initiate secure connections and encrypt sensitive data. {{site.base_gateway}} can use Certificates in the following ways: -* Handle [SSL/TLS termination](/kic/tls-termination-passthrough) for encrypted requests +* Handle SSL/TLS termination for one or more hostnames using the associated [SNI object](/gateway/entities/sni/) * Use as a trusted CA store when validating the peer certificate of a client or Service -* Tie a certificate and key pair to one or more hostnames using the associated [SNI object](/gateway/entities/sni/) ## Schema From 358ada6f3f68a34f754afae03d9ef9b116aa8f24 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 14:32:23 +0000 Subject: [PATCH 10/17] Update Vaults --- app/_gateway_entities/vault.md | 61 ++++++++++++++++++++++------------ 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/app/_gateway_entities/vault.md b/app/_gateway_entities/vault.md index 4577d33b7..b8883d9b0 100644 --- a/app/_gateway_entities/vault.md +++ b/app/_gateway_entities/vault.md @@ -11,9 +11,9 @@ related_resources: url: /secrets-management/ - text: Workspaces url: /gateway/entities/workspace/ - - text: RBAC + - text: RBAC url: /gateway/entities/rbac/ - + faqs: - q: What types of fields can be used in Vaults? @@ -41,9 +41,11 @@ schema: --- ## What is a Vault? -In {{site.base_gateway}}, the Vault object is used to store secrets. A secret is any sensitive piece of information required for API gateway -operations. Secrets can be used as part of the core {{site.base_gateway}} configuration, in plugins, or in configuration associated -with APIs serviced by the gateway. + +Vaults allow you to securely store and then reference secrets from within other entities. This ensures that secrets aren't visible in plaintext throughout the platform, in places such as `kong.conf`, +declarative configuration files, logs, or the UI. + +For example, you could store a certificate and a key in a Vault, then reference them from a [Certificate entity](/gateway/entities/certificate/). This way, the certificate and key are not stored in the entity directly and are more secure. Some of the most common types of secrets used by {{site.base_gateway}} include: @@ -52,20 +54,19 @@ Some of the most common types of secrets used by {{site.base_gateway}} include: * API keys * Sensitive configuration fields, generally used for authentication, hashing, signing, or encryption -## Vault use cases - -Vaults allow you to securely store and then reference secrets from within other entities. This ensures that secrets aren't visible in plaintext throughout the platform, in places such as `kong.conf`, -declarative configuration files, logs, or the UI. - -For example, you could store a certificate and a key in a Vault, then reference them from a [Certificate entity](/gateway/entities/certificate/). This way, the certificate and key are not stored in the entity directly and are more secure. - ## How do I add secrets to a Vault? -You can add secrets to Vaults in one of the following ways: +You can add secrets to Vaults in one of the following ways: * Environment variables * {{site.konnect_short_name}} Config Store * Supported third-party backend vault +## How do I configure access to a Vault? + +Each vault has its own required configuration. You can provide this configuration by creating a Vault entity, or by configuring specific environment variables before starting {{ site.base_gateway }}. + +For more information, choose a Vault below to see the specific configuration required. + ## Supported backends {% feature_table %} @@ -79,8 +80,8 @@ columns: key: supports_konnect features: - - title: Environment variable1 - url: /gateway/entities/vault/#store-secrets-as-environment-variables + - title: Environment variable + url: /how-to/store-secrets-as-env-variables/ oss: true enterprise: true supports_konnect: true @@ -111,8 +112,6 @@ features: supports_konnect: true {% endfeature_table %} -1 You can use environment variables as a Vaults backend either with or without using the Vaults entity. - ## How do I reference secrets stored in a Vault? When you want to use a secret stored in a Vault, you can reference the secret with a `vault` reference. You can use the `vault` reference in places such as `kong.conf`, declarative configuration files, logs, or in the UI. @@ -138,18 +137,38 @@ Would point to a secret object called `pg` inside a HashiCorp Vault, which may r `{vault://hcv/pg/username}`. +Vault references must be used for the whole referenced value. Imagine that you're calling an upstream service with the authentication token `ABC123` + +{% feature_table %} +item_title: Works +columns: + - title: Configuration Value + key: config + - title: Vault Value + key: vault +features: + - title: ❌ + config: 'Bearer {vault://hcv/myservice-auth-token}' + vault: ABC123 + - title: ✅ + config: '{vault://hcv/myservice-auth-token}' + vault: Bearer ABC123 +{% endfeature_table %} + ## Secret rotation in Vaults -By default, {{site.base_gateway}} automatically rotates secrets *once every minute* in the background. You can also configure how often {{site.base_gateway}} rotates secrets using the Vault entity configuration. +By default, {{site.base_gateway}} automatically refreshes secrets *once every minute* in the background. You can also configure how often {{site.base_gateway}} refreshes secrets using the Vault entity configuration. -There are two types of rotation configuration available: -* Rotate periodically using TTLs: For example, check for a new TLS certificate once per day. -* Rotate on failure: For example, on a database authentication failure, check if the secrets were updated, and try again. +There are two types of refresh configuration available: +* Refresh periodically using TTLs: For example, check for a new TLS certificate once per day. +* Refresh on failure: For example, on a database authentication failure, check if the secrets were updated, and try again. For more information, see [Secret management](/secrets-management/). ## Best practices for Vaults +@TODO: Move this to deck docs when available + ### General best practices To keep your environment secure and avoid taking down your proxies by accident, make sure to: From 51aa7d6164664d6f92bf9b6014f3f2f5e3650d1c Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 14:36:50 +0000 Subject: [PATCH 11/17] Keyring is not an entity - moved to reference page --- app/_landing_pages/gateway/entities.yaml | 5 ----- app/{_gateway_entities => gateway}/keyring.md | 6 ++++-- 2 files changed, 4 insertions(+), 7 deletions(-) rename app/{_gateway_entities => gateway}/keyring.md (99%) diff --git a/app/_landing_pages/gateway/entities.yaml b/app/_landing_pages/gateway/entities.yaml index 7763409e2..0d9ab7fa1 100644 --- a/app/_landing_pages/gateway/entities.yaml +++ b/app/_landing_pages/gateway/entities.yaml @@ -79,11 +79,6 @@ rows: - type: entity_card config: entity: key-set - - blocks: - - type: entity_card - config: - entity: keyring - - header: type: h2 diff --git a/app/_gateway_entities/keyring.md b/app/gateway/keyring.md similarity index 99% rename from app/_gateway_entities/keyring.md rename to app/gateway/keyring.md index 8eeb7bbab..dadc83c95 100644 --- a/app/_gateway_entities/keyring.md +++ b/app/gateway/keyring.md @@ -1,8 +1,10 @@ --- title: Keyring content_type: reference -entities: - - keyring +layout: reference + +products: + - gateway description: | A Keyring is a mechanism that encrypts sensitive data fields, such as consumer secrets, before storing them in the database. From b965eaae51d164197c323335ba0a1f2e6fe84856 Mon Sep 17 00:00:00 2001 From: Michael Heap Date: Wed, 22 Jan 2025 15:26:53 +0000 Subject: [PATCH 12/17] Remaining entities --- app/_gateway_entities/group.md | 4 ++-- app/_gateway_entities/license.md | 10 ++++----- app/_gateway_entities/rbac.md | 23 +++------------------ app/_gateway_entities/workspace.md | 17 ++++++--------- app/_how-tos/bootstrap-rbac.md | 22 +++++++++++++++++++- app/_includes/entities/permissions-table.md | 2 +- 6 files changed, 38 insertions(+), 40 deletions(-) diff --git a/app/_gateway_entities/group.md b/app/_gateway_entities/group.md index fa10697ba..afe5309a0 100644 --- a/app/_gateway_entities/group.md +++ b/app/_gateway_entities/group.md @@ -47,7 +47,7 @@ The Group resource can also be used to integrate identity providers like Okta wi ## Service directory mapping -With service directory mapping, Groups can be mapped to [RBAC Roles](/gateway/entities/rbac/#role-configuration). When a user logs in to Kong Manager, they are identified with their Admin username and authenticated with user credentials from a service directory, like [LDAP](/plugins/ldap-auth/). The service directory creates a relationship with the associated RBAC Roles that are defined in {{site.base_gateway}}. +With service directory mapping, Groups can be mapped to [RBAC Roles](/gateway/entities/rbac/#role-configuration). When a user logs in to Kong Manager, they are identified with their Admin username and authenticated with user credentials from a service directory, like [LDAP](https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/). The service directory creates a relationship with the associated RBAC Roles that are defined in {{site.base_gateway}}. This happens in the following order: @@ -56,7 +56,7 @@ This happens in the following order: 3. Groups are associated with an external directory. 4. Permissions are assigned to {{site.base_gateway}} users based on Group assignment. -For more information, read the [LDAP](/plugins/ldap-auth/) documentation. +For more information, read the [Mapping LDAP Service Directory Groups to Kong Roles](https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/) documentation. ## Schema diff --git a/app/_gateway_entities/license.md b/app/_gateway_entities/license.md index 31cbe3f81..41d2ce9da 100644 --- a/app/_gateway_entities/license.md +++ b/app/_gateway_entities/license.md @@ -68,12 +68,12 @@ features: - title: License File url: /gateway/entities/license/#deploy-a-license-with-a-file-on-the-node-filesystem-licensejson traditional: true - hybrid: false + hybrid: true dbless: true - title: Environment variable url: /gateway/entities/license/#deploy-a-license-with-an-environment-variable traditional: true - hybrid: false + hybrid: true dbless: true {% endfeature_table %} @@ -91,17 +91,17 @@ data: payload: "{\"license\":{\"payload\":{\"admin_seats\":\"1\",\"customer\":\"Example Company, Inc\",\"dataplanes\":\"1\",\"license_creation_date\":\"2017-07-20\",\"license_expiration_date\":\"2017-07-20\",\"license_key\":\"00141000017ODj3AAG_a1V41000004wT0OEAU\",\"product_subscription\":\"Konnect Enterprise\",\"support_plan\":\"None\"},\"signature\":\"6985968131533a967fcc721244a979948b1066967f1e9cd65dbd8eeabe060fc32d894a2945f5e4a03c1cd2198c74e058ac63d28b045c2f1fcec95877bd790e1b\",\"version\":\"1\"}}" {% endentity_example %} -[Reload](/how-to/restart-kong-gateway-container/) the {{site.base_gateway}} nodes after adding or updating a License. - {% endnavtab %} {% navtab "license.json" %} ### Deploy a License with `license.json` The license data must contain straight quotes to be considered valid JSON (`'` and `"`, not `’` or `“`). Kong searches for the License by default in `/etc/kong/license.json`. +The control plane **does not** propagate the License to data plane nodes. You **must** add the License to each data plane node, and each node **must** start with the License. The License can't be added after starting the node. + 1. Save your License to a file named `license.json`. 1. Copy the license file to the `/etc/kong`. -1. [Reload](/how-to/restart-kong-gateway-container/) the {{site.base_gateway}} nodes to apply the license by running `kong reload` from within the container. +1. [Restart](/how-to/restart-kong-gateway-container/) the {{site.base_gateway}} nodes to apply the license by running `kong restart` from within the container. {% endnavtab %} {% navtab "Environment variable" %} ### Deploy a License as an environment variable diff --git a/app/_gateway_entities/rbac.md b/app/_gateway_entities/rbac.md index dae1e7aea..8ee32b4cc 100644 --- a/app/_gateway_entities/rbac.md +++ b/app/_gateway_entities/rbac.md @@ -3,8 +3,7 @@ title: RBAC content_type: reference products: - gateway -tiers: - - enterprise +tier: enterprise tools: - admin-api entities: @@ -34,11 +33,9 @@ RBAC in {{site.base_gateway}} conforms to the following core principles: * In {{site.base_gateway}} there are Users * Every user has a Role * Roles are assigned Permissions -* Every Role belongs to a [Group](/gateway/entities/group/) * A Group is a collection of Roles -{{site.base_gateway}} uses a precedence model, from most specificity to least specificity, to determine if a user has access to an endpoint. - +{{site.base_gateway}} uses a [precedence model](#rbac-precedence-order), from most specificity to least specificity, to determine if a user has access to an endpoint. ## What are Permissions? @@ -199,18 +196,4 @@ You can also automate the creation of Admins. For more information, see [creatin ## Schema -{% entity_schema %} - -## Create an RBAC user - -Creating an RBAC User requires [RBAC to be enabled](#enable-rbac) for {{site.base_gateway}}. - -{% entity_example %} -type: rbac -data: - name: my-user - user_token: exampletoken -headers: - admin-api: - - "Kong-Admin-Token: $ADMIN_TOKEN" -{% endentity_example %} \ No newline at end of file +{% entity_schema %} \ No newline at end of file diff --git a/app/_gateway_entities/workspace.md b/app/_gateway_entities/workspace.md index fe7e90036..a2cfa6cb2 100644 --- a/app/_gateway_entities/workspace.md +++ b/app/_gateway_entities/workspace.md @@ -8,9 +8,6 @@ description: Workspaces provide a way to segment {{site.base_gateway}} entities. tools: - admin-api - - kic - - deck - - terraform tier: enterprise schema: @@ -47,7 +44,6 @@ faqs: --- - ## What is a Workspace? Workspaces are a way of namespacing {{site.base_gateway}} entities so they can be managed independently. Workspaces work in combination with RBAC to create isolated environments for teams to operate independently of each other. Workspaces can't share entities, like Services, between them, and only Workspace Admins with the correct permissions, in the Workspace, can manage them. @@ -88,13 +84,12 @@ To route traffic to the appropriate Workspace, {{site.base_gateway}} uses a conf When a Service or Route is **created** or **modified**, the {{site.base_gateway}} Router checks for the existence of that object before allowing the operation to proceed in this order: -1. If the Service or Route created is totally unique and does not match an existing entity, the new entity is created. -2. If an existing Service or Route object that matches the one being created is found, a `409 Conflict` error is returned. -3. If an equivalent Service or a Route is found in a different Workspace, the new entity is created. -4. If an equivalent Service or Route is found in a different Workspace, and the host is a wildcard: - a. If the host field matches in both Workspaces, a `409 Conflict` error is returned. - b. If the host field does not match, the new entity can be created. - c. If the host is an absolute value, a `409 Conflict` error is returned. +1. If the Service or Route created is unique across all Workspaces, the new entity is created. +2. If an existing Service or Route object that matches the one being created is found in the current workspace, a `409 Conflict` error is returned. +4. If an equivalent Service or Route is found in a different Workspace, and the host is provided: + 1. If the host field matches in both workspaces, a `409 Conflict` error is returned. + 1. If the host field does not match, the new entity can be created. + 1. If the host is an absolute value, a `409 Conflict` error is returned. ## Roles, groups, and permissions diff --git a/app/_how-tos/bootstrap-rbac.md b/app/_how-tos/bootstrap-rbac.md index 616760137..e2520c31e 100644 --- a/app/_how-tos/bootstrap-rbac.md +++ b/app/_how-tos/bootstrap-rbac.md @@ -5,6 +5,9 @@ content_type: how_to products: - gateway +tools: + - deck + works_on: - on-prem @@ -19,4 +22,21 @@ min_version: gateway: '3.4' --- -@todo Create a super-admin in KGW set up default workspaces and teams validate isolated workspace. \ No newline at end of file +@todo Create a super-admin in KGW set up default workspaces and teams validate isolated workspace. + +Maybe https://docs.konghq.com/gateway/latest/production/access-control/enable-rbac/ ? + + +## Create an RBAC user + +Creating an RBAC User requires [RBAC to be enabled](#enable-rbac) for {{site.base_gateway}}. + +{% entity_example %} +type: rbac +data: + name: my-user + user_token: exampletoken +headers: + admin-api: + - "Kong-Admin-Token: $ADMIN_TOKEN" +{% endentity_example %} \ No newline at end of file diff --git a/app/_includes/entities/permissions-table.md b/app/_includes/entities/permissions-table.md index 93e17508e..56b28f8aa 100644 --- a/app/_includes/entities/permissions-table.md +++ b/app/_includes/entities/permissions-table.md @@ -4,7 +4,7 @@ By default, when {{site.base_gateway}} is configured, the starting user is confi | Role | Description | | ----------- | ----------- | -| Admin | Full access to all endpoints, across all Workspaces, except the RBAC Admin API | +| `admin` | Full access to all endpoints, across all Workspaces, except the RBAC Admin API | | `super-admin` | Full access to all endpoints, across all Workspaces, ability to assign and modify RBAC permissions. | |`read-only`| Read access to all endpoints, across all Workspaces| From a4e30492af355ff81e03017e42e63236c19b698b Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Wed, 22 Jan 2025 17:01:10 -0800 Subject: [PATCH 13/17] various cleanup for formatting, grammar, etc --- app/_assets/stylesheets/index.css | 4 + app/_gateway_entities/consumer-group.md | 6 +- app/_gateway_entities/consumer.md | 10 +- app/_gateway_entities/group.md | 17 +-- app/_gateway_entities/license.md | 22 ++- app/_gateway_entities/rbac.md | 5 +- app/_gateway_entities/route.md | 46 +++++-- app/_gateway_entities/service.md | 6 +- app/_gateway_entities/target.md | 11 +- app/_gateway_entities/upstream.md | 130 ++++++++---------- app/_gateway_entities/vault.md | 5 +- app/_gateway_entities/workspace.md | 9 +- app/_landing_pages/gateway/entities.yaml | 2 +- app/gateway/health-checks-circuit-breakers.md | 17 +++ app/gateway/ldap-service-directory-mapping.md | 19 +++ app/gateway/routing/expressions.md | 14 +- app/gateway/routing/traditional.md | 118 ++++++++-------- 17 files changed, 251 insertions(+), 190 deletions(-) create mode 100644 app/gateway/health-checks-circuit-breakers.md create mode 100644 app/gateway/ldap-service-directory-mapping.md diff --git a/app/_assets/stylesheets/index.css b/app/_assets/stylesheets/index.css index 4b5841fa5..a4c2ff4c5 100644 --- a/app/_assets/stylesheets/index.css +++ b/app/_assets/stylesheets/index.css @@ -354,6 +354,10 @@ .tabcolumn { @apply list-none flex text-sm ml-0 w-full gap-0; + + ul, li { + @apply list-none; + } } .tab-button { diff --git a/app/_gateway_entities/consumer-group.md b/app/_gateway_entities/consumer-group.md index 0d440d1de..b4f302bc3 100644 --- a/app/_gateway_entities/consumer-group.md +++ b/app/_gateway_entities/consumer-group.md @@ -89,9 +89,11 @@ flowchart LR {% endmermaid %} -Without Consumer Groups there are five Rate Limiting Advanced plugins, once for each consumer. Any time you change the rate limit, you need to update every consumer individually. +Without Consumer Groups, you would have to use five Rate Limiting Advanced plugins, once for each consumer. +Any time you change the rate limit, you would need to update every consumer individually. -Consumer Groups allow you to manage your plugin configuration centrally, and reduce the size of your {{ site.base_gateway }} configuration at the same time. In this example, it's the difference between using two plugins or five plugins. In your production environment, it could be the difference between two plugins and five _million_ plugins. +Consumer Groups allow you to manage your plugin configuration centrally, and reduce the size of your {{ site.base_gateway }} configuration at the same time. +In this example, it's the difference between using two plugins or five plugins. In your production environment, it could be the difference between two plugins and five _million_ plugins. ## Use cases diff --git a/app/_gateway_entities/consumer.md b/app/_gateway_entities/consumer.md index e31f0a904..60211a097 100644 --- a/app/_gateway_entities/consumer.md +++ b/app/_gateway_entities/consumer.md @@ -46,13 +46,13 @@ faqs: - q: Can you scope authentication plugins to Consumers? a: | - No. Authentication plugins must be scoped to either a Route, Service, or globally + No. Authentication plugins must be scoped to either a Route, Service, or globally. - q: Can you manage Consumers with decK? a: | Yes, you can manage Consumers using decK, but take caution if you have a large number of Consumers as the sync time will be high. - To manage a large number of consumers using decK, we recommend a federated configuration management approach where consumers are placed in to Consumer Groups and managed separately to the rest of your configuration. + To manage a large number of consumers using decK, we recommend a federated configuration management approach where consumers are placed in to Consumer Groups and managed separately from the rest of your configuration. tools: - admin-api @@ -84,6 +84,8 @@ For example, adding a Basic Auth plugin to a Gateway Service or Route allows it By attaching a plugin directly to a Consumer, you can manage specific controls at the Consumer level, such as rate limits. + + {% mermaid %} flowchart LR @@ -105,6 +107,8 @@ RL --> Upstream {% endmermaid %} + + ## Use cases for Consumers Common use cases for Consumers: @@ -113,7 +117,7 @@ Common use cases for Consumers: |---------|------------| | Authentication | Client authentication is the most common reason for setting up a Consumer. If you're using an authentication plugin, you'll need a Consumer with credentials. | | Rate limiting | Rate limit specific Consumers based on tiers. | -| Transformation | Add or remove values from response bodies based on the Consumer | +| Transformation | Add or remove values from response bodies based on the Consumer. | ## Schema diff --git a/app/_gateway_entities/group.md b/app/_gateway_entities/group.md index afe5309a0..74969bb3e 100644 --- a/app/_gateway_entities/group.md +++ b/app/_gateway_entities/group.md @@ -12,10 +12,10 @@ related_resources: url: /gateway/entities/rbac/ - text: Admins entity url: /gateway/entities/admin/ - - text: LDAP Authentication - url: /plugin/ldap-auth/ - - text: Workspace + - text: Workspace entity url: /gateway/entities/workspace/ + - text: LDAP Service Directory Mapping + url: /gateway/ldap-service-directory-mapping/ tier: enterprise @@ -40,24 +40,25 @@ faqs: ## What is a Group? -In {{site.base_gateway}}, the Group entity functions as a resource for [RBAC](/gateway/entities/rbac/#role-configuration). {{site.base_gateway}} Admins can map Permissions and Roles to a Group, and use the Group to simplify Role assignment across the {{site.base_gateway}} environment. +In {{site.base_gateway}}, the Group entity functions as a resource for [RBAC](/gateway/entities/rbac/#role-configuration). +{{site.base_gateway}} Admins can map Permissions and Roles to a Group, and use the Group to simplify Role assignment across the {{site.base_gateway}} environment. The Group resource can also be used to integrate identity providers like Okta with Kong Manager, letting you map relationships between your service directory mappings and Kong Manager Roles. ## Service directory mapping -With service directory mapping, Groups can be mapped to [RBAC Roles](/gateway/entities/rbac/#role-configuration). When a user logs in to Kong Manager, they are identified with their Admin username and authenticated with user credentials from a service directory, like [LDAP](https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/). The service directory creates a relationship with the associated RBAC Roles that are defined in {{site.base_gateway}}. +With service directory mapping, Groups can be mapped to [RBAC Roles](/gateway/entities/rbac/#role-configuration). +When a user logs in to Kong Manager, they are identified with their Admin username and authenticated with user credentials from a service directory, like LDAP. +The service directory creates a relationship with the associated RBAC Roles that are defined in {{site.base_gateway}}. This happens in the following order: - 1. Roles are created in {{site.base_gateway}}. 2. Groups are created and associated with RBAC Roles. 3. Groups are associated with an external directory. 4. Permissions are assigned to {{site.base_gateway}} users based on Group assignment. -For more information, read the [Mapping LDAP Service Directory Groups to Kong Roles](https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/) documentation. - +For more information, read the [LDAP Service Directory Mapping](/gateway/ldap-service-directory-mapping/) documentation. ## Schema diff --git a/app/_gateway_entities/license.md b/app/_gateway_entities/license.md index 41d2ce9da..0496fcb62 100644 --- a/app/_gateway_entities/license.md +++ b/app/_gateway_entities/license.md @@ -79,9 +79,13 @@ features: + +## Deploy a License + {% navtabs %} {% navtab "Admin API" %} -### Deploy a License using the Admin API + +You can deploy a License using the Admin API. The control plane sends Licenses configured through the [`/licenses` endpoint](/api/gateway/admin-ee/#/operations/post-licenses) to all data planes in the cluster. The data planes use the most recent `updated_at` License. This is the only method that automatically applies the License to data planes. @@ -93,20 +97,28 @@ data: {% endnavtab %} {% navtab "license.json" %} -### Deploy a License with `license.json` + +You can deploy a License with a `license.json` file. The license data must contain straight quotes to be considered valid JSON (`'` and `"`, not `’` or `“`). Kong searches for the License by default in `/etc/kong/license.json`. -The control plane **does not** propagate the License to data plane nodes. You **must** add the License to each data plane node, and each node **must** start with the License. The License can't be added after starting the node. +{:.info} +> The control plane **does not** propagate the License to data plane nodes. +You **must** add the License to each data plane node, and each node **must** start with the License. +The License can't be added after starting the node. 1. Save your License to a file named `license.json`. 1. Copy the license file to the `/etc/kong`. 1. [Restart](/how-to/restart-kong-gateway-container/) the {{site.base_gateway}} nodes to apply the license by running `kong restart` from within the container. {% endnavtab %} {% navtab "Environment variable" %} -### Deploy a License as an environment variable -If you deploy a License using a `KONG_LICENSE_DATA` or `KONG_LICENSE_PATH` environment variable, the control plane **does not** propagate the License to data plane nodes. You **must** add the License to each data plane node, and each node **must** start with the License. The License can't be added after starting the node. +You can deploy a License as an environment variable. + +{:.info} +> If you deploy a License using a `KONG_LICENSE_DATA` or `KONG_LICENSE_PATH` environment variable, the control plane **does not** propagate the License to data plane nodes. +You **must** add the License to each data plane node, and each node **must** start with the License. +The License can't be added after starting the node. Unlike other `KONG_*` environmental variables, the `KONG_LICENSE_DATA` and `KONG_LICENSE_PATH` can't be defined in-line as part of any `kong` CLI commands. License file environmental variables must be exported to the shell where the Nginx process runs, ahead of the `kong` CLI tool. diff --git a/app/_gateway_entities/rbac.md b/app/_gateway_entities/rbac.md index 8ee32b4cc..efd37b4f7 100644 --- a/app/_gateway_entities/rbac.md +++ b/app/_gateway_entities/rbac.md @@ -11,7 +11,7 @@ entities: description: The RBAC entity is what allows for the RBAC system to be administered. schema: api: gateway/admin-ee - path: /schemas/rbac + path: /schemas/RBAC related_resources: - text: Gateway Workspace entity @@ -60,6 +60,8 @@ If {{site.base_gateway}} finds a matching permission for the current user, endpo This diagram helps explain how individual workspace roles and cross-workspace roles interact: + + {% mermaid %} flowchart LR subgraph team-a-roles [Team A Roles] @@ -105,6 +107,7 @@ flowchart LR {% endmermaid %} + ## RBAC Entities diff --git a/app/_gateway_entities/route.md b/app/_gateway_entities/route.md index f007659a9..ab756f981 100644 --- a/app/_gateway_entities/route.md +++ b/app/_gateway_entities/route.md @@ -38,7 +38,7 @@ schema: ## What is a Route? -Routes fulfil two responsibilities in {{ site.base_gateway }}: +Routes fulfill two responsibilities in {{ site.base_gateway }}: 1. Match incoming requests and route them to the correct [Gateway Service](/gateway/entities/service/) 2. Use plugins to transform the request/response proxied using this Route @@ -58,6 +58,8 @@ But when the internal application accesses the Service using {{site.base_gateway The following diagram illustrates this example: + + {% mermaid %} flowchart LR A(External application) @@ -83,6 +85,8 @@ flowchart LR {% endmermaid %} + + ## Route use cases Common use cases for Routes: @@ -95,16 +99,16 @@ Common use cases for Routes: ## Configuration formats -{{site.base_gateway}} provides two methods to define Routes. The traditional JSON format, and a more powerful DSL-based expressions format. The router used is configured via the `router_flavor` property in `kong.conf`. +{{site.base_gateway}} provides two methods to define Routes: the traditional JSON format, and a more powerful DSL-based expressions format. +The router used is configured via the [`router_flavor`](/gateway/configuration/#router_flavor) property in `kong.conf`. The router you should use depends on your use case and {{site.base_gateway}} version: * **[Expressions router](/gateway/routing/expressions/):** The recommended method for anyone running {{site.base_gateway}} 3.4.x or later. Handles complex routing logic efficiently. -* **[Traditional router](/gateway/routing/traditional/):** -The original {{ site.base_gateway }} routing configuration format. Provide your matching criteria in JSON format. +* **[Traditional router](/gateway/routing/traditional/):** The original {{ site.base_gateway }} routing configuration format. Provide your matching criteria in JSON format. -Setting `router_flavor` to `expressions` allows you to configure both expression based and JSON based routing criteria at the same time. If an `expression` route matches, the JSON format router will not run, regardless of the JSON priority set. +Setting `router_flavor` to `expressions` allows you to configure both expression based and JSON based routing criteria at the same time. If an `expression` route matches, the JSON format router won't run, regardless of the JSON priority set. -To disble the DSL based format, set `router_flavor` to `traditional_compat`. Only JSON routes will be accepted with this configuration. +To disable the DSL-based format, set `router_flavor` to `traditional_compat`. Only JSON routes will be accepted with this configuration. ## Routing criteria @@ -117,7 +121,7 @@ You can match incoming requests against the following routing criteria: - Port: The request's source/destination port - SNI: The server name indicated in a TLS request -For detailed examples of each, see the dedicated [expressions](/gateway/routing/expressions/#routing-criteria) or [traditional](/gateway/routing/traditional/#routing-criteria) sections. +For detailed examples of each, see the dedicated [expressions](/gateway/routing/expressions/#how-requests-are-routed-with-the-expressions-router) or [traditional](/gateway/routing/traditional/#routing-criteria) sections. ## How routing works @@ -133,12 +137,16 @@ For more information, see the detailed [expressions](/gateway/routing/expression ### Route behavior -The Route entity allows you to configure proxy behaviour on a per route basis by setting the `strip_path`, `preserve_host` and `path_handling` values. +The Route entity allows you to configure proxy behaviour on a per route basis by setting the `strip_path`, `preserve_host`, and `path_handling` values. In most cases, `strip_path` and `preserve_host` should be `false` (this is the default value), and `path_handling` should be set to `v0`. + + #### strip_path + + It may be desirable to specify a path prefix to match a route, but not include it in the upstream request. To do so, use the `strip_path` boolean property by configuring a route like so: @@ -170,7 +178,7 @@ GET /path/to/resource HTTP/1.1 Host: ... ``` -The same way, if a Regex path is defined on a route that has `strip_path` +The same way, if a regex path is defined on a route that has `strip_path` enabled, the entirety of the request URL matching sequence will be stripped. For example: @@ -184,7 +192,7 @@ For example: } ``` -The following HTTP request matching the provided Regex path: +The following HTTP request matching the provided regex path: ```http GET /version/1/service/path/to/resource HTTP/1.1 @@ -198,8 +206,12 @@ GET /path/to/resource HTTP/1.1 Host: ... ``` + + #### preserve_host + + When proxying, {{site.base_gateway}}'s default behavior is to set the upstream request's Host header to the hostname specified in the service's `host`. The `preserve_host` field accepts a boolean flag instructing {{site.base_gateway}} not to do so. @@ -231,7 +243,7 @@ GET / HTTP/1.1 Host: ``` -However, by explicitly configuring a route with `preserve_host=true`: +However, by explicitly configuring a Route with `preserve_host=true`: ```json { @@ -258,13 +270,17 @@ GET / HTTP/1.1 Host: service.com ``` -### path_handling + + +#### path_handling + + The `path_handling` parameter accepts `v0` or `v1`. -`v0` is the behavior used in Kong 0.x, 2.x and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed. +* `v0` is the behavior used in Kong 0.x, 2.x, and 3.x. It treats `service.path`, `route.path` and request path as *segments* of a URL. It will always join them via slashes. Given a service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/s/re`. If the resulting path is a single slash, no further transformation is done to it. If it's longer, then the trailing slash is removed. -`v1` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`. +* `v1` is the behavior used in Kong 1.x. It treats `service.path` as a *prefix*, and ignores the initial slashes of the request and route paths. Given service path `/s`, route path `/r` and request path `/re`, the concatenated path will be `/sre`. {:.warning} > `path_handling` v1 is not supported in the `expressions` router and may be removed in a future version of {{ site.base_gateway }}. We **strongly** recommend using `v0`. @@ -274,7 +290,7 @@ slashes.
-Expand this block to see a table showing detailed v0 and v1 examples +Expand this block to see a table showing detailed v0 and v1 examples
service.path
diff --git a/app/_gateway_entities/service.md b/app/_gateway_entities/service.md index 385eefc36..097591108 100644 --- a/app/_gateway_entities/service.md +++ b/app/_gateway_entities/service.md @@ -36,12 +36,14 @@ api_specs: A Gateway Service represents your actual backend API or microservice. -For simple deployments, the upstream URL can be provided directly in the Service. For so phisticated traffic management needs, a Service can point at an [Upstream](/gateway/entities/upstream/). +For simple deployments, the upstream URL can be provided directly in the Service. For sophisticated traffic management needs, a Service can point at an [Upstream](/gateway/entities/upstream/). Gateway Services, in conjunction with [Routes](/gateway/entities/route/), let you expose your services to clients with {{site.base_gateway}}. [Plugins](/gateway/entities/plugin/) can be attached to a Service, and will run against every request that triggers a request to the Service that they're attached to. + + {% mermaid %} flowchart LR A(API client) @@ -66,6 +68,8 @@ flowchart LR {% endmermaid %} + + ## Schema {% entity_schema %} diff --git a/app/_gateway_entities/target.md b/app/_gateway_entities/target.md index 693a98de9..29db28136 100644 --- a/app/_gateway_entities/target.md +++ b/app/_gateway_entities/target.md @@ -36,13 +36,16 @@ The following diagram illustrates how Targets are used by Upstreams for load bal ## Using hostnames -A `target` can also have a hostname instead of an IP address. In that case the name will be resolved and all entries found will individually be added to the load balancer, e.g., adding `api.host.com:123` with `weight=100`. +A `target` can also have a hostname instead of an IP address. +In that case, the name is resolved and all entries found are individually added to the load balancer. -If the hostname `api.host.com` resolves to an A record with 2 IP addresses, both IP addresses are added as target, each with `weight=100` and port 123. +For example, let's say you add `api.host.com:123` with `weight=100`: -If the hostname resolves to an SRV record, then the `port` and `weight` fields from the DNS record are used, and override the port and weight set in the Target. +* If the hostname `api.host.com` resolves to an A record with 2 IP addresses, both IP addresses are added as a target, each with `weight=100` and port 123. +* If the hostname resolves to an SRV record, then the `port` and `weight` fields from the DNS record are used, and override the port and weight set in the Target. -The balancer will honor the DNS record's `ttl` setting. Upon expiry it queries the nameserver and updates the balancer. When a DNS record has `ttl=0`, the hostname will be added as a single target, with the specified weight. The nameserver will be queried for every request, adding latency to the request. +The balancer honors the DNS record's `ttl` setting. Upon expiry, it queries the nameserver and updates the balancer. +When a DNS record has `ttl=0`, the hostname is added as a single target, with the specified weight. The nameserver is queried for every request, adding latency to the request. ## Schema diff --git a/app/_gateway_entities/upstream.md b/app/_gateway_entities/upstream.md index efb99e5cf..a22e2b39f 100644 --- a/app/_gateway_entities/upstream.md +++ b/app/_gateway_entities/upstream.md @@ -26,6 +26,8 @@ related_resources: url: /gateway/routing/ - text: Expressions router url: /gateway/routing/expressions/ + - text: Health checks and circuit breakers + url: /gateway/health-checks-circuit-breakers/ schema: api: gateway/admin-ee @@ -34,7 +36,8 @@ schema: ## What is an Upstream? -An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#active-health-checks), [circuit break](https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/#passive-health-checks-circuit-breakers), and [load balance](#load-balancing-algorithms) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. +An Upstream refers to the service applications sitting behind {{site.base_gateway}}, to which client requests are forwarded. +In {{site.base_gateway}}, an Upstream represents a virtual hostname and can be used to [health check](/gateway/health-checks-circuit-breakers/), [circuit break](/gateway/health-checks-circuit-breakers/), and [load balance](#load-balancing-algorithms) incoming requests over multiple [Gateway Services](/gateway/entities/service/). In addition, the Upstream entity has more advanced functionality algorithms like least-connections, consistent-hashing, and lowest-latency. ## Upstream and Gateway Service interaction @@ -72,117 +75,94 @@ The load balancer supports the following load-balancing algorithms: ### Round-Robin -The round-robin algorithm will be done in a weighted manner. It will be identical -in results to the DNS based load-balancing, but due to it being an `upstream` -the additional features for health-checks and circuit-breakers will be available -in this case. +The round-robin algorithm is done in a weighted manner. It provides identical +results to the default DNS based load-balancing, but due to it being an `upstream`, +the additional features for health-checks and circuit-breakers are also available. When choosing this algorithm, consider the following: -- good distribution of requests. -- fairly static, as only DNS updates or `target` updates can influence the - distribution of traffic. -- does not improve cache-hit ratios. +- Provides good distribution of requests. +- Remains fairly static, as only DNS updates or `target` updates can influence the distribution of traffic. +- Doesn't improve cache-hit ratios. ### Consistent-Hashing -With the consistent-hashing algorithm a configurable client-input will be used to -calculate a hash-value. This hash-value will then be tied to a specific backend +With the consistent-hashing algorithm, a configurable client input is used to +calculate a hash value. This hash value is then tied to a specific backend server. -A common example would be to use the `consumer` as a hash-input. Since this ID is -the same for every request from that user, it will ensure that the same user will -consistently be dealt with by the same backend server. This will allow for cache +A common example would be to use the `consumer` as a hash input. Since this ID is +the same for every request from that user, it ensures that the same user is +handled consistently by the same backend server. This allows for cache optimizations on the backend, since each of the servers only serves a fixed subset -of the users, and hence can improve its cache-hit-ratio for user related data. +of the users, and can improve its cache-hit ratio for user-related data. This algorithm implements the [ketama principle](https://github.com/RJ/ketama) to maximize hashing stability and minimize consistency loss upon changes to the list of known backends. -When using the `consistent-hashing` algorithm, the input for the hash can be either -`none`, `consumer`, `ip`, `header`, or `cookie`. When set to `none`, the -`round-robin` scheme will be used, and hashing will be disabled. The `consistent-hashing` -algorithm supports a primary and a fallback hashing attribute; in case the primary -fails (e.g., if the primary is set to `consumer`, but no Consumer is authenticated), -the fallback attribute is used. This maximizes upstream cache hits. +The input for the consistent-hashing algorithm can be one of the following options: + +| Option | Description | +|--------|-------------| +| `none` | Doesn't use `consistent-hashing`, uses `round-robin` instead (default). Hashing is disabled. | +| `consumer` | Uses the Consumer ID as the hash input. If no Consumer ID is available, it will fall back on the Credential ID (for example, in case of an external authentication mechanism like LDAP). | +| `ip` | Uses the originating IP address as the hash input. Review the configuration settings for [determining the real IP](/gateway/configuration/#real_ip_config) when using this option. | +| `header` | Uses a specified header as the hash input. The header name is specified in either of the Upstream's `hash_on_header` or `hash_fallback_header` fields, depending on whether `header` is a primary or fallback attribute, respectively. | +| `cookie` | Use a specified cookie with a specified path as the hash input. The cookie name is specified in the Upstream's `hash_on_cookie` field and the path is specified in the Upstream's `hash_on_cookie_path` field. If the specified cookie is not present in the request, it will be set by the response. The generated cookie will have a random UUID value, which is then preserved in the cookie.

The `hash_fallback` setting is invalid and can't be used if `cookie` is the primary hashing mechanism. | -Supported hashing attributes are: - -- `none`: Do not use `consistent-hashing`; use `round-robin` instead (default). -- `consumer`: Use the Consumer ID as the hash input. If no Consumer ID is available, - it will fall back on the Credential ID (for example, in case of an external authentication mechanism like LDAP). -- `ip`: Use the originating IP address as the hash input. Review the configuration - settings for [determining the real IP][real-ip-config] when using this. -- `header`: Use a specified header as the hash input. The header name is - specified in either `hash_on_header` or `hash_fallback_header`, depending on whether - `header` is a primary or fallback attribute, respectively. -- `cookie`: Use a specified cookie with a specified path as the hash input. - The cookie name is specified in the `hash_on_cookie` field and the path is - specified in the `hash_on_cookie_path` field. If the specified cookie is not - present in the request, it will be set by the response. Hence, the `hash_fallback` - setting is invalid if `cookie` is the primary hashing mechanism. - The generated cookie will have a random UUID value. So the first assignment will - be random, but then sticks because it is preserved in the cookie. +The `consistent-hashing` algorithm supports a primary and a fallback hashing attribute. +If the primary fails (for example, if the primary is set to `consumer`, but no Consumer is authenticated), +the fallback attribute is used. This maximizes upstream cache hits. The consistent-hashing balancer is designed to work both with a single node as well as in a cluster. When choosing this algorithm, consider the following: -- improves backend cache-hit ratios. -- requires enough cardinality in the hash-inputs to distribute evenly (for example, hashing on - a header that only has 2 possible values does not make sense). -- the cookie based approach will work well for browser based requests, but less so - for machine-2-machine clients which will often omit the cookie. -- avoid using hostnames in the balancer as the - balancers might/will slowly diverge because the DNS ttl has only second precision - and renewal is determined by when a name is actually requested. On top of this is - the issue with some nameservers not returning all entries, which exacerbates - this problem. So when using the hashing approach in a Kong cluster, preferably add - `target` entities by their IP address. This problem can be mitigated by balancer - rebuilds and higher ttl settings. +- Improves backend cache-hit ratios. +- Requires enough cardinality in the hash inputs to distribute evenly. For example, hashing on a header that only has 2 possible values doesn't make sense. +- The cookie-based approach works well for browser-based requests, but less so for machine-to-machine (M2M) clients, which will often omit the cookie. +- When using the hashing approach in a Kong cluster, add `target` entities by their IP address, and avoid using hostnames in the balancer. + The balancers will slowly diverge, as the DNS TTL only has second precision, and renewal is determined by when a name is actually requested. + Additionally, some nameservers don't return all entries, which makes the problem worse. + This problem can be mitigated by balancer rebuilds and higher TTL settings. ### Least-Connections -This algorithm keeps track of the number of in-flight requests for each backend. -The weights are used to calculate "connection-capacity" of a backend. Requests are +The `least-connections` algorithm keeps track of the number of in-flight requests for each backend. +The weights are used to calculate the connection capacity of a backend. Requests are routed towards the backend with the highest spare capacity. When choosing this algorithm, consider the following: -- good distribution of traffic. -- does not improve cache-hit ratio's. -- more dynamic since slower backends will have more connections open, and hence +- Provides good distribution of traffic. +- Doesn't improve cache-hit ratios. +- This option is more dynamic, since slower backends will have more connections open, and new requests will be routed to other backends automatically. ### Latency -The `latency` algorithm is based on peak EWMA (exponentially weighted moving average), -which ensures that the balancer selects the backend by lowest latency +The `latency` algorithm is based on peak EWMA (Exponentially Weighted Moving Average), +which ensures that the balancer selects the backend by the lowest latency (`upstream_response_time`). The latency metric used is the full request cycle, from -TCP connect to body response time. Since it is a moving average, the metrics will -"decay" over time. +TCP connect to body response time. Since it's a moving average, the metrics will +decay over time. -Weights will not be taken into account. +Target weights aren't taken into account. When choosing this algorithm, consider the following: -- good distribution of traffic provided there is enough base-load to keep the - metrics alive, since they are "decaying". -- not suitable for long-lived connections like websockets or server-sent events (SSE) -- very dynamic since it will constantly optimize. -- ideally, this works best with low variance in latencies. This means mostly similar - shaped traffic and even workloads for the backends. For example, usage - with a GraphQL backend serving small-fast queries as well big-slow ones will result - in high variance in the latency metrics, which will skew the metrics. -- properly set up the backend capacity and ensure proper network latency to prevent - resource starvation. For example, use 2 servers: one a small capacity close by (low - network latency), the other high capacity far away (high latency). Most traffic - will be routed to the small one, until its latency starts going up. The latency - going up however means the small server is most likely suffering from resource - starvation. So, in this case, the algorithm will keep the small server in a constant - state of resource starvation, which is most likely not efficient. +- Provides good distribution of traffic, provided there is enough base load to keep the metrics alive, since they are always decaying. +- The algorithm is very dynamic, since it will constantly optimize loads. +- Latency-based load balancing works best with low variance in latencies, meaning mostly similar-shaped traffic and even workloads for the backends. + For example, using this algorithm with a GraphQL backend serving small-fast queries as well big-slow ones will result in high variance in the latency metrics, which will skew the metrics. +- You must properly set up the backend capacity and ensure proper network latency to prevent resource starvation. + For example, you could use 2 servers: a small capacity server close by (low network latency), and a high capacity server far away (high latency). + Most traffic will be routed to the small one until its latency starts going up. + However, the latency going up means the small server is likely suffering from resource starvation. + In this case, the algorithm will keep the small server in a constant state of resource starvation, which is most likely not efficient. +- This option is not suitable for long-lived connections like websockets or server-sent events (SSE). ## Schema diff --git a/app/_gateway_entities/vault.md b/app/_gateway_entities/vault.md index b8883d9b0..68a03f7a3 100644 --- a/app/_gateway_entities/vault.md +++ b/app/_gateway_entities/vault.md @@ -137,7 +137,7 @@ Would point to a secret object called `pg` inside a HashiCorp Vault, which may r `{vault://hcv/pg/username}`. -Vault references must be used for the whole referenced value. Imagine that you're calling an upstream service with the authentication token `ABC123` +Vault references must be used for the whole referenced value. Imagine that you're calling an upstream service with the authentication token `ABC123`: {% feature_table %} item_title: Works @@ -157,7 +157,8 @@ features: ## Secret rotation in Vaults -By default, {{site.base_gateway}} automatically refreshes secrets *once every minute* in the background. You can also configure how often {{site.base_gateway}} refreshes secrets using the Vault entity configuration. +By default, {{site.base_gateway}} automatically refreshes secrets *once every minute* in the background. +You can also configure how often {{site.base_gateway}} refreshes secrets using the Vault entity configuration. There are two types of refresh configuration available: * Refresh periodically using TTLs: For example, check for a new TLS certificate once per day. diff --git a/app/_gateway_entities/workspace.md b/app/_gateway_entities/workspace.md index a2cfa6cb2..097cf6626 100644 --- a/app/_gateway_entities/workspace.md +++ b/app/_gateway_entities/workspace.md @@ -50,6 +50,7 @@ Workspaces are a way of namespacing {{site.base_gateway}} entities so they can b Workspaces support [multi-tenancy](/gateway/multi-tenancy/) by isolating {{site.base_gateway}} configuration objects. When paired with RBAC, {{site.base_gateway}} administrators can effectively create tenants within the control plane. The Workspace administrators have segregated and secure access to only their portion of the {{site.base_gateway}} configuration in Kong Manager, the Admin API, and the declarative configuration tool decK. + {% mermaid %} flowchart LR @@ -76,6 +77,8 @@ flowchart LR {% endmermaid %} + + ### How does {{site.base_gateway}} resolve entity conflicts between Workspaces? Routing rules are configured at the data plane level. The data plane routes client traffic based on the configuration applied across all Workspaces. Configuring entities related to routing, such as [Gateway Services](/gateway/entities/service/) and [Routes](/gateway/entities/route/), alter the client traffic routing behavior of the data plane, but {{site.base_gateway}} will always attempt to ensure that routing rules don't contain conflicts. @@ -85,9 +88,9 @@ To route traffic to the appropriate Workspace, {{site.base_gateway}} uses a conf When a Service or Route is **created** or **modified**, the {{site.base_gateway}} Router checks for the existence of that object before allowing the operation to proceed in this order: 1. If the Service or Route created is unique across all Workspaces, the new entity is created. -2. If an existing Service or Route object that matches the one being created is found in the current workspace, a `409 Conflict` error is returned. -4. If an equivalent Service or Route is found in a different Workspace, and the host is provided: - 1. If the host field matches in both workspaces, a `409 Conflict` error is returned. +1. If an existing Service or Route object that matches the one being created is found in the current Workspace, a `409 Conflict` error is returned. +2. If an equivalent Service or Route is found in a different Workspace, and the host is provided: + 1. If the host field matches in both Workspaces, a `409 Conflict` error is returned. 1. If the host field does not match, the new entity can be created. 1. If the host is an absolute value, a `409 Conflict` error is returned. diff --git a/app/_landing_pages/gateway/entities.yaml b/app/_landing_pages/gateway/entities.yaml index 0d9ab7fa1..2583157cc 100644 --- a/app/_landing_pages/gateway/entities.yaml +++ b/app/_landing_pages/gateway/entities.yaml @@ -66,11 +66,11 @@ rows: - type: entity_card config: entity: ca_certificate + - columns: - blocks: - type: entity_card config: entity: vault - - columns: - blocks: - type: entity_card config: diff --git a/app/gateway/health-checks-circuit-breakers.md b/app/gateway/health-checks-circuit-breakers.md new file mode 100644 index 000000000..e0892522c --- /dev/null +++ b/app/gateway/health-checks-circuit-breakers.md @@ -0,0 +1,17 @@ +--- +title: Health checks and circuit breakers +content_type: reference +layout: reference + +products: + - gateway + +description: | + Kong supports two kinds of health checks, which can be used separately or in conjunction: active and passive (also known as circuit breakers). + +--- + +@todo + +Use https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/ +Probably need a separate how-to as well - how do you actually enable and use a health check? What entities are involved (Upstream, Targets)? Does any of this info actully belong in the Upstream or Target entity docs? \ No newline at end of file diff --git a/app/gateway/ldap-service-directory-mapping.md b/app/gateway/ldap-service-directory-mapping.md new file mode 100644 index 000000000..e24dfde5c --- /dev/null +++ b/app/gateway/ldap-service-directory-mapping.md @@ -0,0 +1,19 @@ +--- +title: LDAP Service Directory Mapping +content_type: reference +layout: reference + +products: + - gateway + +description: | + Service directory mapping allows organizations to use their LDAP Directory for authentication and authorization in Kong Gateway. + +tier: enterprise + +--- + +@todo + +Use https://docs.konghq.com/gateway/latest/kong-manager/auth/ldap/service-directory-mapping/ +Probably need a separate how-to as well. \ No newline at end of file diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index d1c986903..4bdf9ff8f 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -25,11 +25,11 @@ breadcrumbs: faqs: - q: Is there a performance difference between the traditional router and expressions? - a: Both Traditional and Expressions use the same routing engine internally. Traditional mode configures routes with JSON, and Expressions uses a DSL. - - q: Why would I choose Expressions over the Traditional router? - a: The Expressions router provides more routing flexibility, including fast exact matching that is not available in the Traditional router. + a: Both traditional and expressions modes use the same routing engine internally. Traditional mode configures routes with JSON, and expressions uses a DSL. + - q: Why would I choose expressions over the traditional router? + a: The expressions router provides more routing flexibility, including fast exact matching that is not available in the traditional router. - q: When should I keep using the traditional router over expressions? - a: If you are working with APIOps pipelines that manipulate the route using `deck file patch`, the JSON format used by the traditional router is recommended + a: If you are working with APIOps pipelines that manipulate the route using `deck file patch`, we recommend using the JSON format used by the traditional router. --- The expressions router provides a Domain Specific Language (DSL) that allows for complex routing rule definition. The expressions router ensures good runtime matching performance by providing specific routing comparisons such as non-regex equality checks that are not available in the traditional router. @@ -90,7 +90,7 @@ This section explains how to optimize the expressions you write to get the most ### Number of routes -#### Priority Matching +#### Priority matching Expressions routes are always evaluated in the descending `priority` order they were defined. Therefore, it is helpful to put more likely matched routes before (as in, higher priority) @@ -262,13 +262,13 @@ features: -In addition, expressions also supports one composite type, `Array`. Array types are written as `Type[]`. +In addition, the expressions router also supports one composite type, `Array`. Array types are written as `Type[]`. For example: `String[]`, `Int[]`. Currently, arrays can only be present in field values. They are used in case one field could contain multiple values. For example, `http.headers.x` or `http.queries.x`. #### Matching fields -The following table describes the available matching fields, as well as their associated type when using an expressions based router. +The following table describes the available matching fields, as well as their associated type when using an expressions-based router. diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md index 3440dd739..9be08dd63 100644 --- a/app/gateway/routing/traditional.md +++ b/app/gateway/routing/traditional.md @@ -12,6 +12,8 @@ products: related_resources: - text: Route entity url: /gateway/entities/route/ + - text: SNI entity + url: /gateway/entities/sni/ - text: Expressions router url: /gateway/routing/expressions/ @@ -23,12 +25,15 @@ breadcrumbs: faqs: - q: When should I use the traditional router? - a: "@TODO: When using APIOps transforms" + a: | + If you are working with APIOps pipelines that manipulate the route using `deck file patch`, we recommend using the JSON format used by the traditional router. + + @TODO: When using APIOps transforms --- -The traditional router is {{ site.base_gateway }}'s original routing configuration format. It uses JSON to provide a list of routing criteria, including `host`, `path` and `headers`. +The traditional router is {{ site.base_gateway }}'s original routing configuration format. It uses JSON to provide a list of routing criteria, including `host`, `path`, and `headers`. -Routing based on JSON configuration is available when `router_flavor` is set to both `traditional_compat` _or_ `expressions` in `kong.conf`. +Routing based on JSON configuration is available when [`router_flavor`](/gateway/configuration/#router_flavor) is set to `traditional_compat` _or_ `expressions` in `kong.conf`. ## Routing criteria @@ -118,8 +123,8 @@ them via the Admin API: ```bash curl -i -X POST http://localhost:8001/routes/ \ - -H 'Content-Type: application/json' \ - -d '{"hosts":["example.com", "foo-service.com"]}' + --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 @@ -139,7 +144,7 @@ Similarly, any other header can be used for routing: ```sh curl -i -X POST http://localhost:8001/routes/ \ - -d 'headers.region=north' + --data 'headers.region=north' ``` Incoming requests containing a `Region` header set to `North` are routed to @@ -201,21 +206,22 @@ GET / HTTP/1.1 version: v1 ``` -This request will be routed through to the service. The same happens with this one: +This request will be routed through to the Service. The same happens with this one: ```http GET / HTTP/1.1 version: v2 ``` -But this request isn't routed to the service: +This request isn't routed to the Service: ```http GET / HTTP/1.1 version: v3 ``` -**Note**: The `headers` keys are a logical `AND` and their values a logical `OR`. +{:.info} +> **Note**: The `headers` keys are a logical `AND` and their values a logical `OR`. ### Path @@ -254,9 +260,9 @@ request upstream without changing the URL path. When proxying with path prefixes, **the longest paths get evaluated first**. This allow you to define two routes with two paths: `/service` and -`/service/resource`, and ensure that the former does not "shadow" the latter. +`/service/resource`, and ensure that the former doesn't get overshadowed by the latter. -#### Using Regex in paths +#### Using regex in paths For a path to be considered a regular expression, it must be prefixed with a `~`: @@ -270,7 +276,7 @@ Any path that isn't prefixed with a `~` will be considered plain text: "paths": ["/users/\d+/profile", "/following"] ``` -For more information about how the router processes regular expressions, see [performance considerations when using Expressions](/gateway/latest/key-concepts/routes/expressions/#performance-considerations-when-using-expressions). +For more information about how the router processes regular expressions, see the [routing performance considerations](/gateway/entities/route/#routing-performance-recommendations). ##### Regex evaluation order @@ -305,23 +311,24 @@ defined URIs, in this order: 3. `/version/any/` 4. `/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. +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](/gateway/routing/expressions/). If you see unexpected behavior, use the Kong debug header to help track down the source: -1. In `kong.conf`, set [`allow_debug_header: on`](/gateway/{{page.release}}/reference/configuration/#allow_debug_header). @TODO: Update URL +1. In `kong.conf`, set [`allow_debug_header=on`](/gateway/configuration/#allow_debug_header). 1. 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 {{site.base_gateway}} traverses your routes until it finds one that [matches -the most rules](#matching-priorities). +As usual, a request must still match a Route's `hosts` and `methods` properties +as well, and {{site.base_gateway}} traverses your Routes until it finds one that [matches +the most rules](#route-priority). ##### Capture groups Capture groups are also supported, and the matched group will be extracted -from the path and available for plugins consumption. If we consider the +from the path and available for plugins consumption. Consider the following regex: ``` @@ -334,7 +341,7 @@ And the following request path: /version/1/users/john ``` -{{site.base_gateway}} considers the request path a match, and if the overall route is +{{site.base_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: @@ -349,17 +356,18 @@ local router_matches = ngx.ctx.router_matches Keep the following path matching criteria in mind when configuring paths: -1. **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](/gateway/routing/expressions/). +1. **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](/gateway/routing/expressions/). 1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. 1. **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](https://tools.ietf.org/html/rfc3986). -1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. +1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from the client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. #### Path normalization -To prevent trivial route match bypass, the incoming request URI from client +To prevent trivial route match bypass, the incoming request URI from the client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. Specifically, the following normalization techniques are -used for incoming request URIs, which are selected because they generally do not change +used for incoming request URIs, which are selected because they generally don't change semantics of the request URI: 1. Percent-encoded triplets are converted to uppercase. For example: `/foo%3a` becomes `/foo%3A`. @@ -367,28 +375,22 @@ semantics of the request URI: 3. Dot segments are removed as necessary. For example: `/foo/./bar/../baz` becomes `/foo/baz`. 4. Duplicate slashes are merged. For example: `/foo//bar` becomes `/foo/bar`. -The `paths` attribute of the Route object are also normalized. It is achieved by first determining +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. - -For plain text route path: - -Same normalization technique as above is used, that is, methods 1 through 4. - -For regex route path: - -Only methods 1 and 2 are used. In addition, if the decoded character becomes a regex -meta character, it will be escaped with backslash. +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. {{site.base_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 that preserves the original URI semantics. +be in normalized form, which preserves the original URI semantics. ### HTTP method The `methods` field allows matching the requests depending on their HTTP -method. It accepts multiple values. Its default value is empty (the HTTP -method is not used for routing). +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`: @@ -401,7 +403,7 @@ The following route allows routing via `GET` and `HEAD`: } ``` -Such a route would be matched with the following requests: +This route would be matched with the following requests: ```http GET / HTTP/1.1 @@ -413,17 +415,15 @@ HEAD /resource HTTP/1.1 Host: ... ``` -But it would not match a `POST` or `DELETE` request. This allows for much more -granularity when configuring plugins on routes. For example, one could imagine -two routes pointing to the same service: one with unlimited unauthenticated -`GET` requests, and a second one allowing only authenticated and rate-limited +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 -such requests). +those requests). ### Source -{:.note} - +{:.info} > **Note:** This section only applies to TCP and TLS routes. The `sources` routing attribute allows @@ -448,8 +448,7 @@ address "10.2.2.2" or Port "9123" would match such route. ### Destination -{:.note} - +{:.info} > **Note:** This section only applies to TCP and TLS routes. The `destinations` attribute, similarly to `sources`, @@ -459,8 +458,8 @@ uses the destination of the TCP/TLS connection as routing attribute. ### SNI When using secure protocols (`https`, `grpcs`, or `tls`), a [Server -Name Indication][SNI] can be used as a routing attribute. The following route -allows routing via SNIs: +Name Indication](/gateway/entities/sni/) can be used as a routing attribute. +The following route allows routing via SNIs: ```json { @@ -470,22 +469,15 @@ allows routing via SNIs: ``` Incoming requests with a matching hostname set in the TLS connection's SNI -extension would be routed to this route. As mentioned, SNI routing applies not -only to TLS, but also to other protocols carried over TLS - such as HTTPS and -If multiple SNIs are specified in the route, any of them can match with the incoming request's SNI. -with the incoming request (OR relationship between the names). +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 cannot be modified after the TLS connection has +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 match, regardless of the `Host` header. -has been established. This means keepalive connections that send multiple requests -will have the same SNI hostnames while performing router match -(regardless of the `Host` header). - -Please note that creating a route with mismatched SNI and `Host` header matcher -is possible, but generally discouraged. +will have the same SNI hostname while performing router matches, regardless of the value in the `Host` header. -## Route Priority +## Route priority In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: @@ -495,7 +487,7 @@ In `traditional_compat` mode, the priority of a Route is determined as follows, 4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. 5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. -For example, if two routes are configured like so: +For example, if two Routes are configured like so: ```json { From 3699a24527eafed57b421c02b68010ad18229a2e Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Wed, 22 Jan 2025 17:03:09 -0800 Subject: [PATCH 14/17] fix typo --- app/gateway/health-checks-circuit-breakers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/gateway/health-checks-circuit-breakers.md b/app/gateway/health-checks-circuit-breakers.md index e0892522c..05d6f4c06 100644 --- a/app/gateway/health-checks-circuit-breakers.md +++ b/app/gateway/health-checks-circuit-breakers.md @@ -14,4 +14,4 @@ description: | @todo Use https://docs.konghq.com/gateway/latest/how-kong-works/health-checks/ -Probably need a separate how-to as well - how do you actually enable and use a health check? What entities are involved (Upstream, Targets)? Does any of this info actully belong in the Upstream or Target entity docs? \ No newline at end of file +Probably need a separate how-to as well - how do you actually enable and use a health check? What entities are involved (Upstream, Targets)? Does any of this info actually belong in the Upstream or Target entity docs? \ No newline at end of file From 496ae810be210d27a7d8c652f55ae2b87134811b Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Wed, 22 Jan 2025 22:54:49 -0800 Subject: [PATCH 15/17] fix broken link and more vale --- app/_gateway_entities/vault.md | 2 +- app/gateway/ldap-service-directory-mapping.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/_gateway_entities/vault.md b/app/_gateway_entities/vault.md index 68a03f7a3..4f397515d 100644 --- a/app/_gateway_entities/vault.md +++ b/app/_gateway_entities/vault.md @@ -81,7 +81,7 @@ columns: features: - title: Environment variable - url: /how-to/store-secrets-as-env-variables/ + url: /gateway/entities/vault/#store-secrets-as-environment-variables oss: true enterprise: true supports_konnect: true diff --git a/app/gateway/ldap-service-directory-mapping.md b/app/gateway/ldap-service-directory-mapping.md index e24dfde5c..9ff68f4d9 100644 --- a/app/gateway/ldap-service-directory-mapping.md +++ b/app/gateway/ldap-service-directory-mapping.md @@ -7,7 +7,7 @@ products: - gateway description: | - Service directory mapping allows organizations to use their LDAP Directory for authentication and authorization in Kong Gateway. + Service directory mapping allows organizations to use their LDAP Directory for authentication and authorization in {{site.base_gateway}}. tier: enterprise From 7a02c5e232adf7b7caa54e691a97922d13aada38 Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Wed, 22 Jan 2025 23:03:09 -0800 Subject: [PATCH 16/17] phrasing fix --- app/gateway/routing/traditional.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md index 9be08dd63..ca5c077fb 100644 --- a/app/gateway/routing/traditional.md +++ b/app/gateway/routing/traditional.md @@ -259,8 +259,8 @@ one of the routes' `paths` values. By default, {{site.base_gateway}} would then request upstream without changing the URL path. When proxying with path prefixes, **the longest paths get evaluated first**. -This allow you to define two routes with two paths: `/service` and -`/service/resource`, and ensure that the former doesn't get overshadowed by the latter. +This allow you to define two routes with two paths, such as `/service` and +`/service/resource`, and ensure that the former doesn't overshadow the latter. #### Using regex in paths From a91e0a6f8c85ba98bc26f27090fc591684e82bf0 Mon Sep 17 00:00:00 2001 From: lena-larionova Date: Wed, 22 Jan 2025 23:10:24 -0800 Subject: [PATCH 17/17] final grammar check --- app/gateway/routing/expressions.md | 12 ++++++------ app/gateway/routing/traditional.md | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/app/gateway/routing/expressions.md b/app/gateway/routing/expressions.md index 4bdf9ff8f..4c5287bdb 100644 --- a/app/gateway/routing/expressions.md +++ b/app/gateway/routing/expressions.md @@ -51,7 +51,7 @@ In your `kong.conf` file, set `router_flavor = expressions` and restart your {{s At runtime, {{site.base_gateway}} builds two separate routers for the HTTP and Stream (TCP, TLS, UDP) subsystem. When a request/connection comes in, {{site.base_gateway}} looks at which field your configured Routes require, and supplies the value of these fields to the router execution context. -Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route will be evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is updated incrementally as configured Routes change. +Routes are inserted into each router with the appropriate `priority` field set. The priority is a positive integer that defines the order of evaluation of the router. The bigger the priority, the sooner a Route is evaluated. In the case of duplicate priority values between two Routes in the same router, their order of evaluation is undefined. The router is updated incrementally as configured Routes change. As soon as a Route yields a match, the router stops matching and the matched Route is used to process the current request/connection. @@ -403,9 +403,9 @@ The expressions language supports a rich set of operators that can be performed | `>` | Greater than | Field value is greater than the constant value | | `<=` | Less than or equal | Field value is less than or equal to the constant value | | `<` | Less than | Field value is less than the constant value | -| `in` | In | Field value is inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | -| `not in` | Not in | Field value is not inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` will only return `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | -| `contains` | Contains | Field value contains the constant value. This operator is used to check the existence of a string inside another string. For example, `http.path contains "foo"` will return `true` if `foo` can be found anywhere inside `http.path`. This will match a `http.path` that looks like `/foo`, `/abc/foo`, or `/xfooy`, for example. | +| `in` | In | Field value is inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` only returns `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | +| `not in` | Not in | Field value is not inside the constant value. This operator is used with `IpAddr` and `IpCidr` types to perform an efficient IP list check. For example, `net.src.ip in 192.168.0.0/24` only returns `true` if the value of `net.src.ip` is within `192.168.0.0/24`. | +| `contains` | Contains | Field value contains the constant value. This operator is used to check the existence of a string inside another string. For example, `http.path contains "foo"` returns `true` if `foo` can be found anywhere inside `http.path`. This will match a `http.path` that looks like `/foo`, `/abc/foo`, or `/xfooy`, for example. | | `&&` | And | Returns `true` if **both** expressions on the left and right side evaluates to `true` | | `||` | Or | Returns `true` if **any** expressions on the left and right side evaluates to `true` | | | `(Expression)` | Parenthesis | Groups expressions together to be evaluated first | @@ -447,9 +447,9 @@ Depending on the field type, only certain content types and operators are suppor | Prefix based path matching | `http.path ^= "/foo/bar"` | Matches HTTP requests that have a path starting with `/foo/bar` | | Regex based path matching | `http.path ~ r#"/foo/bar/\d+"#` | N/A | | Case insensitive path matching | `lower(http.path) == "/foo/bar"` | Ignores case when performing the path match. | -| Match by header value ("all" style matching) | `http.headers.x_foo ~ r#"bar\d"#` | If there are multiple header values for `X-Foo` and the client sends more than one `X-Foo` header with different values, the above example will ensure **each** instance of the value will match the regex `r#"bar\d"#`. This is called "all" style matching. | +| Match by header value ("all" style matching) | `http.headers.x_foo ~ r#"bar\d"#` | If there are multiple header values for `X-Foo` and the client sends more than one `X-Foo` header with different values, the above example ensures that **each** instance of the value matches the regex `r#"bar\d"#`. This is called "all" style matching. | | Match by header value ("any" style matching) | `any(http.headers.x_foo) ~ r#"bar\d"#` | Returns `true` for the predicate as soon as any of the values pass the comparison. Can be combined with other transformations, like `lower()`. | -| Regex captures | `http.path ~ r#"/foo/(?P.+)"#` | You can define regex capture groups in any regex operation which will be made available later for plugins to use. Currently, this is only supported with the `http.path` field. The matched value of `component` will be made available later to plugins such as [Request Transformer Advanced](/plugins/request-transformer-advanced/). | +| Regex captures | `http.path ~ r#"/foo/(?P.+)"#` | You can define regex capture groups in any regex operation, which will be made available later for plugins to use. Currently, this is only supported with the `http.path` field. The matched value of `component` will be made available later to plugins such as [Request Transformer Advanced](/plugins/request-transformer-advanced/). | ### TCP, TLS, and UDP examples diff --git a/app/gateway/routing/traditional.md b/app/gateway/routing/traditional.md index ca5c077fb..52e4d8250 100644 --- a/app/gateway/routing/traditional.md +++ b/app/gateway/routing/traditional.md @@ -27,8 +27,7 @@ faqs: - q: When should I use the traditional router? a: | If you are working with APIOps pipelines that manipulate the route using `deck file patch`, we recommend using the JSON format used by the traditional router. - - @TODO: When using APIOps transforms + --- The traditional router is {{ site.base_gateway }}'s original routing configuration format. It uses JSON to provide a list of routing criteria, including `host`, `path`, and `headers`. @@ -51,8 +50,8 @@ 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 accepts one or more values, - a request needs only one of the values to be considered a match) + 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: @@ -259,7 +258,7 @@ one of the routes' `paths` values. By default, {{site.base_gateway}} would then request upstream without changing the URL path. When proxying with path prefixes, **the longest paths get evaluated first**. -This allow you to define two routes with two paths, such as `/service` and +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. #### Using regex in paths @@ -270,7 +269,7 @@ For a path to be considered a regular expression, it must be prefixed with a `~` paths: ["~/foo/bar$"] ``` -Any path that isn't prefixed with a `~` will be considered plain text: +Any path that isn't prefixed with a `~` is considered plain text: ``` "paths": ["/users/\d+/profile", "/following"] @@ -358,7 +357,7 @@ Keep the following path matching criteria in mind when configuring paths: 1. **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](/gateway/routing/expressions/). -1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group will be extracted from the path and available for plugins consumption. +1. **Capture groups:** [Regex capture groups](/gateway/routing/expressions/#example-expressions) are also supported, and the matched group is extracted from the path and available for plugin consumption. 1. **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](https://tools.ietf.org/html/rfc3986). 1. **Normalization behavior:** To prevent Route match bypasses, the incoming request URI from the client is always normalized according to [RFC 3986](https://tools.ietf.org/html/rfc3986) before router matching occurs. @@ -457,8 +456,8 @@ uses the destination of the TCP/TLS connection as routing attribute. ### SNI -When using secure protocols (`https`, `grpcs`, or `tls`), a [Server -Name Indication](/gateway/entities/sni/) can be used as a routing attribute. +When using secure protocols (`https`, `grpcs`, or `tls`), a +[Server Name Indication](/gateway/entities/sni/) can be used as a routing attribute. The following route allows routing via SNIs: ```json @@ -481,10 +480,12 @@ will have the same SNI hostname while performing router matches, regardless of t In `traditional_compat` mode, the priority of a Route is determined as follows, by the order of descending significance: -1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. Routes with higher priority point values will be considered before those with lower values. +1. **Priority points:** A priority point is added for every `methods`, `host`, `headers`, and `snis` value that a Route has. +Routes with higher priority point values are considered before those with lower values. 2. **Wildcard hosts:** Among Routes with the same priority point value, Routes without a wildcard host specified (or no host at all) are prioritized before those that have any wildcard host specification. 3. **Header count:** The resulting groups are sorted so the Routes with a higher number of specified headers have higher priority than those with a lower number of headers. -4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. Routes that have no regular expression path are ordered by the length of their paths. +4. **Regular expressions and prefix paths:** Routes that have a regular expression path are considered first and are ordered by their `regex_priority` value. +Routes that have no regular expression path are ordered by the length of their paths. 5. **Creation date:** If all of the above are equal, the router chooses the Route that was created first using the Route's `created_at` value. For example, if two Routes are configured like so: