Skip to content

GEP-1911 - Backend Protocol Selection #1979

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 39 commits into from
Sep 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
1c22bc1
Initial draft of GEP-1911 allowing end-users to specify backend
dprotaso Apr 6, 2023
f471e96
fix tab vs spaces
dprotaso Apr 27, 2023
f0cfa7d
indicate that per-protocol structs can be extended in the future
dprotaso Apr 27, 2023
a55e742
Add small intro
dprotaso Apr 27, 2023
f5976ea
Address Candace's feedback
dprotaso Apr 28, 2023
78e36f9
add an option to consider re-using Route resources
dprotaso Apr 28, 2023
d635744
expand appProtocol based on findings
dprotaso Apr 28, 2023
a837edc
how would we configure certain protocols via appProtocol
dprotaso Apr 28, 2023
e22558e
rewrite doc to focus on supporting Kubernetes Standard Application Pr…
dprotaso May 12, 2023
004cc3e
fix link
dprotaso May 12, 2023
465f284
add back multiple protocols on the same port
dprotaso May 12, 2023
a84a956
change multiple protocol example to TCP/UDP which is what K8s supports
dprotaso Jun 2, 2023
3c81267
fix links
dprotaso Jun 19, 2023
a8fe63e
move alternate API under a detail block so people don't confuse that …
dprotaso Jun 19, 2023
d853a85
add a compatability table
dprotaso Jun 19, 2023
46e4c84
fix links
dprotaso Jun 19, 2023
c295a90
Drop raw support
dprotaso Aug 2, 2023
a6d387f
tweak default protocol clause
dprotaso Aug 2, 2023
e5b11ef
tweak tables so columns are the same
dprotaso Aug 2, 2023
5c93e28
limit multiplex protocols to just those supported by K8s (UDP/TCP for…
dprotaso Aug 2, 2023
9ededdf
tweak new appProtocol section - include an example of using a gateway…
dprotaso Aug 2, 2023
dcfd9af
label open questions explicitly
dprotaso Aug 2, 2023
9947059
three kubernetes.io appProtocols
dprotaso Aug 14, 2023
c17dcda
incompatible backend protocols make the backend invalid
dprotaso Aug 14, 2023
cc2a6ec
add godoc to HTTPBackendRef explaining and invalid backend
dprotaso Aug 14, 2023
eeb25eb
drop alternative example because people keep commenting on it
dprotaso Sep 11, 2023
436effe
Drop alternative mechanic that's used in GAMMA
dprotaso Sep 11, 2023
3eb4e1c
address Nicks comments
dprotaso Sep 14, 2023
ba4ec05
add references to Google and AWS's approach to the problem
dprotaso Sep 14, 2023
9c55bef
TLSConnectionPolicy => BackendTLSPolicy
dprotaso Sep 18, 2023
6c8a566
Merge remote-tracking branch 'upstream/main' into gep-1911
dprotaso Sep 18, 2023
0ba640a
address Rob's feedback
dprotaso Sep 18, 2023
6cbbe3d
drop SCTP multiplexing question
dprotaso Sep 18, 2023
49bdd51
absence of appProtocol doesn't mean implementations disable features
dprotaso Sep 18, 2023
00fe8a9
multiplexing UDP/TCP is optional
dprotaso Sep 18, 2023
6318e5f
TLSRoute paired to non-TLS listener doesn't make sense
dprotaso Sep 18, 2023
8b00cfe
fix casing on some section titles
dprotaso Sep 20, 2023
5baadd3
specific protocol support is optional
dprotaso Sep 20, 2023
f7cd3d5
Update geps/gep-1911.md
dprotaso Sep 27, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apis/v1beta1/httproute_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -1134,12 +1134,17 @@ type HTTPBackendRef struct {
// case, the Reason must be set to `RefNotPermitted` and the Message of the
// Condition must explain which cross-namespace reference is not allowed.
//
// * It refers to a Kubernetes Service that has an incompatible appProtocol
// for the given Route type
//
// Support: Core for Kubernetes Service
//
// Support: Implementation-specific for any other resource
//
// Support for weight: Core
//
// Support for Kubernetes Service appProtocol: Extended
//
// +optional
BackendRef `json:",inline"`

Expand Down
183 changes: 183 additions & 0 deletions geps/gep-1911.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
# GEP-1911: Backend Protocol Selection

* Issue: [#1911](https://github.com/kubernetes-sigs/gateway-api/issues/1911)
* Status: Provisional

(See status definitions [here](overview.md#status).)

## TLDR

Not all implementations support automatic protocol selection. Even in some cases protocols are disabled without an explicit opt-in (eg. websockets with Contour & NGINX). Thus application developers need the ability to specify the protocol(s) that their application supports.

## Goals

- Support protocols that can have a Gateway `*Route` resource as a frontend
- Standardize Gateway API implementations on the protocols & constants defined by the Kubernetes [Standard Application Protocols (KEP-3726)][kep-3726]
- Support backends with multiple protocols on the same port (ie. tcp/udp)

## Non-Goals

- Backend TLS (covered in [GEP-1897](https://github.com/kubernetes-sigs/gateway-api/issues/1897))
- Additional protocol specific configuration
- Disabling Protocols

## Introduction

Since Kubernetes 1.20 the [`core/v1.Service`][k8s-service] and [`core/v1.EndpointSlice`][k8s-endpointslices] resource has a stable `appProtocol` field. It's purpose is to allow end-users to specify an application protocol (L7) for each service port.

Originally the use of this field in the Gateway API was rejected in [GEP-1282](geps/gep-1282#non-goals):
> v1.Service’s appProtocol field is not fit for purpose, because it is defined as accepting values either from the IANA Service Name registry, or domain-prefixed values and we need more flexibility than that.

Since then a Kubernetes enhancement proposal was created [KEP-3726][kep-3726] to repurpose `appProtocol` to include a convention for protocols that are not IANA service names. This would involve prefixing protocol names with `kubernetes.io/*`.

Note: Kubernetes will automatically create `EndpointSlices` for `Services` that have a selector. [Custom `EndpointSlices`](https://kubernetes.io/docs/concepts/services-networking/service/#custom-endpointslices) can manually be created.

## API Semantics

A Gateway implementation MUST recognize the Kubernetes Standard Application Protocols ([KEP-3726][kep-3726]) for specifying the protocol for a backend reference in a Gateway API `*Route` resource

Thus when a `*Route` points to a Kubernetes Service resource the backend protocol for each port can be specified by

- setting the `appProtocol` field on the Kubernetes `Service`
- setting the `appProtocol` field on an `Endpoint`/`EndpointSlice` object associated with a Kubernetes `Service`

At the moment there exists three defined constants:

- `kubernetes.io/h2c` - HTTP/2 over cleartext as described in [RFC7540](https://www.rfc-editor.org/rfc/rfc7540)
- `kubernetes.io/ws` - WebSocket over cleartext as described in [RFC6445](https://www.rfc-editor.org/rfc/rfc6455)
- `kubernetes.io/wss` - WebSocket over TLS as described in [RFC6455](https://www.rfc-editor.org/rfc/rfc6455)

### New Protocols & Reserved Prefix

To add support for a new protocol it should first become a Kubernetes Standard Application Protocol by updating the [KEP-3726][kep-3726]. [KEP-3726][kep-3726] also states the `appProtocol` field accepts a domain-prefixed implementation specific value. Thus, if the suggested protocol is not suited to have a `kubernetes.io/*` prefix, then the Gateway API MAY support the new protocol using it's own prefix `gateway.networking.k8s.io/*`. Please make a PR to this GEP.

For example we may want to add a sentinel `appProtocol` value that prevents Gateway implementations from discovering the protocol of the application. Instead they should just refer to the Service's `protocol` field. Such a constant was rejected upstream (https://github.com/kubernetes/enhancements/pull/4106) but as an example it could be defined in a future addition to this GEP as `gateway.networking.k8s.io/no-sniff`.

### Default Protocols

If a Service `appProtocol` isn't specified an implementation MAY infer the backend protocol through its own means. Implementations MAY infer the protocol from the `Route` type referring to the backend Service.

Absence of the `appProtocol` field does not imply the implementation should disable any features (eg. websocket upgrades).

### Multiple Protocols on the Same Port

Only the Kubernetes `Service` `protocol` field supports multiple protocols on the same port. See the details in [KEP-1435][kep-1435].

Implementations MAY support multiplexing `TCP` and `UDP` on the same port. Otherwise implementations MUST set `ResolvedRefs` condition to `False` with the Reason `UnsupportedProtocol` with a clear message that multiplexing is not supported.

Currently Kubernetes `Service` API only allows different `appProtocol` values for the same port when `protocol` fields differs. At this time there seems to be interest in changing `appProtocol` to be a list in order to faciliate this use-case.

### Supporting Protocols

If a Route attached to a Gateway is not able to send traffic to the backend using the specified protocol then the backend is considered invalid. Implementations MUST set `ResolvedRefs` condition to `False` with the Reason `UnsupportedProtocol`.

Implementations MAY support the following combinations below:

ServicePort Protocol | ServicePort AppProtocol | Route Type | Supported
-|-|-|-
`TCP` | `kubernetes.io/h2c` | `GRPCRoute` | Yes [1]
`TCP` | `kubernetes.io/h2c` | `HTTPRoute` | Yes
`TCP` | `kubernetes.io/ws` | `HTTPRoute` | Yes
`TCP` | `kubernetes.io/wss` | `TLSRoute` | Yes

1. GRPC works over h2c - so a GRPCRoute should be able to connect to an h2c backend

Implementations MAY support the following combinations below:

ServicePort Protocol | ServicePort AppProtocol | Route Type | Supported
-|-|-|-
ServicePort Protocol | ServicePort AppProtocol | Route Type | Supported
`TCP` | `kubernetes.io/wss` | `HTTPRoute` | Conditional [1]

1. Only if there is a corresponding `BackendTLSPolicy` - see [GEP-1897](geps/gep-1897)

## Open Questions

1. TLSRoute & UDP protocol

TLS over UDP seems to be a thing via QUIC/HTTP3 [ref](https://www.smashingmagazine.com/2021/08/http3-core-concepts-part1/).
Likewise there's also [DTLS](https://en.wikipedia.org/wiki/Datagram_Transport_Layer_Security). But it's unclear if Gateway's TLSRoute
applies to an underlying UDP protocol.

2. Websockets & HTTP/2/3

Should we upstream new constants for websocket over [HTTP/2](https://www.rfc-editor.org/rfc/rfc8441.html) & [HTTP/3](https://www.rfc-editor.org/rfc/rfc9220.html) ? HTTP/3 makes things more complicated since its supports UDP as the underlying protocol.

## Alternatives

### Single Meta-resource

The first pass of this GEP proposed a new meta-resource [GEP-713](geps/gep-713) called `BackendProtocol`.

This allows end-users to specify a list of ports and a list of corresponding protocols that that single
port supports.

This was dropped in favour of supporting Kubernetes Standard Application Protocols.

### Multiple Protocol Meta-resources

Rather than bundle protocol details into a single resource an alternative would be to create distinct meta resources.
ie. `HTTP2Backend`, `GPRCBackend`, `WebsocketBackend`.

The advantages of this approach are:

- Easy to introduce new protocols
- Definitions/types would be simpler

The disadvantages of this approach are:

- N resources for N protocols need to be created to describe a single backend
- No easy mechanic to specify priority of protocols

### Adding Properties on Gateway Route Objects

From [GEP-1282](geps/gep-1282#tldr):
> some types of configuration requested by users are more about defining functionality that describes capabilities of the backend more than the route you take to get to the backend.

Backend protocol is specifying capabilities. This configuration is less about routing.

### Kubernetes Service - Expanding Protocol field

The `protocol` field on a Kubernetes service is used to specify a L4 protocol over IP. This field isn't appropriate to describe protocols
that operate at a higher 'application' level (eg. HTTP/GRPC etc.)

### Extending Kubernetes Service

This is considered untenable due to the 'the turnaround time for those changes can be years.' ([ref-1282](geps/gep-1282#non-goals))

### Unstructured Data/Special Values

Unstructured data refers to using labels and annotations.

From [GEP-1282](geps/gep-1282#non-goals):
> these are very sticky and hard to get rid of once you start using them.

Special values refers to using special strings in existing Kubernetes Resources.
For example Istio allows for protocol to be specified by prefixing the Kubernetes
Service's port name with the protocol (ie. `http-`, `grpc-`). This approach is
limiting as it doesn't allow for multiple protocols on the same port and future
configuration per protocol. One protocol per port may be relaxed in the future see
[KEP 1435][kep-1435]

Additionally, annotations are not self-documenting unlike CRD fields which can display
documentation via `kubectl explain`

## References

- [GitHub Discussion](https://github.com/kubernetes-sigs/gateway-api/discussions/1244)
- GEP-1282 - Describing Backend Properties
- [GEP](geps/gep-1282)
- [Issue](https://github.com/kubernetes-sigs/gateway-api/issues/1911)
- [GEP-713 - Metaresources](geps/gep-713)
- [Linkerd Protocol Detection](https://linkerd.io/2.12/features/protocol-detection/)
- [Istio Protocol Selection](https://istio.io/latest/docs/ops/configuration/traffic-management/protocol-selection/)
- Contour Protocol Selection
- [Websockets](https://projectcontour.io/docs/1.24/config/websockets/)
- [GRPC](https://projectcontour.io/docs/1.24/guides/grpc/#httpproxy-configuration)
- [AWS Gateway Protocol Selection](https://github.com/aws/aws-application-networking-k8s/blob/a277fb39449383f53cd7d1e5576b4fa190a1a853/config/crds/bases/application-networking.k8s.aws_targetgrouppolicies.yaml#L109)
- [Google GKE AppProtocol Selection](https://cloud.google.com/kubernetes-engine/docs/concepts/ingress-xlb#https_tls_between_load_balancer_and_your_application)

[k8s-service]: https://kubernetes.io/docs/concepts/services-networking/service/
[k8s-endpointslices]: https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/
[kep-3726]: https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/3726-standard-application-protocols
[kep-1435]: https://github.com/kubernetes/enhancements/tree/master/keps/sig-network/1435-mixed-protocol-lb
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ nav:
- geps/gep-1619.md
- geps/gep-1867.md
- geps/gep-1897.md
- geps/gep-1911.md
- geps/gep-2162.md
# - Implementable:
# -
Expand Down