...

Text file src/sigs.k8s.io/gateway-api/geps/gep-746.md

Documentation: sigs.k8s.io/gateway-api/geps

     1# GEP-746: Replace Cert Refs on HTTPRoute with Cross Namespace Refs from Gateway
     2
     3* Issue: [#746](https://github.com/kubernetes-sigs/gateway-api/issues/746)
     4* Status: Standard
     5
     6## TLDR
     7
     8This GEP proposes that we should remove TLS Certificate references from
     9HTTPRoute and replace them with Cross Namespace Certificate references from
    10Gateways. Although that is not a complete replacement on its own, this GEP shows
    11how a controller could provide the rest of the functionality with this approach.
    12
    13## Goals
    14
    15* Remove a confusing and underspecified part of the API - cert refs on
    16  HTTPRoute.
    17* Add the ability to reference certificates in other namespaces from Gateways
    18  to replace much of the functionality that was enabled by cert refs on
    19  HTTPRoute.
    20* Describe how a controller could automate self service cert attachment to
    21  Gateway listeners.
    22
    23## Non-Goals
    24
    25* Actually provide a core implementation of a controller that can enable self
    26  service cert attachment. This may be worth considering at a later point, but
    27  is out of scope for this GEP.
    28
    29## Introduction
    30
    31TLS Certificate references on HTTPRoute have always been a confusing part of the
    32Gateway API. In the v1alpha2 release, we should consider removing this feature
    33while we still can. This GEP proposes an alternative that is simpler to work
    34with and understand, while also leaving sufficient room to enable all the same
    35capabilities that certificate references on HTTPRoute enabled.
    36
    37### Attaching TLS Certificates with Routes is Confusing
    38One of the most confusing parts of the Gateway API is how certificates can be
    39attached to Routes. There are a variety of different factors that lead to
    40confusion here:
    41
    42* It can be natural to assume that a certificate attached to a Route only
    43  applies to that Route. In reality, it applies to the entire listener(s)
    44  associated with that Route.
    45* This means that a Route can affect any other Routes attached to the same
    46  Gateway Listener. By attaching a Route to a Gateway Listener, you’re
    47  implicitly trusting all other Routes attached to that Gateway Listener.
    48* When multiple Routes specify a certificate for the same Listener, it’s
    49  possible that they will conflict and create more confusion.
    50
    51### Why We Did It
    52To understand how we ended up with the ability to attach TLS certificates with
    53Routes, it’s helpful to look at the use cases for this capability:
    54
    551. Some users want Route owners to be able to attach arbitrary domains and certs
    56   to a Gateway listener.
    57   [#103](https://github.com/kubernetes-sigs/gateway-api/issues/103)
    581. Some users want Route owners to control certs for their applications.
    59
    60### Alternative Solutions
    61
    62#### 1. Automation with tools like Cert-Manager
    63When automation is acceptable, the first use case is entirely possible with
    64tools like cert-manager that can watch Routes, generate certs for them, and
    65attach them to a Gateway.
    66
    67#### 2. Cross Namespace Cert Direct References from Gateways
    68With the already established ReferenceGrant concept, we have established a safe
    69way to reference resources across namespaces. Although this would require some
    70coordination between Gateway and App owners, it would enable App owners to
    71retain full control of the certs used by their app without the extra confusion
    72that certs in HTTPRoute have led to.
    73
    74### Enabling Self-Service Certificate Attachment for App Owners
    75Although this dramatically simplifies the API, it does not completely replace
    76the functionality that certs attached to HTTPRoutes enabled. Most notably, it
    77would be difficult to attach arbitrary self-provided certificates to a Gateway
    78listener without requiring manual changes from a Gateway admin.
    79
    80There are a couple potential solutions here:
    81
    82#### 1. Implement a selector for cert references instead of direct references
    83Although the simplicity of this approach is nice, it ends up with many of the
    84same problems as certificates attached to Routes have and feels inconsistent
    85with how Routes attach to Gateways.
    86
    87#### 2. Implement a controller that attaches certificates to Gateway listeners
    88Similar to cert-manager, it could be possible to implement a controller that
    89watches for Secrets with a certain label, and attaches those to the specified
    90Gateway. Although it's out of scope for this GEP to completely define what a
    91controller like this could look like, it would likely need to include at least
    92one of the following safeguards:
    93
    941. A way to configure which namespaces could attach certificates for each
    95   domain.
    962. A way to configure which namespaces could attach certificates to each
    97   Gateway (or Listener).
    983. A way to use ReferenceGrant to indicate where references from Secrets to
    99   Gateways were trusted from and to.
   100
   101## API
   102
   103The API changes proposed here are quite small, mostly removing fields.
   104
   105### Changes
   1061. The `LocalObjectReference` used for the `CertificateRef` field in
   107   `GatewayTLSConfig` would be replaced with an `ObjectReference`.
   1081. `ReferenceGrant` would be updated to note that references from Gateways to
   109   Secrets were part of the Core support level.
   110
   111### Removals
   112
   113From HTTPRouteSpec:
   114```go
   115    // TLS defines the TLS certificate to use for Hostnames defined in this
   116    // Route. This configuration only takes effect if the AllowRouteOverride
   117    // field is set to true in the associated Gateway resource.
   118    //
   119    // Collisions can happen if multiple HTTPRoutes define a TLS certificate
   120    // for the same hostname. In such a case, conflict resolution guiding
   121    // principles apply, specifically, if hostnames are same and two different
   122    // certificates are specified then the certificate in the
   123    // oldest resource wins.
   124    //
   125    // Please note that HTTP Route-selection takes place after the
   126    // TLS Handshake (ClientHello). Due to this, TLS certificate defined
   127    // here will take precedence even if the request has the potential to
   128    // match multiple routes (in case multiple HTTPRoutes share the same
   129    // hostname).
   130    //
   131    // Support: Core
   132    //
   133    // +optional
   134    TLS *RouteTLSConfig `json:"tls,omitempty"`
   135```
   136
   137And the associated struct:
   138```go
   139// RouteTLSConfig describes a TLS configuration defined at the Route level.
   140type RouteTLSConfig struct {
   141    // CertificateRef is a reference to a Kubernetes object that contains a TLS
   142    // certificate and private key. This certificate is used to establish a TLS
   143    // handshake for requests that match the hostname of the associated HTTPRoute.
   144    // The referenced object MUST reside in the same namespace as HTTPRoute.
   145    //
   146    // CertificateRef can reference a standard Kubernetes resource, i.e. Secret,
   147    // or an implementation-specific custom resource.
   148    //
   149    // Support: Core (Kubernetes Secrets)
   150    //
   151    // Support: Implementation-specific (Other resource types)
   152    //
   153    CertificateRef LocalObjectReference `json:"certificateRef"`
   154}
   155```
   156
   157From GatewayTlsConfig:
   158```go
   159    // RouteOverride dictates if TLS settings can be configured
   160    // via Routes or not.
   161    //
   162    // CertificateRef must be defined even if `routeOverride.certificate` is
   163    // set to 'Allow' as it will be used as the default certificate for the
   164    // listener.
   165    //
   166    // Support: Core
   167    //
   168    // +optional
   169    // +kubebuilder:default={certificate:Deny}
   170    RouteOverride *TLSOverridePolicy `json:"routeOverride,omitempty"`
   171```
   172
   173And the associated types:
   174```go
   175type TLSRouteOverrideType string
   176
   177const (
   178    // Allows the parameter to be configured from all routes.
   179    TLSROuteOVerrideAllow TLSRouteOverrideType = "Allow"
   180
   181    // Prohibits the parameter from being configured from any route.
   182    TLSRouteOverrideDeny TLSRouteOverrideType = "Deny"
   183)
   184
   185// TLSOverridePolicy defines a schema for overriding TLS settings at the Route
   186// level.
   187type TLSOverridePolicy struct {
   188    // Certificate dictates if TLS certificates can be configured
   189    // via Routes. If set to 'Allow', a TLS certificate for a hostname
   190    // defined in a Route takes precedence over the certificate defined in
   191    // Gateway.
   192    //
   193    // Support: Core
   194    //
   195    // +optional
   196    // +kubebuilder:default=Deny
   197    Certificate *TLSRouteOverrideType `json:"certificate,omitempty"`
   198}
   199```
   200
   201## Prior Art
   202
   203OpenShift already supports configuring TLS certificates on Routes. Although
   204largely similar to the Gateway API approach, there are some notable differences:
   205
   206* Each Route can specify a maximum of 1 hostname
   207* When a Route is attached to a hostname, newer Routes can't use the same
   208  hostname unless all of the following are true:
   209    * The Routes are in the same namespace or the Router is configured to allow
   210      sharing hostnames across namespaces
   211    * The Routes have unique, non-overlapping paths specified
   212    * The Routes are not TCP or TLS routes
   213
   214A typical configuration would involve a Router with `*.example.com` that has a
   215wildcard cert. Routes could be attached within those constraints without the
   216need for a cert. Routes can also use a different hostname if they also provide a
   217cert.
   218
   219## Alternatives
   220
   221### 1. Improved Documentation + Extended Support Level
   222My first attempt to improve this was to create a
   223[PR](https://github.com/kubernetes-sigs/gateway-api/pull/739) that would clarify
   224the documentation around how this works and lower the support level to extended.
   225
   226Trying to improve the documentation around this feature made it clear how easy
   227it would be to get confused by how it worked. It would be only natural to assume
   228that a cert attached to a Route would only apply to that Route. The conflict
   229resolution semantics associated with this were both complicated and difficult to
   230surface to a user through status or other means.
   231
   232Lowering the support level from core to extended also didn't make sense.
   233Although some implementers were uncomfortable with supporting this feature due
   234to the potential for vulnerabilities, that was not a sufficient reason to lower
   235the support level. An extended support level should only be used for features
   236that cannot be universally supported. That was not the case here. Instead there
   237were just very real questions around the safety of the feature.
   238
   239The combination of those 2 factors led me to believe that this feature was not
   240well thought out and should be removed. Since this was essentially just a
   241shortcut to attaching certificates to a Gateway listener from different sources,
   242it seemed like there had to be a way that was both safer and easier to
   243understand. That led to this proposal.
   244
   245### 2. Implement Hostname Restrictions
   246Similar to the OpenShift approach described above, we could enforce the
   247following:
   248
   2491. Only a single hostname may be specified for HTTPRoutes with a certificate
   250   reference.
   2511. The oldest HTTPRoute to attach a certificate to a hostname would effectively
   252   own that hostname. No other HTTPRoutes could be attached with the same
   253   hostname unless they were explicitly allowed by that HTTPRoute.
   254
   255The second condition would be difficult to validate. As we've seen elsewhere in
   256the API, it's difficult to determine which resource was first to claim a
   257hostname or path. Instead we have to rely on the oldest resource, which can
   258result in some weird and potentially breaking changes if an older resource
   259chooses to claim a hostname.
   260
   261## References
   262
   263Docs:
   264
   265* [Gateway API: Replacing TLS Certificates in Routes](https://docs.google.com/document/d/1Cv95XFCL6S_9pIyS0drnsDLsfinWc2tHOFl_x3-_SWI/edit)

View as plain text