sigs.k8s.io/gateway-api@v1.0.0/geps/gep-1651.md (about) 1 # GEP-1651: Gateway Routability 2 3 * Issue: [#1651](https://github.com/kubernetes-sigs/gateway-api/issues/1651) 4 * Status: Provisional 5 6 (See status definitions [here](overview.md#status).) 7 8 ## TLDR 9 10 Allow users to configure a Gateway so that it is only routable within 11 a specific scope (ie. public/private/cluster) 12 13 ## Goals 14 15 - Define a mechanic to set the routability on a Gateway 16 - Provide a default set of routability options 17 - Provide a way for vendors to support custom options 18 19 ## Non-Goals 20 21 - Per-request/route scope 22 - Not a lightweight service mesh 23 24 ## Introduction 25 26 One of the early feature requests for Knative was the ability to deploy an 27 application using Knative's HTTP routing support, but make it only available 28 within the cluster. I want to be able to specify both the "cluster" 29 (service.namespace.svc) and "external" (service.namespace.example.com). 30 Gateways using the same GatewayClass on the cluster, but ensure that the 31 "cluster" service is only routable within the cluster. This would greatly 32 simplify deployment for users over the instructions we have today. 33 34 Likewise another use case is to provide load balancing capabilities within a virtual 35 private network. Different IaaS providers offer private load balancers to support 36 these use cases. 37 38 ## API 39 40 We propose adding a new `routability` field under the `spec.infrastructure` stanza of a Gateway. 41 42 ### Predefined Routability Values 43 44 Implementations MAY implement the following values for 'routability' and MUST abide by 45 their defined semantics. 46 47 Value | Scope 48 -|- 49 `Public`|The address is routable on the public internet 50 `Private`|The address is routable inside a private network larger than a single cluster (ie. VPC) and MAY include RFC1918 address space 51 `Cluster`|The address is routable inside the [cluster's network](https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-network-model) 52 53 Values can be compared semantically - `Public` has a larger scope than `Private`, while `Private` has a larger scope than `Cluster`. 54 55 ### Vendor prefixed values 56 57 Implementations can define custom 'routability' values by specifying a vendor prefix followed 58 by a slash `/` and a custom name ie. `com.example.com/my-routability`. 59 60 Comparing vendor prefixed scopes with the pre-defined ones in implementation specific. 61 62 ### Default Routability 63 64 The default value of `routability` is implementation specific. It is RECOMMENDED that 65 the default `routability` remains consistent for Gateways with the same 66 `gatewayClassName`. 67 68 Implementations MUST signal the default routability using the Gateway's `status.addresses`. See 'Status Addresses` 69 for more details. 70 71 ### Mutability 72 73 Implementations MAY prevent end-users from updating the `routability` value of a Gateway. If 74 updates are allowed the semantics and behaviour will depend on the underlying implementation. 75 76 If a Gateway is mutated but does not support the desired routability it MUST set the conditions 77 `Accepted`, `Programmed` to `False` with `Reason` set to `UnsupportedRoutability`. Implementations 78 MAY choose to leave the old Gateway running with the previous generation's configuration. 79 80 ### Go 81 82 ```go 83 84 // GatewayRoutability represents the routability of a Gateway 85 // 86 // The pre-defined values listed in this package can be compared semantically. 87 // `Public` has a larger scope than `Private`, while `Private` has a larger scope than 88 // `Cluster`. 89 // 90 // Implementations can define custom routability values by specifying a vendor 91 // prefix followed by a slash '/' and a custom name ie. `dev.example.com/my-routability`. 92 // 93 // +kubebuilder:validation:MinLength=1 94 // +kubebuilder:validation:MaxLength=253 95 // +kubebuilder:validation:Pattern=`^Public|Private|Cluster|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-_]+$` 96 type GatewayRoutability string 97 98 const ( 99 // GatewayRoutabilityPublic means the Gateway's address MUST 100 // be routable on the public internet 101 // 102 // Implementations MAY support this routability 103 GatewayRoutabilityPublic GatewayRoutability = "Public" 104 105 // GatewayRoutabilityPrivate means the Gateway's address MUST 106 // only be routable inside a private network larger than a single 107 // cluster (ie. VPC) and MAY include the RFC1918 address space 108 // 109 // Implementations MAY support this routability 110 GatewayRoutabilityPrivate GatewayRoutability = "Private" 111 112 // GatewayRoutabilityCluster means the Gateway's address MUST 113 // only be routable inside the [cluster's network] 114 // 115 // Implementations MAY support this routability 116 // 117 // [cluster's network](https://kubernetes.io/docs/concepts/cluster-administration/networking/#how-to-implement-the-kubernetes-network-model) 118 GatewayRoutabilityCluster GatewayRoutability = "Cluster" 119 ) 120 121 type GatewaySpec struct { 122 // Infrastructure defines infrastructure level attributes about this Gateway instance. 123 Infrastructure GatewayInfrastructure `json:"infrastructure"` 124 // ... 125 } 126 type GatewayInfrastructure struct { 127 // Routability allows the Gateway to specify the accessibility of its addresses. Setting 128 // this property will override the default value defined by the GatewayClass. 129 // 130 // If the desired Gateway routability is incompatible with the GatewayClass implementations 131 // MUST set the condition `Accepted` to `False` with `Reason` set to `UnsupportedRoutability`. 132 133 // The default value of routability is implementation specific and MUST remains consistent for 134 // Gateways with the same gatewayClassName 135 // 136 // Implementations MAY prevent end-users from updating the routability value of a Gateway. 137 // If updates are allowed the semantics and behaviour will depend on the underlying implementation. 138 // If a Gateway is mutated but does not support the desired routability it MUST set `Accepted` 139 // and `Programmed` conditions to `False` with `Reason` set to `UnsupportedRoutability`. 140 // 141 // It is RECOMMENDED that in-cluster gateways SHOULD NOT support 'Private' routability. 142 // Kubernetes doesn't have a concept of 'Private' routability for Services. In the future this may 143 // change upstream. 144 // 145 // +optional 146 Routability *GatewayRoutability `json:"routability,omitempty"` 147 } 148 149 type GatewayStatus struct { 150 // Addresses lists the IP addresses that have actually been 151 // bound to the Gateway. These addresses may differ from the 152 // addresses in the Spec, e.g. if the Gateway automatically 153 // assigns an address from a reserved pool. 154 // 155 // Implementations that support Gateway routability MUST include an address 156 // that has the same routable semantics as defined in the Gateway spec. 157 // 158 // Implementations MAY add additional addresses in status, but they MUST be 159 // semantically less than the scope of the requested scope. For example if a 160 // user requests a `Private` routable Gateway then an additional address MAY 161 // have a routability of `Cluster` but MUST NOT include `Public`. 162 // 163 // +optional 164 // +kubebuilder:validation:MaxItems=16 165 Addresses []GatewayStatusAddress `json:"addresses,omitempty"` 166 // ... 167 } 168 169 type GatewayStatusAddress struct { 170 // Routability specifies the routable bounds of this address 171 // Predefined values are: 'Private', 'Public', Cluster 172 // Other values MUST have a vendor prefix. 173 // 174 // Implementations that support Routability MUST populate this 175 // field 176 // 177 // +optional 178 Routability *GatewayRoutability `json:"routability,omitempty"` 179 180 // ... 181 } 182 183 type GatewayClassStatus struct { 184 // Routabilities specifies a list of supported routabilities offered by 185 // the GatewayClass. The first entry in this list will be the default 186 // routability used when Gateways of this class are created. 187 // 188 // Implementations MAY provide a pre-defined set of GatewayClasses that 189 // limit the routability choices of a Gateway. 190 // 191 // Implementations that support routability MUST populate this list with 192 // a subset of the pre-defined GatewayRoutability values or vendored 193 // prefix values. 194 // 195 // +optional 196 // +kubebuilder:validation:MaxItems=8 197 // <gateway:experimental> 198 Routabilities []GatewayRoutability `json:"routabilities"` 199 } 200 ``` 201 202 ### YAML 203 ```yaml 204 apiVersion: gateway.networking.k8s.io/v1beta1 205 kind: Gateway 206 metadata: 207 name: prod-web 208 spec: 209 gatewayClassName: acme-lb 210 infrastructure: 211 routability: Public 212 listeners: 213 - protocol: HTTP 214 port: 80 215 ``` 216 217 ### Semantics 218 219 #### Interaction with GatewayClass 220 221 An infrastructure provider MAY provide a pre-defined set of GatewayClasses that limit the 222 routability choices of a Gateway. If the desired Gateway routability is incompatible with the 223 GatewayClass it MUST set the condition `Accepted` to `False` with `Reason` set to `UnsupportedRoutability`. 224 225 If an implementation supports 'routability' then the GatewayClass MUST list the supported 226 routabilities in the status stanza. The `status.routabilities` MUST contain either 227 a subset of the pre-defined values mentioned above or contain vendored prefixed values. 228 229 The first value in the list will be used as the default value when Gateways of this class 230 are created. This can be overridden by setting the Gateway's `spec.infrastructure.routability`. 231 232 #### Unsupported routability & address values 233 234 If a Gateway is unable to provide an address for the desired routability it MUST set the condition `Accepted` 235 to `False` with `Reason` set to `UnsupportedRoutability` 236 237 #### Status.Addresses 238 239 If a Gateway supports the desired 'routability' implementations MUST populate the `status.addresses` with 240 an address that has the same routable semantics. The GatewayAddress field `routability` MUST be populated. 241 242 Implementations MAY add additional addresses in status, but they MUST be semantically less than the scope 243 of the requested scope. For example if a user requests a `Cluster` routable Gateway then the list of addresses 244 MUST NOT have a routability of `Public` or `Private`. 245 246 We plan on introducing a new type `GatewayStatusAddress` and change Gateway's `status.addresses` to be 247 `[]GatewayStatusAddress`. This will allow the status address type to evolve separately from the spec address. 248 249 #### In-cluster Gateways and 'Private' Routability 250 251 It is RECOMMENDED that in-cluster gateways SHOULD NOT support 'Private' routability. Kubernetes doesn't have 252 a concept of 'Private' routability for Services. In the future this may change upstream. 253 254 ## Examples 255 256 #### 1. Request a GatewayAddress that is routable within the same cluster 257 258 ```yaml 259 apiVersion: gateway.networking.k8s.io/v1beta1 260 kind: Gateway 261 metadata: 262 name: prod-web 263 spec: 264 gatewayClassName: acme-lb 265 infrastructure: 266 routability: Cluster 267 listeners: 268 - protocol: HTTP 269 port: 80 270 ``` 271 272 #### 2. Request a GatewayAddress with a specific routability and address 273 ```yaml 274 apiVersion: gateway.networking.k8s.io/v1beta1 275 kind: Gateway 276 metadata: 277 name: prod-web 278 spec: 279 gatewayClassName: acme-lb 280 infrastructure: 281 routability: Cluster 282 listeners: 283 - protocol: HTTP 284 port: 80 285 addresses: 286 - value: 10.0.0.8 287 ``` 288 289 #### 3. Request a GatewayAddress that is routable on the public internet 290 ```yaml 291 apiVersion: gateway.networking.k8s.io/v1beta1 292 kind: Gateway 293 metadata: 294 name: prod-web 295 spec: 296 gatewayClassName: acme-lb 297 infrastructure: 298 routability: Public 299 listeners: 300 - protocol: HTTP 301 port: 80 302 ``` 303 304 #### 4. Request a GatewayAddress that is a cloud provider's VPC 305 ```yaml 306 apiVersion: gateway.networking.k8s.io/v1beta1 307 kind: Gateway 308 metadata: 309 name: prod-web 310 spec: 311 gatewayClassName: acme-lb 312 infrastructure: 313 routability: Private 314 listeners: 315 - protocol: HTTP 316 port: 80 317 ``` 318 319 ## Alternatives 320 321 ### Introducing new GatewayAddress Types 322 323 We could introduce additional `AddressTypes` (ie. `ClusterLocalIPAddress`) but 324 this would lead to a combinatorial explosion as new dimensions (ie. IPv6) are 325 introduced. 326 327 From: [https://github.com/kubernetes-sigs/gateway-api/pull/1653#issuecomment-1451246877](https://github.com/kubernetes-sigs/gateway-api/pull/1653#issuecomment-1451246877) 328 329 > Although this makes sense in isolation, I'm worried about the long term impacts this could have. In my opinion, ClusterLocal is a modifier, not exactly an address type. For example, it's possible in the future that we'll have a way to provision cluster-local DNS names, we may want to use the same kind of mechanism to request a ClusterLocal DNS name for the Gateway. 330 > 331 > It's also possible that users will want to explicitly request an IP Families (v4, v6, or both). I'd really hate to get into a situation where we have the following options: 332 > 333 > - IPAddress 334 > - IPv4Address 335 > - IPv6Address 336 > - ClusterLocalIPAddress 337 > - ClusterLocalIPv4Address 338 > - ClusterLocalIPv6Address 339 > 340 > For each dimension we avoid adding a separate field for and instead try to embed into a single name, we risk this kind of name explosion. Of course none of the above even begins to cover my idea of NetworkLocal which could further complicate this. 341 342 ### Scope/reachability/routability field on GatewayAddress 343 344 This would allow Gateways to have multiple scopes. 345 346 From: [https://github.com/kubernetes-sigs/gateway-api/pull/1653#issuecomment-1486271913](https://github.com/kubernetes-sigs/gateway-api/pull/1653#issuecomment-1486271913) 347 > The obvious application for multiple scopes seems to be saving on boilerplate, which is a win, but are there are any other advantages to allowing one Gateway to have multiple scopes? 348 > 349 > Multiple scopes Pros: 350 > 351 > Allows a single Gateway to express multiple networks, saving on needing to attach HTTPRoutes to multiple Gateways for each network scope. 352 > 353 > Multiple scopes Cons: 354 > 355 > Complicates the Gateway's purpose. Instead of one Gateway being one set of Listeners, now a Gateway is two sets of listeners that have a totally different scope (and presumably, security context). Personally, I'm also concerned how this will interact with other features like merging and preprovisioning that GEP-1867: Per-Gateway Infrastructure #1868 will allow. 356 357 ### Adding `routability` attribute to GatewayClass 358 359 See [Prior Art - Multiple Gateways Classes](#multiple-gateway-classes) 360 361 ## Survey of Prior Art 362 363 These alternatives are a survey of existing approaches to support cluster 364 local Gateways. Most are implementation specific and are not portable. 365 366 ### Special annotation/label 367 368 Istio let's you specify an annotation `networking.istio.io/service-type` to 369 change the underlying Kubernetes Service type to make it a ClusterIP type. 370 371 ### Re-use of AddressType Hostname 372 373 Istio let's you re-use existing Gateway deployments by setting the address 374 type to `Hostname` and the value to the Istio ingress Kubernetes Service. If an 375 operator configures the Istio deployment to support cluster local traffic a 376 Gateway implementation can select it using the `HostName` attribute. 377 378 ### Multiple Gateway Classes 379 380 Some implementations support multiple deployments on a single cluster where each maps to a 381 GatewayClass. One of these deployments can be configured to serve cluster local traffic. This is 382 sub-optimal because this is implementation specific and the end-user is effectively managing the 383 deployments themselves rather than infrastructure being automatically provisioned. 384 385 Likewise, infrastructure providers may provide a fixed set of GatewayClasses with unique and fixed 386 routability. Thus GatewayClass name is a viable option to control routability. There may be a 387 non-zero cost when requiring additional GatewayClasses - but this depends on the implementation. 388 389 Additionally, if more attributes are added to GatewayClass to constrain Gateways in some 390 form this leads to a combinatorial number of GatewayClassNames. For example, `foo-public` and 391 `foo-cluster` are two GatewayClasses surfacing the values of a single attribute `routability`. 392 Let's say we want to enforce address types to just IP then our `gatewayClassName` would be: 393 394 - `foo-public-ipv4` 395 - `foo-public-ipv6` 396 - `foo-cluster-ipv4` 397 - `foo-cluster-ipv6` 398 399 This may not be as flexible for end-users compared to configuring `routability` when creating 400 a Gateway. 401 402 As howardjohn mentioned [here](https://github.com/kubernetes-sigs/gateway-api/pull/1653#issuecomment-1429992160): 403 > having the ability to configure things at a higher level seems nice for Gateway, but being able to configure them on a per-Gateway basis remains important. 404 405 ## References 406 407 - [Knative - Private Services](https://knative.dev/docs/serving/services/private-services/#configuring-private-services) 408 - [Initial Gateway GitHub Discussion](https://github.com/kubernetes-sigs/gateway-api/discussions/1247) 409 - [Istio Support for Private Gateways](https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api/#automated-deployment) 410 - [Envoy Gateway Support for Private Gateways](https://gateway.envoyproxy.io/latest/api/config_types.html#kubernetesservicespec) 411