sigs.k8s.io/gateway-api@v1.0.0/geps/gep-746.md (about) 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 8 This GEP proposes that we should remove TLS Certificate references from 9 HTTPRoute and replace them with Cross Namespace Certificate references from 10 Gateways. Although that is not a complete replacement on its own, this GEP shows 11 how 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 31 TLS Certificate references on HTTPRoute have always been a confusing part of the 32 Gateway API. In the v1alpha2 release, we should consider removing this feature 33 while we still can. This GEP proposes an alternative that is simpler to work 34 with and understand, while also leaving sufficient room to enable all the same 35 capabilities that certificate references on HTTPRoute enabled. 36 37 ### Attaching TLS Certificates with Routes is Confusing 38 One of the most confusing parts of the Gateway API is how certificates can be 39 attached to Routes. There are a variety of different factors that lead to 40 confusion 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 52 To understand how we ended up with the ability to attach TLS certificates with 53 Routes, it’s helpful to look at the use cases for this capability: 54 55 1. 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) 58 1. Some users want Route owners to control certs for their applications. 59 60 ### Alternative Solutions 61 62 #### 1. Automation with tools like Cert-Manager 63 When automation is acceptable, the first use case is entirely possible with 64 tools like cert-manager that can watch Routes, generate certs for them, and 65 attach them to a Gateway. 66 67 #### 2. Cross Namespace Cert Direct References from Gateways 68 With the already established ReferenceGrant concept, we have established a safe 69 way to reference resources across namespaces. Although this would require some 70 coordination between Gateway and App owners, it would enable App owners to 71 retain full control of the certs used by their app without the extra confusion 72 that certs in HTTPRoute have led to. 73 74 ### Enabling Self-Service Certificate Attachment for App Owners 75 Although this dramatically simplifies the API, it does not completely replace 76 the functionality that certs attached to HTTPRoutes enabled. Most notably, it 77 would be difficult to attach arbitrary self-provided certificates to a Gateway 78 listener without requiring manual changes from a Gateway admin. 79 80 There are a couple potential solutions here: 81 82 #### 1. Implement a selector for cert references instead of direct references 83 Although the simplicity of this approach is nice, it ends up with many of the 84 same problems as certificates attached to Routes have and feels inconsistent 85 with how Routes attach to Gateways. 86 87 #### 2. Implement a controller that attaches certificates to Gateway listeners 88 Similar to cert-manager, it could be possible to implement a controller that 89 watches for Secrets with a certain label, and attaches those to the specified 90 Gateway. Although it's out of scope for this GEP to completely define what a 91 controller like this could look like, it would likely need to include at least 92 one of the following safeguards: 93 94 1. A way to configure which namespaces could attach certificates for each 95 domain. 96 2. A way to configure which namespaces could attach certificates to each 97 Gateway (or Listener). 98 3. A way to use ReferenceGrant to indicate where references from Secrets to 99 Gateways were trusted from and to. 100 101 ## API 102 103 The API changes proposed here are quite small, mostly removing fields. 104 105 ### Changes 106 1. The `LocalObjectReference` used for the `CertificateRef` field in 107 `GatewayTLSConfig` would be replaced with an `ObjectReference`. 108 1. `ReferenceGrant` would be updated to note that references from Gateways to 109 Secrets were part of the Core support level. 110 111 ### Removals 112 113 From 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 137 And the associated struct: 138 ```go 139 // RouteTLSConfig describes a TLS configuration defined at the Route level. 140 type 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 157 From 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 173 And the associated types: 174 ```go 175 type TLSRouteOverrideType string 176 177 const ( 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. 187 type 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 203 OpenShift already supports configuring TLS certificates on Routes. Although 204 largely 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 214 A typical configuration would involve a Router with `*.example.com` that has a 215 wildcard cert. Routes could be attached within those constraints without the 216 need for a cert. Routes can also use a different hostname if they also provide a 217 cert. 218 219 ## Alternatives 220 221 ### 1. Improved Documentation + Extended Support Level 222 My first attempt to improve this was to create a 223 [PR](https://github.com/kubernetes-sigs/gateway-api/pull/739) that would clarify 224 the documentation around how this works and lower the support level to extended. 225 226 Trying to improve the documentation around this feature made it clear how easy 227 it would be to get confused by how it worked. It would be only natural to assume 228 that a cert attached to a Route would only apply to that Route. The conflict 229 resolution semantics associated with this were both complicated and difficult to 230 surface to a user through status or other means. 231 232 Lowering the support level from core to extended also didn't make sense. 233 Although some implementers were uncomfortable with supporting this feature due 234 to the potential for vulnerabilities, that was not a sufficient reason to lower 235 the support level. An extended support level should only be used for features 236 that cannot be universally supported. That was not the case here. Instead there 237 were just very real questions around the safety of the feature. 238 239 The combination of those 2 factors led me to believe that this feature was not 240 well thought out and should be removed. Since this was essentially just a 241 shortcut to attaching certificates to a Gateway listener from different sources, 242 it seemed like there had to be a way that was both safer and easier to 243 understand. That led to this proposal. 244 245 ### 2. Implement Hostname Restrictions 246 Similar to the OpenShift approach described above, we could enforce the 247 following: 248 249 1. Only a single hostname may be specified for HTTPRoutes with a certificate 250 reference. 251 1. 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 255 The second condition would be difficult to validate. As we've seen elsewhere in 256 the API, it's difficult to determine which resource was first to claim a 257 hostname or path. Instead we have to rely on the oldest resource, which can 258 result in some weird and potentially breaking changes if an older resource 259 chooses to claim a hostname. 260 261 ## References 262 263 Docs: 264 265 * [Gateway API: Replacing TLS Certificates in Routes](https://docs.google.com/document/d/1Cv95XFCL6S_9pIyS0drnsDLsfinWc2tHOFl_x3-_SWI/edit)