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