diff --git a/.custom-gcl.yml b/.custom-gcl.yml new file mode 100644 index 0000000000..84754359fa --- /dev/null +++ b/.custom-gcl.yml @@ -0,0 +1,6 @@ +version: v2.2.1 +name: golangci-kube-api-linter +destination: ./bin +plugins: +- module: 'sigs.k8s.io/kube-api-linter' + version: 'v0.0.0-20250715075424-4fab82d26a8e' # Pin to a commit while there's no tag diff --git a/.github/dependabot.yml b/.github/dependabot.yml index bc2eca7f66..2746f0b99c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -30,17 +30,6 @@ updates: - ok-to-test - release-note-none - # Dependencies listed in .github/workflows/*.yml - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - labels: - - github_actions - - dependencies - - ok-to-test - - release-note-none - # Dependencies listed in Dockerfile - package-ecosystem: "docker" directory: "/" diff --git a/.github/workflows/crd-validation.yml b/.github/workflows/crd-validation.yml new file mode 100644 index 0000000000..4aa88c5a99 --- /dev/null +++ b/.github/workflows/crd-validation.yml @@ -0,0 +1,32 @@ +name: CRD Validation + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +# Remove all permissions from GITHUB_TOKEN except metadata. +permissions: {} + +jobs: + crd-validation: + name: CEL + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Available versions at https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/HEAD/envtest-releases.yaml + k8s_version: [v1.33.0, v1.32.0, v1.31.0, v1.30.3, v1.29.5] + crd_channel: [standard, experimental] + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + with: + persist-credentials: false + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 + - name: Run CRD Validation tests + env: + K8S_VERSION: ${{ matrix.k8s_version }} + CRD_CHANNEL: ${{ matrix.crd_channel }} + run: | + make CEL_TEST_K8S_VERSION="${K8S_VERSION}" CEL_TEST_CRD_CHANNEL="${CRD_CHANNEL}" test.crds-validation diff --git a/.github/workflows/kal.yml b/.github/workflows/kal.yml new file mode 100644 index 0000000000..618256e886 --- /dev/null +++ b/.github/workflows/kal.yml @@ -0,0 +1,28 @@ +name: PR golangci-lint + +on: + pull_request: + types: [opened, edited, synchronize, reopened] + +# Remove all permissions from GITHUB_TOKEN except metadata. +permissions: {} + +jobs: + golangci: + name: kube-api-lint + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 + name: Checkout code + with: + persist-credentials: false + - name: Set up Go + uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 + - name: Install Golang CI Lint + run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.2.1 + - name: Build KAL + run: golangci-lint custom + - name: run api linter + run: ./bin/golangci-kube-api-linter run -c ./.golangci-kal.yml ./... diff --git a/.golangci-kal.yml b/.golangci-kal.yml new file mode 100644 index 0000000000..27fdabbef1 --- /dev/null +++ b/.golangci-kal.yml @@ -0,0 +1,38 @@ +version: "2" +linters: + default: none + enable: + - kubeapilinter + settings: + custom: + kubeapilinter: + type: module + description: Kube API LInter lints Kube like APIs based on API conventions and best practices. + settings: + linters: + enable: + - "duplicatemarkers" # Ensure there are no exact duplicate markers. for types and fields. + - "jsontags" # Ensure every field has a json tag. + - "nofloats" # Ensure floats are not used. + - "nomaps" # Ensure maps are not used. + - "nophase" # Phase fields are discouraged by the Kube API conventions, use conditions instead. + - "optionalorrequired" # Every field should be marked as `+optional` or `+required`. + - "ssatags" # Ensure proper Server-Side Apply (SSA) tags on array fields. + - "statussubresource" # All root objects that have a `status` field should have a status subresource. + - "uniquemarkers" # Ensure that types and fields do not contain more than a single definition of a marker that should only be present once. + disable: + - "*" + lintersConfig: {} + exclusions: + generated: strict + paths: + - conformance/ + paths-except: + - apis/ + - apisx/ +issues: + max-issues-per-linter: 0 + max-same-issues: 0 +run: + timeout: 5m + tests: false diff --git a/Makefile b/Makefile index 8328ea218b..3f2fee4146 100644 --- a/Makefile +++ b/Makefile @@ -54,6 +54,10 @@ ROOT := $(abspath $(TOP)) CONFORMANCE_FLAGS ?= GO_TEST_FLAGS ?= +# Flags for CRD validation tests +CEL_TEST_K8S_VERSION ?= +CEL_TEST_CRD_CHANNEL ?= standard + all: generate vet fmt verify test # Run generators for protos, Deepcopy funcs, CRDs, and docs. @@ -85,7 +89,8 @@ test: # Run tests for CRDs validation .PHONY: test.crds-validation test.crds-validation: - ./hack/test-crds-validation.sh $(VERSION) + K8S_VERSION=$(CEL_TEST_K8S_VERSION) CRD_CHANNEL=$(CEL_TEST_CRD_CHANNEL) go test ${GO_TEST_FLAGS} -count=1 -timeout=120s --tags=$(CEL_TEST_CRD_CHANNEL) -v ./pkg/test/cel + K8S_VERSION=$(CEL_TEST_K8S_VERSION) CRD_CHANNEL=$(CEL_TEST_CRD_CHANNEL) go test ${GO_TEST_FLAGS} -count=1 -timeout=120s -v ./pkg/test/crd # Run conformance tests against controller implementation .PHONY: conformance diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 8bdeafe24c..207dd1d776 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -26,15 +26,14 @@ aliases: - howardjohn - mikemorris - kflynn + - LiorLieberman emeritus-gateway-api-mesh-leads: - keithmattix gateway-api-conformance-reviewers: - candita - - michaelbeaumont - sunjayBhatia - - xunzhuo gateway-api-conformance-approvers: - arkodg diff --git a/README.md b/README.md index 3dbd66b39e..e8ebd1ad5b 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Participation in the Kubernetes community is governed by the [spec]: https://gateway-api.sigs.k8s.io/reference/spec/ [concepts]: https://gateway-api.sigs.k8s.io/concepts/api-overview [security-model]: https://gateway-api.sigs.k8s.io/concepts/security-model -[gh_release]: https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.2.1 +[gh_release]: https://github.com/kubernetes-sigs/gateway-api/releases/tag/v1.3.0 [godoc]: https://pkg.go.dev/sigs.k8s.io/gateway-api [conformance-docs]: https://gateway-api.sigs.k8s.io/concepts/conformance/ [reports-readme]: ./conformance/reports/README.md diff --git a/RELEASE_MANAGEMENT.md b/RELEASE_MANAGEMENT.md index cd8f0f1851..78d0020843 100644 --- a/RELEASE_MANAGEMENT.md +++ b/RELEASE_MANAGEMENT.md @@ -107,5 +107,25 @@ volunteers the release may simply end being a smaller **maintenance release**. Release candidates--and the eventual final release--must utilize the [Release Process](/RELEASE.md) for delivery. +As the release nears completion, the release-manager should proactively reach +out to implementations to get them ready to send conformance reports for the +final release when it is cut. + [Release Cycle]:https://gateway-api.sigs.k8s.io/contributing/release-cycle/ [Milestone]:#github-milestone + +## Time Extensions + +Extensions to timelines may be requested by contributors. Our guidelines for +this are based on the Kubernetes process: + +* Extensions can be granted on a per-GEP basis + * The owners of the GEP have to ask and provide a timeline (measured in + days) as to when they believe the GEP will be ready for merge. +* The request and approval for a GEP extension needs to be in public. +* Extensions can only be granted with a majority agreement by maintainers + / release-managers + +For our purposes we use GitHub discussions as the public place for +requesting/approving extensions. Contributors should use an existing +discussion for the release when feasible, otherwise create a discussion. diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index 3e1ec4c7ea..652101ff76 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -33,15 +33,18 @@ import ( // Gateway represents an instance of a service-traffic handling infrastructure // by binding Listeners to a set of IP addresses. type Gateway struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of Gateway. + // +required Spec GatewaySpec `json:"spec"` // Status defines the current state of Gateway. // // +kubebuilder:default={conditions: {{type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"},{type: "Programmed", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}} + // +optional Status GatewayStatus `json:"status,omitempty"` } @@ -63,6 +66,7 @@ type GatewayList struct { type GatewaySpec struct { // GatewayClassName used for this Gateway. This is the name of a // GatewayClass resource. + // +required GatewayClassName ObjectName `json:"gatewayClassName"` // Listeners associated with this Gateway. Listeners define @@ -236,6 +240,7 @@ type GatewaySpec struct { // +kubebuilder:validation:XValidation:message="hostname must not be specified for protocols ['TCP', 'UDP']",rule="self.all(l, l.protocol in ['TCP', 'UDP'] ? (!has(l.hostname) || l.hostname == '') : true)" // +kubebuilder:validation:XValidation:message="Listener name must be unique within the Gateway",rule="self.all(l1, self.exists_one(l2, l1.name == l2.name))" // +kubebuilder:validation:XValidation:message="Combination of port, protocol and hostname must be unique for each listener",rule="self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))" + // +required Listeners []Listener `json:"listeners"` // Addresses requested for this Gateway. This is optional and behavior can @@ -260,6 +265,7 @@ type GatewaySpec struct { // Support: Extended // // +optional + // +listType=atomic // // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="IPAddress values must be unique",rule="self.all(a1, a1.type == 'IPAddress' ? self.exists_one(a2, a2.type == a1.type && a2.value == a1.value) : true )" @@ -273,15 +279,6 @@ type GatewaySpec struct { // +optional Infrastructure *GatewayInfrastructure `json:"infrastructure,omitempty"` - // BackendTLS configures TLS settings for when this Gateway is connecting to - // backends with TLS. - // - // Support: Core - // - // +optional - // - BackendTLS *GatewayBackendTLS `json:"backendTLS,omitempty"` - // AllowedListeners defines which ListenerSets can be attached to this Gateway. // While this feature is experimental, the default value is to allow no ListenerSets. // @@ -289,6 +286,14 @@ type GatewaySpec struct { // // +optional AllowedListeners *AllowedListeners `json:"allowedListeners,omitempty"` + // + // TLS specifies frontend and backend tls configuration for entire gateway. + // + // Support: Extended + // + // +optional + // + TLS *GatewayTLSConfig `json:"tls,omitempty"` } // AllowedListeners defines which ListenerSets can be attached to this Gateway. @@ -333,6 +338,7 @@ type Listener struct { // Gateway. // // Support: Core + // +required Name SectionName `json:"name"` // Hostname specifies the virtual hostname to match for protocol types that @@ -390,18 +396,24 @@ type Listener struct { // same port, subject to the Listener compatibility rules. // // Support: Core + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + // + // +required Port PortNumber `json:"port"` // Protocol specifies the network protocol this listener expects to receive. // // Support: Core + // +required Protocol ProtocolType `json:"protocol"` // TLS is the TLS configuration for the Listener. This field is required if // the Protocol field is "HTTPS" or "TLS". It is invalid to set this field // if the Protocol field is "HTTP", "TCP", or "UDP". // - // The association of SNIs to Certificate defined in GatewayTLSConfig is + // The association of SNIs to Certificate defined in ListenerTLSConfig is // defined based on the Hostname field for this listener. // // The GatewayClass MUST use the longest matching SNI out of all @@ -410,7 +422,7 @@ type Listener struct { // Support: Core // // +optional - TLS *GatewayTLSConfig `json:"tls,omitempty"` + TLS *ListenerTLSConfig `json:"tls,omitempty"` // AllowedRoutes defines the types of routes that MAY be attached to a // Listener and the trusted namespaces where those Route resources MAY be @@ -504,8 +516,6 @@ type GatewayBackendTLS struct { // ClientCertificateRef can reference to standard Kubernetes resources, i.e. // Secret, or implementation-specific custom resources. // - // This setting can be overridden on the service level by use of BackendTLSPolicy. - // // Support: Core // // +optional @@ -513,10 +523,10 @@ type GatewayBackendTLS struct { ClientCertificateRef *SecretObjectReference `json:"clientCertificateRef,omitempty"` } -// GatewayTLSConfig describes a TLS configuration. +// ListenerTLSConfig describes a TLS configuration for a listener. // // +kubebuilder:validation:XValidation:message="certificateRefs or options must be specified when mode is Terminate",rule="self.mode == 'Terminate' ? size(self.certificateRefs) > 0 || size(self.options) > 0 : true" -type GatewayTLSConfig struct { +type ListenerTLSConfig struct { // Mode defines the TLS behavior for the TLS session initiated by the client. // There are two possible modes: // @@ -561,21 +571,10 @@ type GatewayTLSConfig struct { // Support: Implementation-specific (More than one reference or other resource types) // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=64 CertificateRefs []SecretObjectReference `json:"certificateRefs,omitempty"` - // FrontendValidation holds configuration information for validating the frontend (client). - // Setting this field will require clients to send a client certificate - // required for validation during the TLS handshake. In browsers this may result in a dialog appearing - // that requests a user to specify the client certificate. - // The maximum depth of a certificate chain accepted in verification is Implementation specific. - // - // Support: Extended - // - // +optional - // - FrontendValidation *FrontendTLSValidation `json:"frontendValidation,omitempty"` - // Options are a list of key/value pairs to enable extended TLS // configuration for each implementation. For example, configuring the // minimum TLS version or supported cipher suites. @@ -592,6 +591,58 @@ type GatewayTLSConfig struct { Options map[AnnotationKey]AnnotationValue `json:"options,omitempty"` } +// GatewayTLSConfig specifies frontend and backend tls configuration for gateway. +type GatewayTLSConfig struct { + // Backend describes TLS configuration for gateway when connecting + // to backends. + // + // Note that this contains only details for the Gateway as a TLS client, + // and does _not_ imply behavior about how to choose which backend should + // get a TLS connection. That is determined by the presence of a BackendTLSPolicy. + // + // Support: Core + // + // +optional + // + Backend *GatewayBackendTLS `json:"backend,omitempty"` + + // Frontend describes TLS config when client connects to Gateway. + // Support: Core + // + // +optional + // + Frontend *FrontendTLSConfig `json:"frontend,omitempty"` +} + +// FrontendTLSConfig specifies frontend tls configuration for gateway. +type FrontendTLSConfig struct { + // Default specifies the default client certificate validation configuration + // for all Listeners handling HTTPS traffic, unless a per-port configuration + // is defined. + // + // support: Core + // + // +required + // + Default TLSConfig `json:"default"` + + // PerPort specifies tls configuration assigned per port. + // Per port configuration is optional. Once set this configuration overrides + // the default configuration for all Listeners handling HTTPS traffic + // that match this port. + // Each override port requires a unique TLS configuration. + // + // support: Core + // + // +optional + // +listType=map + // +listMapKey=port + // +kubebuilder:validation:MaxItems=64 + // +kubebuilder:validation:XValidation:message="Port for TLS configuration must be unique within the Gateway",rule="self.all(t1, self.exists_one(t2, t1.port == t2.port))" + // + PerPort []TLSPortConfig `json:"perPort,omitempty"` +} + // TLSModeType type defines how a Gateway handles TLS sessions. // // +kubebuilder:validation:Enum=Terminate;Passthrough @@ -610,6 +661,46 @@ const ( TLSModePassthrough TLSModeType = "Passthrough" ) +// TLSConfig describes TLS configuration that can apply to multiple Listeners +// within this Gateway. Currently, it stores only the client certificate validation +// configuration, but this may be extended in the future. +type TLSConfig struct { + // Validation holds configuration information for validating the frontend (client). + // Setting this field will result in mutual authentication when connecting to the gateway. + // In browsers this may result in a dialog appearing + // that requests a user to specify the client certificate. + // The maximum depth of a certificate chain accepted in verification is Implementation specific. + // + // Support: Core + // + // +optional + // + Validation *FrontendTLSValidation `json:"validation,omitempty"` +} + +type TLSPortConfig struct { + // The Port indicates the Port Number to which the TLS configuration will be + // applied. This configuration will be applied to all Listeners handling HTTPS + // traffic that match this port. + // + // Support: Core + // + // +required + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + // + Port PortNumber `json:"port"` + + // TLS store the configuration that will be applied to all Listeners handling + // HTTPS traffic and matching given port. + // + // Support: Core + // + // +required + // + TLS TLSConfig `json:"tls"` +} + // FrontendTLSValidation holds configuration information that can be used to validate // the frontend initiating the TLS connection type FrontendTLSValidation struct { @@ -626,8 +717,8 @@ type FrontendTLSValidation struct { // Support: Core - A single reference to a Kubernetes ConfigMap // with the CA certificate in a key named `ca.crt`. // - // Support: Implementation-specific (More than one reference, or other kinds - // of resources). + // Support: Implementation-specific (More than one certificate in a ConfigMap + // with different keys or more than one reference, or other kinds of resources). // // References to a resource in a different namespace are invalid UNLESS there // is a ReferenceGrant in the target namespace that allows the certificate @@ -635,11 +726,53 @@ type FrontendTLSValidation struct { // "ResolvedRefs" condition MUST be set to False for this listener with the // "RefNotPermitted" reason. // + // +required + // +listType=atomic // +kubebuilder:validation:MaxItems=8 // +kubebuilder:validation:MinItems=1 - CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"` + CACertificateRefs []ObjectReference `json:"caCertificateRefs"` + + // FrontendValidationMode defines the mode for validating the client certificate. + // There are two possible modes: + // + // - AllowValidOnly: In this mode, the gateway will accept connections only if + // the client presents a valid certificate. This certificate must successfully + // pass validation against the CA certificates specified in `CACertificateRefs`. + // - AllowInsecureFallback: In this mode, the gateway will accept connections + // even if the client certificate is not presented or fails verification. + // + // This approach delegates client authorization to the backend and introduce + // a significant security risk. It should be used in testing environments or + // on a temporary basis in non-testing environments. + // + // Defaults to AllowValidOnly. + // + // Support: Core + // + // +optional + // +kubebuilder:default=AllowValidOnly + Mode FrontendValidationModeType `json:"mode,omitempty"` } +// FrontendValidationModeType type defines how a Gateway validates client certificates. +// +// +kubebuilder:validation:Enum=AllowValidOnly;AllowInsecureFallback +type FrontendValidationModeType string + +const ( + // AllowValidOnly indicates that a client certificate is required + // during the TLS handshake and MUST pass validation. + // + // Support: Core + AllowValidOnly FrontendValidationModeType = "AllowValidOnly" + + // AllowInsecureFallback indicates that a client certificate may not be + // presented during the handshake or the validation against CA certificates may fail. + // + // Support: Extended + AllowInsecureFallback FrontendValidationModeType = "AllowInsecureFallback" +) + // AllowedRoutes defines which Routes may be attached to this Listener. type AllowedRoutes struct { // Namespaces indicates namespaces from which Routes may be attached to this @@ -648,6 +781,7 @@ type AllowedRoutes struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:default={from: Same} Namespaces *RouteNamespaces `json:"namespaces,omitempty"` @@ -664,6 +798,7 @@ type AllowedRoutes struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=8 Kinds []RouteGroupKind `json:"kinds,omitempty"` } @@ -721,6 +856,7 @@ type RouteGroupKind struct { Group *Group `json:"group,omitempty"` // Kind is the kind of the Route. + // +required Kind Kind `json:"kind"` } @@ -764,6 +900,7 @@ type GatewayStatusAddress struct { // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 + // +required Value string `json:"value"` } @@ -780,6 +917,7 @@ type GatewayStatus struct { // * a specified address was unusable (e.g. already in use) // // +optional + // +listType=atomic // // +kubebuilder:validation:MaxItems=16 Addresses []GatewayStatusAddress `json:"addresses,omitempty"` @@ -797,6 +935,34 @@ type GatewayStatus struct { // * "Programmed" // * "Ready" // + // + // Notes for implementors: + // + // Conditions are a listType `map`, which means that they function like a + // map with a key of the `type` field _in the k8s apiserver_. + // + // This means that implementations must obey some rules when updating this + // section. + // + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // * Implementations MUST NOT remove or reorder Conditions that they are not + // directly responsible for. For example, if an implementation sees a Condition + // with type `special.io/SomeField`, it MUST NOT remove, change or update that + // Condition. + // * Implementations MUST always _merge_ changes into Conditions of the same Type, + // rather than creating more than one Condition of the same Type. + // * Implementations MUST always update the `observedGeneration` field of the + // Condition to the `metadata.generation` of the Gateway at the time of update creation. + // * If the `observedGeneration` of a Condition is _greater than_ the value the + // implementation knows about, then it MUST NOT perform the update on that Condition, + // but must wait for a future reconciliation and status update. (The assumption is that + // the implementation's copy of the object is stale and an update will be re-triggered + // if relevant.) + // + // // +optional // +listType=map // +listMapKey=type @@ -873,15 +1039,18 @@ type GatewayInfrastructure struct { // configuration resource within the namespace. type LocalParametersReference struct { // Group is the group of the referent. + // +required Group Group `json:"group"` // Kind is kind of the referent. + // +required Kind Kind `json:"kind"` // Name is the name of the referent. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 + // +required Name string `json:"name"` } @@ -969,6 +1138,13 @@ const ( // information on which address is causing the problem and how to resolve it // in the condition message. GatewayReasonAddressNotUsable GatewayConditionReason = "AddressNotUsable" + // This condition indicates `FrontendValidationModeType` changed from + // `AllowValidOnly` to `AllowInsecureFallback`. + GatewayConditionInsecureFrontendValidationMode GatewayConditionReason = "InsecureFrontendValidationMode" + // This reason MUST be set for GatewayConditionInsecureFrontendValidationMode + // when client change FrontendValidationModeType for a Gateway or per port override + // to `AllowInsecureFallback`. + GatewayReasonConfigurationChanged GatewayConditionReason = "ConfigurationChanged" ) const ( @@ -1062,9 +1238,41 @@ const ( GatewayReasonListenersNotReady GatewayConditionReason = "ListenersNotReady" ) +const ( + // AttachedListenerSets is a condition that is true when the Gateway has + // at least one ListenerSet attached to it. + // + // Possible reasons for this condition to be True are: + // + // * "ListenerSetsAttached" + // + // Possible reasons for this condition to be False are: + // + // * "NoListenerSetsAttached" + // * "ListenerSetsNotAllowed" + // + // Controllers may raise this condition with other reasons, + // but should prefer to use the reasons listed above to improve + // interoperability. + GatewayConditionAttachedListenerSets GatewayConditionType = "AttachedListenerSets" + + // This reason is used with the "AttachedListenerSets" condition when the + // Gateway has at least one ListenerSet attached to it. + GatewayReasonListenerSetsAttached GatewayConditionReason = "ListenerSetsAttached" + + // This reason is used with the "AttachedListenerSets" condition when the + // Gateway has no ListenerSets attached to it. + GatewayReasonNoListenerSetsAttached GatewayConditionReason = "NoListenerSetsAttached" + + // This reason is used with the "AttachedListenerSets" condition when the + // Gateway has ListenerSets attached to it, but the ListenerSets are not allowed. + GatewayReasonListenerSetsNotAllowed GatewayConditionReason = "ListenerSetsNotAllowed" +) + // ListenerStatus is the status associated with a Listener. type ListenerStatus struct { // Name is the name of the Listener that this status corresponds to. + // +required Name SectionName `json:"name"` // SupportedKinds is the list indicating the Kinds supported by this @@ -1077,6 +1285,8 @@ type ListenerStatus struct { // and invalid Route kinds are specified, the implementation MUST // reference the valid Route kinds that have been specified. // + // +required + // +listType=atomic // +kubebuilder:validation:MaxItems=8 SupportedKinds []RouteGroupKind `json:"supportedKinds"` @@ -1097,13 +1307,45 @@ type ListenerStatus struct { // // Uses for this field include troubleshooting Route attachment and // measuring blast radius/impact of changes to a Listener. + // +required AttachedRoutes int32 `json:"attachedRoutes"` // Conditions describe the current condition of this listener. // + // + // + // Notes for implementors: + // + // Conditions are a listType `map`, which means that they function like a + // map with a key of the `type` field _in the k8s apiserver_. + // + // This means that implementations must obey some rules when updating this + // section. + // + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // * Implementations MUST NOT remove or reorder Conditions that they are not + // directly responsible for. For example, if an implementation sees a Condition + // with type `special.io/SomeField`, it MUST NOT remove, change or update that + // Condition. + // * Implementations MUST always _merge_ changes into Conditions of the same Type, + // rather than creating more than one Condition of the same Type. + // * Implementations MUST always update the `observedGeneration` field of the + // Condition to the `metadata.generation` of the Gateway at the time of update creation. + // * If the `observedGeneration` of a Condition is _greater than_ the value the + // implementation knows about, then it MUST NOT perform the update on that Condition, + // but must wait for a future reconciliation and status update. (The assumption is that + // the implementation's copy of the object is stale and an update will be re-triggered + // if relevant.) + // + // + // // +listType=map // +listMapKey=type // +kubebuilder:validation:MaxItems=8 + // +required Conditions []metav1.Condition `json:"conditions"` } diff --git a/apis/v1/gatewayclass_types.go b/apis/v1/gatewayclass_types.go index 6699e7a18f..f9b779c7b3 100644 --- a/apis/v1/gatewayclass_types.go +++ b/apis/v1/gatewayclass_types.go @@ -49,10 +49,12 @@ import ( // // GatewayClass is a Cluster level resource. type GatewayClass struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of GatewayClass. + // +required Spec GatewayClassSpec `json:"spec"` // Status defines the current state of GatewayClass. @@ -61,6 +63,7 @@ type GatewayClass struct { // specify their controller name. // // +kubebuilder:default={conditions: {{type: "Accepted", status: "Unknown", message: "Waiting for controller", reason: "Pending", lastTransitionTime: "1970-01-01T00:00:00Z"}}} + // +optional Status GatewayClassStatus `json:"status,omitempty"` } @@ -83,6 +86,7 @@ type GatewayClassSpec struct { // Support: Core // // +kubebuilder:validation:XValidation:message="Value is immutable",rule="self == oldSelf" + // +required ControllerName GatewayController `json:"controllerName"` // ParametersRef is a reference to a resource that contains the configuration @@ -118,15 +122,18 @@ type GatewayClassSpec struct { // configuration resource within the cluster. type ParametersReference struct { // Group is the group of the referent. + // +required Group Group `json:"group"` // Kind is kind of the referent. + // +required Kind Kind `json:"kind"` // Name is the name of the referent. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 + // +required Name string `json:"name"` // Namespace is the namespace of the referent. @@ -256,6 +263,35 @@ type GatewayClassStatus struct { // Controllers should prefer to publish conditions using values // of GatewayClassConditionType for the type of each Condition. // + // + // Notes for implementors: + // + // Conditions are a listType `map`, which means that they function like a + // map with a key of the `type` field _in the k8s apiserver_. + // + // This means that implementations must obey some rules when updating this + // section. + // + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // * Implementations MUST NOT remove or reorder Conditions that they are not + // directly responsible for. For example, if an implementation sees a Condition + // with type `special.io/SomeField`, it MUST NOT remove, change or update that + // Condition. + // * Implementations MUST always _merge_ changes into Conditions of the same Type, + // rather than creating more than one Condition of the same Type. + // * Implementations MUST always update the `observedGeneration` field of the + // Condition to the `metadata.generation` of the Gateway at the time of update creation. + // * If the `observedGeneration` of a Condition is _greater than_ the value the + // implementation knows about, then it MUST NOT perform the update on that Condition, + // but must wait for a future reconciliation and status update. (The assumption is that + // the implementation's copy of the object is stale and an update will be re-triggered + // if relevant.) + // + // + // // +optional // +listType=map // +listMapKey=type @@ -287,5 +323,6 @@ type GatewayClassList struct { type FeatureName string type SupportedFeature struct { + // +required Name FeatureName `json:"name"` } diff --git a/apis/v1/gatewayclass_types_overrides.go b/apis/v1/gatewayclass_types_overrides.go index f635084782..8d768fdea0 100644 --- a/apis/v1/gatewayclass_types_overrides.go +++ b/apis/v1/gatewayclass_types_overrides.go @@ -51,6 +51,7 @@ func (s *SupportedFeature) UnmarshalJSON(data []byte) error { // This is solely for the purpose of ensuring backward compatibility and // SHOULD NOT be used elsewhere. type supportedFeatureInternal struct { + // +required Name FeatureName `json:"name"` } diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index 0cae5e5020..5f9bde7a8e 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -56,13 +56,16 @@ import ( // Implementations MAY also accept HTTP/2 connections with an upgrade from // HTTP/1, i.e. without prior knowledge. type GRPCRoute struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of GRPCRoute. + // +required Spec GRPCRouteSpec `json:"spec,omitempty"` // Status defines the current state of GRPCRoute. + // +optional Status GRPCRouteStatus `json:"status,omitempty"` } @@ -136,12 +139,14 @@ type GRPCRouteSpec struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 Hostnames []Hostname `json:"hostnames,omitempty"` // Rules are a list of GRPC matchers, filters and actions. // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less than 128",rule="(self.size() > 0 ? (has(self[0].matches) ? self[0].matches.size() : 0) : 0) + (self.size() > 1 ? (has(self[1].matches) ? self[1].matches.size() : 0) : 0) + (self.size() > 2 ? (has(self[2].matches) ? self[2].matches.size() : 0) : 0) + (self.size() > 3 ? (has(self[3].matches) ? self[3].matches.size() : 0) : 0) + (self.size() > 4 ? (has(self[4].matches) ? self[4].matches.size() : 0) : 0) + (self.size() > 5 ? (has(self[5].matches) ? self[5].matches.size() : 0) : 0) + (self.size() > 6 ? (has(self[6].matches) ? self[6].matches.size() : 0) : 0) + (self.size() > 7 ? (has(self[7].matches) ? self[7].matches.size() : 0) : 0) + (self.size() > 8 ? (has(self[8].matches) ? self[8].matches.size() : 0) : 0) + (self.size() > 9 ? (has(self[9].matches) ? self[9].matches.size() : 0) : 0) + (self.size() > 10 ? (has(self[10].matches) ? self[10].matches.size() : 0) : 0) + (self.size() > 11 ? (has(self[11].matches) ? self[11].matches.size() : 0) : 0) + (self.size() > 12 ? (has(self[12].matches) ? self[12].matches.size() : 0) : 0) + (self.size() > 13 ? (has(self[13].matches) ? self[13].matches.size() : 0) : 0) + (self.size() > 14 ? (has(self[14].matches) ? self[14].matches.size() : 0) : 0) + (self.size() > 15 ? (has(self[15].matches) ? self[15].matches.size() : 0) : 0) <= 128" // @@ -156,7 +161,6 @@ type GRPCRouteRule struct { // // Support: Extended // +optional - // Name *SectionName `json:"name,omitempty"` // Matches define conditions used for matching the rule against incoming @@ -210,6 +214,7 @@ type GRPCRouteRule struct { // the above criteria. // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=64 Matches []GRPCRouteMatch `json:"matches,omitempty"` @@ -239,6 +244,7 @@ type GRPCRouteRule struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" @@ -274,6 +280,7 @@ type GRPCRouteRule struct { // Support for weight: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 BackendRefs []GRPCBackendRef `json:"backendRefs,omitempty"` @@ -405,12 +412,14 @@ type GRPCHeaderMatch struct { // entries with an equivalent header name MUST be ignored. Due to the // case-insensitivity of header names, "foo" and "Foo" are considered // equivalent. + // +required Name GRPCHeaderName `json:"name"` // Value is the value of the gRPC Header to be matched. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=4096 + // +required Value string `json:"value"` } @@ -521,6 +530,7 @@ type GRPCRouteFilter struct { // +unionDiscriminator // +kubebuilder:validation:Enum=ResponseHeaderModifier;RequestHeaderModifier;RequestMirror;ExtensionRef // + // +required Type GRPCRouteFilterType `json:"type"` // RequestHeaderModifier defines a schema for a filter that modifies request @@ -631,6 +641,7 @@ type GRPCBackendRef struct { // Filters field in GRPCRouteRule.) // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 6131d70b7b..5dad01e00a 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -33,13 +33,16 @@ import ( // used to specify additional processing steps. Backends specify where matching // requests should be routed. type HTTPRoute struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of HTTPRoute. + // +required Spec HTTPRouteSpec `json:"spec"` // Status defines the current state of HTTPRoute. + // +optional Status HTTPRouteStatus `json:"status,omitempty"` } @@ -111,12 +114,14 @@ type HTTPRouteSpec struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 Hostnames []Hostname `json:"hostnames,omitempty"` // Rules are a list of HTTP matchers, filters and actions. // // +optional + // +listType=atomic // // +kubebuilder:validation:MaxItems=16 // +kubebuilder:default={{matches: {{path: {type: "PathPrefix", value: "/"}}}}} @@ -138,7 +143,6 @@ type HTTPRouteRule struct { // // Support: Extended // +optional - // Name *SectionName `json:"name,omitempty"` // Matches define conditions used for matching the rule against incoming @@ -199,6 +203,7 @@ type HTTPRouteRule struct { // parent a request is coming from, a HTTP 404 status code MUST be returned. // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=64 // +kubebuilder:default={{path:{ type: "PathPrefix", value: "/"}}} Matches []HTTPRouteMatch `json:"matches,omitempty"` @@ -241,6 +246,7 @@ type HTTPRouteRule struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))" // +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" @@ -286,6 +292,7 @@ type HTTPRouteRule struct { // Support for weight: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 BackendRefs []HTTPBackendRef `json:"backendRefs,omitempty"` @@ -380,6 +387,7 @@ type HTTPRouteRetry struct { // Support: Extended // // +optional + // +listType=atomic Codes []HTTPRouteRetryStatusCode `json:"codes,omitempty"` // Attempts specifies the maximum number of times an individual request @@ -609,12 +617,14 @@ type HTTPHeaderMatch struct { // Generally, proxies should follow the guidance from the RFC: // https://www.rfc-editor.org/rfc/rfc7230.html#section-3.2.2 regarding // processing a repeated header, with special handling for "Set-Cookie". + // +required Name HTTPHeaderName `json:"name"` // Value is the value of HTTP Header to be matched. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=4096 + // +required Value string `json:"value"` } @@ -676,12 +686,14 @@ type HTTPQueryParamMatch struct { // // Users SHOULD NOT route traffic based on repeated query params to guard // themselves against potential differences in the implementations. + // +required Name HTTPHeaderName `json:"name"` // Value is the value of HTTP query param to be matched. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=1024 + // +required Value string `json:"value"` } @@ -792,6 +804,8 @@ type HTTPRouteMatch struct { // +kubebuilder:validation:XValidation:message="filter.urlRewrite must be specified for URLRewrite filter.type",rule="!(!has(self.urlRewrite) && self.type == 'URLRewrite')" // // +// +// // +kubebuilder:validation:XValidation:message="filter.extensionRef must be nil if the filter.type is not ExtensionRef",rule="!(has(self.extensionRef) && self.type != 'ExtensionRef')" // +kubebuilder:validation:XValidation:message="filter.extensionRef must be specified for ExtensionRef filter.type",rule="!(!has(self.extensionRef) && self.type == 'ExtensionRef')" type HTTPRouteFilter struct { @@ -830,7 +844,8 @@ type HTTPRouteFilter struct { // // +unionDiscriminator // +kubebuilder:validation:Enum=RequestHeaderModifier;ResponseHeaderModifier;RequestMirror;RequestRedirect;URLRewrite;ExtensionRef - // + // + // +required Type HTTPRouteFilterType `json:"type"` // RequestHeaderModifier defines a schema for a filter that modifies request @@ -888,6 +903,19 @@ type HTTPRouteFilter struct { // CORS *HTTPCORSFilter `json:"cors,omitempty"` + // ExternalAuth configures settings related to sending request details + // to an external auth service. The external service MUST authenticate + // the request, and MAY authorize the request as well. + // + // If there is any problem communicating with the external service, + // this filter MUST fail closed. + // + // Support: Extended + // + // +optional + // + ExternalAuth *HTTPExternalAuthFilter `json:"externalAuth,omitempty"` + // ExtensionRef is an optional, implementation-specific extension to the // "filter" behavior. For example, resource "myroutefilter" in group // "networking.example.net"). ExtensionRef MUST NOT be used for core and @@ -959,6 +987,18 @@ const ( // HTTPRouteFilterCORS HTTPRouteFilterType = "CORS" + // HTTPRouteFilterExternalAuth can be used to configure a Gateway implementation + // to call out to an external Auth server, which MUST perform Authentication + // and MAY perform Authorization on the matched request before the request + // is forwarded to the backend. + // + // Support in HTTPRouteRule: Extended + // + // Feature Name: HTTPRouteExternalAuth + // + // + HTTPRouteFilterExternalAuth HTTPRouteFilterType = "ExternalAuth" + // HTTPRouteFilterExtensionRef should be used for configuring custom // HTTP filters. // @@ -978,21 +1018,23 @@ type HTTPHeader struct { // with an equivalent header name MUST be ignored. Due to the // case-insensitivity of header names, "foo" and "Foo" are considered // equivalent. + // +required Name HTTPHeaderName `json:"name"` // Value is the value of HTTP Header to be matched. // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=4096 + // +required Value string `json:"value"` } // HTTPHeaderFilter defines a filter that modifies the headers of an HTTP -// request or response. Only one action for a given header name is permitted. -// Filters specifying multiple actions of the same or different type for any one -// header name are invalid and will be rejected by CRD validation. -// Configuration to set or add multiple values for a header must use RFC 7230 -// header value formatting, separating each value with a comma. +// request or response. Only one action for a given header name is +// permitted. Filters specifying multiple actions of the same or different +// type for any one header name are invalid. Configuration to set or add +// multiple values for a header must use RFC 7230 header value formatting, +// separating each value with a comma. type HTTPHeaderFilter struct { // Set overwrites the request with the given header (name, value) // before the action. @@ -1102,6 +1144,7 @@ type HTTPPathModifier struct { // Reason of `UnsupportedValue`. // // +kubebuilder:validation:Enum=ReplaceFullPath;ReplacePrefixMatch + // +required Type HTTPPathModifierType `json:"type"` // ReplaceFullPath specifies the value with which to replace the full path @@ -1209,6 +1252,9 @@ type HTTPRequestRedirectFilter struct { // Support: Extended // // +optional + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 Port *PortNumber `json:"port,omitempty"` // StatusCode is the HTTP status code to be used in response. @@ -1275,6 +1321,7 @@ type HTTPRequestMirrorFilter struct { // Support: Extended for Kubernetes Service // // Support: Implementation-specific for any other resource + // +required BackendRef BackendObjectReference `json:"backendRef"` // Percent represents the percentage of requests that should be @@ -1345,9 +1392,9 @@ type HTTPCORSFilter struct { // Therefore, the client doesn't attempt the actual cross-origin request. // // The `Access-Control-Allow-Origin` response header can only use `*` - // wildcard as value when the `AllowCredentials` field is unspecified. + // wildcard as value when the `AllowCredentials` field is false or omitted. // - // When the `AllowCredentials` field is specified and `AllowOrigins` field + // When the `AllowCredentials` field is true and `AllowOrigins` field // specified with the `*` wildcard, the gateway must return a single origin // in the value of the `Access-Control-Allow-Origin` response header, // instead of specifying the `*` wildcard. The value of the header @@ -1357,22 +1404,24 @@ type HTTPCORSFilter struct { // Support: Extended // +listType=set // +kubebuilder:validation:MaxItems=64 - AllowOrigins []AbsoluteURI `json:"allowOrigins,omitempty"` + // +kubebuilder:validation:XValidation:message="AllowOrigins cannot contain '*' alongside other origins",rule="!('*' in self && self.size() > 1)" + // +optional + AllowOrigins []CORSOrigin `json:"allowOrigins,omitempty"` // AllowCredentials indicates whether the actual cross-origin request allows // to include credentials. // - // The only valid value for the `Access-Control-Allow-Credentials` response - // header is true (case-sensitive). + // When set to true, the gateway will include the `Access-Control-Allow-Credentials` + // response header with value true (case-sensitive). // - // If the credentials are not allowed in cross-origin requests, the gateway - // will omit the header `Access-Control-Allow-Credentials` entirely rather - // than setting its value to false. + // When set to false or omitted the gateway will omit the header + // `Access-Control-Allow-Credentials` entirely (this is the standard CORS + // behavior). // // Support: Extended // // +optional - AllowCredentials TrueField `json:"allowCredentials,omitempty"` + AllowCredentials *bool `json:"allowCredentials,omitempty"` // AllowMethods indicates which HTTP methods are supported for accessing the // requested resource. @@ -1401,9 +1450,9 @@ type HTTPCORSFilter struct { // side. // // The `Access-Control-Allow-Methods` response header can only use `*` - // wildcard as value when the `AllowCredentials` field is unspecified. + // wildcard as value when the `AllowCredentials` field is false or omitted. // - // When the `AllowCredentials` field is specified and `AllowMethods` field + // When the `AllowCredentials` field is true and `AllowMethods` field // specified with the `*` wildcard, the gateway must specify one HTTP method // in the value of the Access-Control-Allow-Methods response header. The // value of the header `Access-Control-Allow-Methods` is same as the @@ -1418,6 +1467,7 @@ type HTTPCORSFilter struct { // +listType=set // +kubebuilder:validation:MaxItems=9 // +kubebuilder:validation:XValidation:message="AllowMethods cannot contain '*' alongside other methods",rule="!('*' in self && self.size() > 1)" + // +optional AllowMethods []HTTPMethodWithWildcard `json:"allowMethods,omitempty"` // AllowHeaders indicates which HTTP request headers are supported for @@ -1443,9 +1493,9 @@ type HTTPCORSFilter struct { // // A wildcard indicates that the requests with all HTTP headers are allowed. // The `Access-Control-Allow-Headers` response header can only use `*` - // wildcard as value when the `AllowCredentials` field is unspecified. + // wildcard as value when the `AllowCredentials` field is false or omitted. // - // When the `AllowCredentials` field is specified and `AllowHeaders` field + // When the `AllowCredentials` field is true and `AllowHeaders` field // specified with the `*` wildcard, the gateway must specify one or more // HTTP headers in the value of the `Access-Control-Allow-Headers` response // header. The value of the header `Access-Control-Allow-Headers` is same as @@ -1459,6 +1509,7 @@ type HTTPCORSFilter struct { // // +listType=set // +kubebuilder:validation:MaxItems=64 + // +optional AllowHeaders []HTTPHeaderName `json:"allowHeaders,omitempty"` // ExposeHeaders indicates which HTTP response headers can be exposed @@ -1488,8 +1539,7 @@ type HTTPCORSFilter struct { // // A wildcard indicates that the responses with all HTTP headers are exposed // to clients. The `Access-Control-Expose-Headers` response header can only - // use `*` wildcard as value when the `AllowCredentials` field is - // unspecified. + // use `*` wildcard as value when the `AllowCredentials` field is false or omitted. // // Support: Extended // @@ -1514,6 +1564,203 @@ type HTTPCORSFilter struct { MaxAge int32 `json:"maxAge,omitempty"` } +// HTTPRouteExternalAuthProtcol specifies what protocol should be used +// for communicating with an external authorization server. +// +// Valid values are supplied as constants below. +type HTTPRouteExternalAuthProtocol string + +const ( + HTTPRouteExternalAuthGRPCProtocol HTTPRouteExternalAuthProtocol = "GRPC" + HTTPRouteExternalAuthHTTPProtocol HTTPRouteExternalAuthProtocol = "HTTP" +) + +// HTTPExternalAuthFilter defines a filter that modifies requests by sending +// request details to an external authorization server. +// +// Support: Extended +// Feature Name: HTTPRouteExternalAuth +// +kubebuilder:validation:XValidation:message="grpc must be specified when protocol is set to 'GRPC'",rule="self.protocol == 'GRPC' ? has(self.grpc) : true" +// +kubebuilder:validation:XValidation:message="protocol must be 'GRPC' when grpc is set",rule="has(self.grpc) ? self.protocol == 'GRPC' : true" +// +kubebuilder:validation:XValidation:message="http must be specified when protocol is set to 'HTTP'",rule="self.protocol == 'HTTP' ? has(self.http) : true" +// +kubebuilder:validation:XValidation:message="protocol must be 'HTTP' when http is set",rule="has(self.http) ? self.protocol == 'HTTP' : true" +type HTTPExternalAuthFilter struct { + // ExternalAuthProtocol describes which protocol to use when communicating with an + // ext_authz authorization server. + // + // When this is set to GRPC, each backend must use the Envoy ext_authz protocol + // on the port specified in `backendRefs`. Requests and responses are defined + // in the protobufs explained at: + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + // + // When this is set to HTTP, each backend must respond with a `200` status + // code in on a successful authorization. Any other code is considered + // an authorization failure. + // + // Feature Names: + // GRPC Support - HTTPRouteExternalAuthGRPC + // HTTP Support - HTTPRouteExternalAuthHTTP + // + // +unionDiscriminator + // +required + // +kubebuilder:validation:Enum=HTTP;GRPC + ExternalAuthProtocol HTTPRouteExternalAuthProtocol `json:"protocol,omitempty"` + + // BackendRef is a reference to a backend to send authorization + // requests to. + // + // The backend must speak the selected protocol (GRPC or HTTP) on the + // referenced port. + // + // If the backend service requires TLS, use BackendTLSPolicy to tell the + // implementation to supply the TLS details to be used to connect to that + // backend. + // + // +required + BackendRef BackendObjectReference `json:"backendRef,omitempty"` + + // GRPCAuthConfig contains configuration for communication with ext_authz + // protocol-speaking backends. + // + // If unset, implementations must assume the default behavior for each + // included field is intended. + // + // +optional + GRPCAuthConfig *GRPCAuthConfig `json:"grpc,omitempty"` + + // HTTPAuthConfig contains configuration for communication with HTTP-speaking + // backends. + // + // If unset, implementations must assume the default behavior for each + // included field is intended. + // + // +optional + HTTPAuthConfig *HTTPAuthConfig `json:"http,omitempty"` + + // ForwardBody controls if requests to the authorization server should include + // the body of the client request; and if so, how big that body is allowed + // to be. + // + // It is expected that implementations will buffer the request body up to + // `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + // 4xx series error (413 or 403 are common examples), and fail processing + // of the filter. + // + // If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + // be forwarded. + // + // Feature Name: HTTPRouteExternalAuthForwardBody + // + // + // +optional + ForwardBody *ForwardBodyConfig `json:"forwardBody,omitempty"` +} + +// GRPCAuthConfig contains configuration for communication with Auth server +// backends that speak Envoy's ext_authz gRPC protocol. +// +// Requests and responses are defined in the protobufs explained at: +// https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto +type GRPCAuthConfig struct { + // AllowedRequestHeaders specifies what headers from the client request + // will be sent to the authorization server. + // + // If this list is empty, then the following headers must be sent: + // + // - `Authorization` + // - `Location` + // - `Proxy-Authenticate` + // - `Set-Cookie` + // - `WWW-Authenticate` + // + // If the list has entries, only those entries must be sent. + // + // +optional + // +listType=set + // +kubebuilder:validation:MaxLength=64 + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` +} + +// HTTPAuthConfig contains configuration for communication with HTTP-speaking +// backends. +type HTTPAuthConfig struct { + // Path sets the prefix that paths from the client request will have added + // when forwarded to the authorization server. + // + // When empty or unspecified, no prefix is added. + // + // Valid values are the same as the "value" regex for path values in the `match` + // stanza, and the validation regex will screen out invalid paths in the same way. + // Even with the validation, implementations MUST sanitize this input before using it + // directly. + // + // +optional + // +kubebuilder:validation:MaxLength=1024 + // +kubebuilder:validation:Pattern="^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$" + Path string `json:"path,omitempty"` + + // AllowedRequestHeaders specifies what additional headers from the client request + // will be sent to the authorization server. + // + // The following headers must always be sent to the authorization server, + // regardless of this setting: + // + // * `Host` + // * `Method` + // * `Path` + // * `Content-Length` + // * `Authorization` + // + // If this list is empty, then only those headers must be sent. + // + // Note that `Content-Length` has a special behavior, in that the length + // sent must be correct for the actual request to the external authorization + // server - that is, it must reflect the actual number of bytes sent in the + // body of the request to the authorization server. + // + // So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + // to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + // to anything other than `0`, then the `Content-Length` of the authorization + // request must be set to the actual number of bytes forwarded. + // + // +optional + // +listType=set + // +kubebuilder:validation:MaxLength=64 + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` + + // AllowedResponseHeaders specifies what headers from the authorization response + // will be copied into the request to the backend. + // + // If this list is empty, then all headers from the authorization server + // except Authority or Host must be copied. + // + // +optional + // +listType=set + // +kubebuilder:validation:MaxLength=64 + AllowedResponseHeaders []string `json:"allowedResponseHeaders,omitempty"` +} + +// ForwardBody configures if requests to the authorization server should include +// the body of the client request; and if so, how big that body is allowed +// to be. +// +// If empty or unset, do not forward the body. +type ForwardBodyConfig struct { + // MaxSize specifies how large in bytes the largest body that will be buffered + // and sent to the authorization server. If the body size is larger than + // `maxSize`, then the body sent to the authorization server must be + // truncated to `maxSize` bytes. + // + // Experimental note: This behavior needs to be checked against + // various dataplanes; it may need to be changed. + // See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 + // for more. + // + // If 0, the body will not be sent to the authorization server. + // +optional + MaxSize uint16 `json:"maxSize,omitempty"` +} + // HTTPBackendRef defines how a HTTPRoute forwards a HTTP request. // // Note that when a namespace different than the local namespace is specified, a @@ -1590,9 +1837,9 @@ type HTTPBackendRef struct { // Filters field in HTTPRouteRule.) // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))" - // +kubebuilder:validation:XValidation:message="May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both",rule="!(self.exists(f, f.type == 'RequestRedirect') && self.exists(f, f.type == 'URLRewrite'))" // +kubebuilder:validation:XValidation:message="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="ResponseHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'ResponseHeaderModifier').size() <= 1" // +kubebuilder:validation:XValidation:message="RequestRedirect filter cannot be repeated",rule="self.filter(f, f.type == 'RequestRedirect').size() <= 1" diff --git a/apis/v1/object_reference_types.go b/apis/v1/object_reference_types.go index dd507b2136..414e39b947 100644 --- a/apis/v1/object_reference_types.go +++ b/apis/v1/object_reference_types.go @@ -27,12 +27,15 @@ package v1 type LocalObjectReference struct { // Group is the group of the referent. For example, "gateway.networking.k8s.io". // When unspecified or empty string, core API group is inferred. + // +required Group Group `json:"group"` // Kind is kind of the referent. For example "HTTPRoute" or "Service". + // +required Kind Kind `json:"kind"` // Name is the name of the referent. + // +required Name ObjectName `json:"name"` } @@ -60,6 +63,7 @@ type SecretObjectReference struct { Kind *Kind `json:"kind"` // Name is the name of the referent. + // +required Name ObjectName `json:"name"` // Namespace is the namespace of the referenced object. When unspecified, the local @@ -121,6 +125,7 @@ type BackendObjectReference struct { Kind *Kind `json:"kind,omitempty"` // Name is the name of the referent. + // +required Name ObjectName `json:"name"` // Namespace is the namespace of the backend. When unspecified, the local @@ -143,6 +148,8 @@ type BackendObjectReference struct { // resource or this field. // // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 Port *PortNumber `json:"port,omitempty"` } @@ -157,12 +164,15 @@ type BackendObjectReference struct { type ObjectReference struct { // Group is the group of the referent. For example, "gateway.networking.k8s.io". // When set to the empty string, core API group is inferred. + // +required Group Group `json:"group"` // Kind is kind of the referent. For example "ConfigMap" or "Service". + // +required Kind Kind `json:"kind"` // Name is the name of the referent. + // +required Name ObjectName `json:"name"` // Namespace is the namespace of the referenced object. When unspecified, the local diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index e059b98145..99299acda8 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -86,6 +86,7 @@ type ParentReference struct { // Name is the name of the referent. // // Support: Core + // +required Name ObjectName `json:"name"` // SectionName is the name of a section within the target resource. In the @@ -148,6 +149,9 @@ type ParentReference struct { // Support: Extended // // +optional + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 Port *PortNumber `json:"port,omitempty"` } @@ -218,6 +222,7 @@ type CommonRouteSpec struct { // // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=32 // // @@ -227,9 +232,6 @@ type CommonRouteSpec struct { } // PortNumber defines a network port. -// -// +kubebuilder:validation:Minimum=1 -// +kubebuilder:validation:Maximum=65535 type PortNumber int32 // BackendRef defines how a Route should forward a request to a Kubernetes @@ -436,6 +438,7 @@ const ( type RouteParentStatus struct { // ParentRef corresponds with a ParentRef in the spec that this // RouteParentStatus struct describes the status of. + // +required ParentRef ParentReference `json:"parentRef"` // ControllerName is a domain/path string that indicates the name of the @@ -451,6 +454,7 @@ type RouteParentStatus struct { // Controllers MUST populate this field when writing status. Controllers should ensure that // entries to status populated with their ControllerName are cleaned up when they are no // longer necessary. + // +required ControllerName GatewayController `json:"controllerName"` // Conditions describes the status of the route with respect to the Gateway. @@ -473,10 +477,41 @@ type RouteParentStatus struct { // * The Route is of a type that the controller does not support. // * The Route is in a namespace the controller does not have access to. // + // + // + // Notes for implementors: + // + // Conditions are a listType `map`, which means that they function like a + // map with a key of the `type` field _in the k8s apiserver_. + // + // This means that implementations must obey some rules when updating this + // section. + // + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // * Implementations MUST NOT remove or reorder Conditions that they are not + // directly responsible for. For example, if an implementation sees a Condition + // with type `special.io/SomeField`, it MUST NOT remove, change or update that + // Condition. + // * Implementations MUST always _merge_ changes into Conditions of the same Type, + // rather than creating more than one Condition of the same Type. + // * Implementations MUST always update the `observedGeneration` field of the + // Condition to the `metadata.generation` of the Gateway at the time of update creation. + // * If the `observedGeneration` of a Condition is _greater than_ the value the + // implementation knows about, then it MUST NOT perform the update on that Condition, + // but must wait for a future reconciliation and status update. (The assumption is that + // the implementation's copy of the object is stale and an update will be re-triggered + // if relevant.) + // + // + // // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=8 + // +required Conditions []metav1.Condition `json:"conditions,omitempty"` } @@ -498,6 +533,31 @@ type RouteStatus struct { // A maximum of 32 Gateways will be represented in this list. An empty list // means the route has not been attached to any Gateway. // + // + // Notes for implementors: + // + // While parents is not a listType `map`, this is due to the fact that the + // list key is not scalar, and Kubernetes is unable to represent this. + // + // Parent status MUST be considered to be namespaced by the combination of + // the parentRef and controllerName fields, and implementations should keep + // the following rules in mind when updating this status: + // + // * Implementations MUST update only entries that have a matching value of + // `controllerName` for that implementation. + // * Implementations MUST NOT update entries with non-matching `controllerName` + // fields. + // * Implementations MUST treat each `parentRef`` in the Route separately and + // update its status based on the relationship with that parent. + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // + // + // + // +required + // +listType=atomic // +kubebuilder:validation:MaxItems=32 Parents []RouteParentStatus `json:"parents"` } @@ -548,6 +608,17 @@ type PreciseHostname string // +kubebuilder:validation:Pattern=`^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))?` type AbsoluteURI string +// The CORSOrigin MUST NOT be a relative URI, and it MUST follow the URI syntax and +// encoding rules specified in RFC3986. The CORSOrigin MUST include both a +// scheme (e.g., "http" or "spiffe") and a scheme-specific-part, or it should be a single '*' character. +// URIs that include an authority MUST include a fully qualified domain name or +// IP address as the host. +// The below regex was generated to simplify the assertion of scheme://host: being port optional +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=253 +// +kubebuilder:validation:Pattern=`(^\*$)|(^([a-zA-Z][a-zA-Z0-9+\-.]+):\/\/([^:/?#]+)(:([0-9]{1,5}))?$)` +type CORSOrigin string + // Group refers to a Kubernetes Group. It must either be an empty string or a // RFC 1123 subdomain. // @@ -764,11 +835,6 @@ type HeaderName string // +kubebuilder:validation:Pattern=`^([0-9]{1,5}(h|m|s|ms)){1,4}$` type Duration string -// TrueField is a boolean value that can only be set to true -// -// +kubebuilder:validation:Enum=true -type TrueField bool - const ( // A textual representation of a numeric IP address. IPv4 // addresses must be in dotted-decimal form. IPv6 addresses @@ -918,6 +984,7 @@ const ( // +kubebuilder:validation:XValidation:message="numerator must be less than or equal to denominator",rule="self.numerator <= self.denominator" type Fraction struct { // +kubebuilder:validation:Minimum=0 + // +required Numerator int32 `json:"numerator"` // +optional diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index 0f32a067ee..be8e2485c2 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -170,6 +170,21 @@ func (in *CookieConfig) DeepCopy() *CookieConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ForwardBodyConfig) DeepCopyInto(out *ForwardBodyConfig) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ForwardBodyConfig. +func (in *ForwardBodyConfig) DeepCopy() *ForwardBodyConfig { + if in == nil { + return nil + } + out := new(ForwardBodyConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Fraction) DeepCopyInto(out *Fraction) { *out = *in @@ -190,6 +205,29 @@ func (in *Fraction) DeepCopy() *Fraction { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FrontendTLSConfig) DeepCopyInto(out *FrontendTLSConfig) { + *out = *in + in.Default.DeepCopyInto(&out.Default) + if in.PerPort != nil { + in, out := &in.PerPort, &out.PerPort + *out = make([]TLSPortConfig, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FrontendTLSConfig. +func (in *FrontendTLSConfig) DeepCopy() *FrontendTLSConfig { + if in == nil { + return nil + } + out := new(FrontendTLSConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FrontendTLSValidation) DeepCopyInto(out *FrontendTLSValidation) { *out = *in @@ -212,6 +250,26 @@ func (in *FrontendTLSValidation) DeepCopy() *FrontendTLSValidation { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GRPCAuthConfig) DeepCopyInto(out *GRPCAuthConfig) { + *out = *in + if in.AllowedRequestHeaders != nil { + in, out := &in.AllowedRequestHeaders, &out.AllowedRequestHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GRPCAuthConfig. +func (in *GRPCAuthConfig) DeepCopy() *GRPCAuthConfig { + if in == nil { + return nil + } + out := new(GRPCAuthConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GRPCBackendRef) DeepCopyInto(out *GRPCBackendRef) { *out = *in @@ -742,16 +800,16 @@ func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec) { *out = new(GatewayInfrastructure) (*in).DeepCopyInto(*out) } - if in.BackendTLS != nil { - in, out := &in.BackendTLS, &out.BackendTLS - *out = new(GatewayBackendTLS) - (*in).DeepCopyInto(*out) - } if in.AllowedListeners != nil { in, out := &in.AllowedListeners, &out.AllowedListeners *out = new(AllowedListeners) (*in).DeepCopyInto(*out) } + if in.TLS != nil { + in, out := &in.TLS, &out.TLS + *out = new(GatewayTLSConfig) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewaySpec. @@ -843,29 +901,15 @@ func (in *GatewayStatusAddress) DeepCopy() *GatewayStatusAddress { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GatewayTLSConfig) DeepCopyInto(out *GatewayTLSConfig) { *out = *in - if in.Mode != nil { - in, out := &in.Mode, &out.Mode - *out = new(TLSModeType) - **out = **in - } - if in.CertificateRefs != nil { - in, out := &in.CertificateRefs, &out.CertificateRefs - *out = make([]SecretObjectReference, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.FrontendValidation != nil { - in, out := &in.FrontendValidation, &out.FrontendValidation - *out = new(FrontendTLSValidation) + if in.Backend != nil { + in, out := &in.Backend, &out.Backend + *out = new(GatewayBackendTLS) (*in).DeepCopyInto(*out) } - if in.Options != nil { - in, out := &in.Options, &out.Options - *out = make(map[AnnotationKey]AnnotationValue, len(*in)) - for key, val := range *in { - (*out)[key] = val - } + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(FrontendTLSConfig) + (*in).DeepCopyInto(*out) } } @@ -879,6 +923,31 @@ func (in *GatewayTLSConfig) DeepCopy() *GatewayTLSConfig { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPAuthConfig) DeepCopyInto(out *HTTPAuthConfig) { + *out = *in + if in.AllowedRequestHeaders != nil { + in, out := &in.AllowedRequestHeaders, &out.AllowedRequestHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.AllowedResponseHeaders != nil { + in, out := &in.AllowedResponseHeaders, &out.AllowedResponseHeaders + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPAuthConfig. +func (in *HTTPAuthConfig) DeepCopy() *HTTPAuthConfig { + if in == nil { + return nil + } + out := new(HTTPAuthConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPBackendRef) DeepCopyInto(out *HTTPBackendRef) { *out = *in @@ -907,9 +976,14 @@ func (in *HTTPCORSFilter) DeepCopyInto(out *HTTPCORSFilter) { *out = *in if in.AllowOrigins != nil { in, out := &in.AllowOrigins, &out.AllowOrigins - *out = make([]AbsoluteURI, len(*in)) + *out = make([]CORSOrigin, len(*in)) copy(*out, *in) } + if in.AllowCredentials != nil { + in, out := &in.AllowCredentials, &out.AllowCredentials + *out = new(bool) + **out = **in + } if in.AllowMethods != nil { in, out := &in.AllowMethods, &out.AllowMethods *out = make([]HTTPMethodWithWildcard, len(*in)) @@ -937,6 +1011,37 @@ func (in *HTTPCORSFilter) DeepCopy() *HTTPCORSFilter { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HTTPExternalAuthFilter) DeepCopyInto(out *HTTPExternalAuthFilter) { + *out = *in + in.BackendRef.DeepCopyInto(&out.BackendRef) + if in.GRPCAuthConfig != nil { + in, out := &in.GRPCAuthConfig, &out.GRPCAuthConfig + *out = new(GRPCAuthConfig) + (*in).DeepCopyInto(*out) + } + if in.HTTPAuthConfig != nil { + in, out := &in.HTTPAuthConfig, &out.HTTPAuthConfig + *out = new(HTTPAuthConfig) + (*in).DeepCopyInto(*out) + } + if in.ForwardBody != nil { + in, out := &in.ForwardBody, &out.ForwardBody + *out = new(ForwardBodyConfig) + **out = **in + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HTTPExternalAuthFilter. +func (in *HTTPExternalAuthFilter) DeepCopy() *HTTPExternalAuthFilter { + if in == nil { + return nil + } + out := new(HTTPExternalAuthFilter) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *HTTPHeader) DeepCopyInto(out *HTTPHeader) { *out = *in @@ -1198,6 +1303,11 @@ func (in *HTTPRouteFilter) DeepCopyInto(out *HTTPRouteFilter) { *out = new(HTTPCORSFilter) (*in).DeepCopyInto(*out) } + if in.ExternalAuth != nil { + in, out := &in.ExternalAuth, &out.ExternalAuth + *out = new(HTTPExternalAuthFilter) + (*in).DeepCopyInto(*out) + } if in.ExtensionRef != nil { in, out := &in.ExtensionRef, &out.ExtensionRef *out = new(LocalObjectReference) @@ -1476,7 +1586,7 @@ func (in *Listener) DeepCopyInto(out *Listener) { } if in.TLS != nil { in, out := &in.TLS, &out.TLS - *out = new(GatewayTLSConfig) + *out = new(ListenerTLSConfig) (*in).DeepCopyInto(*out) } if in.AllowedRoutes != nil { @@ -1550,6 +1660,40 @@ func (in *ListenerStatus) DeepCopy() *ListenerStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ListenerTLSConfig) DeepCopyInto(out *ListenerTLSConfig) { + *out = *in + if in.Mode != nil { + in, out := &in.Mode, &out.Mode + *out = new(TLSModeType) + **out = **in + } + if in.CertificateRefs != nil { + in, out := &in.CertificateRefs, &out.CertificateRefs + *out = make([]SecretObjectReference, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Options != nil { + in, out := &in.Options, &out.Options + *out = make(map[AnnotationKey]AnnotationValue, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ListenerTLSConfig. +func (in *ListenerTLSConfig) DeepCopy() *ListenerTLSConfig { + if in == nil { + return nil + } + out := new(ListenerTLSConfig) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LocalObjectReference) DeepCopyInto(out *LocalObjectReference) { *out = *in @@ -1834,3 +1978,39 @@ func (in *SupportedFeature) DeepCopy() *SupportedFeature { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { + *out = *in + if in.Validation != nil { + in, out := &in.Validation, &out.Validation + *out = new(FrontendTLSValidation) + (*in).DeepCopyInto(*out) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig. +func (in *TLSConfig) DeepCopy() *TLSConfig { + if in == nil { + return nil + } + out := new(TLSConfig) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSPortConfig) DeepCopyInto(out *TLSPortConfig) { + *out = *in + in.TLS.DeepCopyInto(&out.TLS) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSPortConfig. +func (in *TLSPortConfig) DeepCopy() *TLSPortConfig { + if in == nil { + return nil + } + out := new(TLSPortConfig) + in.DeepCopyInto(out) + return out +} diff --git a/apis/v1alpha2/policy_types.go b/apis/v1alpha2/policy_types.go index bc2ef766a9..d24bb2ee74 100644 --- a/apis/v1alpha2/policy_types.go +++ b/apis/v1alpha2/policy_types.go @@ -38,12 +38,15 @@ const ( // the policy attachment documentation for Gateway API. type LocalPolicyTargetReference struct { // Group is the group of the target resource. + // +required Group Group `json:"group"` // Kind is kind of the target resource. + // +required Kind Kind `json:"kind"` // Name is the name of the target resource. + // +required Name ObjectName `json:"name"` } @@ -55,12 +58,15 @@ type LocalPolicyTargetReference struct { // documentation for Gateway API. type NamespacedPolicyTargetReference struct { // Group is the group of the target resource. + // +required Group Group `json:"group"` // Kind is kind of the target resource. + // +required Kind Kind `json:"kind"` // Name is the name of the target resource. + // +required Name ObjectName `json:"name"` // Namespace is the namespace of the referent. When unspecified, the local @@ -174,6 +180,7 @@ const ( type PolicyAncestorStatus struct { // AncestorRef corresponds with a ParentRef in the spec that this // PolicyAncestorStatus struct describes the status of. + // +required AncestorRef ParentReference `json:"ancestorRef"` // ControllerName is a domain/path string that indicates the name of the @@ -189,10 +196,42 @@ type PolicyAncestorStatus struct { // Controllers MUST populate this field when writing status. Controllers should ensure that // entries to status populated with their ControllerName are cleaned up when they are no // longer necessary. + // +required ControllerName GatewayController `json:"controllerName"` // Conditions describes the status of the Policy with respect to the given Ancestor. // + // + // + // Notes for implementors: + // + // Conditions are a listType `map`, which means that they function like a + // map with a key of the `type` field _in the k8s apiserver_. + // + // This means that implementations must obey some rules when updating this + // section. + // + // * Implementations MUST perform a read-modify-write cycle on this field + // before modifying it. That is, when modifying this field, implementations + // must be confident they have fetched the most recent version of this field, + // and ensure that changes they make are on that recent version. + // * Implementations MUST NOT remove or reorder Conditions that they are not + // directly responsible for. For example, if an implementation sees a Condition + // with type `special.io/SomeField`, it MUST NOT remove, change or update that + // Condition. + // * Implementations MUST always _merge_ changes into Conditions of the same Type, + // rather than creating more than one Condition of the same Type. + // * Implementations MUST always update the `observedGeneration` field of the + // Condition to the `metadata.generation` of the Gateway at the time of update creation. + // * If the `observedGeneration` of a Condition is _greater than_ the value the + // implementation knows about, then it MUST NOT perform the update on that Condition, + // but must wait for a future reconciliation and status update. (The assumption is that + // the implementation's copy of the object is stale and an update will be re-triggered + // if relevant.) + // + // + // + // +required // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=1 @@ -233,6 +272,8 @@ type PolicyStatus struct { // additional Gateways would be able to reference the Service targeted by // the BackendTLSPolicy. // + // +required + // +listType=atomic // +kubebuilder:validation:MaxItems=16 Ancestors []PolicyAncestorStatus `json:"ancestors"` } diff --git a/apis/v1alpha2/shared_types.go b/apis/v1alpha2/shared_types.go index 2fb84d5f3b..3d2f787909 100644 --- a/apis/v1alpha2/shared_types.go +++ b/apis/v1alpha2/shared_types.go @@ -40,9 +40,6 @@ type ParentReference = v1.ParentReference type CommonRouteSpec = v1.CommonRouteSpec // PortNumber defines a network port. -// -// +kubebuilder:validation:Minimum=1 -// +kubebuilder:validation:Maximum=65535 type PortNumber = v1.PortNumber // BackendRef defines how a Route should forward a request to a Kubernetes diff --git a/apis/v1alpha2/tcproute_types.go b/apis/v1alpha2/tcproute_types.go index e383af495d..e545e6fdab 100644 --- a/apis/v1alpha2/tcproute_types.go +++ b/apis/v1alpha2/tcproute_types.go @@ -31,13 +31,16 @@ import ( // listener, it can be used to forward connections on the port specified by the // listener to a set of backends specified by the TCPRoute. type TCPRoute struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of TCPRoute. + // +required Spec TCPRouteSpec `json:"spec"` // Status defines the current state of TCPRoute. + // +optional Status TCPRouteStatus `json:"status,omitempty"` } @@ -47,6 +50,8 @@ type TCPRouteSpec struct { // Rules are a list of TCP matchers and actions. // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -81,6 +86,8 @@ type TCPRouteRule struct { // // Support for weight: Extended // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 BackendRefs []BackendRef `json:"backendRefs,omitempty"` diff --git a/apis/v1alpha2/tlsroute_types.go b/apis/v1alpha2/tlsroute_types.go index f21fe3fc50..8ca02d370d 100644 --- a/apis/v1alpha2/tlsroute_types.go +++ b/apis/v1alpha2/tlsroute_types.go @@ -24,7 +24,6 @@ import ( // +kubebuilder:object:root=true // +kubebuilder:resource:categories=gateway-api // +kubebuilder:subresource:status -// +kubebuilder:storageversion // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` // The TLSRoute resource is similar to TCPRoute, but can be configured @@ -34,13 +33,16 @@ import ( // If you need to forward traffic to a single target for a TLS listener, you // could choose to use a TCPRoute with a TLS listener. type TLSRoute struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of TLSRoute. + // +required Spec TLSRouteSpec `json:"spec"` // Status defines the current state of TLSRoute. + // +optional Status TLSRouteStatus `json:"status,omitempty"` } @@ -83,11 +85,14 @@ type TLSRouteSpec struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 Hostnames []Hostname `json:"hostnames,omitempty"` // Rules are a list of TLS matchers and actions. // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -125,6 +130,8 @@ type TLSRouteRule struct { // // Support for weight: Extended // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 BackendRefs []BackendRef `json:"backendRefs,omitempty"` diff --git a/apis/v1alpha2/udproute_types.go b/apis/v1alpha2/udproute_types.go index c7e92b92b4..f5f8feff77 100644 --- a/apis/v1alpha2/udproute_types.go +++ b/apis/v1alpha2/udproute_types.go @@ -31,13 +31,16 @@ import ( // listener, it can be used to forward traffic on the port specified by the // listener to a set of backends specified by the UDPRoute. type UDPRoute struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of UDPRoute. + // +required Spec UDPRouteSpec `json:"spec"` // Status defines the current state of UDPRoute. + // +optional Status UDPRouteStatus `json:"status,omitempty"` } @@ -47,6 +50,8 @@ type UDPRouteSpec struct { // Rules are a list of UDP matchers and actions. // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -81,6 +86,8 @@ type UDPRouteRule struct { // // Support for weight: Extended // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 BackendRefs []BackendRef `json:"backendRefs,omitempty"` diff --git a/apis/v1alpha3/backendtlspolicy_types.go b/apis/v1alpha3/backendtlspolicy_types.go index 394fa46c23..9c5c019d46 100644 --- a/apis/v1alpha3/backendtlspolicy_types.go +++ b/apis/v1alpha3/backendtlspolicy_types.go @@ -36,13 +36,16 @@ import ( // BackendTLSPolicy provides a way to configure how a Gateway // connects to a Backend via TLS. type BackendTLSPolicy struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of BackendTLSPolicy. + // +required Spec BackendTLSPolicySpec `json:"spec"` // Status defines the current state of BackendTLSPolicy. + // +optional Status v1alpha2.PolicyStatus `json:"status,omitempty"` } @@ -77,6 +80,8 @@ type BackendTLSPolicySpec struct { // // Support: Implementation-specific for any other resource // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // +kubebuilder:validation:XValidation:message="sectionName must be specified when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.all(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name ? ((!has(p1.sectionName) || p1.sectionName == '') == (!has(p2.sectionName) || p2.sectionName == '')) : true))" @@ -84,6 +89,7 @@ type BackendTLSPolicySpec struct { TargetRefs []v1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"` // Validation contains backend TLS validation configuration. + // +required Validation BackendTLSPolicyValidation `json:"validation"` // Options are a list of key/value pairs to enable extended TLS @@ -115,8 +121,32 @@ type BackendTLSPolicyValidation struct { // not both. If CACertificateRefs is empty or unspecified, the configuration for // WellKnownCACertificates MUST be honored instead if supported by the implementation. // - // References to a resource in a different namespace are invalid for the - // moment, although we will revisit this in the future. + // A CACertificateRef is invalid if: + // + // * It refers to a resource that cannot be resolved (e.g., the referenced resource + // does not exist) or is misconfigured (e.g., a ConfigMap does not contain a key + // named `ca.crt`). In this case, the Reason must be set to `InvalidCACertificateRef` + // and the Message of the Condition must indicate which reference is invalid and why. + // + // * It refers to an unknown or unsupported kind of resource. In this case, the Reason + // must be set to `InvalidKind` and the Message of the Condition must explain which + // kind of resource is unknown or unsupported. + // + // * It refers to a resource in another namespace. This may change in future + // spec updates. + // + // Implementations MAY choose to perform further validation of the certificate + // content (e.g., checking expiry or enforcing specific formats). In such cases, + // an implementation-specific Reason and Message must be set for the invalid reference. + // + // In all cases, the implementation MUST ensure the `ResolvedRefs` Condition on + // the BackendTLSPolicy is set to `status: False`, with a Reason and Message + // that indicate the cause of the error. Connections using an invalid + // CACertificateRef MUST fail, and the client MUST receive an HTTP 5xx error + // response. If ALL CACertificateRefs are invalid, the implementation MUST also + // ensure the `Accepted` Condition on the BackendTLSPolicy is set to + // `status: False`, with a Reason `NoValidCACertificate`. + // // // A single CACertificateRef to a Kubernetes ConfigMap kind has "Core" support. // Implementations MAY choose to support attaching multiple certificates to @@ -125,11 +155,12 @@ type BackendTLSPolicyValidation struct { // Support: Core - An optional single reference to a Kubernetes ConfigMap, // with the CA certificate in a key named `ca.crt`. // - // Support: Implementation-specific (More than one reference, or other kinds - // of resources). + // Support: Implementation-specific - More than one reference, other kinds + // of resources, or a single reference that includes multiple certificates. // - // +kubebuilder:validation:MaxItems=8 // +optional + // +listType=atomic + // +kubebuilder:validation:MaxItems=8 CACertificateRefs []v1.LocalObjectReference `json:"caCertificateRefs,omitempty"` // WellKnownCACertificates specifies whether system CA certificates may be used in @@ -137,14 +168,16 @@ type BackendTLSPolicyValidation struct { // // If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs // must be specified with at least one entry for a valid configuration. Only one of - // CACertificateRefs or WellKnownCACertificates may be specified, not both. If an - // implementation does not support the WellKnownCACertificates field or the value - // supplied is not supported, the Status Conditions on the Policy MUST be - // updated to include an Accepted: False Condition with Reason: Invalid. + // CACertificateRefs or WellKnownCACertificates may be specified, not both. + // If an implementation does not support the WellKnownCACertificates field, or + // the supplied value is not recognized, the implementation MUST ensure the + // `Accepted` Condition on the BackendTLSPolicy is set to `status: False`, with + // a Reason `Invalid`. // // Support: Implementation-specific // // +optional + // +listType=atomic WellKnownCACertificates *WellKnownCACertificatesType `json:"wellKnownCACertificates,omitempty"` // Hostname is used for two purposes in the connection between Gateways and @@ -152,10 +185,10 @@ type BackendTLSPolicyValidation struct { // // 1. Hostname MUST be used as the SNI to connect to the backend (RFC 6066). // 2. Hostname MUST be used for authentication and MUST match the certificate served by the matching backend, unless SubjectAltNames is specified. - // authentication and MUST match the certificate served by the matching - // backend. // // Support: Core + // + // +required Hostname v1.PreciseHostname `json:"hostname"` // SubjectAltNames contains one or more Subject Alternative Names. @@ -165,6 +198,7 @@ type BackendTLSPolicyValidation struct { // Support: Extended // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=5 SubjectAltNames []SubjectAltName `json:"subjectAltNames,omitempty"` } @@ -178,6 +212,8 @@ type SubjectAltName struct { // Type determines the format of the Subject Alternative Name. Always required. // // Support: Core + // + // +required Type SubjectAltNameType `json:"type"` // Hostname contains Subject Alternative Name specified in DNS name format. @@ -224,3 +260,43 @@ const ( // Support: Core URISubjectAltNameType SubjectAltNameType = "URI" ) + +const ( + // This reason is used with the "Accepted" condition when it is + // set to false because all CACertificateRefs of the + // BackendTLSPolicy are invalid. + BackendTLSPolicyReasonNoValidCACertificate v1alpha2.PolicyConditionReason = "NoValidCACertificate" +) + +const ( + // This condition indicates whether the controller was able to resolve all + // object references for the BackendTLSPolicy. + // + // Possible reasons for this condition to be True are: + // + // * "ResolvedRefs" + // + // Possible reasons for this condition to be False are: + // + // * "InvalidCACertificateRef" + // * "InvalidKind" + // + // Controllers may raise this condition with other reasons, but should + // prefer to use the reasons listed above to improve interoperability. + BackendTLSPolicyConditionResolvedRefs v1alpha2.PolicyConditionType = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when the condition + // is true. + BackendTLSPolicyReasonResolvedRefs v1alpha2.PolicyConditionReason = "ResolvedRefs" + + // This reason is used with the "ResolvedRefs" condition when one of the + // BackendTLSPolicy's CACertificateRefs is invalid. + // A CACertificateRef is considered invalid when it refers to a nonexistent + // resource or when the data within that resource is malformed. + BackendTLSPolicyReasonInvalidCACertificateRef v1alpha2.PolicyConditionReason = "InvalidCACertificateRef" + + // This reason is used with the "ResolvedRefs" condition when one of the + // BackendTLSPolicy's CACertificateRefs references an unknown or unsupported + // Group and/or Kind. + BackendTLSPolicyReasonInvalidKind v1alpha2.PolicyConditionReason = "InvalidKind" +) diff --git a/apis/v1alpha3/shared_types.go b/apis/v1alpha3/shared_types.go new file mode 100644 index 0000000000..fa487f96d4 --- /dev/null +++ b/apis/v1alpha3/shared_types.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import v1 "sigs.k8s.io/gateway-api/apis/v1" + +// CommonRouteSpec defines the common attributes that all Routes MUST include +// within their spec. +// +k8s:deepcopy-gen=false +type CommonRouteSpec = v1.CommonRouteSpec + +// BackendRef defines how a Route should forward a request to a Kubernetes +// resource. +// +// Note that when a namespace different than the local namespace is specified, a +// ReferenceGrant object is required in the referent namespace to allow that +// namespace's owner to accept the reference. See the ReferenceGrant +// documentation for details. +// +k8s:deepcopy-gen=false +type BackendRef = v1.BackendRef + +// RouteStatus defines the common attributes that all Routes MUST include within +// their status. +// +k8s:deepcopy-gen=false +type RouteStatus = v1.RouteStatus + +// Hostname is the fully qualified domain name of a network host. This matches +// the RFC 1123 definition of a hostname with 2 notable exceptions: +// +// 1. IPs are not allowed. +// 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard +// label must appear by itself as the first label. +// +// Hostname can be "precise" which is a domain name without the terminating +// dot of a network host (e.g. "foo.example.com") or "wildcard", which is a +// domain name prefixed with a single wildcard label (e.g. `*.example.com`). +// +// Note that as per RFC1035 and RFC1123, a *label* must consist of lower case +// alphanumeric characters or '-', and must start and end with an alphanumeric +// character. No other punctuation is allowed. +// +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=253 +// +kubebuilder:validation:Pattern=`^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` +type Hostname = v1.Hostname + +// SectionName is the name of a section in a Kubernetes resource. +// +// In the following resources, SectionName is interpreted as the following: +// +// * Gateway: Listener name +// * HTTPRoute: HTTPRouteRule name +// * Service: Port name +// +// Section names can have a variety of forms, including RFC 1123 subdomains, +// RFC 1123 labels, or RFC 1035 labels. +// +// This validation is based off of the corresponding Kubernetes validation: +// https://github.com/kubernetes/apimachinery/blob/02cfb53916346d085a6c6c7c66f882e3c6b0eca6/pkg/util/validation/validation.go#L208 +// +// Valid values include: +// +// * "example" +// * "foo-example" +// * "example.com" +// * "foo.example.com" +// +// Invalid values include: +// +// * "example.com/bar" - "/" is an invalid character +// +// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$` +// +kubebuilder:validation:MinLength=1 +// +kubebuilder:validation:MaxLength=253 +type SectionName = v1.SectionName diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go new file mode 100644 index 0000000000..8ae5b51866 --- /dev/null +++ b/apis/v1alpha3/tlsroute_types.go @@ -0,0 +1,113 @@ +/* +Copyright 2020 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha3 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "sigs.k8s.io/gateway-api/apis/v1alpha2" +) + +// +genclient +// +kubebuilder:object:root=true +// +kubebuilder:resource:categories=gateway-api +// +kubebuilder:subresource:status +// +kubebuilder:storageversion +// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` + +// The TLSRoute resource is similar to TCPRoute, but can be configured +// to match against TLS-specific metadata. This allows more flexibility +// in matching streams for a given TLS listener. +// +// If you need to forward traffic to a single target for a TLS listener, you +// could choose to use a TCPRoute with a TLS listener. +type TLSRoute struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of TLSRoute. + // +required + Spec TLSRouteSpec `json:"spec"` + + // Status defines the current state of TLSRoute. + // +optional + Status v1alpha2.TLSRouteStatus `json:"status,omitempty"` +} + +// TLSRouteSpec defines the desired state of a TLSRoute resource. +type TLSRouteSpec struct { + CommonRouteSpec `json:",inline"` + + // Hostnames defines a set of SNI hostnames that should match against the + // SNI attribute of TLS ClientHello message in TLS handshake. This matches + // the RFC 1123 definition of a hostname with 2 notable exceptions: + // + // 1. IPs are not allowed in SNI hostnames per RFC 6066. + // 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + // label must appear by itself as the first label. + // + // If a hostname is specified by both the Listener and TLSRoute, there + // must be at least one intersecting hostname for the TLSRoute to be + // attached to the Listener. For example: + // + // * A Listener with `test.example.com` as the hostname matches TLSRoutes + // that have specified at least one of `test.example.com` or + // `*.example.com`. + // * A Listener with `*.example.com` as the hostname matches TLSRoutes + // that have specified at least one hostname that matches the Listener + // hostname. For example, `test.example.com` and `*.example.com` would both + // match. On the other hand, `example.com` and `test.example.net` would not + // match. + // + // If both the Listener and TLSRoute have specified hostnames, any + // TLSRoute hostnames that do not match the Listener hostname MUST be + // ignored. For example, if a Listener specified `*.example.com`, and the + // TLSRoute specified `test.example.com` and `test.example.net`, + // `test.example.net` must not be considered for a match. + // + // If both the Listener and TLSRoute have specified hostnames, and none + // match with the criteria above, then the TLSRoute is not accepted. The + // implementation must raise an 'Accepted' Condition with a status of + // `False` in the corresponding RouteParentStatus. + // + // Support: Core + // + // +required + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + Hostnames []Hostname `json:"hostnames,omitempty"` + + // Rules are a list of actions. + // + // +required + // +listType=atomic + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=1 + // + Rules []v1alpha2.TLSRouteRule `json:"rules,omitempty"` +} + +// +kubebuilder:object:root=true + +// TLSRouteList contains a list of TLSRoute +type TLSRouteList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []TLSRoute `json:"items"` +} diff --git a/apis/v1alpha3/zz_generated.deepcopy.go b/apis/v1alpha3/zz_generated.deepcopy.go index 876ac9f7b6..9b659eadab 100644 --- a/apis/v1alpha3/zz_generated.deepcopy.go +++ b/apis/v1alpha3/zz_generated.deepcopy.go @@ -159,3 +159,90 @@ func (in *SubjectAltName) DeepCopy() *SubjectAltName { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSRoute) DeepCopyInto(out *TLSRoute) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSRoute. +func (in *TLSRoute) DeepCopy() *TLSRoute { + if in == nil { + return nil + } + out := new(TLSRoute) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TLSRoute) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSRouteList) DeepCopyInto(out *TLSRouteList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TLSRoute, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSRouteList. +func (in *TLSRouteList) DeepCopy() *TLSRouteList { + if in == nil { + return nil + } + out := new(TLSRouteList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TLSRouteList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TLSRouteSpec) DeepCopyInto(out *TLSRouteSpec) { + *out = *in + in.CommonRouteSpec.DeepCopyInto(&out.CommonRouteSpec) + if in.Hostnames != nil { + in, out := &in.Hostnames, &out.Hostnames + *out = make([]Hostname, len(*in)) + copy(*out, *in) + } + if in.Rules != nil { + in, out := &in.Rules, &out.Rules + *out = make([]v1alpha2.TLSRouteRule, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSRouteSpec. +func (in *TLSRouteSpec) DeepCopy() *TLSRouteSpec { + if in == nil { + return nil + } + out := new(TLSRouteSpec) + in.DeepCopyInto(out) + return out +} diff --git a/apis/v1alpha3/zz_generated.register.go b/apis/v1alpha3/zz_generated.register.go index d1caca01be..bc61a8b310 100644 --- a/apis/v1alpha3/zz_generated.register.go +++ b/apis/v1alpha3/zz_generated.register.go @@ -63,6 +63,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &BackendTLSPolicy{}, &BackendTLSPolicyList{}, + &TLSRoute{}, + &TLSRouteList{}, ) // AddToGroupVersion allows the serialization of client types like ListOptions. v1.AddToGroupVersion(scheme, SchemeGroupVersion) diff --git a/apis/v1beta1/gateway_types.go b/apis/v1beta1/gateway_types.go index 80c746fcdd..60bac20c94 100644 --- a/apis/v1beta1/gateway_types.go +++ b/apis/v1beta1/gateway_types.go @@ -88,9 +88,9 @@ type Listener = v1.Listener // +k8s:deepcopy-gen=false type ProtocolType = v1.ProtocolType -// GatewayTLSConfig describes a TLS configuration. +// ListenerTLSConfig describes a TLS configuration. // +k8s:deepcopy-gen=false -type GatewayTLSConfig = v1.GatewayTLSConfig +type ListenerTLSConfig = v1.ListenerTLSConfig // TLSModeType type defines how a Gateway handles TLS sessions. // @@ -131,7 +131,7 @@ type RouteNamespaces = v1.RouteNamespaces // +k8s:deepcopy-gen=false type RouteGroupKind = v1.RouteGroupKind -// GatewayAddress describes an address that can be bound to a Gateway. +// GatewaySpecAddress describes an address that can be bound to a Gateway. // +k8s:deepcopy-gen=false type GatewaySpecAddress = v1.GatewaySpecAddress diff --git a/apis/v1beta1/referencegrant_types.go b/apis/v1beta1/referencegrant_types.go index 0b0caf7088..bed43bc957 100644 --- a/apis/v1beta1/referencegrant_types.go +++ b/apis/v1beta1/referencegrant_types.go @@ -41,10 +41,12 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" // no grant, and MUST respond to the removal of a grant by revoking the access // that the grant allowed. type ReferenceGrant struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of ReferenceGrant. + // +optional Spec ReferenceGrantSpec `json:"spec,omitempty"` // Note that `Status` sub-resource has been excluded at the @@ -70,6 +72,8 @@ type ReferenceGrantSpec struct { // // Support: Core // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 From []ReferenceGrantFrom `json:"from"` @@ -81,6 +85,8 @@ type ReferenceGrantSpec struct { // // Support: Core // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 To []ReferenceGrantTo `json:"to"` @@ -92,6 +98,8 @@ type ReferenceGrantFrom struct { // When empty, the Kubernetes core API group is inferred. // // Support: Core + // + // +required Group Group `json:"group"` // Kind is the kind of the referent. Although implementations may support @@ -109,11 +117,14 @@ type ReferenceGrantFrom struct { // * TCPRoute // * TLSRoute // * UDPRoute + // +required Kind Kind `json:"kind"` // Namespace is the namespace of the referent. // // Support: Core + // + // +required Namespace Namespace `json:"namespace"` } @@ -124,6 +135,8 @@ type ReferenceGrantTo struct { // When empty, the Kubernetes core API group is inferred. // // Support: Core + // + // +required Group Group `json:"group"` // Kind is the kind of the referent. Although implementations may support @@ -132,6 +145,8 @@ type ReferenceGrantTo struct { // // * Secret when used to permit a SecretObjectReference // * Service when used to permit a BackendObjectReference + // + // +required Kind Kind `json:"kind"` // Name is the name of the referent. When unspecified, this policy diff --git a/apis/v1beta1/shared_types.go b/apis/v1beta1/shared_types.go index 3dbcc280fc..ce1c430649 100644 --- a/apis/v1beta1/shared_types.go +++ b/apis/v1beta1/shared_types.go @@ -40,9 +40,6 @@ type ParentReference = v1.ParentReference type CommonRouteSpec = v1.CommonRouteSpec // PortNumber defines a network port. -// -// +kubebuilder:validation:Minimum=1 -// +kubebuilder:validation:Maximum=65535 type PortNumber = v1.PortNumber // BackendRef defines how a Route should forward a request to a Kubernetes diff --git a/apisx/v1alpha1/shared_types.go b/apisx/v1alpha1/shared_types.go index f811ace877..848ff53b18 100644 --- a/apisx/v1alpha1/shared_types.go +++ b/apisx/v1alpha1/shared_types.go @@ -25,7 +25,7 @@ type ( // +k8s:deepcopy-gen=false AllowedRoutes = v1.AllowedRoutes // +k8s:deepcopy-gen=false - GatewayTLSConfig = v1.GatewayTLSConfig + ListenerTLSConfig = v1.ListenerTLSConfig // +k8s:deepcopy-gen=false Group = v1.Group // +k8s:deepcopy-gen=false @@ -70,6 +70,7 @@ type ParentGatewayReference struct { Kind *Kind `json:"kind"` // Name is the name of the referent. + // +required Name ObjectName `json:"name"` // Namespace is the namespace of the referent. If not present, @@ -87,6 +88,7 @@ type RequestRate struct { // Support: Extended // +kubebuilder:validation:Minimum=1 // +kubebuilder:validation:Maximum=1000000 + // +optional Count *int `json:"count,omitempty"` // Interval specifies the divisor of the rate of requests, the amount of @@ -94,5 +96,6 @@ type RequestRate struct { // // Support: Extended // +kubebuilder:validation:XValidation:message="interval can not be greater than one hour",rule="!(duration(self) == duration('0s') || duration(self) > duration('1h'))" + // +optional Interval *Duration `json:"interval,omitempty"` } diff --git a/apisx/v1alpha1/xbackendtrafficpolicy_types.go b/apisx/v1alpha1/xbackendtrafficpolicy_types.go index b2dcba6985..3ac5163693 100644 --- a/apisx/v1alpha1/xbackendtrafficpolicy_types.go +++ b/apisx/v1alpha1/xbackendtrafficpolicy_types.go @@ -37,13 +37,16 @@ type XBackendTrafficPolicy struct { // // +optional - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of BackendTrafficPolicy. + // +required Spec BackendTrafficPolicySpec `json:"spec"` // Status defines the current state of BackendTrafficPolicy. + // +optional Status PolicyStatus `json:"status,omitempty"` } @@ -72,6 +75,7 @@ type BackendTrafficPolicySpec struct { // +listMapKey=name // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 + // +required TargetRefs []LocalPolicyTargetReference `json:"targetRefs"` // RetryConstraint defines the configuration for when to allow or prevent diff --git a/apisx/v1alpha1/xlistenerset_types.go b/apisx/v1alpha1/xlistenerset_types.go index 529b7f3508..f8198c8659 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -29,24 +29,53 @@ import ( // +kubebuilder:printcolumn:name="Programmed",type=string,JSONPath=`.status.conditions[?(@.type=="Programmed")].status` // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp` -// XListenerSet defines a set of additional listeners -// to attach to an existing Gateway. +// XListenerSet defines a set of additional listeners to attach to an existing Gateway. +// This resource provides a mechanism to merge multiple listeners into a single Gateway. +// +// The parent Gateway must explicitly allow ListenerSet attachment through its +// AllowedListeners configuration. By default, Gateways do not allow ListenerSet +// attachment. +// +// Routes can attach to a ListenerSet by specifying it as a parentRef, and can +// optionally target specific listeners using the sectionName field. +// +// Policy Attachment: +// - Policies that attach to a ListenerSet apply to all listeners defined in that resource +// - Policies do not impact listeners in the parent Gateway +// - Different ListenerSets attached to the same Gateway can have different policies +// - If an implementation cannot apply a policy to specific listeners, it should reject the policy +// +// ReferenceGrant Semantics: +// - ReferenceGrants applied to a Gateway are not inherited by child ListenerSets +// - ReferenceGrants applied to a ListenerSet do not grant permission to the parent Gateway's listeners +// - A ListenerSet can reference secrets/backends in its own namespace without a ReferenceGrant +// +// Gateway Integration: +// - The parent Gateway's status will include an "AttachedListenerSets" condition +// - This condition will be: +// - True: when AllowedListeners is set and at least one child ListenerSet is attached +// - False: when AllowedListeners is set but no valid listeners are attached, or when AllowedListeners is not set or false +// - Unknown: when no AllowedListeners config is present type XListenerSet struct { - metav1.TypeMeta `json:",inline"` + metav1.TypeMeta `json:",inline"` + // +optional metav1.ObjectMeta `json:"metadata,omitempty"` // Spec defines the desired state of ListenerSet. + // +required Spec ListenerSetSpec `json:"spec"` // Status defines the current state of ListenerSet. // // +kubebuilder:default={conditions: {{type: "Accepted", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"},{type: "Programmed", status: "Unknown", reason:"Pending", message:"Waiting for controller", lastTransitionTime: "1970-01-01T00:00:00Z"}}} + // +optional Status ListenerSetStatus `json:"status,omitempty"` } // ListenerSetSpec defines the desired state of a ListenerSet. type ListenerSetSpec struct { // ParentRef references the Gateway that the listeners are attached to. + // +required ParentRef ParentGatewayReference `json:"parentRef"` // Listeners associated with this ListenerSet. Listeners define @@ -63,10 +92,10 @@ type ListenerSetSpec struct { // // 1. "parent" Gateway // 2. ListenerSet ordered by creation time (oldest first) - // 3. ListenerSet ordered alphabetically by “{namespace}/{name}”. + // 3. ListenerSet ordered alphabetically by "{namespace}/{name}". // // An implementation MAY reject listeners by setting the ListenerEntryStatus - // `Accepted`` condition to False with the Reason `TooManyListeners` + // `Accepted` condition to False with the Reason `TooManyListeners` // // If a listener has a conflict, this will be reported in the // Status.ListenerEntryStatus setting the `Conflicted` condition to True. @@ -85,6 +114,7 @@ type ListenerSetSpec struct { // +kubebuilder:validation:XValidation:message="hostname must not be specified for protocols ['TCP', 'UDP']",rule="self.all(l, l.protocol in ['TCP', 'UDP'] ? (!has(l.hostname) || l.hostname == '') : true)" // +kubebuilder:validation:XValidation:message="Listener name must be unique within the Gateway",rule="self.all(l1, self.exists_one(l2, l1.name == l2.name))" // +kubebuilder:validation:XValidation:message="Combination of port, protocol and hostname must be unique for each listener",rule="self.all(l1, !has(l1.port) || self.exists_one(l2, has(l2.port) && l1.port == l2.port && l1.protocol == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))" + // +required Listeners []ListenerEntry `json:"listeners"` } @@ -95,6 +125,7 @@ type ListenerEntry struct { // Name is not required to be unique across a Gateway and ListenerSets. // Routes can attach to a Listener by having a ListenerSet as a parentRef // and setting the SectionName + // +required Name SectionName `json:"name"` // Hostname specifies the virtual hostname to match for protocol types that @@ -127,23 +158,35 @@ type ListenerEntry struct { // Port is the network port. Multiple listeners may use the // same port, subject to the Listener compatibility rules. - Port PortNumber `json:"port"` + // + // If the port is not set or specified as zero, the implementation will assign + // a unique port. If the implementation does not support dynamic port + // assignment, it MUST set `Accepted` condition to `False` with the + // `UnsupportedPort` reason. + // + // +optional + // + // +kubebuilder:default=0 + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=65535 + Port PortNumber `json:"port,omitempty"` // Protocol specifies the network protocol this listener expects to receive. + // +required Protocol ProtocolType `json:"protocol"` // TLS is the TLS configuration for the Listener. This field is required if // the Protocol field is "HTTPS" or "TLS". It is invalid to set this field // if the Protocol field is "HTTP", "TCP", or "UDP". // - // The association of SNIs to Certificate defined in GatewayTLSConfig is + // The association of SNIs to Certificate defined in ListenerTLSConfig is // defined based on the Hostname field for this listener. // // The GatewayClass MUST use the longest matching SNI out of all // available certificates for any TLS handshake. // // +optional - TLS *GatewayTLSConfig `json:"tls,omitempty"` + TLS *ListenerTLSConfig `json:"tls,omitempty"` // AllowedRoutes defines the types of routes that MAY be attached to a // Listener and the trusted namespaces where those Route resources MAY be @@ -205,9 +248,15 @@ type ListenerSetStatus struct { // ListenerStatus is the status associated with a Listener. type ListenerEntryStatus struct { // Name is the name of the Listener that this status corresponds to. + // +required Name SectionName `json:"name"` // Port is the network port the listener is configured to listen on. + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 + // + // +required Port PortNumber `json:"port"` // SupportedKinds is the list indicating the Kinds supported by this @@ -220,6 +269,8 @@ type ListenerEntryStatus struct { // and invalid Route kinds are specified, the implementation MUST // reference the valid Route kinds that have been specified. // + // +required + // +listType=atomic // +kubebuilder:validation:MaxItems=8 SupportedKinds []RouteGroupKind `json:"supportedKinds"` @@ -240,6 +291,7 @@ type ListenerEntryStatus struct { // // Uses for this field include troubleshooting Route attachment and // measuring blast radius/impact of changes to a Listener. + // +required AttachedRoutes int32 `json:"attachedRoutes"` // Conditions describe the current condition of this listener. @@ -247,6 +299,7 @@ type ListenerEntryStatus struct { // +listType=map // +listMapKey=type // +kubebuilder:validation:MaxItems=8 + // +required Conditions []metav1.Condition `json:"conditions"` } diff --git a/apisx/v1alpha1/zz_generated.deepcopy.go b/apisx/v1alpha1/zz_generated.deepcopy.go index bd5348692d..802d371927 100644 --- a/apisx/v1alpha1/zz_generated.deepcopy.go +++ b/apisx/v1alpha1/zz_generated.deepcopy.go @@ -92,7 +92,7 @@ func (in *ListenerEntry) DeepCopyInto(out *ListenerEntry) { } if in.TLS != nil { in, out := &in.TLS, &out.TLS - *out = new(GatewayTLSConfig) + *out = new(ListenerTLSConfig) (*in).DeepCopyInto(*out) } if in.AllowedRoutes != nil { diff --git a/applyconfiguration/apis/v1/forwardbodyconfig.go b/applyconfiguration/apis/v1/forwardbodyconfig.go new file mode 100644 index 0000000000..79707409bc --- /dev/null +++ b/applyconfiguration/apis/v1/forwardbodyconfig.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// ForwardBodyConfigApplyConfiguration represents a declarative configuration of the ForwardBodyConfig type for use +// with apply. +type ForwardBodyConfigApplyConfiguration struct { + MaxSize *uint16 `json:"maxSize,omitempty"` +} + +// ForwardBodyConfigApplyConfiguration constructs a declarative configuration of the ForwardBodyConfig type for use with +// apply. +func ForwardBodyConfig() *ForwardBodyConfigApplyConfiguration { + return &ForwardBodyConfigApplyConfiguration{} +} + +// WithMaxSize sets the MaxSize field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the MaxSize field is set to the value of the last call. +func (b *ForwardBodyConfigApplyConfiguration) WithMaxSize(value uint16) *ForwardBodyConfigApplyConfiguration { + b.MaxSize = &value + return b +} diff --git a/applyconfiguration/apis/v1/frontendtlsconfig.go b/applyconfiguration/apis/v1/frontendtlsconfig.go new file mode 100644 index 0000000000..4cf8464927 --- /dev/null +++ b/applyconfiguration/apis/v1/frontendtlsconfig.go @@ -0,0 +1,53 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// FrontendTLSConfigApplyConfiguration represents a declarative configuration of the FrontendTLSConfig type for use +// with apply. +type FrontendTLSConfigApplyConfiguration struct { + Default *TLSConfigApplyConfiguration `json:"default,omitempty"` + PerPort []TLSPortConfigApplyConfiguration `json:"perPort,omitempty"` +} + +// FrontendTLSConfigApplyConfiguration constructs a declarative configuration of the FrontendTLSConfig type for use with +// apply. +func FrontendTLSConfig() *FrontendTLSConfigApplyConfiguration { + return &FrontendTLSConfigApplyConfiguration{} +} + +// WithDefault sets the Default field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Default field is set to the value of the last call. +func (b *FrontendTLSConfigApplyConfiguration) WithDefault(value *TLSConfigApplyConfiguration) *FrontendTLSConfigApplyConfiguration { + b.Default = value + return b +} + +// WithPerPort adds the given value to the PerPort field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the PerPort field. +func (b *FrontendTLSConfigApplyConfiguration) WithPerPort(values ...*TLSPortConfigApplyConfiguration) *FrontendTLSConfigApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithPerPort") + } + b.PerPort = append(b.PerPort, *values[i]) + } + return b +} diff --git a/applyconfiguration/apis/v1/frontendtlsvalidation.go b/applyconfiguration/apis/v1/frontendtlsvalidation.go index 5342400ccf..fada2ba15e 100644 --- a/applyconfiguration/apis/v1/frontendtlsvalidation.go +++ b/applyconfiguration/apis/v1/frontendtlsvalidation.go @@ -18,10 +18,15 @@ limitations under the License. package v1 +import ( + apisv1 "sigs.k8s.io/gateway-api/apis/v1" +) + // FrontendTLSValidationApplyConfiguration represents a declarative configuration of the FrontendTLSValidation type for use // with apply. type FrontendTLSValidationApplyConfiguration struct { CACertificateRefs []ObjectReferenceApplyConfiguration `json:"caCertificateRefs,omitempty"` + Mode *apisv1.FrontendValidationModeType `json:"mode,omitempty"` } // FrontendTLSValidationApplyConfiguration constructs a declarative configuration of the FrontendTLSValidation type for use with @@ -42,3 +47,11 @@ func (b *FrontendTLSValidationApplyConfiguration) WithCACertificateRefs(values . } return b } + +// WithMode sets the Mode field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Mode field is set to the value of the last call. +func (b *FrontendTLSValidationApplyConfiguration) WithMode(value apisv1.FrontendValidationModeType) *FrontendTLSValidationApplyConfiguration { + b.Mode = &value + return b +} diff --git a/applyconfiguration/apis/v1/gatewayspec.go b/applyconfiguration/apis/v1/gatewayspec.go index bdfeba84d4..e976dc4827 100644 --- a/applyconfiguration/apis/v1/gatewayspec.go +++ b/applyconfiguration/apis/v1/gatewayspec.go @@ -29,8 +29,8 @@ type GatewaySpecApplyConfiguration struct { Listeners []ListenerApplyConfiguration `json:"listeners,omitempty"` Addresses []GatewaySpecAddressApplyConfiguration `json:"addresses,omitempty"` Infrastructure *GatewayInfrastructureApplyConfiguration `json:"infrastructure,omitempty"` - BackendTLS *GatewayBackendTLSApplyConfiguration `json:"backendTLS,omitempty"` AllowedListeners *AllowedListenersApplyConfiguration `json:"allowedListeners,omitempty"` + TLS *GatewayTLSConfigApplyConfiguration `json:"tls,omitempty"` } // GatewaySpecApplyConfiguration constructs a declarative configuration of the GatewaySpec type for use with @@ -81,14 +81,6 @@ func (b *GatewaySpecApplyConfiguration) WithInfrastructure(value *GatewayInfrast return b } -// WithBackendTLS sets the BackendTLS field in the declarative configuration to the given value -// and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the BackendTLS field is set to the value of the last call. -func (b *GatewaySpecApplyConfiguration) WithBackendTLS(value *GatewayBackendTLSApplyConfiguration) *GatewaySpecApplyConfiguration { - b.BackendTLS = value - return b -} - // WithAllowedListeners sets the AllowedListeners field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the AllowedListeners field is set to the value of the last call. @@ -96,3 +88,11 @@ func (b *GatewaySpecApplyConfiguration) WithAllowedListeners(value *AllowedListe b.AllowedListeners = value return b } + +// WithTLS sets the TLS field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TLS field is set to the value of the last call. +func (b *GatewaySpecApplyConfiguration) WithTLS(value *GatewayTLSConfigApplyConfiguration) *GatewaySpecApplyConfiguration { + b.TLS = value + return b +} diff --git a/applyconfiguration/apis/v1/gatewaytlsconfig.go b/applyconfiguration/apis/v1/gatewaytlsconfig.go index 896e3e56b3..4ec825dbee 100644 --- a/applyconfiguration/apis/v1/gatewaytlsconfig.go +++ b/applyconfiguration/apis/v1/gatewaytlsconfig.go @@ -18,17 +18,11 @@ limitations under the License. package v1 -import ( - apisv1 "sigs.k8s.io/gateway-api/apis/v1" -) - // GatewayTLSConfigApplyConfiguration represents a declarative configuration of the GatewayTLSConfig type for use // with apply. type GatewayTLSConfigApplyConfiguration struct { - Mode *apisv1.TLSModeType `json:"mode,omitempty"` - CertificateRefs []SecretObjectReferenceApplyConfiguration `json:"certificateRefs,omitempty"` - FrontendValidation *FrontendTLSValidationApplyConfiguration `json:"frontendValidation,omitempty"` - Options map[apisv1.AnnotationKey]apisv1.AnnotationValue `json:"options,omitempty"` + Backend *GatewayBackendTLSApplyConfiguration `json:"backend,omitempty"` + Frontend *FrontendTLSConfigApplyConfiguration `json:"frontend,omitempty"` } // GatewayTLSConfigApplyConfiguration constructs a declarative configuration of the GatewayTLSConfig type for use with @@ -37,45 +31,18 @@ func GatewayTLSConfig() *GatewayTLSConfigApplyConfiguration { return &GatewayTLSConfigApplyConfiguration{} } -// WithMode sets the Mode field in the declarative configuration to the given value +// WithBackend sets the Backend field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the Mode field is set to the value of the last call. -func (b *GatewayTLSConfigApplyConfiguration) WithMode(value apisv1.TLSModeType) *GatewayTLSConfigApplyConfiguration { - b.Mode = &value - return b -} - -// WithCertificateRefs adds the given value to the CertificateRefs field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, values provided by each call will be appended to the CertificateRefs field. -func (b *GatewayTLSConfigApplyConfiguration) WithCertificateRefs(values ...*SecretObjectReferenceApplyConfiguration) *GatewayTLSConfigApplyConfiguration { - for i := range values { - if values[i] == nil { - panic("nil value passed to WithCertificateRefs") - } - b.CertificateRefs = append(b.CertificateRefs, *values[i]) - } +// If called multiple times, the Backend field is set to the value of the last call. +func (b *GatewayTLSConfigApplyConfiguration) WithBackend(value *GatewayBackendTLSApplyConfiguration) *GatewayTLSConfigApplyConfiguration { + b.Backend = value return b } -// WithFrontendValidation sets the FrontendValidation field in the declarative configuration to the given value +// WithFrontend sets the Frontend field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. -// If called multiple times, the FrontendValidation field is set to the value of the last call. -func (b *GatewayTLSConfigApplyConfiguration) WithFrontendValidation(value *FrontendTLSValidationApplyConfiguration) *GatewayTLSConfigApplyConfiguration { - b.FrontendValidation = value - return b -} - -// WithOptions puts the entries into the Options field in the declarative configuration -// and returns the receiver, so that objects can be build by chaining "With" function invocations. -// If called multiple times, the entries provided by each call will be put on the Options field, -// overwriting an existing map entries in Options field with the same key. -func (b *GatewayTLSConfigApplyConfiguration) WithOptions(entries map[apisv1.AnnotationKey]apisv1.AnnotationValue) *GatewayTLSConfigApplyConfiguration { - if b.Options == nil && len(entries) > 0 { - b.Options = make(map[apisv1.AnnotationKey]apisv1.AnnotationValue, len(entries)) - } - for k, v := range entries { - b.Options[k] = v - } +// If called multiple times, the Frontend field is set to the value of the last call. +func (b *GatewayTLSConfigApplyConfiguration) WithFrontend(value *FrontendTLSConfigApplyConfiguration) *GatewayTLSConfigApplyConfiguration { + b.Frontend = value return b } diff --git a/applyconfiguration/apis/v1/grpcauthconfig.go b/applyconfiguration/apis/v1/grpcauthconfig.go new file mode 100644 index 0000000000..1a5c7d33c3 --- /dev/null +++ b/applyconfiguration/apis/v1/grpcauthconfig.go @@ -0,0 +1,41 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// GRPCAuthConfigApplyConfiguration represents a declarative configuration of the GRPCAuthConfig type for use +// with apply. +type GRPCAuthConfigApplyConfiguration struct { + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` +} + +// GRPCAuthConfigApplyConfiguration constructs a declarative configuration of the GRPCAuthConfig type for use with +// apply. +func GRPCAuthConfig() *GRPCAuthConfigApplyConfiguration { + return &GRPCAuthConfigApplyConfiguration{} +} + +// WithAllowedRequestHeaders adds the given value to the AllowedRequestHeaders field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AllowedRequestHeaders field. +func (b *GRPCAuthConfigApplyConfiguration) WithAllowedRequestHeaders(values ...string) *GRPCAuthConfigApplyConfiguration { + for i := range values { + b.AllowedRequestHeaders = append(b.AllowedRequestHeaders, values[i]) + } + return b +} diff --git a/applyconfiguration/apis/v1/httpauthconfig.go b/applyconfiguration/apis/v1/httpauthconfig.go new file mode 100644 index 0000000000..eff6ff903a --- /dev/null +++ b/applyconfiguration/apis/v1/httpauthconfig.go @@ -0,0 +1,61 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// HTTPAuthConfigApplyConfiguration represents a declarative configuration of the HTTPAuthConfig type for use +// with apply. +type HTTPAuthConfigApplyConfiguration struct { + Path *string `json:"path,omitempty"` + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` + AllowedResponseHeaders []string `json:"allowedResponseHeaders,omitempty"` +} + +// HTTPAuthConfigApplyConfiguration constructs a declarative configuration of the HTTPAuthConfig type for use with +// apply. +func HTTPAuthConfig() *HTTPAuthConfigApplyConfiguration { + return &HTTPAuthConfigApplyConfiguration{} +} + +// WithPath sets the Path field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Path field is set to the value of the last call. +func (b *HTTPAuthConfigApplyConfiguration) WithPath(value string) *HTTPAuthConfigApplyConfiguration { + b.Path = &value + return b +} + +// WithAllowedRequestHeaders adds the given value to the AllowedRequestHeaders field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AllowedRequestHeaders field. +func (b *HTTPAuthConfigApplyConfiguration) WithAllowedRequestHeaders(values ...string) *HTTPAuthConfigApplyConfiguration { + for i := range values { + b.AllowedRequestHeaders = append(b.AllowedRequestHeaders, values[i]) + } + return b +} + +// WithAllowedResponseHeaders adds the given value to the AllowedResponseHeaders field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the AllowedResponseHeaders field. +func (b *HTTPAuthConfigApplyConfiguration) WithAllowedResponseHeaders(values ...string) *HTTPAuthConfigApplyConfiguration { + for i := range values { + b.AllowedResponseHeaders = append(b.AllowedResponseHeaders, values[i]) + } + return b +} diff --git a/applyconfiguration/apis/v1/httpcorsfilter.go b/applyconfiguration/apis/v1/httpcorsfilter.go index c2cf023c25..b4b9776b3a 100644 --- a/applyconfiguration/apis/v1/httpcorsfilter.go +++ b/applyconfiguration/apis/v1/httpcorsfilter.go @@ -25,8 +25,8 @@ import ( // HTTPCORSFilterApplyConfiguration represents a declarative configuration of the HTTPCORSFilter type for use // with apply. type HTTPCORSFilterApplyConfiguration struct { - AllowOrigins []apisv1.AbsoluteURI `json:"allowOrigins,omitempty"` - AllowCredentials *apisv1.TrueField `json:"allowCredentials,omitempty"` + AllowOrigins []apisv1.CORSOrigin `json:"allowOrigins,omitempty"` + AllowCredentials *bool `json:"allowCredentials,omitempty"` AllowMethods []apisv1.HTTPMethodWithWildcard `json:"allowMethods,omitempty"` AllowHeaders []apisv1.HTTPHeaderName `json:"allowHeaders,omitempty"` ExposeHeaders []apisv1.HTTPHeaderName `json:"exposeHeaders,omitempty"` @@ -42,7 +42,7 @@ func HTTPCORSFilter() *HTTPCORSFilterApplyConfiguration { // WithAllowOrigins adds the given value to the AllowOrigins field in the declarative configuration // and returns the receiver, so that objects can be build by chaining "With" function invocations. // If called multiple times, values provided by each call will be appended to the AllowOrigins field. -func (b *HTTPCORSFilterApplyConfiguration) WithAllowOrigins(values ...apisv1.AbsoluteURI) *HTTPCORSFilterApplyConfiguration { +func (b *HTTPCORSFilterApplyConfiguration) WithAllowOrigins(values ...apisv1.CORSOrigin) *HTTPCORSFilterApplyConfiguration { for i := range values { b.AllowOrigins = append(b.AllowOrigins, values[i]) } @@ -52,7 +52,7 @@ func (b *HTTPCORSFilterApplyConfiguration) WithAllowOrigins(values ...apisv1.Abs // WithAllowCredentials sets the AllowCredentials field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the AllowCredentials field is set to the value of the last call. -func (b *HTTPCORSFilterApplyConfiguration) WithAllowCredentials(value apisv1.TrueField) *HTTPCORSFilterApplyConfiguration { +func (b *HTTPCORSFilterApplyConfiguration) WithAllowCredentials(value bool) *HTTPCORSFilterApplyConfiguration { b.AllowCredentials = &value return b } diff --git a/applyconfiguration/apis/v1/httpexternalauthfilter.go b/applyconfiguration/apis/v1/httpexternalauthfilter.go new file mode 100644 index 0000000000..e56b112f2a --- /dev/null +++ b/applyconfiguration/apis/v1/httpexternalauthfilter.go @@ -0,0 +1,79 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apisv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +// HTTPExternalAuthFilterApplyConfiguration represents a declarative configuration of the HTTPExternalAuthFilter type for use +// with apply. +type HTTPExternalAuthFilterApplyConfiguration struct { + ExternalAuthProtocol *apisv1.HTTPRouteExternalAuthProtocol `json:"protocol,omitempty"` + BackendRef *BackendObjectReferenceApplyConfiguration `json:"backendRef,omitempty"` + GRPCAuthConfig *GRPCAuthConfigApplyConfiguration `json:"grpc,omitempty"` + HTTPAuthConfig *HTTPAuthConfigApplyConfiguration `json:"http,omitempty"` + ForwardBody *ForwardBodyConfigApplyConfiguration `json:"forwardBody,omitempty"` +} + +// HTTPExternalAuthFilterApplyConfiguration constructs a declarative configuration of the HTTPExternalAuthFilter type for use with +// apply. +func HTTPExternalAuthFilter() *HTTPExternalAuthFilterApplyConfiguration { + return &HTTPExternalAuthFilterApplyConfiguration{} +} + +// WithExternalAuthProtocol sets the ExternalAuthProtocol field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExternalAuthProtocol field is set to the value of the last call. +func (b *HTTPExternalAuthFilterApplyConfiguration) WithExternalAuthProtocol(value apisv1.HTTPRouteExternalAuthProtocol) *HTTPExternalAuthFilterApplyConfiguration { + b.ExternalAuthProtocol = &value + return b +} + +// WithBackendRef sets the BackendRef field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the BackendRef field is set to the value of the last call. +func (b *HTTPExternalAuthFilterApplyConfiguration) WithBackendRef(value *BackendObjectReferenceApplyConfiguration) *HTTPExternalAuthFilterApplyConfiguration { + b.BackendRef = value + return b +} + +// WithGRPCAuthConfig sets the GRPCAuthConfig field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GRPCAuthConfig field is set to the value of the last call. +func (b *HTTPExternalAuthFilterApplyConfiguration) WithGRPCAuthConfig(value *GRPCAuthConfigApplyConfiguration) *HTTPExternalAuthFilterApplyConfiguration { + b.GRPCAuthConfig = value + return b +} + +// WithHTTPAuthConfig sets the HTTPAuthConfig field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the HTTPAuthConfig field is set to the value of the last call. +func (b *HTTPExternalAuthFilterApplyConfiguration) WithHTTPAuthConfig(value *HTTPAuthConfigApplyConfiguration) *HTTPExternalAuthFilterApplyConfiguration { + b.HTTPAuthConfig = value + return b +} + +// WithForwardBody sets the ForwardBody field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ForwardBody field is set to the value of the last call. +func (b *HTTPExternalAuthFilterApplyConfiguration) WithForwardBody(value *ForwardBodyConfigApplyConfiguration) *HTTPExternalAuthFilterApplyConfiguration { + b.ForwardBody = value + return b +} diff --git a/applyconfiguration/apis/v1/httproutefilter.go b/applyconfiguration/apis/v1/httproutefilter.go index 2a46046bc6..d76c141316 100644 --- a/applyconfiguration/apis/v1/httproutefilter.go +++ b/applyconfiguration/apis/v1/httproutefilter.go @@ -32,6 +32,7 @@ type HTTPRouteFilterApplyConfiguration struct { RequestRedirect *HTTPRequestRedirectFilterApplyConfiguration `json:"requestRedirect,omitempty"` URLRewrite *HTTPURLRewriteFilterApplyConfiguration `json:"urlRewrite,omitempty"` CORS *HTTPCORSFilterApplyConfiguration `json:"cors,omitempty"` + ExternalAuth *HTTPExternalAuthFilterApplyConfiguration `json:"externalAuth,omitempty"` ExtensionRef *LocalObjectReferenceApplyConfiguration `json:"extensionRef,omitempty"` } @@ -97,6 +98,14 @@ func (b *HTTPRouteFilterApplyConfiguration) WithCORS(value *HTTPCORSFilterApplyC return b } +// WithExternalAuth sets the ExternalAuth field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ExternalAuth field is set to the value of the last call. +func (b *HTTPRouteFilterApplyConfiguration) WithExternalAuth(value *HTTPExternalAuthFilterApplyConfiguration) *HTTPRouteFilterApplyConfiguration { + b.ExternalAuth = value + return b +} + // WithExtensionRef sets the ExtensionRef field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the ExtensionRef field is set to the value of the last call. diff --git a/applyconfiguration/apis/v1/listener.go b/applyconfiguration/apis/v1/listener.go index 35be06a768..c7d3b08023 100644 --- a/applyconfiguration/apis/v1/listener.go +++ b/applyconfiguration/apis/v1/listener.go @@ -25,12 +25,12 @@ import ( // ListenerApplyConfiguration represents a declarative configuration of the Listener type for use // with apply. type ListenerApplyConfiguration struct { - Name *apisv1.SectionName `json:"name,omitempty"` - Hostname *apisv1.Hostname `json:"hostname,omitempty"` - Port *apisv1.PortNumber `json:"port,omitempty"` - Protocol *apisv1.ProtocolType `json:"protocol,omitempty"` - TLS *GatewayTLSConfigApplyConfiguration `json:"tls,omitempty"` - AllowedRoutes *AllowedRoutesApplyConfiguration `json:"allowedRoutes,omitempty"` + Name *apisv1.SectionName `json:"name,omitempty"` + Hostname *apisv1.Hostname `json:"hostname,omitempty"` + Port *apisv1.PortNumber `json:"port,omitempty"` + Protocol *apisv1.ProtocolType `json:"protocol,omitempty"` + TLS *ListenerTLSConfigApplyConfiguration `json:"tls,omitempty"` + AllowedRoutes *AllowedRoutesApplyConfiguration `json:"allowedRoutes,omitempty"` } // ListenerApplyConfiguration constructs a declarative configuration of the Listener type for use with @@ -74,7 +74,7 @@ func (b *ListenerApplyConfiguration) WithProtocol(value apisv1.ProtocolType) *Li // WithTLS sets the TLS field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the TLS field is set to the value of the last call. -func (b *ListenerApplyConfiguration) WithTLS(value *GatewayTLSConfigApplyConfiguration) *ListenerApplyConfiguration { +func (b *ListenerApplyConfiguration) WithTLS(value *ListenerTLSConfigApplyConfiguration) *ListenerApplyConfiguration { b.TLS = value return b } diff --git a/applyconfiguration/apis/v1/listenertlsconfig.go b/applyconfiguration/apis/v1/listenertlsconfig.go new file mode 100644 index 0000000000..6ab72f1526 --- /dev/null +++ b/applyconfiguration/apis/v1/listenertlsconfig.go @@ -0,0 +1,72 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apisv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +// ListenerTLSConfigApplyConfiguration represents a declarative configuration of the ListenerTLSConfig type for use +// with apply. +type ListenerTLSConfigApplyConfiguration struct { + Mode *apisv1.TLSModeType `json:"mode,omitempty"` + CertificateRefs []SecretObjectReferenceApplyConfiguration `json:"certificateRefs,omitempty"` + Options map[apisv1.AnnotationKey]apisv1.AnnotationValue `json:"options,omitempty"` +} + +// ListenerTLSConfigApplyConfiguration constructs a declarative configuration of the ListenerTLSConfig type for use with +// apply. +func ListenerTLSConfig() *ListenerTLSConfigApplyConfiguration { + return &ListenerTLSConfigApplyConfiguration{} +} + +// WithMode sets the Mode field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Mode field is set to the value of the last call. +func (b *ListenerTLSConfigApplyConfiguration) WithMode(value apisv1.TLSModeType) *ListenerTLSConfigApplyConfiguration { + b.Mode = &value + return b +} + +// WithCertificateRefs adds the given value to the CertificateRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the CertificateRefs field. +func (b *ListenerTLSConfigApplyConfiguration) WithCertificateRefs(values ...*SecretObjectReferenceApplyConfiguration) *ListenerTLSConfigApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithCertificateRefs") + } + b.CertificateRefs = append(b.CertificateRefs, *values[i]) + } + return b +} + +// WithOptions puts the entries into the Options field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Options field, +// overwriting an existing map entries in Options field with the same key. +func (b *ListenerTLSConfigApplyConfiguration) WithOptions(entries map[apisv1.AnnotationKey]apisv1.AnnotationValue) *ListenerTLSConfigApplyConfiguration { + if b.Options == nil && len(entries) > 0 { + b.Options = make(map[apisv1.AnnotationKey]apisv1.AnnotationValue, len(entries)) + } + for k, v := range entries { + b.Options[k] = v + } + return b +} diff --git a/applyconfiguration/apis/v1/tlsconfig.go b/applyconfiguration/apis/v1/tlsconfig.go new file mode 100644 index 0000000000..99a42ca482 --- /dev/null +++ b/applyconfiguration/apis/v1/tlsconfig.go @@ -0,0 +1,39 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +// TLSConfigApplyConfiguration represents a declarative configuration of the TLSConfig type for use +// with apply. +type TLSConfigApplyConfiguration struct { + Validation *FrontendTLSValidationApplyConfiguration `json:"validation,omitempty"` +} + +// TLSConfigApplyConfiguration constructs a declarative configuration of the TLSConfig type for use with +// apply. +func TLSConfig() *TLSConfigApplyConfiguration { + return &TLSConfigApplyConfiguration{} +} + +// WithValidation sets the Validation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Validation field is set to the value of the last call. +func (b *TLSConfigApplyConfiguration) WithValidation(value *FrontendTLSValidationApplyConfiguration) *TLSConfigApplyConfiguration { + b.Validation = value + return b +} diff --git a/applyconfiguration/apis/v1/tlsportconfig.go b/applyconfiguration/apis/v1/tlsportconfig.go new file mode 100644 index 0000000000..bc9043a149 --- /dev/null +++ b/applyconfiguration/apis/v1/tlsportconfig.go @@ -0,0 +1,52 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1 + +import ( + apisv1 "sigs.k8s.io/gateway-api/apis/v1" +) + +// TLSPortConfigApplyConfiguration represents a declarative configuration of the TLSPortConfig type for use +// with apply. +type TLSPortConfigApplyConfiguration struct { + Port *apisv1.PortNumber `json:"port,omitempty"` + TLS *TLSConfigApplyConfiguration `json:"tls,omitempty"` +} + +// TLSPortConfigApplyConfiguration constructs a declarative configuration of the TLSPortConfig type for use with +// apply. +func TLSPortConfig() *TLSPortConfigApplyConfiguration { + return &TLSPortConfigApplyConfiguration{} +} + +// WithPort sets the Port field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Port field is set to the value of the last call. +func (b *TLSPortConfigApplyConfiguration) WithPort(value apisv1.PortNumber) *TLSPortConfigApplyConfiguration { + b.Port = &value + return b +} + +// WithTLS sets the TLS field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the TLS field is set to the value of the last call. +func (b *TLSPortConfigApplyConfiguration) WithTLS(value *TLSConfigApplyConfiguration) *TLSPortConfigApplyConfiguration { + b.TLS = value + return b +} diff --git a/applyconfiguration/apis/v1alpha3/tlsroute.go b/applyconfiguration/apis/v1alpha3/tlsroute.go new file mode 100644 index 0000000000..ff65509c71 --- /dev/null +++ b/applyconfiguration/apis/v1alpha3/tlsroute.go @@ -0,0 +1,265 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + managedfields "k8s.io/apimachinery/pkg/util/managedfields" + v1 "k8s.io/client-go/applyconfigurations/meta/v1" + apisv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + v1alpha2 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1alpha2" + internal "sigs.k8s.io/gateway-api/applyconfiguration/internal" +) + +// TLSRouteApplyConfiguration represents a declarative configuration of the TLSRoute type for use +// with apply. +type TLSRouteApplyConfiguration struct { + v1.TypeMetaApplyConfiguration `json:",inline"` + *v1.ObjectMetaApplyConfiguration `json:"metadata,omitempty"` + Spec *TLSRouteSpecApplyConfiguration `json:"spec,omitempty"` + Status *v1alpha2.TLSRouteStatusApplyConfiguration `json:"status,omitempty"` +} + +// TLSRoute constructs a declarative configuration of the TLSRoute type for use with +// apply. +func TLSRoute(name, namespace string) *TLSRouteApplyConfiguration { + b := &TLSRouteApplyConfiguration{} + b.WithName(name) + b.WithNamespace(namespace) + b.WithKind("TLSRoute") + b.WithAPIVersion("gateway.networking.k8s.io/v1alpha3") + return b +} + +// ExtractTLSRoute extracts the applied configuration owned by fieldManager from +// tLSRoute. If no managedFields are found in tLSRoute for fieldManager, a +// TLSRouteApplyConfiguration is returned with only the Name, Namespace (if applicable), +// APIVersion and Kind populated. It is possible that no managed fields were found for because other +// field managers have taken ownership of all the fields previously owned by fieldManager, or because +// the fieldManager never owned fields any fields. +// tLSRoute must be a unmodified TLSRoute API object that was retrieved from the Kubernetes API. +// ExtractTLSRoute provides a way to perform a extract/modify-in-place/apply workflow. +// Note that an extracted apply configuration will contain fewer fields than what the fieldManager previously +// applied if another fieldManager has updated or force applied any of the previously applied fields. +// Experimental! +func ExtractTLSRoute(tLSRoute *apisv1alpha3.TLSRoute, fieldManager string) (*TLSRouteApplyConfiguration, error) { + return extractTLSRoute(tLSRoute, fieldManager, "") +} + +// ExtractTLSRouteStatus is the same as ExtractTLSRoute except +// that it extracts the status subresource applied configuration. +// Experimental! +func ExtractTLSRouteStatus(tLSRoute *apisv1alpha3.TLSRoute, fieldManager string) (*TLSRouteApplyConfiguration, error) { + return extractTLSRoute(tLSRoute, fieldManager, "status") +} + +func extractTLSRoute(tLSRoute *apisv1alpha3.TLSRoute, fieldManager string, subresource string) (*TLSRouteApplyConfiguration, error) { + b := &TLSRouteApplyConfiguration{} + err := managedfields.ExtractInto(tLSRoute, internal.Parser().Type("io.k8s.sigs.gateway-api.apis.v1alpha3.TLSRoute"), fieldManager, b, subresource) + if err != nil { + return nil, err + } + b.WithName(tLSRoute.Name) + b.WithNamespace(tLSRoute.Namespace) + + b.WithKind("TLSRoute") + b.WithAPIVersion("gateway.networking.k8s.io/v1alpha3") + return b, nil +} + +// WithKind sets the Kind field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Kind field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithKind(value string) *TLSRouteApplyConfiguration { + b.TypeMetaApplyConfiguration.Kind = &value + return b +} + +// WithAPIVersion sets the APIVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the APIVersion field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithAPIVersion(value string) *TLSRouteApplyConfiguration { + b.TypeMetaApplyConfiguration.APIVersion = &value + return b +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithName(value string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Name = &value + return b +} + +// WithGenerateName sets the GenerateName field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the GenerateName field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithGenerateName(value string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.GenerateName = &value + return b +} + +// WithNamespace sets the Namespace field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Namespace field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithNamespace(value string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Namespace = &value + return b +} + +// WithUID sets the UID field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the UID field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithUID(value types.UID) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.UID = &value + return b +} + +// WithResourceVersion sets the ResourceVersion field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the ResourceVersion field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithResourceVersion(value string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.ResourceVersion = &value + return b +} + +// WithGeneration sets the Generation field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Generation field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithGeneration(value int64) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.Generation = &value + return b +} + +// WithCreationTimestamp sets the CreationTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the CreationTimestamp field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithCreationTimestamp(value metav1.Time) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.CreationTimestamp = &value + return b +} + +// WithDeletionTimestamp sets the DeletionTimestamp field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionTimestamp field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithDeletionTimestamp(value metav1.Time) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionTimestamp = &value + return b +} + +// WithDeletionGracePeriodSeconds sets the DeletionGracePeriodSeconds field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the DeletionGracePeriodSeconds field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithDeletionGracePeriodSeconds(value int64) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + b.ObjectMetaApplyConfiguration.DeletionGracePeriodSeconds = &value + return b +} + +// WithLabels puts the entries into the Labels field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Labels field, +// overwriting an existing map entries in Labels field with the same key. +func (b *TLSRouteApplyConfiguration) WithLabels(entries map[string]string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Labels == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Labels = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Labels[k] = v + } + return b +} + +// WithAnnotations puts the entries into the Annotations field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, the entries provided by each call will be put on the Annotations field, +// overwriting an existing map entries in Annotations field with the same key. +func (b *TLSRouteApplyConfiguration) WithAnnotations(entries map[string]string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + if b.ObjectMetaApplyConfiguration.Annotations == nil && len(entries) > 0 { + b.ObjectMetaApplyConfiguration.Annotations = make(map[string]string, len(entries)) + } + for k, v := range entries { + b.ObjectMetaApplyConfiguration.Annotations[k] = v + } + return b +} + +// WithOwnerReferences adds the given value to the OwnerReferences field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the OwnerReferences field. +func (b *TLSRouteApplyConfiguration) WithOwnerReferences(values ...*v1.OwnerReferenceApplyConfiguration) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + if values[i] == nil { + panic("nil value passed to WithOwnerReferences") + } + b.ObjectMetaApplyConfiguration.OwnerReferences = append(b.ObjectMetaApplyConfiguration.OwnerReferences, *values[i]) + } + return b +} + +// WithFinalizers adds the given value to the Finalizers field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Finalizers field. +func (b *TLSRouteApplyConfiguration) WithFinalizers(values ...string) *TLSRouteApplyConfiguration { + b.ensureObjectMetaApplyConfigurationExists() + for i := range values { + b.ObjectMetaApplyConfiguration.Finalizers = append(b.ObjectMetaApplyConfiguration.Finalizers, values[i]) + } + return b +} + +func (b *TLSRouteApplyConfiguration) ensureObjectMetaApplyConfigurationExists() { + if b.ObjectMetaApplyConfiguration == nil { + b.ObjectMetaApplyConfiguration = &v1.ObjectMetaApplyConfiguration{} + } +} + +// WithSpec sets the Spec field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Spec field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithSpec(value *TLSRouteSpecApplyConfiguration) *TLSRouteApplyConfiguration { + b.Spec = value + return b +} + +// WithStatus sets the Status field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Status field is set to the value of the last call. +func (b *TLSRouteApplyConfiguration) WithStatus(value *v1alpha2.TLSRouteStatusApplyConfiguration) *TLSRouteApplyConfiguration { + b.Status = value + return b +} + +// GetName retrieves the value of the Name field in the declarative configuration. +func (b *TLSRouteApplyConfiguration) GetName() *string { + b.ensureObjectMetaApplyConfigurationExists() + return b.ObjectMetaApplyConfiguration.Name +} diff --git a/applyconfiguration/apis/v1alpha3/tlsrouterule.go b/applyconfiguration/apis/v1alpha3/tlsrouterule.go new file mode 100644 index 0000000000..3b0bfe3b04 --- /dev/null +++ b/applyconfiguration/apis/v1alpha3/tlsrouterule.go @@ -0,0 +1,58 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1 "sigs.k8s.io/gateway-api/apis/v1" + apisv1 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1" +) + +// TLSRouteRuleApplyConfiguration represents a declarative configuration of the TLSRouteRule type for use +// with apply. +type TLSRouteRuleApplyConfiguration struct { + Name *v1.SectionName `json:"name,omitempty"` + BackendRefs []apisv1.BackendRefApplyConfiguration `json:"backendRefs,omitempty"` +} + +// TLSRouteRuleApplyConfiguration constructs a declarative configuration of the TLSRouteRule type for use with +// apply. +func TLSRouteRule() *TLSRouteRuleApplyConfiguration { + return &TLSRouteRuleApplyConfiguration{} +} + +// WithName sets the Name field in the declarative configuration to the given value +// and returns the receiver, so that objects can be built by chaining "With" function invocations. +// If called multiple times, the Name field is set to the value of the last call. +func (b *TLSRouteRuleApplyConfiguration) WithName(value v1.SectionName) *TLSRouteRuleApplyConfiguration { + b.Name = &value + return b +} + +// WithBackendRefs adds the given value to the BackendRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the BackendRefs field. +func (b *TLSRouteRuleApplyConfiguration) WithBackendRefs(values ...*apisv1.BackendRefApplyConfiguration) *TLSRouteRuleApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithBackendRefs") + } + b.BackendRefs = append(b.BackendRefs, *values[i]) + } + return b +} diff --git a/applyconfiguration/apis/v1alpha3/tlsroutespec.go b/applyconfiguration/apis/v1alpha3/tlsroutespec.go new file mode 100644 index 0000000000..47c7e06fd6 --- /dev/null +++ b/applyconfiguration/apis/v1alpha3/tlsroutespec.go @@ -0,0 +1,75 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + apisv1 "sigs.k8s.io/gateway-api/apis/v1" + v1 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1" + v1alpha2 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1alpha2" +) + +// TLSRouteSpecApplyConfiguration represents a declarative configuration of the TLSRouteSpec type for use +// with apply. +type TLSRouteSpecApplyConfiguration struct { + v1.CommonRouteSpecApplyConfiguration `json:",inline"` + Hostnames []apisv1.Hostname `json:"hostnames,omitempty"` + Rules []v1alpha2.TLSRouteRuleApplyConfiguration `json:"rules,omitempty"` +} + +// TLSRouteSpecApplyConfiguration constructs a declarative configuration of the TLSRouteSpec type for use with +// apply. +func TLSRouteSpec() *TLSRouteSpecApplyConfiguration { + return &TLSRouteSpecApplyConfiguration{} +} + +// WithParentRefs adds the given value to the ParentRefs field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the ParentRefs field. +func (b *TLSRouteSpecApplyConfiguration) WithParentRefs(values ...*v1.ParentReferenceApplyConfiguration) *TLSRouteSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithParentRefs") + } + b.CommonRouteSpecApplyConfiguration.ParentRefs = append(b.CommonRouteSpecApplyConfiguration.ParentRefs, *values[i]) + } + return b +} + +// WithHostnames adds the given value to the Hostnames field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Hostnames field. +func (b *TLSRouteSpecApplyConfiguration) WithHostnames(values ...apisv1.Hostname) *TLSRouteSpecApplyConfiguration { + for i := range values { + b.Hostnames = append(b.Hostnames, values[i]) + } + return b +} + +// WithRules adds the given value to the Rules field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Rules field. +func (b *TLSRouteSpecApplyConfiguration) WithRules(values ...*v1alpha2.TLSRouteRuleApplyConfiguration) *TLSRouteSpecApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithRules") + } + b.Rules = append(b.Rules, *values[i]) + } + return b +} diff --git a/applyconfiguration/apis/v1alpha3/tlsroutestatus.go b/applyconfiguration/apis/v1alpha3/tlsroutestatus.go new file mode 100644 index 0000000000..3b5a1f319b --- /dev/null +++ b/applyconfiguration/apis/v1alpha3/tlsroutestatus.go @@ -0,0 +1,48 @@ +/* +Copyright The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by applyconfiguration-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + v1 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1" +) + +// TLSRouteStatusApplyConfiguration represents a declarative configuration of the TLSRouteStatus type for use +// with apply. +type TLSRouteStatusApplyConfiguration struct { + v1.RouteStatusApplyConfiguration `json:",inline"` +} + +// TLSRouteStatusApplyConfiguration constructs a declarative configuration of the TLSRouteStatus type for use with +// apply. +func TLSRouteStatus() *TLSRouteStatusApplyConfiguration { + return &TLSRouteStatusApplyConfiguration{} +} + +// WithParents adds the given value to the Parents field in the declarative configuration +// and returns the receiver, so that objects can be build by chaining "With" function invocations. +// If called multiple times, values provided by each call will be appended to the Parents field. +func (b *TLSRouteStatusApplyConfiguration) WithParents(values ...*v1.RouteParentStatusApplyConfiguration) *TLSRouteStatusApplyConfiguration { + for i := range values { + if values[i] == nil { + panic("nil value passed to WithParents") + } + b.RouteStatusApplyConfiguration.Parents = append(b.RouteStatusApplyConfiguration.Parents, *values[i]) + } + return b +} diff --git a/applyconfiguration/apisx/v1alpha1/listenerentry.go b/applyconfiguration/apisx/v1alpha1/listenerentry.go index e6396bf199..b72cf4e044 100644 --- a/applyconfiguration/apisx/v1alpha1/listenerentry.go +++ b/applyconfiguration/apisx/v1alpha1/listenerentry.go @@ -26,12 +26,12 @@ import ( // ListenerEntryApplyConfiguration represents a declarative configuration of the ListenerEntry type for use // with apply. type ListenerEntryApplyConfiguration struct { - Name *v1.SectionName `json:"name,omitempty"` - Hostname *v1.Hostname `json:"hostname,omitempty"` - Port *v1.PortNumber `json:"port,omitempty"` - Protocol *v1.ProtocolType `json:"protocol,omitempty"` - TLS *apisv1.GatewayTLSConfigApplyConfiguration `json:"tls,omitempty"` - AllowedRoutes *apisv1.AllowedRoutesApplyConfiguration `json:"allowedRoutes,omitempty"` + Name *v1.SectionName `json:"name,omitempty"` + Hostname *v1.Hostname `json:"hostname,omitempty"` + Port *v1.PortNumber `json:"port,omitempty"` + Protocol *v1.ProtocolType `json:"protocol,omitempty"` + TLS *apisv1.ListenerTLSConfigApplyConfiguration `json:"tls,omitempty"` + AllowedRoutes *apisv1.AllowedRoutesApplyConfiguration `json:"allowedRoutes,omitempty"` } // ListenerEntryApplyConfiguration constructs a declarative configuration of the ListenerEntry type for use with @@ -75,7 +75,7 @@ func (b *ListenerEntryApplyConfiguration) WithProtocol(value v1.ProtocolType) *L // WithTLS sets the TLS field in the declarative configuration to the given value // and returns the receiver, so that objects can be built by chaining "With" function invocations. // If called multiple times, the TLS field is set to the value of the last call. -func (b *ListenerEntryApplyConfiguration) WithTLS(value *apisv1.GatewayTLSConfigApplyConfiguration) *ListenerEntryApplyConfiguration { +func (b *ListenerEntryApplyConfiguration) WithTLS(value *apisv1.ListenerTLSConfigApplyConfiguration) *ListenerEntryApplyConfiguration { b.TLS = value return b } diff --git a/applyconfiguration/internal/internal.go b/applyconfiguration/internal/internal.go index 7a69ee3876..974c4bd20f 100644 --- a/applyconfiguration/internal/internal.go +++ b/applyconfiguration/internal/internal.go @@ -288,6 +288,12 @@ var schemaYAML = typed.YAMLObject(`types: - name: lifetimeType type: scalar: string +- name: io.k8s.sigs.gateway-api.apis.v1.ForwardBodyConfig + map: + fields: + - name: maxSize + type: + scalar: numeric - name: io.k8s.sigs.gateway-api.apis.v1.Fraction map: fields: @@ -298,6 +304,21 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: numeric default: 0 +- name: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSConfig + map: + fields: + - name: default + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.TLSConfig + default: {} + - name: perPort + type: + list: + elementType: + namedType: io.k8s.sigs.gateway-api.apis.v1.TLSPortConfig + elementRelationship: associative + keys: + - port - name: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation map: fields: @@ -307,6 +328,18 @@ var schemaYAML = typed.YAMLObject(`types: elementType: namedType: io.k8s.sigs.gateway-api.apis.v1.ObjectReference elementRelationship: atomic + - name: mode + type: + scalar: string +- name: io.k8s.sigs.gateway-api.apis.v1.GRPCAuthConfig + map: + fields: + - name: allowedHeaders + type: + list: + elementType: + scalar: string + elementRelationship: associative - name: io.k8s.sigs.gateway-api.apis.v1.GRPCBackendRef map: fields: @@ -580,9 +613,6 @@ var schemaYAML = typed.YAMLObject(`types: - name: allowedListeners type: namedType: io.k8s.sigs.gateway-api.apis.v1.AllowedListeners - - name: backendTLS - type: - namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayBackendTLS - name: gatewayClassName type: scalar: string @@ -598,6 +628,9 @@ var schemaYAML = typed.YAMLObject(`types: elementRelationship: associative keys: - name + - name: tls + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig - name: io.k8s.sigs.gateway-api.apis.v1.GatewaySpecAddress map: fields: @@ -645,23 +678,30 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig map: fields: - - name: certificateRefs + - name: backend type: - list: - elementType: - namedType: io.k8s.sigs.gateway-api.apis.v1.SecretObjectReference - elementRelationship: atomic - - name: frontendValidation + namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayBackendTLS + - name: frontend type: - namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation - - name: mode + namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSConfig +- name: io.k8s.sigs.gateway-api.apis.v1.HTTPAuthConfig + map: + fields: + - name: allowedHeaders type: - scalar: string - - name: options + list: + elementType: + scalar: string + elementRelationship: associative + - name: allowedResponseHeaders type: - map: + list: elementType: scalar: string + elementRelationship: associative + - name: path + type: + scalar: string - name: io.k8s.sigs.gateway-api.apis.v1.HTTPBackendRef map: fields: @@ -723,6 +763,25 @@ var schemaYAML = typed.YAMLObject(`types: - name: maxAge type: scalar: numeric +- name: io.k8s.sigs.gateway-api.apis.v1.HTTPExternalAuthFilter + map: + fields: + - name: backendRef + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.BackendObjectReference + default: {} + - name: forwardBody + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.ForwardBodyConfig + - name: grpc + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.GRPCAuthConfig + - name: http + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.HTTPAuthConfig + - name: protocol + type: + scalar: string - name: io.k8s.sigs.gateway-api.apis.v1.HTTPHeader map: fields: @@ -870,6 +929,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: extensionRef type: namedType: io.k8s.sigs.gateway-api.apis.v1.LocalObjectReference + - name: externalAuth + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.HTTPExternalAuthFilter - name: requestHeaderModifier type: namedType: io.k8s.sigs.gateway-api.apis.v1.HTTPHeaderFilter @@ -1033,7 +1095,7 @@ var schemaYAML = typed.YAMLObject(`types: default: "" - name: tls type: - namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig + namedType: io.k8s.sigs.gateway-api.apis.v1.ListenerTLSConfig - name: io.k8s.sigs.gateway-api.apis.v1.ListenerNamespaces map: fields: @@ -1068,6 +1130,23 @@ var schemaYAML = typed.YAMLObject(`types: elementType: namedType: io.k8s.sigs.gateway-api.apis.v1.RouteGroupKind elementRelationship: atomic +- name: io.k8s.sigs.gateway-api.apis.v1.ListenerTLSConfig + map: + fields: + - name: certificateRefs + type: + list: + elementType: + namedType: io.k8s.sigs.gateway-api.apis.v1.SecretObjectReference + elementRelationship: atomic + - name: mode + type: + scalar: string + - name: options + type: + map: + elementType: + scalar: string - name: io.k8s.sigs.gateway-api.apis.v1.LocalObjectReference map: fields: @@ -1235,6 +1314,23 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string default: "" +- name: io.k8s.sigs.gateway-api.apis.v1.TLSConfig + map: + fields: + - name: validation + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation +- name: io.k8s.sigs.gateway-api.apis.v1.TLSPortConfig + map: + fields: + - name: port + type: + scalar: numeric + default: 0 + - name: tls + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.TLSConfig + default: {} - name: io.k8s.sigs.gateway-api.apis.v1alpha2.GRPCRoute map: fields: @@ -1585,6 +1681,48 @@ var schemaYAML = typed.YAMLObject(`types: - name: uri type: scalar: string +- name: io.k8s.sigs.gateway-api.apis.v1alpha3.TLSRoute + map: + fields: + - name: apiVersion + type: + scalar: string + - name: kind + type: + scalar: string + - name: metadata + type: + namedType: io.k8s.apimachinery.pkg.apis.meta.v1.ObjectMeta + default: {} + - name: spec + type: + namedType: io.k8s.sigs.gateway-api.apis.v1alpha3.TLSRouteSpec + default: {} + - name: status + type: + namedType: io.k8s.sigs.gateway-api.apis.v1alpha2.TLSRouteStatus + default: {} +- name: io.k8s.sigs.gateway-api.apis.v1alpha3.TLSRouteSpec + map: + fields: + - name: hostnames + type: + list: + elementType: + scalar: string + elementRelationship: atomic + - name: parentRefs + type: + list: + elementType: + namedType: io.k8s.sigs.gateway-api.apis.v1.ParentReference + elementRelationship: atomic + - name: rules + type: + list: + elementType: + namedType: io.k8s.sigs.gateway-api.apis.v1alpha2.TLSRouteRule + elementRelationship: atomic - name: io.k8s.sigs.gateway-api.apis.v1beta1.Gateway map: fields: @@ -1753,14 +1891,13 @@ var schemaYAML = typed.YAMLObject(`types: - name: port type: scalar: numeric - default: 0 - name: protocol type: scalar: string default: "" - name: tls type: - namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig + namedType: io.k8s.sigs.gateway-api.apis.v1.ListenerTLSConfig - name: io.k8s.sigs.gateway-api.apisx.v1alpha1.ListenerEntryStatus map: fields: diff --git a/applyconfiguration/utils.go b/applyconfiguration/utils.go index 8e23441166..274736cd6c 100644 --- a/applyconfiguration/utils.go +++ b/applyconfiguration/utils.go @@ -52,8 +52,12 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.CommonRouteSpecApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("CookieConfig"): return &apisv1.CookieConfigApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("ForwardBodyConfig"): + return &apisv1.ForwardBodyConfigApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("Fraction"): return &apisv1.FractionApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("FrontendTLSConfig"): + return &apisv1.FrontendTLSConfigApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("FrontendTLSValidation"): return &apisv1.FrontendTLSValidationApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("Gateway"): @@ -78,6 +82,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.GatewayStatusAddressApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("GatewayTLSConfig"): return &apisv1.GatewayTLSConfigApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("GRPCAuthConfig"): + return &apisv1.GRPCAuthConfigApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("GRPCBackendRef"): return &apisv1.GRPCBackendRefApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("GRPCHeaderMatch"): @@ -96,10 +102,14 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.GRPCRouteSpecApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("GRPCRouteStatus"): return &apisv1.GRPCRouteStatusApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("HTTPAuthConfig"): + return &apisv1.HTTPAuthConfigApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("HTTPBackendRef"): return &apisv1.HTTPBackendRefApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("HTTPCORSFilter"): return &apisv1.HTTPCORSFilterApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("HTTPExternalAuthFilter"): + return &apisv1.HTTPExternalAuthFilterApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("HTTPHeader"): return &apisv1.HTTPHeaderApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("HTTPHeaderFilter"): @@ -140,6 +150,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.ListenerNamespacesApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("ListenerStatus"): return &apisv1.ListenerStatusApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("ListenerTLSConfig"): + return &apisv1.ListenerTLSConfigApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("LocalObjectReference"): return &apisv1.LocalObjectReferenceApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("LocalParametersReference"): @@ -164,6 +176,10 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1.SessionPersistenceApplyConfiguration{} case v1.SchemeGroupVersion.WithKind("SupportedFeature"): return &apisv1.SupportedFeatureApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TLSConfig"): + return &apisv1.TLSConfigApplyConfiguration{} + case v1.SchemeGroupVersion.WithKind("TLSPortConfig"): + return &apisv1.TLSPortConfigApplyConfiguration{} // Group=gateway.networking.k8s.io, Version=v1alpha2 case v1alpha2.SchemeGroupVersion.WithKind("GRPCRoute"): @@ -212,6 +228,10 @@ func ForKind(kind schema.GroupVersionKind) interface{} { return &apisv1alpha3.BackendTLSPolicyValidationApplyConfiguration{} case v1alpha3.SchemeGroupVersion.WithKind("SubjectAltName"): return &apisv1alpha3.SubjectAltNameApplyConfiguration{} + case v1alpha3.SchemeGroupVersion.WithKind("TLSRoute"): + return &apisv1alpha3.TLSRouteApplyConfiguration{} + case v1alpha3.SchemeGroupVersion.WithKind("TLSRouteSpec"): + return &apisv1alpha3.TLSRouteSpecApplyConfiguration{} // Group=gateway.networking.k8s.io, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithKind("Gateway"): diff --git a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml index 6a9e653a31..b5a05f1be6 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml @@ -149,6 +149,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName must be specified when targetRefs includes 2 or more references to the same target @@ -177,8 +178,31 @@ spec: not both. If CACertificateRefs is empty or unspecified, the configuration for WellKnownCACertificates MUST be honored instead if supported by the implementation. - References to a resource in a different namespace are invalid for the - moment, although we will revisit this in the future. + A CACertificateRef is invalid if: + + * It refers to a resource that cannot be resolved (e.g., the referenced resource + does not exist) or is misconfigured (e.g., a ConfigMap does not contain a key + named `ca.crt`). In this case, the Reason must be set to `InvalidCACertificateRef` + and the Message of the Condition must indicate which reference is invalid and why. + + * It refers to an unknown or unsupported kind of resource. In this case, the Reason + must be set to `InvalidKind` and the Message of the Condition must explain which + kind of resource is unknown or unsupported. + + * It refers to a resource in another namespace. This may change in future + spec updates. + + Implementations MAY choose to perform further validation of the certificate + content (e.g., checking expiry or enforcing specific formats). In such cases, + an implementation-specific Reason and Message must be set for the invalid reference. + + In all cases, the implementation MUST ensure the `ResolvedRefs` Condition on + the BackendTLSPolicy is set to `status: False`, with a Reason and Message + that indicate the cause of the error. Connections using an invalid + CACertificateRef MUST fail, and the client MUST receive an HTTP 5xx error + response. If ALL CACertificateRefs are invalid, the implementation MUST also + ensure the `Accepted` Condition on the BackendTLSPolicy is set to + `status: False`, with a Reason `NoValidCACertificate`. A single CACertificateRef to a Kubernetes ConfigMap kind has "Core" support. Implementations MAY choose to support attaching multiple certificates to @@ -187,8 +211,8 @@ spec: Support: Core - An optional single reference to a Kubernetes ConfigMap, with the CA certificate in a key named `ca.crt`. - Support: Implementation-specific (More than one reference, or other kinds - of resources). + Support: Implementation-specific - More than one reference, other kinds + of resources, or a single reference that includes multiple certificates. items: description: |- LocalObjectReference identifies an API object within the namespace of the @@ -226,6 +250,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic hostname: description: |- Hostname is used for two purposes in the connection between Gateways and @@ -233,8 +258,6 @@ spec: 1. Hostname MUST be used as the SNI to connect to the backend (RFC 6066). 2. Hostname MUST be used for authentication and MUST match the certificate served by the matching backend, unless SubjectAltNames is specified. - authentication and MUST match the certificate served by the matching - backend. Support: Core maxLength: 253 @@ -304,6 +327,7 @@ spec: "")' maxItems: 5 type: array + x-kubernetes-list-type: atomic wellKnownCACertificates: description: |- WellKnownCACertificates specifies whether system CA certificates may be used in @@ -311,10 +335,11 @@ spec: If WellKnownCACertificates is unspecified or empty (""), then CACertificateRefs must be specified with at least one entry for a valid configuration. Only one of - CACertificateRefs or WellKnownCACertificates may be specified, not both. If an - implementation does not support the WellKnownCACertificates field or the value - supplied is not supported, the Status Conditions on the Policy MUST be - updated to include an Accepted: False Condition with Reason: Invalid. + CACertificateRefs or WellKnownCACertificates may be specified, not both. + If an implementation does not support the WellKnownCACertificates field, or + the supplied value is not recognized, the implementation MUST ensure the + `Accepted` Condition on the BackendTLSPolicy is set to `status: False`, with + a Reason `Invalid`. Support: Implementation-specific enum: @@ -625,10 +650,12 @@ spec: type: string required: - ancestorRef + - conditions - controllerName type: object maxItems: 16 type: array + x-kubernetes-list-type: atomic required: - ancestors type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml index 328999eee9..6e154e9548 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml @@ -126,6 +126,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: IPAddress values must be unique rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, @@ -214,70 +215,6 @@ spec: x-kubernetes-map-type: atomic type: object type: object - backendTLS: - description: |- - BackendTLS configures TLS settings for when this Gateway is connecting to - backends with TLS. - - Support: Core - properties: - clientCertificateRef: - description: |- - ClientCertificateRef is a reference to an object that contains a Client - Certificate and the associated private key. - - References to a resource in different namespace are invalid UNLESS there - is a ReferenceGrant in the target namespace that allows the certificate - to be attached. If a ReferenceGrant does not allow this reference, the - "ResolvedRefs" condition MUST be set to False for this listener with the - "RefNotPermitted" reason. - - ClientCertificateRef can reference to standard Kubernetes resources, i.e. - Secret, or implementation-specific custom resources. - - This setting can be overridden on the service level by use of BackendTLSPolicy. - - Support: Core - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "Secret". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the referenced object. When unspecified, the local - namespace is inferred. - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - type: object gatewayClassName: description: |- GatewayClassName used for this Gateway. This is the name of a @@ -633,6 +570,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -800,7 +738,7 @@ spec: the Protocol field is "HTTPS" or "TLS". It is invalid to set this field if the Protocol field is "HTTP", "TCP", or "UDP". - The association of SNIs to Certificate defined in GatewayTLSConfig is + The association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener. The GatewayClass MUST use the longest matching SNI out of all @@ -887,93 +825,7 @@ spec: type: object maxItems: 64 type: array - frontendValidation: - description: |- - FrontendValidation holds configuration information for validating the frontend (client). - Setting this field will require clients to send a client certificate - required for validation during the TLS handshake. In browsers this may result in a dialog appearing - that requests a user to specify the client certificate. - The maximum depth of a certificate chain accepted in verification is Implementation specific. - - Support: Extended - properties: - caCertificateRefs: - description: |- - CACertificateRefs contains one or more references to - Kubernetes objects that contain TLS certificates of - the Certificate Authorities that can be used - as a trust anchor to validate the certificates presented by the client. - - A single CA certificate reference to a Kubernetes ConfigMap - has "Core" support. - Implementations MAY choose to support attaching multiple CA certificates to - a Listener, but this behavior is implementation-specific. - - Support: Core - A single reference to a Kubernetes ConfigMap - with the CA certificate in a key named `ca.crt`. - - Support: Implementation-specific (More than one reference, or other kinds - of resources). - - References to a resource in a different namespace are invalid UNLESS there - is a ReferenceGrant in the target namespace that allows the certificate - to be attached. If a ReferenceGrant does not allow this reference, the - "ResolvedRefs" condition MUST be set to False for this listener with the - "RefNotPermitted" reason. - items: - description: |- - ObjectReference identifies an API object including its namespace. - - The API object must be valid in the cluster; the Group and Kind must - be registered in the cluster for this reference to be valid. - - References to objects with invalid Group and Kind are not valid, and must - be rejected by the implementation, with appropriate Conditions set - on the containing object. - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When set to the empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For - example "ConfigMap" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the referenced object. When unspecified, the local - namespace is inferred. - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - maxItems: 8 - minItems: 1 - type: array - type: object + x-kubernetes-list-type: atomic mode: default: Terminate description: |- @@ -1052,6 +904,366 @@ spec: rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + tls: + description: |- + TLS specifies frontend and backend tls configuration for entire gateway. + + Support: Extended + properties: + backend: + description: |- + Backend describes TLS configuration for gateway when connecting + to backends. + + Note that this contains only details for the Gateway as a TLS client, + and does _not_ imply behavior about how to choose which backend should + get a TLS connection. That is determined by the presence of a BackendTLSPolicy. + + Support: Core + properties: + clientCertificateRef: + description: |- + ClientCertificateRef is a reference to an object that contains a Client + Certificate and the associated private key. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + ClientCertificateRef can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + frontend: + description: |- + Frontend describes TLS config when client connects to Gateway. + Support: Core + properties: + default: + description: |- + Default specifies the default client certificate validation configuration + for all Listeners handling HTTPS traffic, unless a per-port configuration + is defined. + + support: Core + properties: + validation: + description: |- + Validation holds configuration information for validating the frontend (client). + Setting this field will result in mutual authentication when connecting to the gateway. + In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Core + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one certificate in a ConfigMap + with different keys or more than one reference, or other kinds of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When set to the empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + mode: + default: AllowValidOnly + description: |- + FrontendValidationMode defines the mode for validating the client certificate. + There are two possible modes: + + - AllowValidOnly: In this mode, the gateway will accept connections only if + the client presents a valid certificate. This certificate must successfully + pass validation against the CA certificates specified in `CACertificateRefs`. + - AllowInsecureFallback: In this mode, the gateway will accept connections + even if the client certificate is not presented or fails verification. + + This approach delegates client authorization to the backend and introduce + a significant security risk. It should be used in testing environments or + on a temporary basis in non-testing environments. + + Defaults to AllowValidOnly. + + Support: Core + enum: + - AllowValidOnly + - AllowInsecureFallback + type: string + required: + - caCertificateRefs + type: object + type: object + perPort: + description: |- + PerPort specifies tls configuration assigned per port. + Per port configuration is optional. Once set this configuration overrides + the default configuration for all Listeners handling HTTPS traffic + that match this port. + Each override port requires a unique TLS configuration. + + support: Core + items: + properties: + port: + description: |- + The Port indicates the Port Number to which the TLS configuration will be + applied. This configuration will be applied to all Listeners handling HTTPS + traffic that match this port. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: |- + TLS store the configuration that will be applied to all Listeners handling + HTTPS traffic and matching given port. + + Support: Core + properties: + validation: + description: |- + Validation holds configuration information for validating the frontend (client). + Setting this field will result in mutual authentication when connecting to the gateway. + In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Core + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one certificate in a ConfigMap + with different keys or more than one reference, or other kinds of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When set to the empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + For example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + mode: + default: AllowValidOnly + description: |- + FrontendValidationMode defines the mode for validating the client certificate. + There are two possible modes: + + - AllowValidOnly: In this mode, the gateway will accept connections only if + the client presents a valid certificate. This certificate must successfully + pass validation against the CA certificates specified in `CACertificateRefs`. + - AllowInsecureFallback: In this mode, the gateway will accept connections + even if the client certificate is not presented or fails verification. + + This approach delegates client authorization to the backend and introduce + a significant security risk. It should be used in testing environments or + on a temporary basis in non-testing environments. + + Defaults to AllowValidOnly. + + Support: Core + enum: + - AllowValidOnly + - AllowInsecureFallback + type: string + required: + - caCertificateRefs + type: object + type: object + required: + - port + - tls + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - port + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: Port for TLS configuration must be unique within + the Gateway + rule: self.all(t1, self.exists_one(t2, t1.port == t2.port)) + required: + - default + type: object + type: object required: - gatewayClassName - listeners @@ -1126,6 +1338,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -1339,6 +1552,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions @@ -1464,6 +1678,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: IPAddress values must be unique rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, @@ -1552,70 +1767,6 @@ spec: x-kubernetes-map-type: atomic type: object type: object - backendTLS: - description: |- - BackendTLS configures TLS settings for when this Gateway is connecting to - backends with TLS. - - Support: Core - properties: - clientCertificateRef: - description: |- - ClientCertificateRef is a reference to an object that contains a Client - Certificate and the associated private key. - - References to a resource in different namespace are invalid UNLESS there - is a ReferenceGrant in the target namespace that allows the certificate - to be attached. If a ReferenceGrant does not allow this reference, the - "ResolvedRefs" condition MUST be set to False for this listener with the - "RefNotPermitted" reason. - - ClientCertificateRef can reference to standard Kubernetes resources, i.e. - Secret, or implementation-specific custom resources. - - This setting can be overridden on the service level by use of BackendTLSPolicy. - - Support: Core - properties: - group: - default: "" - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When unspecified or empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - default: Secret - description: Kind is kind of the referent. For example "Secret". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the referenced object. When unspecified, the local - namespace is inferred. - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - name - type: object - type: object gatewayClassName: description: |- GatewayClassName used for this Gateway. This is the name of a @@ -1971,6 +2122,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -2138,7 +2290,7 @@ spec: the Protocol field is "HTTPS" or "TLS". It is invalid to set this field if the Protocol field is "HTTP", "TCP", or "UDP". - The association of SNIs to Certificate defined in GatewayTLSConfig is + The association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener. The GatewayClass MUST use the longest matching SNI out of all @@ -2225,93 +2377,7 @@ spec: type: object maxItems: 64 type: array - frontendValidation: - description: |- - FrontendValidation holds configuration information for validating the frontend (client). - Setting this field will require clients to send a client certificate - required for validation during the TLS handshake. In browsers this may result in a dialog appearing - that requests a user to specify the client certificate. - The maximum depth of a certificate chain accepted in verification is Implementation specific. - - Support: Extended - properties: - caCertificateRefs: - description: |- - CACertificateRefs contains one or more references to - Kubernetes objects that contain TLS certificates of - the Certificate Authorities that can be used - as a trust anchor to validate the certificates presented by the client. - - A single CA certificate reference to a Kubernetes ConfigMap - has "Core" support. - Implementations MAY choose to support attaching multiple CA certificates to - a Listener, but this behavior is implementation-specific. - - Support: Core - A single reference to a Kubernetes ConfigMap - with the CA certificate in a key named `ca.crt`. - - Support: Implementation-specific (More than one reference, or other kinds - of resources). - - References to a resource in a different namespace are invalid UNLESS there - is a ReferenceGrant in the target namespace that allows the certificate - to be attached. If a ReferenceGrant does not allow this reference, the - "ResolvedRefs" condition MUST be set to False for this listener with the - "RefNotPermitted" reason. - items: - description: |- - ObjectReference identifies an API object including its namespace. - - The API object must be valid in the cluster; the Group and Kind must - be registered in the cluster for this reference to be valid. - - References to objects with invalid Group and Kind are not valid, and must - be rejected by the implementation, with appropriate Conditions set - on the containing object. - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When set to the empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For - example "ConfigMap" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the referenced object. When unspecified, the local - namespace is inferred. - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - maxItems: 8 - minItems: 1 - type: array - type: object + x-kubernetes-list-type: atomic mode: default: Terminate description: |- @@ -2390,6 +2456,366 @@ spec: rule: 'self.all(l1, self.exists_one(l2, l1.port == l2.port && l1.protocol == l2.protocol && (has(l1.hostname) && has(l2.hostname) ? l1.hostname == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' + tls: + description: |- + TLS specifies frontend and backend tls configuration for entire gateway. + + Support: Extended + properties: + backend: + description: |- + Backend describes TLS configuration for gateway when connecting + to backends. + + Note that this contains only details for the Gateway as a TLS client, + and does _not_ imply behavior about how to choose which backend should + get a TLS connection. That is determined by the presence of a BackendTLSPolicy. + + Support: Core + properties: + clientCertificateRef: + description: |- + ClientCertificateRef is a reference to an object that contains a Client + Certificate and the associated private key. + + References to a resource in different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + + ClientCertificateRef can reference to standard Kubernetes resources, i.e. + Secret, or implementation-specific custom resources. + + Support: Core + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Secret + description: Kind is kind of the referent. For example + "Secret". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - name + type: object + type: object + frontend: + description: |- + Frontend describes TLS config when client connects to Gateway. + Support: Core + properties: + default: + description: |- + Default specifies the default client certificate validation configuration + for all Listeners handling HTTPS traffic, unless a per-port configuration + is defined. + + support: Core + properties: + validation: + description: |- + Validation holds configuration information for validating the frontend (client). + Setting this field will result in mutual authentication when connecting to the gateway. + In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Core + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one certificate in a ConfigMap + with different keys or more than one reference, or other kinds of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When set to the empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. For + example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + mode: + default: AllowValidOnly + description: |- + FrontendValidationMode defines the mode for validating the client certificate. + There are two possible modes: + + - AllowValidOnly: In this mode, the gateway will accept connections only if + the client presents a valid certificate. This certificate must successfully + pass validation against the CA certificates specified in `CACertificateRefs`. + - AllowInsecureFallback: In this mode, the gateway will accept connections + even if the client certificate is not presented or fails verification. + + This approach delegates client authorization to the backend and introduce + a significant security risk. It should be used in testing environments or + on a temporary basis in non-testing environments. + + Defaults to AllowValidOnly. + + Support: Core + enum: + - AllowValidOnly + - AllowInsecureFallback + type: string + required: + - caCertificateRefs + type: object + type: object + perPort: + description: |- + PerPort specifies tls configuration assigned per port. + Per port configuration is optional. Once set this configuration overrides + the default configuration for all Listeners handling HTTPS traffic + that match this port. + Each override port requires a unique TLS configuration. + + support: Core + items: + properties: + port: + description: |- + The Port indicates the Port Number to which the TLS configuration will be + applied. This configuration will be applied to all Listeners handling HTTPS + traffic that match this port. + + Support: Core + format: int32 + maximum: 65535 + minimum: 1 + type: integer + tls: + description: |- + TLS store the configuration that will be applied to all Listeners handling + HTTPS traffic and matching given port. + + Support: Core + properties: + validation: + description: |- + Validation holds configuration information for validating the frontend (client). + Setting this field will result in mutual authentication when connecting to the gateway. + In browsers this may result in a dialog appearing + that requests a user to specify the client certificate. + The maximum depth of a certificate chain accepted in verification is Implementation specific. + + Support: Core + properties: + caCertificateRefs: + description: |- + CACertificateRefs contains one or more references to + Kubernetes objects that contain TLS certificates of + the Certificate Authorities that can be used + as a trust anchor to validate the certificates presented by the client. + + A single CA certificate reference to a Kubernetes ConfigMap + has "Core" support. + Implementations MAY choose to support attaching multiple CA certificates to + a Listener, but this behavior is implementation-specific. + + Support: Core - A single reference to a Kubernetes ConfigMap + with the CA certificate in a key named `ca.crt`. + + Support: Implementation-specific (More than one certificate in a ConfigMap + with different keys or more than one reference, or other kinds of resources). + + References to a resource in a different namespace are invalid UNLESS there + is a ReferenceGrant in the target namespace that allows the certificate + to be attached. If a ReferenceGrant does not allow this reference, the + "ResolvedRefs" condition MUST be set to False for this listener with the + "RefNotPermitted" reason. + items: + description: |- + ObjectReference identifies an API object including its namespace. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + + References to objects with invalid Group and Kind are not valid, and must + be rejected by the implementation, with appropriate Conditions set + on the containing object. + properties: + group: + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When set to the empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + description: Kind is kind of the referent. + For example "ConfigMap" or "Service". + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + required: + - group + - kind + - name + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + mode: + default: AllowValidOnly + description: |- + FrontendValidationMode defines the mode for validating the client certificate. + There are two possible modes: + + - AllowValidOnly: In this mode, the gateway will accept connections only if + the client presents a valid certificate. This certificate must successfully + pass validation against the CA certificates specified in `CACertificateRefs`. + - AllowInsecureFallback: In this mode, the gateway will accept connections + even if the client certificate is not presented or fails verification. + + This approach delegates client authorization to the backend and introduce + a significant security risk. It should be used in testing environments or + on a temporary basis in non-testing environments. + + Defaults to AllowValidOnly. + + Support: Core + enum: + - AllowValidOnly + - AllowInsecureFallback + type: string + required: + - caCertificateRefs + type: object + type: object + required: + - port + - tls + type: object + maxItems: 64 + type: array + x-kubernetes-list-map-keys: + - port + x-kubernetes-list-type: map + x-kubernetes-validations: + - message: Port for TLS configuration must be unique within + the Gateway + rule: self.all(t1, self.exists_one(t2, t1.port == t2.port)) + required: + - default + type: object + type: object required: - gatewayClassName - listeners @@ -2464,6 +2890,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -2677,6 +3104,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index 9e8dd64201..3a40ee2314 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -151,6 +151,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -363,6 +364,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -984,6 +986,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: RequestHeaderModifier filter cannot be repeated rule: self.filter(f, f.type == 'RequestHeaderModifier').size() @@ -1080,6 +1083,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -1630,6 +1634,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: RequestHeaderModifier filter cannot be repeated rule: self.filter(f, f.type == 'RequestHeaderModifier').size() @@ -1807,6 +1812,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -1908,6 +1914,7 @@ spec: type: object maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -2196,14 +2203,18 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 9f5f93d222..0329311362 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -131,6 +131,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -343,6 +344,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -468,16 +470,14 @@ spec: AllowCredentials indicates whether the actual cross-origin request allows to include credentials. - The only valid value for the `Access-Control-Allow-Credentials` response - header is true (case-sensitive). + When set to true, the gateway will include the `Access-Control-Allow-Credentials` + response header with value true (case-sensitive). - If the credentials are not allowed in cross-origin requests, the gateway - will omit the header `Access-Control-Allow-Credentials` entirely rather - than setting its value to false. + When set to false or omitted the gateway will omit the header + `Access-Control-Allow-Credentials` entirely (this is the standard CORS + behavior). Support: Extended - enum: - - true type: boolean allowHeaders: description: |- @@ -504,9 +504,9 @@ spec: A wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowHeaders` field + When the `AllowCredentials` field is true and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as @@ -567,9 +567,9 @@ spec: side. The `Access-Control-Allow-Methods` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowMethods` field + When the `AllowCredentials` field is true and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the @@ -645,9 +645,9 @@ spec: Therefore, the client doesn't attempt the actual cross-origin request. The `Access-Control-Allow-Origin` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowOrigins` field + When the `AllowCredentials` field is true and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header @@ -657,18 +657,22 @@ spec: Support: Extended items: description: |- - The AbsoluteURI MUST NOT be a relative URI, and it MUST follow the URI syntax and - encoding rules specified in RFC3986. The AbsoluteURI MUST include both a - scheme (e.g., "http" or "spiffe") and a scheme-specific-part. URIs that - include an authority MUST include a fully qualified domain name or + The CORSOrigin MUST NOT be a relative URI, and it MUST follow the URI syntax and + encoding rules specified in RFC3986. The CORSOrigin MUST include both a + scheme (e.g., "http" or "spiffe") and a scheme-specific-part, or it should be a single '*' character. + URIs that include an authority MUST include a fully qualified domain name or IP address as the host. maxLength: 253 minLength: 1 - pattern: ^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))? + pattern: (^\*$)|(^([a-zA-Z][a-zA-Z0-9+\-.]+):\/\/([^:/?#]+)(:([0-9]{1,5}))?$) type: string maxItems: 64 type: array x-kubernetes-list-type: set + x-kubernetes-validations: + - message: AllowOrigins cannot contain '*' alongside + other origins + rule: '!(''*'' in self && self.size() > 1)' exposeHeaders: description: |- ExposeHeaders indicates which HTTP response headers can be exposed @@ -698,8 +702,7 @@ spec: A wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only - use `*` wildcard as value when the `AllowCredentials` field is - unspecified. + use `*` wildcard as value when the `AllowCredentials` field is false or omitted. Support: Extended items: @@ -774,6 +777,259 @@ spec: - kind - name type: object + externalAuth: + description: |- + ExternalAuth configures settings related to sending request details + to an external auth service. The external service MUST authenticate + the request, and MAY authorize the request as well. + + If there is any problem communicating with the external service, + this filter MUST fail closed. + + Support: Extended + properties: + backendRef: + description: |- + BackendRef is a reference to a backend to send authorization + requests to. + + The backend must speak the selected protocol (GRPC or HTTP) on the + referenced port. + + If the backend service requires TLS, use BackendTLSPolicy to tell the + implementation to supply the TLS details to be used to connect to that + backend. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + forwardBody: + description: |- + ForwardBody controls if requests to the authorization server should include + the body of the client request; and if so, how big that body is allowed + to be. + + It is expected that implementations will buffer the request body up to + `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + 4xx series error (413 or 403 are common examples), and fail processing + of the filter. + + If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + be forwarded. + + Feature Name: HTTPRouteExternalAuthForwardBody + properties: + maxSize: + description: |- + MaxSize specifies how large in bytes the largest body that will be buffered + and sent to the authorization server. If the body size is larger than + `maxSize`, then the body sent to the authorization server must be + truncated to `maxSize` bytes. + + Experimental note: This behavior needs to be checked against + various dataplanes; it may need to be changed. + See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 + for more. + + If 0, the body will not be sent to the authorization server. + type: integer + type: object + grpc: + description: |- + GRPCAuthConfig contains configuration for communication with ext_authz + protocol-speaking backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what headers from the client request + will be sent to the authorization server. + + If this list is empty, then the following headers must be sent: + + - `Authorization` + - `Location` + - `Proxy-Authenticate` + - `Set-Cookie` + - `WWW-Authenticate` + + If the list has entries, only those entries must be sent. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + http: + description: |- + HTTPAuthConfig contains configuration for communication with HTTP-speaking + backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what additional headers from the client request + will be sent to the authorization server. + + The following headers must always be sent to the authorization server, + regardless of this setting: + + * `Host` + * `Method` + * `Path` + * `Content-Length` + * `Authorization` + + If this list is empty, then only those headers must be sent. + + Note that `Content-Length` has a special behavior, in that the length + sent must be correct for the actual request to the external authorization + server - that is, it must reflect the actual number of bytes sent in the + body of the request to the authorization server. + + So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + to anything other than `0`, then the `Content-Length` of the authorization + request must be set to the actual number of bytes forwarded. + items: + type: string + type: array + x-kubernetes-list-type: set + allowedResponseHeaders: + description: |- + AllowedResponseHeaders specifies what headers from the authorization response + will be copied into the request to the backend. + + If this list is empty, then all headers from the authorization server + except Authority or Host must be copied. + items: + type: string + type: array + x-kubernetes-list-type: set + path: + description: |- + Path sets the prefix that paths from the client request will have added + when forwarded to the authorization server. + + When empty or unspecified, no prefix is added. + + Valid values are the same as the "value" regex for path values in the `match` + stanza, and the validation regex will screen out invalid paths in the same way. + Even with the validation, implementations MUST sanitize this input before using it + directly. + maxLength: 1024 + pattern: ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$ + type: string + type: object + protocol: + description: |- + ExternalAuthProtocol describes which protocol to use when communicating with an + ext_authz authorization server. + + When this is set to GRPC, each backend must use the Envoy ext_authz protocol + on the port specified in `backendRefs`. Requests and responses are defined + in the protobufs explained at: + https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + + When this is set to HTTP, each backend must respond with a `200` status + code in on a successful authorization. Any other code is considered + an authorization failure. + + Feature Names: + GRPC Support - HTTPRouteExternalAuthGRPC + HTTP Support - HTTPRouteExternalAuthHTTP + enum: + - HTTP + - GRPC + type: string + required: + - backendRef + - protocol + type: object + x-kubernetes-validations: + - message: grpc must be specified when protocol + is set to 'GRPC' + rule: 'self.protocol == ''GRPC'' ? has(self.grpc) + : true' + - message: protocol must be 'GRPC' when grpc is + set + rule: 'has(self.grpc) ? self.protocol == ''GRPC'' + : true' + - message: http must be specified when protocol + is set to 'HTTP' + rule: 'self.protocol == ''HTTP'' ? has(self.http) + : true' + - message: protocol must be 'HTTP' when http is + set + rule: 'has(self.http) ? self.protocol == ''HTTP'' + : true' requestHeaderModifier: description: |- RequestHeaderModifier defines a schema for a filter that modifies request @@ -1387,6 +1643,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -1524,13 +1781,16 @@ spec: rule: '!(has(self.cors) && self.type != ''CORS'')' - message: filter.cors must be specified for CORS filter.type rule: '!(!has(self.cors) && self.type == ''CORS'')' + - message: filter.externalAuth must be nil if the filter.type + is not ExternalAuth + rule: '!(has(self.externalAuth) && self.type != ''ExternalAuth'')' + - message: filter.externalAuth must be specified for + ExternalAuth filter.type + rule: '!(!has(self.externalAuth) && self.type == ''ExternalAuth'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -1636,6 +1896,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -1695,16 +1956,14 @@ spec: AllowCredentials indicates whether the actual cross-origin request allows to include credentials. - The only valid value for the `Access-Control-Allow-Credentials` response - header is true (case-sensitive). + When set to true, the gateway will include the `Access-Control-Allow-Credentials` + response header with value true (case-sensitive). - If the credentials are not allowed in cross-origin requests, the gateway - will omit the header `Access-Control-Allow-Credentials` entirely rather - than setting its value to false. + When set to false or omitted the gateway will omit the header + `Access-Control-Allow-Credentials` entirely (this is the standard CORS + behavior). Support: Extended - enum: - - true type: boolean allowHeaders: description: |- @@ -1731,9 +1990,9 @@ spec: A wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowHeaders` field + When the `AllowCredentials` field is true and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as @@ -1794,9 +2053,9 @@ spec: side. The `Access-Control-Allow-Methods` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowMethods` field + When the `AllowCredentials` field is true and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the @@ -1872,9 +2131,9 @@ spec: Therefore, the client doesn't attempt the actual cross-origin request. The `Access-Control-Allow-Origin` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowOrigins` field + When the `AllowCredentials` field is true and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header @@ -1884,18 +2143,22 @@ spec: Support: Extended items: description: |- - The AbsoluteURI MUST NOT be a relative URI, and it MUST follow the URI syntax and - encoding rules specified in RFC3986. The AbsoluteURI MUST include both a - scheme (e.g., "http" or "spiffe") and a scheme-specific-part. URIs that - include an authority MUST include a fully qualified domain name or + The CORSOrigin MUST NOT be a relative URI, and it MUST follow the URI syntax and + encoding rules specified in RFC3986. The CORSOrigin MUST include both a + scheme (e.g., "http" or "spiffe") and a scheme-specific-part, or it should be a single '*' character. + URIs that include an authority MUST include a fully qualified domain name or IP address as the host. maxLength: 253 minLength: 1 - pattern: ^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))? + pattern: (^\*$)|(^([a-zA-Z][a-zA-Z0-9+\-.]+):\/\/([^:/?#]+)(:([0-9]{1,5}))?$) type: string maxItems: 64 type: array x-kubernetes-list-type: set + x-kubernetes-validations: + - message: AllowOrigins cannot contain '*' alongside + other origins + rule: '!(''*'' in self && self.size() > 1)' exposeHeaders: description: |- ExposeHeaders indicates which HTTP response headers can be exposed @@ -1925,8 +2188,7 @@ spec: A wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only - use `*` wildcard as value when the `AllowCredentials` field is - unspecified. + use `*` wildcard as value when the `AllowCredentials` field is false or omitted. Support: Extended items: @@ -2001,6 +2263,257 @@ spec: - kind - name type: object + externalAuth: + description: |- + ExternalAuth configures settings related to sending request details + to an external auth service. The external service MUST authenticate + the request, and MAY authorize the request as well. + + If there is any problem communicating with the external service, + this filter MUST fail closed. + + Support: Extended + properties: + backendRef: + description: |- + BackendRef is a reference to a backend to send authorization + requests to. + + The backend must speak the selected protocol (GRPC or HTTP) on the + referenced port. + + If the backend service requires TLS, use BackendTLSPolicy to tell the + implementation to supply the TLS details to be used to connect to that + backend. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + forwardBody: + description: |- + ForwardBody controls if requests to the authorization server should include + the body of the client request; and if so, how big that body is allowed + to be. + + It is expected that implementations will buffer the request body up to + `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + 4xx series error (413 or 403 are common examples), and fail processing + of the filter. + + If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + be forwarded. + + Feature Name: HTTPRouteExternalAuthForwardBody + properties: + maxSize: + description: |- + MaxSize specifies how large in bytes the largest body that will be buffered + and sent to the authorization server. If the body size is larger than + `maxSize`, then the body sent to the authorization server must be + truncated to `maxSize` bytes. + + Experimental note: This behavior needs to be checked against + various dataplanes; it may need to be changed. + See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 + for more. + + If 0, the body will not be sent to the authorization server. + type: integer + type: object + grpc: + description: |- + GRPCAuthConfig contains configuration for communication with ext_authz + protocol-speaking backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what headers from the client request + will be sent to the authorization server. + + If this list is empty, then the following headers must be sent: + + - `Authorization` + - `Location` + - `Proxy-Authenticate` + - `Set-Cookie` + - `WWW-Authenticate` + + If the list has entries, only those entries must be sent. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + http: + description: |- + HTTPAuthConfig contains configuration for communication with HTTP-speaking + backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what additional headers from the client request + will be sent to the authorization server. + + The following headers must always be sent to the authorization server, + regardless of this setting: + + * `Host` + * `Method` + * `Path` + * `Content-Length` + * `Authorization` + + If this list is empty, then only those headers must be sent. + + Note that `Content-Length` has a special behavior, in that the length + sent must be correct for the actual request to the external authorization + server - that is, it must reflect the actual number of bytes sent in the + body of the request to the authorization server. + + So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + to anything other than `0`, then the `Content-Length` of the authorization + request must be set to the actual number of bytes forwarded. + items: + type: string + type: array + x-kubernetes-list-type: set + allowedResponseHeaders: + description: |- + AllowedResponseHeaders specifies what headers from the authorization response + will be copied into the request to the backend. + + If this list is empty, then all headers from the authorization server + except Authority or Host must be copied. + items: + type: string + type: array + x-kubernetes-list-type: set + path: + description: |- + Path sets the prefix that paths from the client request will have added + when forwarded to the authorization server. + + When empty or unspecified, no prefix is added. + + Valid values are the same as the "value" regex for path values in the `match` + stanza, and the validation regex will screen out invalid paths in the same way. + Even with the validation, implementations MUST sanitize this input before using it + directly. + maxLength: 1024 + pattern: ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$ + type: string + type: object + protocol: + description: |- + ExternalAuthProtocol describes which protocol to use when communicating with an + ext_authz authorization server. + + When this is set to GRPC, each backend must use the Envoy ext_authz protocol + on the port specified in `backendRefs`. Requests and responses are defined + in the protobufs explained at: + https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + + When this is set to HTTP, each backend must respond with a `200` status + code in on a successful authorization. Any other code is considered + an authorization failure. + + Feature Names: + GRPC Support - HTTPRouteExternalAuthGRPC + HTTP Support - HTTPRouteExternalAuthHTTP + enum: + - HTTP + - GRPC + type: string + required: + - backendRef + - protocol + type: object + x-kubernetes-validations: + - message: grpc must be specified when protocol is set + to 'GRPC' + rule: 'self.protocol == ''GRPC'' ? has(self.grpc) : + true' + - message: protocol must be 'GRPC' when grpc is set + rule: 'has(self.grpc) ? self.protocol == ''GRPC'' : + true' + - message: http must be specified when protocol is set + to 'HTTP' + rule: 'self.protocol == ''HTTP'' ? has(self.http) : + true' + - message: protocol must be 'HTTP' when http is set + rule: 'has(self.http) ? self.protocol == ''HTTP'' : + true' requestHeaderModifier: description: |- RequestHeaderModifier defines a schema for a filter that modifies request @@ -2610,6 +3123,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -2744,8 +3258,15 @@ spec: rule: '!(has(self.cors) && self.type != ''CORS'')' - message: filter.cors must be specified for CORS filter.type rule: '!(!has(self.cors) && self.type == ''CORS'')' + - message: filter.externalAuth must be nil if the filter.type + is not ExternalAuth + rule: '!(has(self.externalAuth) && self.type != ''ExternalAuth'')' + - message: filter.externalAuth must be specified for ExternalAuth + filter.type + rule: '!(!has(self.externalAuth) && self.type == ''ExternalAuth'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -3057,6 +3578,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -3152,6 +3674,7 @@ spec: minimum: 400 type: integer type: array + x-kubernetes-list-type: atomic type: object sessionPersistence: description: |- @@ -3347,6 +3870,7 @@ spec: != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -3629,11 +4153,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object @@ -3757,6 +4283,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -3969,6 +4496,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -4094,16 +4622,14 @@ spec: AllowCredentials indicates whether the actual cross-origin request allows to include credentials. - The only valid value for the `Access-Control-Allow-Credentials` response - header is true (case-sensitive). + When set to true, the gateway will include the `Access-Control-Allow-Credentials` + response header with value true (case-sensitive). - If the credentials are not allowed in cross-origin requests, the gateway - will omit the header `Access-Control-Allow-Credentials` entirely rather - than setting its value to false. + When set to false or omitted the gateway will omit the header + `Access-Control-Allow-Credentials` entirely (this is the standard CORS + behavior). Support: Extended - enum: - - true type: boolean allowHeaders: description: |- @@ -4130,9 +4656,9 @@ spec: A wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowHeaders` field + When the `AllowCredentials` field is true and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as @@ -4193,9 +4719,9 @@ spec: side. The `Access-Control-Allow-Methods` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowMethods` field + When the `AllowCredentials` field is true and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the @@ -4271,9 +4797,9 @@ spec: Therefore, the client doesn't attempt the actual cross-origin request. The `Access-Control-Allow-Origin` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowOrigins` field + When the `AllowCredentials` field is true and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header @@ -4283,18 +4809,22 @@ spec: Support: Extended items: description: |- - The AbsoluteURI MUST NOT be a relative URI, and it MUST follow the URI syntax and - encoding rules specified in RFC3986. The AbsoluteURI MUST include both a - scheme (e.g., "http" or "spiffe") and a scheme-specific-part. URIs that - include an authority MUST include a fully qualified domain name or + The CORSOrigin MUST NOT be a relative URI, and it MUST follow the URI syntax and + encoding rules specified in RFC3986. The CORSOrigin MUST include both a + scheme (e.g., "http" or "spiffe") and a scheme-specific-part, or it should be a single '*' character. + URIs that include an authority MUST include a fully qualified domain name or IP address as the host. maxLength: 253 minLength: 1 - pattern: ^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))? + pattern: (^\*$)|(^([a-zA-Z][a-zA-Z0-9+\-.]+):\/\/([^:/?#]+)(:([0-9]{1,5}))?$) type: string maxItems: 64 type: array x-kubernetes-list-type: set + x-kubernetes-validations: + - message: AllowOrigins cannot contain '*' alongside + other origins + rule: '!(''*'' in self && self.size() > 1)' exposeHeaders: description: |- ExposeHeaders indicates which HTTP response headers can be exposed @@ -4324,8 +4854,7 @@ spec: A wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only - use `*` wildcard as value when the `AllowCredentials` field is - unspecified. + use `*` wildcard as value when the `AllowCredentials` field is false or omitted. Support: Extended items: @@ -4400,6 +4929,259 @@ spec: - kind - name type: object + externalAuth: + description: |- + ExternalAuth configures settings related to sending request details + to an external auth service. The external service MUST authenticate + the request, and MAY authorize the request as well. + + If there is any problem communicating with the external service, + this filter MUST fail closed. + + Support: Extended + properties: + backendRef: + description: |- + BackendRef is a reference to a backend to send authorization + requests to. + + The backend must speak the selected protocol (GRPC or HTTP) on the + referenced port. + + If the backend service requires TLS, use BackendTLSPolicy to tell the + implementation to supply the TLS details to be used to connect to that + backend. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind + == ''Service'') ? has(self.port) : true' + forwardBody: + description: |- + ForwardBody controls if requests to the authorization server should include + the body of the client request; and if so, how big that body is allowed + to be. + + It is expected that implementations will buffer the request body up to + `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + 4xx series error (413 or 403 are common examples), and fail processing + of the filter. + + If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + be forwarded. + + Feature Name: HTTPRouteExternalAuthForwardBody + properties: + maxSize: + description: |- + MaxSize specifies how large in bytes the largest body that will be buffered + and sent to the authorization server. If the body size is larger than + `maxSize`, then the body sent to the authorization server must be + truncated to `maxSize` bytes. + + Experimental note: This behavior needs to be checked against + various dataplanes; it may need to be changed. + See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 + for more. + + If 0, the body will not be sent to the authorization server. + type: integer + type: object + grpc: + description: |- + GRPCAuthConfig contains configuration for communication with ext_authz + protocol-speaking backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what headers from the client request + will be sent to the authorization server. + + If this list is empty, then the following headers must be sent: + + - `Authorization` + - `Location` + - `Proxy-Authenticate` + - `Set-Cookie` + - `WWW-Authenticate` + + If the list has entries, only those entries must be sent. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + http: + description: |- + HTTPAuthConfig contains configuration for communication with HTTP-speaking + backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what additional headers from the client request + will be sent to the authorization server. + + The following headers must always be sent to the authorization server, + regardless of this setting: + + * `Host` + * `Method` + * `Path` + * `Content-Length` + * `Authorization` + + If this list is empty, then only those headers must be sent. + + Note that `Content-Length` has a special behavior, in that the length + sent must be correct for the actual request to the external authorization + server - that is, it must reflect the actual number of bytes sent in the + body of the request to the authorization server. + + So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + to anything other than `0`, then the `Content-Length` of the authorization + request must be set to the actual number of bytes forwarded. + items: + type: string + type: array + x-kubernetes-list-type: set + allowedResponseHeaders: + description: |- + AllowedResponseHeaders specifies what headers from the authorization response + will be copied into the request to the backend. + + If this list is empty, then all headers from the authorization server + except Authority or Host must be copied. + items: + type: string + type: array + x-kubernetes-list-type: set + path: + description: |- + Path sets the prefix that paths from the client request will have added + when forwarded to the authorization server. + + When empty or unspecified, no prefix is added. + + Valid values are the same as the "value" regex for path values in the `match` + stanza, and the validation regex will screen out invalid paths in the same way. + Even with the validation, implementations MUST sanitize this input before using it + directly. + maxLength: 1024 + pattern: ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$ + type: string + type: object + protocol: + description: |- + ExternalAuthProtocol describes which protocol to use when communicating with an + ext_authz authorization server. + + When this is set to GRPC, each backend must use the Envoy ext_authz protocol + on the port specified in `backendRefs`. Requests and responses are defined + in the protobufs explained at: + https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + + When this is set to HTTP, each backend must respond with a `200` status + code in on a successful authorization. Any other code is considered + an authorization failure. + + Feature Names: + GRPC Support - HTTPRouteExternalAuthGRPC + HTTP Support - HTTPRouteExternalAuthHTTP + enum: + - HTTP + - GRPC + type: string + required: + - backendRef + - protocol + type: object + x-kubernetes-validations: + - message: grpc must be specified when protocol + is set to 'GRPC' + rule: 'self.protocol == ''GRPC'' ? has(self.grpc) + : true' + - message: protocol must be 'GRPC' when grpc is + set + rule: 'has(self.grpc) ? self.protocol == ''GRPC'' + : true' + - message: http must be specified when protocol + is set to 'HTTP' + rule: 'self.protocol == ''HTTP'' ? has(self.http) + : true' + - message: protocol must be 'HTTP' when http is + set + rule: 'has(self.http) ? self.protocol == ''HTTP'' + : true' requestHeaderModifier: description: |- RequestHeaderModifier defines a schema for a filter that modifies request @@ -5013,6 +5795,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -5150,13 +5933,16 @@ spec: rule: '!(has(self.cors) && self.type != ''CORS'')' - message: filter.cors must be specified for CORS filter.type rule: '!(!has(self.cors) && self.type == ''CORS'')' + - message: filter.externalAuth must be nil if the filter.type + is not ExternalAuth + rule: '!(has(self.externalAuth) && self.type != ''ExternalAuth'')' + - message: filter.externalAuth must be specified for + ExternalAuth filter.type + rule: '!(!has(self.externalAuth) && self.type == ''ExternalAuth'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -5262,6 +6048,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -5321,16 +6108,14 @@ spec: AllowCredentials indicates whether the actual cross-origin request allows to include credentials. - The only valid value for the `Access-Control-Allow-Credentials` response - header is true (case-sensitive). + When set to true, the gateway will include the `Access-Control-Allow-Credentials` + response header with value true (case-sensitive). - If the credentials are not allowed in cross-origin requests, the gateway - will omit the header `Access-Control-Allow-Credentials` entirely rather - than setting its value to false. + When set to false or omitted the gateway will omit the header + `Access-Control-Allow-Credentials` entirely (this is the standard CORS + behavior). Support: Extended - enum: - - true type: boolean allowHeaders: description: |- @@ -5357,9 +6142,9 @@ spec: A wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowHeaders` field + When the `AllowCredentials` field is true and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as @@ -5420,9 +6205,9 @@ spec: side. The `Access-Control-Allow-Methods` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowMethods` field + When the `AllowCredentials` field is true and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the @@ -5498,9 +6283,9 @@ spec: Therefore, the client doesn't attempt the actual cross-origin request. The `Access-Control-Allow-Origin` response header can only use `*` - wildcard as value when the `AllowCredentials` field is unspecified. + wildcard as value when the `AllowCredentials` field is false or omitted. - When the `AllowCredentials` field is specified and `AllowOrigins` field + When the `AllowCredentials` field is true and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header @@ -5510,18 +6295,22 @@ spec: Support: Extended items: description: |- - The AbsoluteURI MUST NOT be a relative URI, and it MUST follow the URI syntax and - encoding rules specified in RFC3986. The AbsoluteURI MUST include both a - scheme (e.g., "http" or "spiffe") and a scheme-specific-part. URIs that - include an authority MUST include a fully qualified domain name or + The CORSOrigin MUST NOT be a relative URI, and it MUST follow the URI syntax and + encoding rules specified in RFC3986. The CORSOrigin MUST include both a + scheme (e.g., "http" or "spiffe") and a scheme-specific-part, or it should be a single '*' character. + URIs that include an authority MUST include a fully qualified domain name or IP address as the host. maxLength: 253 minLength: 1 - pattern: ^(([^:/?#]+):)(//([^/?#]*))([^?#]*)(\?([^#]*))?(#(.*))? + pattern: (^\*$)|(^([a-zA-Z][a-zA-Z0-9+\-.]+):\/\/([^:/?#]+)(:([0-9]{1,5}))?$) type: string maxItems: 64 type: array x-kubernetes-list-type: set + x-kubernetes-validations: + - message: AllowOrigins cannot contain '*' alongside + other origins + rule: '!(''*'' in self && self.size() > 1)' exposeHeaders: description: |- ExposeHeaders indicates which HTTP response headers can be exposed @@ -5551,8 +6340,7 @@ spec: A wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only - use `*` wildcard as value when the `AllowCredentials` field is - unspecified. + use `*` wildcard as value when the `AllowCredentials` field is false or omitted. Support: Extended items: @@ -5627,6 +6415,257 @@ spec: - kind - name type: object + externalAuth: + description: |- + ExternalAuth configures settings related to sending request details + to an external auth service. The external service MUST authenticate + the request, and MAY authorize the request as well. + + If there is any problem communicating with the external service, + this filter MUST fail closed. + + Support: Extended + properties: + backendRef: + description: |- + BackendRef is a reference to a backend to send authorization + requests to. + + The backend must speak the selected protocol (GRPC or HTTP) on the + referenced port. + + If the backend service requires TLS, use BackendTLSPolicy to tell the + implementation to supply the TLS details to be used to connect to that + backend. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + forwardBody: + description: |- + ForwardBody controls if requests to the authorization server should include + the body of the client request; and if so, how big that body is allowed + to be. + + It is expected that implementations will buffer the request body up to + `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + 4xx series error (413 or 403 are common examples), and fail processing + of the filter. + + If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + be forwarded. + + Feature Name: HTTPRouteExternalAuthForwardBody + properties: + maxSize: + description: |- + MaxSize specifies how large in bytes the largest body that will be buffered + and sent to the authorization server. If the body size is larger than + `maxSize`, then the body sent to the authorization server must be + truncated to `maxSize` bytes. + + Experimental note: This behavior needs to be checked against + various dataplanes; it may need to be changed. + See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 + for more. + + If 0, the body will not be sent to the authorization server. + type: integer + type: object + grpc: + description: |- + GRPCAuthConfig contains configuration for communication with ext_authz + protocol-speaking backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what headers from the client request + will be sent to the authorization server. + + If this list is empty, then the following headers must be sent: + + - `Authorization` + - `Location` + - `Proxy-Authenticate` + - `Set-Cookie` + - `WWW-Authenticate` + + If the list has entries, only those entries must be sent. + items: + type: string + type: array + x-kubernetes-list-type: set + type: object + http: + description: |- + HTTPAuthConfig contains configuration for communication with HTTP-speaking + backends. + + If unset, implementations must assume the default behavior for each + included field is intended. + properties: + allowedHeaders: + description: |- + AllowedRequestHeaders specifies what additional headers from the client request + will be sent to the authorization server. + + The following headers must always be sent to the authorization server, + regardless of this setting: + + * `Host` + * `Method` + * `Path` + * `Content-Length` + * `Authorization` + + If this list is empty, then only those headers must be sent. + + Note that `Content-Length` has a special behavior, in that the length + sent must be correct for the actual request to the external authorization + server - that is, it must reflect the actual number of bytes sent in the + body of the request to the authorization server. + + So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + to anything other than `0`, then the `Content-Length` of the authorization + request must be set to the actual number of bytes forwarded. + items: + type: string + type: array + x-kubernetes-list-type: set + allowedResponseHeaders: + description: |- + AllowedResponseHeaders specifies what headers from the authorization response + will be copied into the request to the backend. + + If this list is empty, then all headers from the authorization server + except Authority or Host must be copied. + items: + type: string + type: array + x-kubernetes-list-type: set + path: + description: |- + Path sets the prefix that paths from the client request will have added + when forwarded to the authorization server. + + When empty or unspecified, no prefix is added. + + Valid values are the same as the "value" regex for path values in the `match` + stanza, and the validation regex will screen out invalid paths in the same way. + Even with the validation, implementations MUST sanitize this input before using it + directly. + maxLength: 1024 + pattern: ^(?:[-A-Za-z0-9/._~!$&'()*+,;=:@]|[%][0-9a-fA-F]{2})+$ + type: string + type: object + protocol: + description: |- + ExternalAuthProtocol describes which protocol to use when communicating with an + ext_authz authorization server. + + When this is set to GRPC, each backend must use the Envoy ext_authz protocol + on the port specified in `backendRefs`. Requests and responses are defined + in the protobufs explained at: + https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + + When this is set to HTTP, each backend must respond with a `200` status + code in on a successful authorization. Any other code is considered + an authorization failure. + + Feature Names: + GRPC Support - HTTPRouteExternalAuthGRPC + HTTP Support - HTTPRouteExternalAuthHTTP + enum: + - HTTP + - GRPC + type: string + required: + - backendRef + - protocol + type: object + x-kubernetes-validations: + - message: grpc must be specified when protocol is set + to 'GRPC' + rule: 'self.protocol == ''GRPC'' ? has(self.grpc) : + true' + - message: protocol must be 'GRPC' when grpc is set + rule: 'has(self.grpc) ? self.protocol == ''GRPC'' : + true' + - message: http must be specified when protocol is set + to 'HTTP' + rule: 'self.protocol == ''HTTP'' ? has(self.http) : + true' + - message: protocol must be 'HTTP' when http is set + rule: 'has(self.http) ? self.protocol == ''HTTP'' : + true' requestHeaderModifier: description: |- RequestHeaderModifier defines a schema for a filter that modifies request @@ -6236,6 +7275,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -6370,8 +7410,15 @@ spec: rule: '!(has(self.cors) && self.type != ''CORS'')' - message: filter.cors must be specified for CORS filter.type rule: '!(!has(self.cors) && self.type == ''CORS'')' + - message: filter.externalAuth must be nil if the filter.type + is not ExternalAuth + rule: '!(has(self.externalAuth) && self.type != ''ExternalAuth'')' + - message: filter.externalAuth must be specified for ExternalAuth + filter.type + rule: '!(!has(self.externalAuth) && self.type == ''ExternalAuth'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -6683,6 +7730,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -6778,6 +7826,7 @@ spec: minimum: 400 type: integer type: array + x-kubernetes-list-type: atomic type: object sessionPersistence: description: |- @@ -6973,6 +8022,7 @@ spec: != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -7255,11 +8305,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_referencegrants.yaml b/config/crd/experimental/gateway.networking.k8s.io_referencegrants.yaml index a4952e39a6..ac146b270c 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_referencegrants.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_referencegrants.yaml @@ -124,6 +124,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic to: description: |- To describes the resources that may be referenced by the resources @@ -173,6 +174,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic required: - from - to diff --git a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml index 7365304e2a..9de083257d 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml @@ -262,6 +262,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -426,6 +427,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -435,10 +437,13 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string + required: + - backendRefs type: object maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: Rule name must be unique within the route rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) @@ -709,11 +714,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index eaac6b6692..dce65f876b 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -110,6 +110,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -322,6 +323,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -489,6 +491,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -498,15 +501,797 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string + required: + - backendRefs type: object maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: Rule name must be unique within the route + rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) + && l1.name == l2.name)) + required: + - rules + type: object + status: + description: Status defines the current state of TLSRoute. + properties: + parents: + description: |- + Parents is a list of parent resources (usually Gateways) that are + associated with the route, and the status of the route with respect to + each parent. When this route attaches to a parent, the controller that + manages the parent must add an entry to this list when the controller + first sees the route and should update the entry as appropriate when the + route or gateway is modified. + + Note that parent references that cannot be resolved by an implementation + of this API will not be added to this list. Implementations of this API + can only populate Route status for the Gateways/parent resources they are + responsible for. + + A maximum of 32 Gateways will be represented in this list. An empty list + means the route has not been attached to any Gateway. + items: + description: |- + RouteParentStatus describes the status of a route with respect to an + associated Parent. + properties: + conditions: + description: |- + Conditions describes the status of the route with respect to the Gateway. + Note that the route's availability is also subject to the Gateway's own + status conditions and listener status. + + If the Route's ParentRef specifies an existing Gateway that supports + Routes of this kind AND that Gateway's controller has sufficient access, + then that Gateway's controller MUST set the "Accepted" condition on the + Route, to indicate whether the route has been accepted or rejected by the + Gateway, and why. + + A Route MUST be considered "Accepted" if at least one of the Route's + rules is implemented by the Gateway. + + There are a number of cases where the "Accepted" condition may not be set + due to lack of controller visibility, that includes when: + + * The Route refers to a nonexistent parent. + * The Route is of a type that the controller does not support. + * The Route is in a namespace the controller does not have access to. + items: + description: Condition contains details for one aspect of + the current state of this API Resource. + properties: + lastTransitionTime: + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, + Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + maxItems: 8 + minItems: 1 + type: array + x-kubernetes-list-map-keys: + - type + x-kubernetes-list-type: map + controllerName: + description: |- + ControllerName is a domain/path string that indicates the name of the + controller that wrote this status. This corresponds with the + controllerName field on GatewayClass. + + Example: "example.net/gateway-controller". + + The format of this field is DOMAIN "/" PATH, where DOMAIN and PATH are + valid Kubernetes names + (https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names). + + Controllers MUST populate this field when writing status. Controllers should ensure that + entries to status populated with their ControllerName are cleaned up when they are no + longer necessary. + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*\/[A-Za-z0-9\/\-._~%!$&'()*+,;=:]+$ + type: string + parentRef: + description: |- + ParentRef corresponds with a ParentRef in the spec that this + RouteParentStatus struct describes the status of. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + required: + - conditions + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + required: + - parents + type: object + required: + - spec + type: object + served: true + storage: false + subresources: + status: {} + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha3 + schema: + openAPIV3Schema: + description: |- + The TLSRoute resource is similar to TCPRoute, but can be configured + to match against TLS-specific metadata. This allows more flexibility + in matching streams for a given TLS listener. + + If you need to forward traffic to a single target for a TLS listener, you + could choose to use a TCPRoute with a TLS listener. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of TLSRoute. + properties: + hostnames: + description: |- + Hostnames defines a set of SNI hostnames that should match against the + SNI attribute of TLS ClientHello message in TLS handshake. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed in SNI hostnames per RFC 6066. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + If a hostname is specified by both the Listener and TLSRoute, there + must be at least one intersecting hostname for the TLSRoute to be + attached to the Listener. For example: + + * A Listener with `test.example.com` as the hostname matches TLSRoutes + that have specified at least one of `test.example.com` or + `*.example.com`. + * A Listener with `*.example.com` as the hostname matches TLSRoutes + that have specified at least one hostname that matches the Listener + hostname. For example, `test.example.com` and `*.example.com` would both + match. On the other hand, `example.com` and `test.example.net` would not + match. + + If both the Listener and TLSRoute have specified hostnames, any + TLSRoute hostnames that do not match the Listener hostname MUST be + ignored. For example, if a Listener specified `*.example.com`, and the + TLSRoute specified `test.example.com` and `test.example.net`, + `test.example.net` must not be considered for a match. + + If both the Listener and TLSRoute have specified hostnames, and none + match with the criteria above, then the TLSRoute is not accepted. The + implementation must raise an 'Accepted' Condition with a status of + `False` in the corresponding RouteParentStatus. + + Support: Core + items: + description: |- + Hostname is the fully qualified domain name of a network host. This matches + the RFC 1123 definition of a hostname with 2 notable exceptions: + + 1. IPs are not allowed. + 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard + label must appear by itself as the first label. + + Hostname can be "precise" which is a domain name without the terminating + dot of a network host (e.g. "foo.example.com") or "wildcard", which is a + domain name prefixed with a single wildcard label (e.g. `*.example.com`). + + Note that as per RFC1035 and RFC1123, a *label* must consist of lower case + alphanumeric characters or '-', and must start and end with an alphanumeric + character. No other punctuation is allowed. + maxLength: 253 + minLength: 1 + pattern: ^(\*\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + parentRefs: + description: |- + ParentRefs references the resources (usually Gateways) that a Route wants + to be attached to. Note that the referenced parent resource needs to + allow this for the attachment to be complete. For Gateways, that means + the Gateway needs to allow attachment from Routes of this kind and + namespace. For Services, that means the Service must either be in the same + namespace for a "producer" route, or the mesh implementation must support + and allow "consumer" routes for the referenced Service. ReferenceGrant is + not applicable for governing ParentRefs to Services - it is not possible to + create a "producer" route for a Service in a different namespace from the + Route. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + ParentRefs must be _distinct_. This means either that: + + * They select different objects. If this is the case, then parentRef + entries are distinct. In terms of fields, this means that the + multi-part key defined by `group`, `kind`, `namespace`, and `name` must + be unique across all parentRef entries in the Route. + * They do not select different objects, but for each optional field used, + each ParentRef that selects the same object must set the same set of + optional fields to different values. If one ParentRef sets a + combination of optional fields, all must set the same combination. + + Some examples: + + * If one ParentRef sets `sectionName`, all ParentRefs referencing the + same object must also set `sectionName`. + * If one ParentRef sets `port`, all ParentRefs referencing the same + object must also set `port`. + * If one ParentRef sets `sectionName` and `port`, all ParentRefs + referencing the same object must also set `sectionName` and `port`. + + It is possible to separately reference multiple distinct objects that may + be collapsed by an implementation. For example, some implementations may + choose to merge compatible Gateway Listeners together. If that is the + case, the list of routes attached to those resources should also be + merged. + + Note that for ParentRefs that cross namespace boundaries, there are specific + rules. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example, + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable other kinds of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + items: + description: |- + ParentReference identifies an API object (usually a Gateway) that can be considered + a parent of this resource (usually a route). There are two kinds of parent resources + with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + This API may be extended in the future to support additional kinds of parent + resources. + + The API object must be valid in the cluster; the Group and Kind must + be registered in the cluster for this reference to be valid. + properties: + group: + default: gateway.networking.k8s.io + description: |- + Group is the group of the referent. + When unspecified, "gateway.networking.k8s.io" is inferred. + To set the core API group (such as for a "Service" kind referent), + Group must be explicitly set to "" (empty string). + + Support: Core + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Gateway + description: |- + Kind is kind of the referent. + + There are two kinds of parent resources with "Core" support: + + * Gateway (Gateway conformance profile) + * Service (Mesh conformance profile, ClusterIP Services only) + + Support for other resources is Implementation-Specific. + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: |- + Name is the name of the referent. + + Support: Core + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the referent. When unspecified, this refers + to the local namespace of the Route. + + Note that there are specific rules for ParentRefs which cross namespace + boundaries. Cross-namespace references are only valid if they are explicitly + allowed by something in the namespace they are referring to. For example: + Gateway has the AllowedRoutes field, and ReferenceGrant provides a + generic way to enable any other kind of cross-namespace reference. + + + ParentRefs from a Route to a Service in the same namespace are "producer" + routes, which apply default routing rules to inbound connections from + any namespace to the Service. + + ParentRefs from a Route to a Service in a different namespace are + "consumer" routes, and these routing rules are only applied to outbound + connections originating from the same namespace as the Route, for which + the intended destination of the connections are a Service targeted as a + ParentRef of the Route. + + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port is the network port this Route targets. It can be interpreted + differently based on the type of parent resource. + + When the parent resource is a Gateway, this targets all listeners + listening on the specified port that also support this kind of Route(and + select this Route). It's not recommended to set `Port` unless the + networking behaviors specified in a Route must apply to a specific port + as opposed to a listener(s) whose port(s) may be changed. When both Port + and SectionName are specified, the name and port of the selected listener + must match both specified values. + + + When the parent resource is a Service, this targets a specific port in the + Service spec. When both Port (experimental) and SectionName are specified, + the name and port of the selected port must match both specified values. + + + Implementations MAY choose to support other parent resources. + Implementations supporting other types of parent resources MUST clearly + document how/if Port is interpreted. + + For the purpose of status, an attachment is considered successful as + long as the parent resource accepts it partially. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment + from the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, + the Route MUST be considered detached from the Gateway. + + Support: Extended + format: int32 + maximum: 65535 + minimum: 1 + type: integer + sectionName: + description: |- + SectionName is the name of a section within the target resource. In the + following resources, SectionName is interpreted as the following: + + * Gateway: Listener name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + * Service: Port name. When both Port (experimental) and SectionName + are specified, the name and port of the selected listener must match + both specified values. + + Implementations MAY choose to support attaching Routes to other resources. + If that is the case, they MUST clearly document how SectionName is + interpreted. + + When unspecified (empty string), this will reference the entire resource. + For the purpose of status, an attachment is considered successful if at + least one section in the parent resource accepts it. For example, Gateway + listeners can restrict which Routes can attach to them by Route kind, + namespace, or hostname. If 1 of 2 Gateway listeners accept attachment from + the referencing Route, the Route MUST be considered successfully + attached. If no Gateway listeners accept attachment from this Route, the + Route MUST be considered detached from the Gateway. + + Support: Core + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - name + type: object + maxItems: 32 + type: array + x-kubernetes-list-type: atomic + x-kubernetes-validations: + - message: sectionName or port must be specified when parentRefs includes + 2 or more references to the same parent + rule: 'self.all(p1, self.all(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '''') && (!has(p2.__namespace__) || p2.__namespace__ + == '''')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__)) ? ((!has(p1.sectionName) + || p1.sectionName == '''') == (!has(p2.sectionName) || p2.sectionName + == '''') && (!has(p1.port) || p1.port == 0) == (!has(p2.port) + || p2.port == 0)): true))' + - message: sectionName or port must be unique when parentRefs includes + 2 or more references to the same parent + rule: self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind + == p2.kind && p1.name == p2.name && (((!has(p1.__namespace__) + || p1.__namespace__ == '') && (!has(p2.__namespace__) || p2.__namespace__ + == '')) || (has(p1.__namespace__) && has(p2.__namespace__) && + p1.__namespace__ == p2.__namespace__ )) && (((!has(p1.sectionName) + || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName + == '')) || ( has(p1.sectionName) && has(p2.sectionName) && p1.sectionName + == p2.sectionName)) && (((!has(p1.port) || p1.port == 0) && (!has(p2.port) + || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port + == p2.port)))) + rules: + description: Rules are a list of actions. + items: + description: TLSRouteRule is the configuration for a given rule. + properties: + backendRefs: + description: |- + BackendRefs defines the backend(s) where matching requests should be + sent. If unspecified or invalid (refers to a nonexistent resource or + a Service with no endpoints), the rule performs no forwarding; if no + filters are specified that would result in a response being sent, the + underlying implementation must actively reject request attempts to this + backend, by rejecting the connection or returning a 500 status code. + Request rejections must respect weight; if an invalid backend is + requested to have 80% of requests, then 80% of requests must be rejected + instead. + + Support: Core for Kubernetes Service + + Support: Extended for Kubernetes ServiceImport + + Support: Implementation-specific for any other resource + + Support for weight: Extended + items: + description: |- + BackendRef defines how a Route should forward a request to a Kubernetes + resource. + + Note that when a namespace different than the local namespace is specified, a + ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + + When the BackendRef points to a Kubernetes Service, implementations SHOULD + honor the appProtocol field if it is set for the target Service Port. + + Implementations supporting appProtocol SHOULD recognize the Kubernetes + Standard Application Protocols defined in KEP-3726. + + 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. + + If a Route is not able to send traffic to the backend using the specified + protocol then the backend is considered invalid. Implementations MUST set the + "ResolvedRefs" condition to "False" with the "UnsupportedProtocol" reason. + + + Note that when the BackendTLSPolicy object is enabled by the implementation, + there are some extra rules about validity to consider here. See the fields + where this struct is used for more information about the exact behavior. + properties: + group: + default: "" + description: |- + Group is the group of the referent. For example, "gateway.networking.k8s.io". + When unspecified or empty string, core API group is inferred. + maxLength: 253 + pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + kind: + default: Service + description: |- + Kind is the Kubernetes resource kind of the referent. For example + "Service". + + Defaults to "Service" when not specified. + + ExternalName services can refer to CNAME DNS records that may live + outside of the cluster and as such are difficult to reason about in + terms of conformance. They also may not be safe to forward to (see + CVE-2021-25740 for more information). Implementations SHOULD NOT + support ExternalName Services. + + Support: Core (Services with a type other than ExternalName) + + Support: Implementation-specific (Services with type ExternalName) + maxLength: 63 + minLength: 1 + pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ + type: string + name: + description: Name is the name of the referent. + maxLength: 253 + minLength: 1 + type: string + namespace: + description: |- + Namespace is the namespace of the backend. When unspecified, the local + namespace is inferred. + + Note that when a namespace different than the local namespace is specified, + a ReferenceGrant object is required in the referent namespace to allow that + namespace's owner to accept the reference. See the ReferenceGrant + documentation for details. + + Support: Core + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + type: string + port: + description: |- + Port specifies the destination port number to use for this resource. + Port is required when the referent is a Kubernetes Service. In this + case, the port number is the service port number, not the target port. + For other resources, destination port might be derived from the referent + resource or this field. + format: int32 + maximum: 65535 + minimum: 1 + type: integer + weight: + default: 1 + description: |- + Weight specifies the proportion of requests forwarded to the referenced + backend. This is computed as weight/(sum of all weights in this + BackendRefs list). For non-zero values, there may be some epsilon from + the exact proportion defined here depending on the precision an + implementation supports. Weight is not a percentage and the sum of + weights does not need to equal 100. + + If only one backend is specified and it has a weight greater than 0, 100% + of the traffic is forwarded to that backend. If weight is set to 0, no + traffic should be forwarded for this entry. If unspecified, weight + defaults to 1. + + Support for this field varies based on the context where used. + format: int32 + maximum: 1000000 + minimum: 0 + type: integer + required: + - name + type: object + x-kubernetes-validations: + - message: Must have port for Service reference + rule: '(size(self.group) == 0 && self.kind == ''Service'') + ? has(self.port) : true' + maxItems: 16 + minItems: 1 + type: array + x-kubernetes-list-type: atomic + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string + required: + - backendRefs + type: object + maxItems: 1 + minItems: 1 + type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: Rule name must be unique within the route rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name)) required: + - hostnames - rules type: object status: @@ -772,11 +1557,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml index 5ef205c1d2..1f7be3d34c 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml @@ -262,6 +262,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName or port must be specified when parentRefs includes 2 or more references to the same parent @@ -426,6 +427,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic name: description: |- Name is the name of the route rule. This name MUST be unique within a Route if it is set. @@ -435,10 +437,13 @@ spec: minLength: 1 pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string + required: + - backendRefs type: object maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: Rule name must be unique within the route rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) @@ -709,11 +714,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object diff --git a/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml b/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml index a4674dec56..3e6d06b210 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml @@ -583,10 +583,12 @@ spec: type: string required: - ancestorRef + - conditions - controllerName type: object maxItems: 16 type: array + x-kubernetes-list-type: atomic required: - ancestors type: object diff --git a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml index 5176322413..6d5a5bd5f9 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml @@ -34,8 +34,33 @@ spec: schema: openAPIV3Schema: description: |- - XListenerSet defines a set of additional listeners - to attach to an existing Gateway. + XListenerSet defines a set of additional listeners to attach to an existing Gateway. + This resource provides a mechanism to merge multiple listeners into a single Gateway. + + The parent Gateway must explicitly allow ListenerSet attachment through its + AllowedListeners configuration. By default, Gateways do not allow ListenerSet + attachment. + + Routes can attach to a ListenerSet by specifying it as a parentRef, and can + optionally target specific listeners using the sectionName field. + + Policy Attachment: + - Policies that attach to a ListenerSet apply to all listeners defined in that resource + - Policies do not impact listeners in the parent Gateway + - Different ListenerSets attached to the same Gateway can have different policies + - If an implementation cannot apply a policy to specific listeners, it should reject the policy + + ReferenceGrant Semantics: + - ReferenceGrants applied to a Gateway are not inherited by child ListenerSets + - ReferenceGrants applied to a ListenerSet do not grant permission to the parent Gateway's listeners + - A ListenerSet can reference secrets/backends in its own namespace without a ReferenceGrant + + Gateway Integration: + - The parent Gateway's status will include an "AttachedListenerSets" condition + - This condition will be: + - True: when AllowedListeners is set and at least one child ListenerSet is attached + - False: when AllowedListeners is set but no valid listeners are attached, or when AllowedListeners is not set or false + - Unknown: when no AllowedListeners config is present properties: apiVersion: description: |- @@ -73,10 +98,10 @@ spec: 1. "parent" Gateway 2. ListenerSet ordered by creation time (oldest first) - 3. ListenerSet ordered alphabetically by “{namespace}/{name}”. + 3. ListenerSet ordered alphabetically by "{namespace}/{name}". An implementation MAY reject listeners by setting the ListenerEntryStatus - `Accepted`` condition to False with the Reason `TooManyListeners` + `Accepted` condition to False with the Reason `TooManyListeners` If a listener has a conflict, this will be reported in the Status.ListenerEntryStatus setting the `Conflicted` condition to True. @@ -149,6 +174,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -271,12 +297,18 @@ spec: pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ type: string port: + default: 0 description: |- Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules. + + If the port is not set or specified as zero, the implementation will assign + a unique port. If the implementation does not support dynamic port + assignment, it MUST set `Accepted` condition to `False` with the + `UnsupportedPort` reason. format: int32 maximum: 65535 - minimum: 1 + minimum: 0 type: integer protocol: description: Protocol specifies the network protocol this listener @@ -291,7 +323,7 @@ spec: the Protocol field is "HTTPS" or "TLS". It is invalid to set this field if the Protocol field is "HTTP", "TCP", or "UDP". - The association of SNIs to Certificate defined in GatewayTLSConfig is + The association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener. The GatewayClass MUST use the longest matching SNI out of all @@ -376,93 +408,7 @@ spec: type: object maxItems: 64 type: array - frontendValidation: - description: |- - FrontendValidation holds configuration information for validating the frontend (client). - Setting this field will require clients to send a client certificate - required for validation during the TLS handshake. In browsers this may result in a dialog appearing - that requests a user to specify the client certificate. - The maximum depth of a certificate chain accepted in verification is Implementation specific. - - Support: Extended - properties: - caCertificateRefs: - description: |- - CACertificateRefs contains one or more references to - Kubernetes objects that contain TLS certificates of - the Certificate Authorities that can be used - as a trust anchor to validate the certificates presented by the client. - - A single CA certificate reference to a Kubernetes ConfigMap - has "Core" support. - Implementations MAY choose to support attaching multiple CA certificates to - a Listener, but this behavior is implementation-specific. - - Support: Core - A single reference to a Kubernetes ConfigMap - with the CA certificate in a key named `ca.crt`. - - Support: Implementation-specific (More than one reference, or other kinds - of resources). - - References to a resource in a different namespace are invalid UNLESS there - is a ReferenceGrant in the target namespace that allows the certificate - to be attached. If a ReferenceGrant does not allow this reference, the - "ResolvedRefs" condition MUST be set to False for this listener with the - "RefNotPermitted" reason. - items: - description: |- - ObjectReference identifies an API object including its namespace. - - The API object must be valid in the cluster; the Group and Kind must - be registered in the cluster for this reference to be valid. - - References to objects with invalid Group and Kind are not valid, and must - be rejected by the implementation, with appropriate Conditions set - on the containing object. - properties: - group: - description: |- - Group is the group of the referent. For example, "gateway.networking.k8s.io". - When set to the empty string, core API group is inferred. - maxLength: 253 - pattern: ^$|^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ - type: string - kind: - description: Kind is kind of the referent. For - example "ConfigMap" or "Service". - maxLength: 63 - minLength: 1 - pattern: ^[a-zA-Z]([-a-zA-Z0-9]*[a-zA-Z0-9])?$ - type: string - name: - description: Name is the name of the referent. - maxLength: 253 - minLength: 1 - type: string - namespace: - description: |- - Namespace is the namespace of the referenced object. When unspecified, the local - namespace is inferred. - - Note that when a namespace different than the local namespace is specified, - a ReferenceGrant object is required in the referent namespace to allow that - namespace's owner to accept the reference. See the ReferenceGrant - documentation for details. - - Support: Core - maxLength: 63 - minLength: 1 - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string - required: - - group - - kind - - name - type: object - maxItems: 8 - minItems: 1 - type: array - type: object + x-kubernetes-list-type: atomic mode: default: Terminate description: |- @@ -514,7 +460,6 @@ spec: > 0 || size(self.options) > 0 : true' required: - name - - port - protocol type: object maxItems: 64 @@ -814,6 +759,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions diff --git a/config/crd/standard/gateway.networking.k8s.io_gateways.yaml b/config/crd/standard/gateway.networking.k8s.io_gateways.yaml index 2952481bdb..8b7b0a02e5 100644 --- a/config/crd/standard/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_gateways.yaml @@ -126,6 +126,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: IPAddress values must be unique rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, @@ -488,6 +489,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -655,7 +657,7 @@ spec: the Protocol field is "HTTPS" or "TLS". It is invalid to set this field if the Protocol field is "HTTP", "TCP", or "UDP". - The association of SNIs to Certificate defined in GatewayTLSConfig is + The association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener. The GatewayClass MUST use the longest matching SNI out of all @@ -742,6 +744,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic mode: default: Terminate description: |- @@ -894,6 +897,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -1107,6 +1111,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions @@ -1232,6 +1237,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: IPAddress values must be unique rule: 'self.all(a1, a1.type == ''IPAddress'' ? self.exists_one(a2, @@ -1594,6 +1600,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -1761,7 +1768,7 @@ spec: the Protocol field is "HTTPS" or "TLS". It is invalid to set this field if the Protocol field is "HTTP", "TCP", or "UDP". - The association of SNIs to Certificate defined in GatewayTLSConfig is + The association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener. The GatewayClass MUST use the longest matching SNI out of all @@ -1848,6 +1855,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic mode: default: Terminate description: |- @@ -2000,6 +2008,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -2213,6 +2222,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 3bbc0af4ca..4e81b08878 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -151,6 +151,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -334,6 +335,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName must be specified when parentRefs includes 2 or more references to the same parent @@ -937,6 +939,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: RequestHeaderModifier filter cannot be repeated rule: self.filter(f, f.type == 'RequestHeaderModifier').size() @@ -1033,6 +1036,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -1583,6 +1587,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: RequestHeaderModifier filter cannot be repeated rule: self.filter(f, f.type == 'RequestHeaderModifier').size() @@ -1760,9 +1765,20 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string type: object maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -2030,14 +2046,18 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 7f3b970a7a..dfa6af4c77 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -131,6 +131,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -314,6 +315,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName must be specified when parentRefs includes 2 or more references to the same parent @@ -1190,11 +1192,8 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -1300,6 +1299,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -2121,6 +2121,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -2432,6 +2433,16 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string timeouts: description: |- Timeouts defines the timeouts that can be configured for an HTTP request. @@ -2537,6 +2548,7 @@ spec: != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -2798,11 +2810,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object @@ -2926,6 +2940,7 @@ spec: type: string maxItems: 16 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -3109,6 +3124,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: sectionName must be specified when parentRefs includes 2 or more references to the same parent @@ -3985,11 +4001,8 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - - message: May specify either httpRouteFilterRequestRedirect - or httpRouteFilterRequestRewrite, but not both - rule: '!(self.exists(f, f.type == ''RequestRedirect'') - && self.exists(f, f.type == ''URLRewrite''))' - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both rule: '!(self.exists(f, f.type == ''RequestRedirect'') @@ -4095,6 +4108,7 @@ spec: ? has(self.port) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic filters: description: |- Filters define the filters that are applied to requests that match @@ -4916,6 +4930,7 @@ spec: rule: '!(!has(self.extensionRef) && self.type == ''ExtensionRef'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -5227,6 +5242,16 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic + name: + description: |- + Name is the name of the route rule. This name MUST be unique within a Route if it is set. + + Support: Extended + maxLength: 253 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$ + type: string timeouts: description: |- Timeouts defines the timeouts that can be configured for an HTTP request. @@ -5332,6 +5357,7 @@ spec: != ''PathPrefix'') ? false : true) : true' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: While 16 rules and 64 matches per rule are allowed, the total number of matches across all rules in a route must be less @@ -5593,11 +5619,13 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object diff --git a/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml b/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml index da71ceaac4..6a2d368971 100644 --- a/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml @@ -124,6 +124,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic to: description: |- To describes the resources that may be referenced by the resources @@ -173,6 +174,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic required: - from - to diff --git a/conformance/base/manifests.yaml b/conformance/base/manifests.yaml index a3163bf837..d8f8c45a1c 100644 --- a/conformance/base/manifests.yaml +++ b/conformance/base/manifests.yaml @@ -95,6 +95,39 @@ spec: matchLabels: gateway-conformance: backend --- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: gateway-backendtlspolicy + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + listeners: + - name: http + port: 80 + protocol: HTTP + hostname: "abc.example.com" + allowedRoutes: + namespaces: + from: Same + kinds: + - kind: HTTPRoute + - name: https + port: 443 + protocol: HTTPS + tls: + mode: Terminate + certificateRefs: + - group: "" + kind: Secret + name: tls-checks-certificate + hostname: "abc.example.com" + allowedRoutes: + namespaces: + from: Same + kinds: + - kind: HTTPRoute +--- apiVersion: v1 kind: Service metadata: @@ -138,7 +171,7 @@ spec: spec: containers: - name: infra-backend-v1 - # From https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/images/echoserver + # Originally from https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/images/echoserver image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd env: - name: POD_NAME @@ -300,7 +333,7 @@ spec: volumes: - name: secret-volume secret: - secretName: tls-passthrough-checks-certificate + secretName: tls-checks-certificate items: - key: tls.crt path: crt diff --git a/conformance/conformance.go b/conformance/conformance.go index ce264a9441..ce7a465c60 100644 --- a/conformance/conformance.go +++ b/conformance/conformance.go @@ -144,6 +144,7 @@ func logOptions(t *testing.T, opts suite.ConformanceOptions) { t.Logf(" Enable All Features: %t", opts.EnableAllSupportedFeatures) t.Logf(" Supported Features: %v", opts.SupportedFeatures.UnsortedList()) t.Logf(" ExemptFeatures: %v", opts.ExemptFeatures.UnsortedList()) + t.Logf(" ConformanceProfiles: %v", opts.ConformanceProfiles.UnsortedList()) } func writeReport(logf func(string, ...any), report confv1.ConformanceReport, output string) error { diff --git a/conformance/reports/v1.1.0/airlock-microgateway/README.md b/conformance/reports/v1.1.0/airlock-microgateway/README.md index c746409217..37084e909e 100644 --- a/conformance/reports/v1.1.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.1.0/airlock-microgateway/README.md @@ -4,19 +4,20 @@ | API channel | Implementation version | Mode | Report | |--------------|----------------------------------------------------------------------|---------|--------------------------------------------------| -| experimental | [v4.4.0](https://github.com/airlock/microgateway/releases/tag/4.4.0) | default | [v4.4.0 report](./experimental-4.4.0-default-report.yaml) | -| standard | [v4.5.0](https://github.com/airlock/microgateway/releases/tag/4.5.0) | default | [v4.5.0 report](./standard-4.5.0-default-report.yaml) | - +| experimental | [v4.4.0](https://github.com/airlock/microgateway/releases/tag/4.4.0) | default | [link](./experimental-4.4.0-default-report.yaml) | +| standard | [v4.5.0](https://github.com/airlock/microgateway/releases/tag/4.5.0) | default | [link](./standard-4.5.0-default-report.yaml) | +| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [link](./standard-4.6.0-default-report.yaml) | +| standard | [v4.7.0](https://github.com/airlock/microgateway/releases/tag/4.7.0) | default | [link](./standard-4.7.0-default-report.yaml) | ## Reproduce -The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/conformance.md) on GitHub. +The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/conformance.md) on GitHub. > [!NOTE] > The `HTTPRouteWeight` test fires 10 concurrent request to 3 backends totaling in 500 requests to assert a distribution that matches the configured weight. -> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. +> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/?topic=MGW-00000056) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. > To successfully pass this test a [premium license](https://www.airlock.com/en/secure-access-hub/components/microgateway/premium-edition) is required. > > The Airlock Microgateway drops all request headers except for a well-known built-in standard and tracing headers list (e.g., Accept, Cookie, X-CSRF-TOKEN) to reduce the attack surface. -> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. -> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. \ No newline at end of file +> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. +> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. diff --git a/conformance/reports/v1.1.0/airlock-microgateway/standard-4.6.0-default-report.yaml b/conformance/reports/v1.1.0/airlock-microgateway/standard-4.6.0-default-report.yaml new file mode 100644 index 0000000000..5152c07e47 --- /dev/null +++ b/conformance/reports/v1.1.0/airlock-microgateway/standard-4.6.0-default-report.yaml @@ -0,0 +1,47 @@ +apiVersion: gateway.networking.k8s.io/v1alpha1 +date: "2025-05-19T14:32:51Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.1.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.6.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + supportedFeatures: + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.1.0/airlock-microgateway/standard-4.7.0-default-report.yaml b/conformance/reports/v1.1.0/airlock-microgateway/standard-4.7.0-default-report.yaml new file mode 100644 index 0000000000..37091df4ee --- /dev/null +++ b/conformance/reports/v1.1.0/airlock-microgateway/standard-4.7.0-default-report.yaml @@ -0,0 +1,47 @@ +apiVersion: gateway.networking.k8s.io/v1alpha1 +date: "2025-08-25T13:36:52Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.1.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.7.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + supportedFeatures: + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.1.1/airlock-microgateway/README.md b/conformance/reports/v1.1.1/airlock-microgateway/README.md index 27868c3f1f..66143c04c5 100644 --- a/conformance/reports/v1.1.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.1.1/airlock-microgateway/README.md @@ -5,16 +5,18 @@ | API channel | Implementation version | Mode | Report | |-------------|----------------------------------------------------------------------|---------|----------------------------------------------| | standard | [v4.5.0](https://github.com/airlock/microgateway/releases/tag/4.5.0) | default | [link](./standard-4.5.0-default-report.yaml) | +| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [link](./standard-4.6.0-default-report.yaml) | +| standard | [v4.7.0](https://github.com/airlock/microgateway/releases/tag/4.7.0) | default | [link](./standard-4.7.0-default-report.yaml) | ## Reproduce -The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/conformance.md) on GitHub. +The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/conformance.md) on GitHub. > [!NOTE] > The `HTTPRouteWeight` test fires 10 concurrent request to 3 backends totaling in 500 requests to assert a distribution that matches the configured weight. -> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. +> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/?topic=MGW-00000056) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. > To successfully pass this test a [premium license](https://www.airlock.com/en/secure-access-hub/components/microgateway/premium-edition) is required. > > The Airlock Microgateway drops all request headers except for a well-known built-in standard and tracing headers list (e.g., Accept, Cookie, X-CSRF-TOKEN) to reduce the attack surface. -> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. -> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. \ No newline at end of file +> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. +> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. diff --git a/conformance/reports/v1.1.1/airlock-microgateway/standard-4.6.0-default-report.yaml b/conformance/reports/v1.1.1/airlock-microgateway/standard-4.6.0-default-report.yaml new file mode 100644 index 0000000000..93c2a25197 --- /dev/null +++ b/conformance/reports/v1.1.1/airlock-microgateway/standard-4.6.0-default-report.yaml @@ -0,0 +1,47 @@ +apiVersion: gateway.networking.k8s.io/v1alpha1 +date: "2025-05-19T14:32:48Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.1.1 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.6.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + supportedFeatures: + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.1.1/airlock-microgateway/standard-4.7.0-default-report.yaml b/conformance/reports/v1.1.1/airlock-microgateway/standard-4.7.0-default-report.yaml new file mode 100644 index 0000000000..3bc63624b0 --- /dev/null +++ b/conformance/reports/v1.1.1/airlock-microgateway/standard-4.7.0-default-report.yaml @@ -0,0 +1,47 @@ +apiVersion: gateway.networking.k8s.io/v1alpha1 +date: "2025-08-25T13:37:05Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.1.1 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.7.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + supportedFeatures: + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.2.0/airlock-microgateway/README.md b/conformance/reports/v1.2.0/airlock-microgateway/README.md index 27868c3f1f..66143c04c5 100644 --- a/conformance/reports/v1.2.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.0/airlock-microgateway/README.md @@ -5,16 +5,18 @@ | API channel | Implementation version | Mode | Report | |-------------|----------------------------------------------------------------------|---------|----------------------------------------------| | standard | [v4.5.0](https://github.com/airlock/microgateway/releases/tag/4.5.0) | default | [link](./standard-4.5.0-default-report.yaml) | +| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [link](./standard-4.6.0-default-report.yaml) | +| standard | [v4.7.0](https://github.com/airlock/microgateway/releases/tag/4.7.0) | default | [link](./standard-4.7.0-default-report.yaml) | ## Reproduce -The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/conformance.md) on GitHub. +The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/conformance.md) on GitHub. > [!NOTE] > The `HTTPRouteWeight` test fires 10 concurrent request to 3 backends totaling in 500 requests to assert a distribution that matches the configured weight. -> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. +> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/?topic=MGW-00000056) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. > To successfully pass this test a [premium license](https://www.airlock.com/en/secure-access-hub/components/microgateway/premium-edition) is required. > > The Airlock Microgateway drops all request headers except for a well-known built-in standard and tracing headers list (e.g., Accept, Cookie, X-CSRF-TOKEN) to reduce the attack surface. -> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. -> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. \ No newline at end of file +> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. +> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. diff --git a/conformance/reports/v1.2.0/airlock-microgateway/standard-4.6.0-default-report.yaml b/conformance/reports/v1.2.0/airlock-microgateway/standard-4.6.0-default-report.yaml new file mode 100644 index 0000000000..cce72e9086 --- /dev/null +++ b/conformance/reports/v1.2.0/airlock-microgateway/standard-4.6.0-default-report.yaml @@ -0,0 +1,53 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-19T14:33:20Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.6.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.2.0/airlock-microgateway/standard-4.7.0-default-report.yaml b/conformance/reports/v1.2.0/airlock-microgateway/standard-4.7.0-default-report.yaml new file mode 100644 index 0000000000..af660c0276 --- /dev/null +++ b/conformance/reports/v1.2.0/airlock-microgateway/standard-4.7.0-default-report.yaml @@ -0,0 +1,53 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-25T13:37:00Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.7.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.2.1/airlock-microgateway/README.md b/conformance/reports/v1.2.1/airlock-microgateway/README.md index 6e691ffb1e..e6c945bede 100644 --- a/conformance/reports/v1.2.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.1/airlock-microgateway/README.md @@ -5,16 +5,18 @@ | API channel | Implementation version | Mode | Report | |--------------|----------------------------------------------------------------------|---------|--------------------------------------------------| | experimental | [v4.5.0](https://github.com/airlock/microgateway/releases/tag/4.5.0) | default | [link](./experimental-4.5.0-default-report.yaml) | +| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [link](./standard-4.6.0-default-report.yaml) | +| standard | [v4.7.0](https://github.com/airlock/microgateway/releases/tag/4.7.0) | default | [link](./standard-4.7.0-default-report.yaml) | ## Reproduce -The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/conformance.md) on GitHub. +The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/conformance.md) on GitHub. > [!NOTE] > The `HTTPRouteWeight` test fires 10 concurrent request to 3 backends totaling in 500 requests to assert a distribution that matches the configured weight. -> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/#data/1675772882054.html) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. +> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/?topic=MGW-00000056) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. > To successfully pass this test a [premium license](https://www.airlock.com/en/secure-access-hub/components/microgateway/premium-edition) is required. > > The Airlock Microgateway drops all request headers except for a well-known built-in standard and tracing headers list (e.g., Accept, Cookie, X-CSRF-TOKEN) to reduce the attack surface. -> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/examples/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. -> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. \ No newline at end of file +> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. +> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. diff --git a/conformance/reports/v1.2.1/airlock-microgateway/standard-4.6.0-default-report.yaml b/conformance/reports/v1.2.1/airlock-microgateway/standard-4.6.0-default-report.yaml new file mode 100644 index 0000000000..0589d7e379 --- /dev/null +++ b/conformance/reports/v1.2.1/airlock-microgateway/standard-4.6.0-default-report.yaml @@ -0,0 +1,53 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-19T14:36:18Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.1 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.6.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.2.1/airlock-microgateway/standard-4.7.0-default-report.yaml b/conformance/reports/v1.2.1/airlock-microgateway/standard-4.7.0-default-report.yaml new file mode 100644 index 0000000000..53f5311c92 --- /dev/null +++ b/conformance/reports/v1.2.1/airlock-microgateway/standard-4.7.0-default-report.yaml @@ -0,0 +1,53 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-25T13:37:50Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.1 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.7.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.2.1/azure-application-gateway-for-containers/README.md b/conformance/reports/v1.2.1/azure-application-gateway-for-containers/README.md new file mode 100644 index 0000000000..22b7f94910 --- /dev/null +++ b/conformance/reports/v1.2.1/azure-application-gateway-for-containers/README.md @@ -0,0 +1,13 @@ +# Azure Application Gateway for Containers + +[Application Gateway for Containers][azure-application-gateway-for-containers] is a managed application (layer 7) load balancing solution, providing dynamic traffic management capabilities for workloads running in a Kubernetes cluster in Azure. Follow the [quickstart guide][azure-application-gateway-for-containers-quickstart-controller] to deploy the ALB controller and get started with Gateway API. + +## Table of Contents + +|API channel|Implementation version|Mode|Report| +|-----------|----------------------|----|------| +|standard|[v1.2.1](https://learn.microsoft.com/azure/application-gateway/for-containers/alb-controller-release-notes#latest-release-recommended)|default|[v1.2.1 report](./standard-v1.2.1-default-report.yaml)| + + +[azure-application-gateway-for-containers]:https://aka.ms/appgwcontainers/docs +[azure-application-gateway-for-containers-quickstart-controller]:https://aka.ms/appgwcontainers/docs diff --git a/conformance/reports/v1.2.1/azure-application-gateway-for-containers/standard-v1.2.1-default-report.yaml b/conformance/reports/v1.2.1/azure-application-gateway-for-containers/standard-v1.2.1-default-report.yaml new file mode 100644 index 0000000000..b15b81ef39 --- /dev/null +++ b/conformance/reports/v1.2.1/azure-application-gateway-for-containers/standard-v1.2.1-default-report.yaml @@ -0,0 +1,59 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-07-18T23:02:29Z" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.1 +implementation: + organization: Microsoft Azure + project: Application Gateway for Containers + url: https://aka.ms/appgwcontainers/docs + version: "1.7.9" + contact: + - agcfeedback@microsoft.com +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + name: GATEWAY-GRPC + summary: Core tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 9 + Skipped: 0 + supportedFeatures: + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteParentRefPort + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.2.1/kubvernor/README.md b/conformance/reports/v1.2.1/kubvernor/README.md new file mode 100644 index 0000000000..56b93da84f --- /dev/null +++ b/conformance/reports/v1.2.1/kubvernor/README.md @@ -0,0 +1,51 @@ +# Kubvernor + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|:-------------:|:------------------------------------------------------------------:|:-------------:|:--------------------------------------------------:| +|standard |[v0.1.0](https://github.com/kubvernor/kubvernor/releases/tag/0.1.0) |default |[Report](./kubvernor-conformance-output-1.2.1.yaml) | + + + + +## Reproduce + +0. Install Docker and Kind + +1. Clone the Kubvernor GitHub repository + + ```bash + git clone https://github.com/kubvernor/kubvernor && cd kubvernor + ``` + +2. Deploy your cluster + + ```bash + curl --proto '=https' --tlsv1.2 -sSf https://github.com/kubernetes-sigs/gateway-api/blob/main/hack/implementations/common/create-cluster.sh | sh + + ``` + +3. Compile and run Kubvernor + + ```bash + # Install Rust + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh + + # Start Kubvernor + export CONTROL_PLANE_IP= + ./run_kubvernor.sh + + ``` + +4. Run conformance tests + + ```bash + ./run_conformance_tests.sh + ``` + +5. Check the results + + ```bash + cat conformance/kubvernor-conformance-output-1.2.1.yaml + ``` diff --git a/conformance/reports/v1.2.1/kubvernor/kubvernor-conformance-output-1.2.1.yaml b/conformance/reports/v1.2.1/kubvernor/kubvernor-conformance-output-1.2.1.yaml new file mode 100644 index 0000000000..c5002fbec1 --- /dev/null +++ b/conformance/reports/v1.2.1/kubvernor/kubvernor-conformance-output-1.2.1.yaml @@ -0,0 +1,30 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-24T16:25:25+01:00" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.2.1 +implementation: + contact: + - nowakd@gmail.com + organization: kubvernor + project: kubvernor + url: https://github.com/kubvernor/kubvernor + version: 0.1.0 +kind: ConformanceReport +mode: default +profiles: + - core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + name: GATEWAY-GRPC + summary: Core tests succeeded. + - core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + name: GATEWAY-HTTP + summary: Core tests succeeded. diff --git a/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/README.md b/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/README.md index 75cbb4c14b..ab4c83009e 100644 --- a/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/README.md +++ b/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/README.md @@ -5,6 +5,7 @@ | API channel | Implementation version | Mode | Report | |--------------|-----------------------------------------------------------------------------|---------|--------------------------------------------------| | experimental | [v1.6.0](https://github.com/nginx/nginx-gateway-fabric/releases/tag/v1.6.0) | default | [v1.6.0 report](./experimental-1.6.0-default-report.yaml) | +| experimental | [v2.0.2](https://github.com/nginx/nginx-gateway-fabric/releases/tag/v2.0.2) | default | [v2.0.2 report](./experimental-2.0.2-default-report.yaml) | ## Reproduce diff --git a/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/experimental-2.0.2-default-report.yaml b/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/experimental-2.0.2-default-report.yaml new file mode 100644 index 0000000000..6f42f47e4a --- /dev/null +++ b/conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/experimental-2.0.2-default-report.yaml @@ -0,0 +1,93 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-07-25T15:36:44Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.2.1 +implementation: + contact: + - https://github.com/nginx/nginx-gateway-fabric/discussions/new/choose + organization: nginx + project: nginx-gateway-fabric + url: https://github.com/nginx/nginx-gateway-fabric + version: v2.0.2 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 14 + Skipped: 0 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteParentRefPort + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.2.1/projectcontour-contour/README.md b/conformance/reports/v1.2.1/projectcontour-contour/README.md new file mode 100644 index 0000000000..2023c68db3 --- /dev/null +++ b/conformance/reports/v1.2.1/projectcontour-contour/README.md @@ -0,0 +1,48 @@ +# Projectcontour Contour + +## Table of Contents + +|API channel|Implementation version|Mode|Report| +|-----------|----------------------|----|------| +|experimental|[v1.31.0](https://github.com/projectcontour/contour/releases/tag/v1.31.0)|x|[v1.31.0 report](./experimental-v1.31.0-default-report.yaml)| + +## Reproduce + +### Prerequisites + +Follow the Contour [contribution guide][0] documentation for setting up your local development environment, which includes ensuring `kubectl`, `docker`, `kinD`, and other tools are installed. + +### Steps + +1. Clone the Contour GitHub repository + + ```bash + git clone https://github.com/projectcontour/contour && cd contour + ``` + +2. Check out the desired version + + ```bash + export VERSION=v + git checkout $VERSION + ``` + +3. Run the conformance tests + + ```bash + export CONTOUR_E2E_IMAGE="ghcr.io/projectcontour/contour:$VERSION" + export GENERATE_GATEWAY_CONFORMANCE_REPORT="true" + make setup-kind-cluster run-gateway-conformance cleanup-kind + ``` + + Note: you can omit the `cleanup-kind` target if you would prefer to keep the `kinD` cluster. + +4. Check the produced report + + ```bash + cat gateway-conformance-report/projectcontour-contour-*.yaml + ``` + + Note: you can set `GATEWAY_CONFORMANCE_REPORT_OUTDIR` before running the tests to customize the output location. + +[0]: https://github.com/projectcontour/contour/blob/main/CONTRIBUTING.md#building-from-source diff --git a/conformance/reports/v1.2.1/projectcontour-contour/experimental-v1.31.0-default-report.yaml b/conformance/reports/v1.2.1/projectcontour-contour/experimental-v1.31.0-default-report.yaml new file mode 100644 index 0000000000..b3c0be99d4 --- /dev/null +++ b/conformance/reports/v1.2.1/projectcontour-contour/experimental-v1.31.0-default-report.yaml @@ -0,0 +1,101 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-06T14:44:31-04:00" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.2.1 +implementation: + contact: + - '@projectcontour/maintainers' + organization: projectcontour + project: contour + url: https://projectcontour.io/ + version: v1.31.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: partial + skippedTests: + - HTTPRouteHTTPSListener + statistics: + Failed: 0 + Passed: 32 + Skipped: 1 + extended: + result: partial + skippedTests: + - GatewayStaticAddresses + - HTTPRouteInvalidParentRefSectionNameNotMatchingPort + - HTTPRouteRedirectPortAndScheme + statistics: + Failed: 0 + Passed: 20 + Skipped: 3 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + name: GATEWAY-HTTP + summary: Core tests partially succeeded with 1 test skips. Extended tests partially + succeeded with 3 test skips. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: partial + skippedTests: + - GatewayStaticAddresses + statistics: + Failed: 0 + Passed: 1 + Skipped: 1 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests partially succeeded with 1 test skips. +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: partial + skippedTests: + - GatewayStaticAddresses + statistics: + Failed: 0 + Passed: 1 + Skipped: 1 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests partially succeeded with 1 test skips. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.3.0/agentgateway-agentgateway/README.md b/conformance/reports/v1.3.0/agentgateway-agentgateway/README.md new file mode 100644 index 0000000000..2f3ce8ab39 --- /dev/null +++ b/conformance/reports/v1.3.0/agentgateway-agentgateway/README.md @@ -0,0 +1,22 @@ +# Agent Gateway (with kgateway) + +## Table of Contents + +|API channel|Implementation version|Mode|Report| +|-----------|----------------------|----|------| +|experimental|[v0.6.0]|default|[report](./experimental-0.6.0-report.yaml)| + +## Reproduce + +``` +go test./conformance -run TestConformance -args \ + --report-output /tmp/report.yaml \ + --conformance-profiles=GATEWAY-HTTP \ + --gateway-class agentgateway \ + --all-features \ + --organization agentgateway \ + --project agentgateway \ + --url http://agentgateway.dev/ \ + --version v0.6.0-dev \ + --contact "github.com/agentgateway/agentgateway/issues/new/choose" +``` diff --git a/conformance/reports/v1.3.0/agentgateway-agentgateway/experimental-0.6.0-report.yaml b/conformance/reports/v1.3.0/agentgateway-agentgateway/experimental-0.6.0-report.yaml new file mode 100644 index 0000000000..459ca1196f --- /dev/null +++ b/conformance/reports/v1.3.0/agentgateway-agentgateway/experimental-0.6.0-report.yaml @@ -0,0 +1,55 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-07-09T12:34:09-07:00" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - github.com/agentgateway/agentgateway/issues/new/choose + organization: agentgateway + project: agentgateway + url: http://agentgateway.dev/ + version: v0.6.0-dev +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 25 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure +- HTTPRouteRequestPercentageMirror diff --git a/conformance/reports/v1.3.0/airlock-microgateway/README.md b/conformance/reports/v1.3.0/airlock-microgateway/README.md new file mode 100644 index 0000000000..6270457010 --- /dev/null +++ b/conformance/reports/v1.3.0/airlock-microgateway/README.md @@ -0,0 +1,21 @@ +# Airlock Microgateway + +## Table of contents + +| API channel | Implementation version | Mode | Report | +|--------------|----------------------------------------------------------------------|---------|--------------------------------------------------| +| experimental | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [link](./experimental-4.6.0-default-report.yaml) | +| experimental | [v4.7.0](https://github.com/airlock/microgateway/releases/tag/4.7.0) | default | [link](./experimental-4.7.0-default-report.yaml) | + +## Reproduce + +The Airlock Microgateway conformance report can be reproduced by following the steps in the [Gateway API conformance guide](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/conformance.md) on GitHub. + +> [!NOTE] +> The `HTTPRouteWeight` test fires 10 concurrent request to 3 backends totaling in 500 requests to assert a distribution that matches the configured weight. +> Please be aware that this test exceeds the [5 req/sec rate-limit](https://docs.airlock.com/microgateway/latest/?topic=MGW-00000056) enforced in the [community edition](https://www.airlock.com/en/secure-access-hub/components/microgateway/community-edition) , causing the test to fail. +> To successfully pass this test a [premium license](https://www.airlock.com/en/secure-access-hub/components/microgateway/premium-edition) is required. +> +> The Airlock Microgateway drops all request headers except for a well-known built-in standard and tracing headers list (e.g., Accept, Cookie, X-CSRF-TOKEN) to reduce the attack surface. +> Therefore, to run the conformance tests, a `ContentSecurityPolicy` with a `HeaderRewrites` (see [`conformance-report.yaml`](https://github.com/airlock/microgateway/tree/main/gateway-api/conformance/manifests/conformance-report.yaml)) is required to disable request header filtering for all `HTTPRoute` tests relying on the `MakeRequestAndExpectEventuallyConsistentResponse` assertion. +> Regardless of whether request header filtering is enabled or disabled, header-based routing works as specified in the Gateway API, as the headers are only filtered before the request is forwarded to the upstream. diff --git a/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.6.0-default-report.yaml b/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.6.0-default-report.yaml new file mode 100644 index 0000000000..e0548256ea --- /dev/null +++ b/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.6.0-default-report.yaml @@ -0,0 +1,55 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-19T14:29:59Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.6.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.7.0-default-report.yaml b/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.7.0-default-report.yaml new file mode 100644 index 0000000000..000e78772b --- /dev/null +++ b/conformance/reports/v1.3.0/airlock-microgateway/experimental-4.7.0-default-report.yaml @@ -0,0 +1,55 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-25T13:33:58Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://www.airlock.com/en/contact + organization: airlock + project: microgateway + url: https://github.com/airlock/microgateway + version: 4.7.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 18 + Skipped: 0 + supportedFeatures: + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/README.md b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/README.md new file mode 100644 index 0000000000..e598c55fd2 --- /dev/null +++ b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/README.md @@ -0,0 +1,32 @@ +# Buoyant Enterprise for Linkerd + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|--------------|-------------------------------------------|---------|--------------------------------------------------------| +| standard | [enterprise-2.18](https://docs.buoyant.io/buoyant-enterprise-linkerd/latest/overview//) | default | [enterprise-2.18 report](./standard-2.18-default-report.yaml) | + +## Notes + +This report uses the v1.3.0 Gateway API CRDs, but was run using the tests on +the `main` branch at commit `6cd1558a9e`, in order to take advantage more +effective tests for the `MESH` conformance profile that landed after v1.3.0 +was cut. + +## Reproduce + +To reproduce a Buoyant Enterprise for Linkerd conformance test report: + +0. `cd` to the top level of this repository. + +1. Create an empty cluster. + +2. Run `bash conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/run-conformance.sh`. + + You can set `LINKERD_VERSION`, `GATEWAY_API_CHANNEL`, and + `GATEWAY_API_VERSION` if you want to try different versions of things. + (Note that if you set `GATEWAY_API_VERSION`, you'll need to be on a + matching Gateway API branch.) + +3. The conformance report will be written to the + `conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/` directory. diff --git a/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/run-conformance.sh b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/run-conformance.sh new file mode 100644 index 0000000000..fc9efcd444 --- /dev/null +++ b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/run-conformance.sh @@ -0,0 +1,65 @@ +#!/bin/sh + +# Copyright 2025 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Set these as needed. +LINKERD_VERSION=${LINKERD_VERSION:-enterprise-2.18} +GATEWAY_API_CHANNEL=${GATEWAY_API_CHANNEL:-standard} +GATEWAY_API_VERSION=${GATEWAY_API_VERSION:-v1.3.0} + +UNSUPPORTED_FEATURES="MeshHTTPRouteRedirectPath,MeshHTTPRouteRewritePath" + +CONFORMANCE_PRODUCT=buoyant-enterprise-for-linkerd +CONFORMANCE_VERSION=$(echo $LINKERD_VERSION | cut -d- -f2-) +GATEWAY_API_BASE_URL=https://github.com/kubernetes-sigs/gateway-api/releases/download + +echo "Using Buoyant Enterprise for Linkerd version $LINKERD_VERSION" +echo "Using Gateway API $GATEWAY_API_VERSION $GATEWAY_API_CHANNEL" + +# Install the Linkerd CLI. +curl --proto '=https' --tlsv1.2 -sSfL https://enterprise.buoyant.io/install \ + | env LINKERD2_VERSION=${LINKERD_EDGE_VERSION} sh + +export PATH=$HOME/.linkerd2/bin:$PATH + +# Install the Gateway API CRDs. + +kubectl apply -f ${GATEWAY_API_BASE_URL}/${GATEWAY_API_VERSION}/${GATEWAY_API_CHANNEL}-install.yaml + +# Install the Linkerd control plane. +linkerd install --crds | kubectl apply -f - +linkerd install | kubectl apply -f - +linkerd check + +# Run the conformance tests. + +REPORT_NAME=${GATEWAY_API_CHANNEL}-${CONFORMANCE_VERSION}-default-report.yaml +REPORT_PATH=reports/${GATEWAY_API_VERSION}/${CONFORMANCE_PRODUCT}/${REPORT_NAME} + +go test \ + -p 4 \ + ./conformance \ + -run TestConformance \ + -args \ + --organization Buoyant \ + --project "Buoyant Enterprise for Linkerd" \ + --url https://buoyant.io/ \ + --version ${LINKERD_VERSION} \ + --contact "gateway-api@buoyant.io" \ + --report-output ${REPORT_PATH} \ + --conformance-profiles=MESH-HTTP,MESH-GRPC \ + --all-features \ + --exempt-features=Gateway,ReferenceGrant,${UNSUPPORTED_FEATURES} \ + --namespace-annotations=linkerd.io/inject=enabled diff --git a/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/standard-2.18-default-report.yaml b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/standard-2.18-default-report.yaml new file mode 100644 index 0000000000..90e4e77a22 --- /dev/null +++ b/conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/standard-2.18-default-report.yaml @@ -0,0 +1,64 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-06-11T14:31:02-04:00" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - gateway-api@buoyant.io + organization: Buoyant + project: Buoyant Enterprise for Linkerd + url: https://buoyant.io/ + version: enterprise-2.18 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + name: MESH-GRPC + summary: Core tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 7 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 8 + Skipped: 0 + supportedFeatures: + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + - MeshClusterIPMatching + - MeshConsumerRoute + - MeshHTTPRouteBackendRequestHeaderModification + - MeshHTTPRouteQueryParamMatching + - MeshHTTPRouteRedirectPort + - MeshHTTPRouteSchemeRedirect + unsupportedFeatures: + - MeshHTTPRouteRedirectPath + - MeshHTTPRouteRewritePath + name: MESH-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.3.0/cilium-cilium/README.md b/conformance/reports/v1.3.0/cilium-cilium/README.md new file mode 100644 index 0000000000..81b4fe1760 --- /dev/null +++ b/conformance/reports/v1.3.0/cilium-cilium/README.md @@ -0,0 +1,12 @@ +# Cilium + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|--------------|-------------------------------------------|---------|--------------------------------------------------------| +| experimental | [main](https://github.com/cilium/cilium/) | default | [main report](./experimental-main-default-report.yaml) | + +## Reproduce + +Cilium conformance tests can be reproduced by follow the steps in CI `.github/workflows/conformance-gateway-api.yaml` +from within the [Cilium repo](https://github.com/cilium/cilium). diff --git a/conformance/reports/v1.3.0/cilium-cilium/experimental-main-default-report.yaml b/conformance/reports/v1.3.0/cilium-cilium/experimental-main-default-report.yaml new file mode 100644 index 0000000000..7784449030 --- /dev/null +++ b/conformance/reports/v1.3.0/cilium-cilium/experimental-main-default-report.yaml @@ -0,0 +1,140 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-19T11:21:16Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/cilium/community/blob/main/roles/Maintainers.md + organization: cilium + project: cilium + url: github.com/cilium/cilium + version: main +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 23 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - HTTPRouteParentRefPort + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + name: MESH-GRPC + summary: Core tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + supportedFeatures: + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + - MeshClusterIPMatching + unsupportedFeatures: + - HTTPRouteParentRefPort + - MeshConsumerRoute + name: MESH-HTTP + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure +- HTTPRouteRequestPercentageMirror diff --git a/conformance/reports/v1.3.0/envoy-gateway/README.md b/conformance/reports/v1.3.0/envoy-gateway/README.md new file mode 100644 index 0000000000..6baa7b7b2d --- /dev/null +++ b/conformance/reports/v1.3.0/envoy-gateway/README.md @@ -0,0 +1,47 @@ +# Envoy Gateway + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|--------------|---------------------------------------------------------------------|------------------------------|------------------------------------------------------------------| +| experimental | [v1.5.0](https://github.com/envoyproxy/gateway/releases/tag/v1.5.0) | ControllerNamespace(default) | [link](./experimental-v1.5.0-default-report.yaml) | +| experimental | [v1.5.0](https://github.com/envoyproxy/gateway/releases/tag/v1.5.0) | GatewayNamespace | [link](./experimental-v1.5.0-gateway-namespace-mode-report.yaml) | + + +## Overview + +Envoy Gateway supports different deployment [modes](https://gateway.envoyproxy.io/docs/tasks/operations/deployment-mode/#supported-modes), +including a controller namespace mode(the default one) and a [gateway namespace mode](https://gateway.envoyproxy.io/docs/tasks/operations/deployment-mode/#gateway-namespace-mode). +The conformance tests are run against both modes to ensure compatibility and functionality. + +## Reproduce + +1. Clone the Envoy Gateway GitHub repository + + ```bash + git clone https://github.com/envoyproxy/gateway.git && cd gateway + ``` + +2. Check out the desired version + + ```bash + export VERSION=v + git checkout $VERSION + ``` + +3. Run the conformance tests + + ```bash + KUBE_DEPLOY_PROFILE=default CONFORMANCE_REPORT_PATH=conformance-report-k8s.yaml make experimental-conformance + ``` + or + + ```bash + KUBE_DEPLOY_PROFILE=gateway-namespace-mode CONFORMANCE_REPORT_PATH=conformance-report-k8s.yaml make experimental-conformance + ``` + +4. Check the produced report + + ```bash + cat ./conformance-report-k8s.yaml + ``` diff --git a/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml new file mode 100644 index 0000000000..14775c504e --- /dev/null +++ b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml @@ -0,0 +1,71 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-08T05:23:48Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/envoyproxy/gateway/blob/main/GOVERNANCE.md + organization: envoyproxy + project: envoy-gateway + url: https://github.com/envoyproxy/gateway + version: v1.5.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 23 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayInfrastructurePropagation + - GatewayStaticAddresses + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + name: GATEWAY-TLS + summary: Core tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + name: GATEWAY-GRPC + summary: Core tests succeeded. +succeededProvisionalTests: +- HTTPRouteRequestPercentageMirror diff --git a/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-gateway-namespace-mode-report.yaml b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-gateway-namespace-mode-report.yaml new file mode 100644 index 0000000000..0cc86f7694 --- /dev/null +++ b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-gateway-namespace-mode-report.yaml @@ -0,0 +1,98 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-08T05:25:57Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/envoyproxy/gateway/blob/main/GOVERNANCE.md + organization: envoyproxy + project: envoy-gateway + url: https://github.com/envoyproxy/gateway + version: v1.5.0 +kind: ConformanceReport +mode: GatewayNamespace +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 24 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure +- HTTPRouteRequestPercentageMirror diff --git a/conformance/reports/v1.3.0/istio-istio/README.md b/conformance/reports/v1.3.0/istio-istio/README.md new file mode 100644 index 0000000000..e188b4f7e9 --- /dev/null +++ b/conformance/reports/v1.3.0/istio-istio/README.md @@ -0,0 +1,11 @@ +# Istio + +## Table of Contents + +|API channel|Implementation version|Mode|Report| +|-----------|----------------------|----|------| +|x|[1.26.1](https://github.com/istio/istio/releases/tag/1.26.1)|x|[1.26.1 report](./experimental-1.26.1-default-report.yaml)| + +## Reproduce + +Istio conformance tests can be reproduced by running `prow/integ-suite-kind.sh test.integration.pilot.kube` from within the [Istio repo](https://github.com/istio/istio). diff --git a/conformance/reports/v1.3.0/istio-istio/experimental-1.26.1-default-report.yaml b/conformance/reports/v1.3.0/istio-istio/experimental-1.26.1-default-report.yaml new file mode 100644 index 0000000000..e55868fe2f --- /dev/null +++ b/conformance/reports/v1.3.0/istio-istio/experimental-1.26.1-default-report.yaml @@ -0,0 +1,131 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-27T17:51:14Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - '@istio/maintainers' + organization: istio + project: istio + url: https://istio.io/ + version: "1.26.1" +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 3 + Skipped: 0 + supportedFeatures: + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + - MeshConsumerRoute + unsupportedFeatures: + - MeshClusterIPMatching + name: MESH-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 25 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 2 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure +- HTTPRouteRequestPercentageMirror diff --git a/conformance/reports/v1.3.0/kgateway/README.md b/conformance/reports/v1.3.0/kgateway/README.md new file mode 100644 index 0000000000..ddd082e545 --- /dev/null +++ b/conformance/reports/v1.3.0/kgateway/README.md @@ -0,0 +1,40 @@ +# kgateway + +## Table of contents + +| API channel | Implementation version | Mode | Report | +|--------------|-------------------------------------------------------------------------------|---------|-----------------------------------------------------------| +| experimental | [main](https://github.com/kgateway-dev/kgateway) | default | [Link](./v2.1.0-main-report.yaml) | + +## Reproduce + +### Steps + +1. Clone the kgateway repository: + + ```sh + git clone https://github.com/kgateway-dev/kgateway.git && cd kgateway + ``` + +2. Override the version Makefile variable: + + > Note: The main branch defaults to version `1.0.1-dev` for Helm chart validation purposes. For conformance testing, + > we need to override this with a more descriptive version that reflects the main branch: + + ```sh + export VERSION="v2.1.0-main" + ``` + +3. Bootstrap a KinD cluster: + + ```sh + make run + ``` + +4. Run the conformance tests: + + ```sh + make conformance + ``` + +5. View and verify the conformance report: `cat _test/conformance/v2.1.0-main-report.yaml` diff --git a/conformance/reports/v1.3.0/kgateway/v2.1.0-main-report.yaml b/conformance/reports/v1.3.0/kgateway/v2.1.0-main-report.yaml new file mode 100644 index 0000000000..6724903275 --- /dev/null +++ b/conformance/reports/v1.3.0/kgateway/v2.1.0-main-report.yaml @@ -0,0 +1,53 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-06-18T15:07:19-04:00" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - github.com/kgateway-dev/kgateway/issues/new/choose + organization: kgateway-dev + project: kgateway + url: github.com/kgateway-dev/kgateway + version: v2.1.0-main +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 13 + Skipped: 0 + supportedFeatures: + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendTimeout + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - GatewayStaticAddresses + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteDestinationPortMatching + - HTTPRouteParentRefPort + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.3.0/linkerd-linkerd/README.md b/conformance/reports/v1.3.0/linkerd-linkerd/README.md new file mode 100644 index 0000000000..19a73bc729 --- /dev/null +++ b/conformance/reports/v1.3.0/linkerd-linkerd/README.md @@ -0,0 +1,65 @@ +# Linkerd + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|--------------|-------------------------------------------|---------|--------------------------------------------------------| +| standard | [version-2.18](https://github.com/linkerd/linkerd2/releases/tag/version-2.18/) | default | [version-2.18 report](./standard-2.18-default-report.yaml) | + +## Notes + +This report uses the v1.3.0 Gateway API CRDs, but was run using the tests on +the `main` branch at commit `6cd1558a9e`, in order to take advantage of more +effective tests for the `MESH` conformance profile that landed after v1.3.0 +was cut. + +### Linkerd Versioning + +The Linkerd project publishes and announces _versions_ that correspond to +specific project milestones and sets of new features. This report is for +Linkerd 2.18. + +Linkerd versions are available in different types of _release artifacts_: + +- _Edge releases_ are published on a weekly or near-weekly basis by the + Linkerd open-source project. Their names are `edge-y.m.n`, where `y` is the + two-digit year, `m` is the numeric month, and `n` is the number of the edge + release in that month (e.g. `edge-25.5.1` is the first edge release in May + of 2025). + + Each major version of Linkerd has a corresponding edge release, indicated by + a `version-2.X` tag. For example, Linkerd 2.18 corresponds to `edge-25.4.4`, + and therefore the `version-2.18` tag and the `edge-25.4.4` tag are on the + same commit. + +- _Stable releases_ of Linkerd follow semantic versioning, and are published + by the vendor community around Linkerd. + +For more information on Linkerd versioning, see the Linkerd [Releases and +Versions] documentation. + +Since Gateway API conformance tests require semantic versioning for the +implementation version, the Linkerd project reports conformance using the +`version` tags. However, the `run_conformance.sh` script referenced below +installs the corresponding `edge` tag, because the Linkerd CLI is actually +published using the `edge` tag. + +[Releases and Versions]: https://linkerd.io/releases/ + +## Reproduce + +To reproduce a Linkerd conformance test report: + +0. `cd` to the top level of this repository. + +1. Create an empty cluster. + +2. Run `bash conformance/reports/v1.3.0/linkerd-linkerd/run-conformance.sh`. + + You can set `LINKERD_VERSION`, `LINKERD_EDGE_VERSION`, + `GATEWAY_API_CHANNEL`, and `GATEWAY_API_VERSION` if you want to try + different versions of things. (Note that if you set `GATEWAY_API_VERSION`, + you'll need to be on a matching Gateway API branch.) + +3. The conformance report will be written to the + `conformance/reports/v1.3.0/linkerd-linkerd/` directory. diff --git a/conformance/reports/v1.3.0/linkerd-linkerd/run-conformance.sh b/conformance/reports/v1.3.0/linkerd-linkerd/run-conformance.sh new file mode 100644 index 0000000000..93d0b210f2 --- /dev/null +++ b/conformance/reports/v1.3.0/linkerd-linkerd/run-conformance.sh @@ -0,0 +1,66 @@ +#!/bin/sh + +# Copyright 2025 The Kubernetes Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Set these as needed. +LINKERD_VERSION=${LINKERD_VERSION:-version-2.18} +LINKERD_EDGE_VERSION=${LINKERD_EDGE_VERSION:-edge-25.4.4} +GATEWAY_API_CHANNEL=${GATEWAY_API_CHANNEL:-standard} +GATEWAY_API_VERSION=${GATEWAY_API_VERSION:-v1.3.0} + +UNSUPPORTED_FEATURES="MeshHTTPRouteRedirectPath,MeshHTTPRouteRewritePath" + +CONFORMANCE_PRODUCT=linkerd-linkerd +CONFORMANCE_VERSION=$(echo $LINKERD_VERSION | cut -d- -f2-) +GATEWAY_API_BASE_URL=https://github.com/kubernetes-sigs/gateway-api/releases/download + +echo "Using Linkerd version $LINKERD_VERSION (AKA $LINKERD_EDGE_VERSION)" +echo "Using Gateway API $GATEWAY_API_VERSION $GATEWAY_API_CHANNEL" + +# Install the Linkerd CLI. +curl --proto '=https' --tlsv1.2 -sSfL https://run.linkerd.io/install-edge \ + | env LINKERD2_VERSION=${LINKERD_EDGE_VERSION} sh + +export PATH=$HOME/.linkerd2/bin:$PATH + +# Install the Gateway API CRDs. + +kubectl apply -f ${GATEWAY_API_BASE_URL}/${GATEWAY_API_VERSION}/${GATEWAY_API_CHANNEL}-install.yaml + +# Install the Linkerd control plane. +linkerd install --crds | kubectl apply -f - +linkerd install | kubectl apply -f - +linkerd check + +# Run the conformance tests. + +REPORT_NAME=${GATEWAY_API_CHANNEL}-${CONFORMANCE_VERSION}-default-report.yaml +REPORT_PATH=reports/${GATEWAY_API_VERSION}/${CONFORMANCE_PRODUCT}/${REPORT_NAME} + +go test \ + -p 4 \ + ./conformance \ + -run TestConformance \ + -args \ + --organization Linkerd \ + --project Linkerd \ + --url https://github.com/linkerd/linkerd2 \ + --version ${LINKERD_VERSION} \ + --contact https://github.com/linkerd/linkerd2/blob/main/MAINTAINERS.md \ + --report-output ${REPORT_PATH} \ + --conformance-profiles=MESH-HTTP,MESH-GRPC \ + --all-features \ + --exempt-features=Gateway,ReferenceGrant,${UNSUPPORTED_FEATURES} \ + --namespace-annotations=linkerd.io/inject=enabled diff --git a/conformance/reports/v1.3.0/linkerd-linkerd/standard-2.18-default-report.yaml b/conformance/reports/v1.3.0/linkerd-linkerd/standard-2.18-default-report.yaml new file mode 100644 index 0000000000..54d0503085 --- /dev/null +++ b/conformance/reports/v1.3.0/linkerd-linkerd/standard-2.18-default-report.yaml @@ -0,0 +1,64 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-06-11T14:21:05-04:00" +gatewayAPIChannel: standard +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/linkerd/linkerd2/blob/main/MAINTAINERS.md + organization: Linkerd + project: Linkerd + url: https://github.com/linkerd/linkerd2 + version: version-2.18 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + name: MESH-GRPC + summary: Core tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 7 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 8 + Skipped: 0 + supportedFeatures: + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRouteParentRefPort + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + - MeshClusterIPMatching + - MeshConsumerRoute + - MeshHTTPRouteBackendRequestHeaderModification + - MeshHTTPRouteQueryParamMatching + - MeshHTTPRouteRedirectPort + - MeshHTTPRouteSchemeRedirect + unsupportedFeatures: + - MeshHTTPRouteRedirectPath + - MeshHTTPRouteRewritePath + name: MESH-HTTP + summary: Core tests succeeded. Extended tests succeeded. diff --git a/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md new file mode 100644 index 0000000000..6074dc7bf6 --- /dev/null +++ b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md @@ -0,0 +1,24 @@ +# Nginx NGINX Gateway Fabric + +## Table of Contents + +| API channel | Implementation version | Mode | Report | +|--------------|-----------------------------------------------------------------------------|---------|--------------------------------------------------| +| experimental | [v2.0.0](https://github.com/nginx/nginx-gateway-fabric/releases/tag/v2.0.0) | default | [v2.0.0 report](./experimental-2.0.0-default-report.yaml) | +| experimental | [v2.1.0](https://github.com/nginx/nginx-gateway-fabric/releases/tag/v2.1.0) | default | [v2.1.0 report](./experimental-2.1.0-default-report.yaml) | + +## Reproduce + +To reproduce results, clone the NGF repository: + +```shell +git clone https://github.com/nginx/nginx-gateway-fabric.git && cd nginx-gateway-fabric/tests +``` + +Follow the steps in the [NGINX Gateway Fabric Testing](https://github.com/nginx/nginx-gateway-fabric/blob/main/tests/README.md) document to run the conformance tests. If you are running tests on the `edge` version, then you don't need to build any images. Otherwise, you'll need to check out the specific release tag that you want to test, and then build and load the images onto your cluster, per the steps in the README. + +After running, see the conformance report: + +```shell +cat conformance-profile.yaml +``` diff --git a/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.0.0-default-report.yaml b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.0.0-default-report.yaml new file mode 100644 index 0000000000..571ab045c8 --- /dev/null +++ b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.0.0-default-report.yaml @@ -0,0 +1,97 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-06-05T16:32:34Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/nginx/nginx-gateway-fabric/discussions/new/choose + organization: nginx + project: nginx-gateway-fabric + url: https://github.com/nginx/nginx-gateway-fabric + version: v2.0.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 15 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteParentRefPort + - HTTPRouteRequestPercentageMirror + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure diff --git a/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.1.0-default-report.yaml b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.1.0-default-report.yaml new file mode 100644 index 0000000000..b9f14ea8bf --- /dev/null +++ b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.1.0-default-report.yaml @@ -0,0 +1,98 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-08-18T20:07:45Z" +gatewayAPIChannel: experimental +gatewayAPIVersion: v1.3.0 +implementation: + contact: + - https://github.com/nginx/nginx-gateway-fabric/discussions/new/choose + organization: nginx + project: nginx-gateway-fabric + url: https://github.com/nginx/nginx-gateway-fabric + version: v2.1.0 +kind: ConformanceReport +mode: default +profiles: +- core: + result: success + statistics: + Failed: 0 + Passed: 12 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-GRPC + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 33 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 16 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteBackendProtocolWebSocket + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteRequestPercentageMirror + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayStaticAddresses + - HTTPRouteBackendProtocolH2C + - HTTPRouteBackendRequestHeaderModification + - HTTPRouteBackendTimeout + - HTTPRouteDestinationPortMatching + - HTTPRouteParentRefPort + - HTTPRouteRequestTimeout + name: GATEWAY-HTTP + summary: Core tests succeeded. Extended tests succeeded. +- core: + result: success + statistics: + Failed: 0 + Passed: 11 + Skipped: 0 + extended: + result: success + statistics: + Failed: 0 + Passed: 1 + Skipped: 0 + supportedFeatures: + - GatewayAddressEmpty + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure +- HTTPRouteRequestPercentageMirror diff --git a/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.go b/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.go new file mode 100644 index 0000000000..824d8dd199 --- /dev/null +++ b/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.go @@ -0,0 +1,98 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + h "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, BackendTLSPolicyInvalidCACertificateRef) +} + +var BackendTLSPolicyInvalidCACertificateRef = suite.ConformanceTest{ + ShortName: "BackendTLSPolicyInvalidCACertificateRef", + Description: "A BackendTLSPolicy that specifies a single invalid CACertificateRef should have the Accepted and ResolvedRefs status condition set False with appropriate reasons, and HTTP requests to a backend targeted by this policy should fail with a 5xx response.", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportBackendTLSPolicy, + }, + Manifests: []string{"tests/backendtlspolicy-invalid-ca-certificate-ref.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "backendtlspolicy-invalid-ca-certificate-ref", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + + serverStr := "abc.example.com" + + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN) + + for _, policyNN := range []types.NamespacedName{ + {Name: "nonexistent-ca-certificate-ref", Namespace: ns}, + {Name: "malformed-ca-certificate-ref", Namespace: ns}, + } { + t.Run("BackendTLSPolicy_"+policyNN.Name, func(t *testing.T) { + t.Run("BackendTLSPolicy with a single invalid CACertificateRef has a Accepted Condition with status False and Reason NoValidCACertificate", func(t *testing.T) { + acceptedCond := metav1.Condition{ + Type: string(gatewayv1alpha2.PolicyConditionAccepted), + Status: metav1.ConditionFalse, + Reason: string(gatewayv1alpha3.BackendTLSPolicyReasonNoValidCACertificate), + } + + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, acceptedCond) + }) + + t.Run("BackendTLSPolicy with a single invalid CACertificateRef has a ResolvedRefs Condition with status False and Reason InvalidCACertificateRef", func(t *testing.T) { + resolvedRefsCond := metav1.Condition{ + Type: string(gatewayv1alpha3.BackendTLSPolicyConditionResolvedRefs), + Status: metav1.ConditionFalse, + Reason: string(gatewayv1alpha3.BackendTLSPolicyReasonInvalidCACertificateRef), + } + + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, resolvedRefsCond) + }) + + t.Run("HTTP Request to backend targeted by an invalid BackendTLSPolicy receive a 5xx", func(t *testing.T) { + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendtlspolicy-" + policyNN.Name, + }, + Response: h.Response{ + StatusCodes: []int{500, 502, 503}, + }, + }) + }) + }) + } + }, +} diff --git a/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.yaml b/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.yaml new file mode 100644 index 0000000000..138812fddb --- /dev/null +++ b/conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.yaml @@ -0,0 +1,97 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: backendtlspolicy-invalid-ca-certificate-ref + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + namespace: gateway-conformance-infra + hostnames: + - abc.example.com + rules: + - backendRefs: + - name: backendtlspolicy-nonexistent-ca-certificate-ref-test + port: 443 + matches: + - path: + type: Exact + value: /backendtlspolicy-nonexistent-ca-certificate-ref + - backendRefs: + - name: backendtlspolicy-malformed-ca-certificate-ref-test + port: 443 + matches: + - path: + type: Exact + value: /backendtlspolicy-malformed-ca-certificate-ref +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-nonexistent-ca-certificate-ref-test + namespace: gateway-conformance-infra +spec: + selector: + app: tls-backend + ports: + - name: "https" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-malformed-ca-certificate-ref-test + namespace: gateway-conformance-infra +spec: + selector: + app: tls-backend + ports: + - name: "https" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: nonexistent-ca-certificate-ref + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-nonexistent-ca-certificate-ref-test" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + name: "nonexistent-ca-certificate" + hostname: "abc.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: malformed-ca-certificate-ref + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-malformed-ca-certificate-ref-test" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + name: "malformed-ca-certificate" + hostname: "abc.example.com" +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: malformed-ca-certificate + namespace: gateway-conformance-infra +data: {} diff --git a/conformance/tests/backendtlspolicy-invalid-kind.go b/conformance/tests/backendtlspolicy-invalid-kind.go new file mode 100644 index 0000000000..5a3bba597e --- /dev/null +++ b/conformance/tests/backendtlspolicy-invalid-kind.go @@ -0,0 +1,93 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2" + gatewayv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + h "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, BackendTLSPolicyInvalidKind) +} + +var BackendTLSPolicyInvalidKind = suite.ConformanceTest{ + ShortName: "BackendTLSPolicyInvalidKind", + Description: "A BackendTLSPolicy that specifies a single CACertificateRef with an invalid kind should have the Accepted and ResolvedRefs status condition set False with appropriate reasons, and HTTP requests to a backend targeted by this policy should fail with a 5xx response.", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportBackendTLSPolicy, + }, + Manifests: []string{"tests/backendtlspolicy-invalid-kind.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "backendtlspolicy-invalid-kind-test", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + + serverStr := "abc.example.com" + + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN) + + policyNN := types.NamespacedName{Name: "invalid-kind", Namespace: ns} + + t.Run("BackendTLSPolicy with a single invalid CACertificateRef has a Accepted Condition with status False and Reason NoValidCACertificate", func(t *testing.T) { + acceptedCond := metav1.Condition{ + Type: string(gatewayv1alpha2.PolicyConditionAccepted), + Status: metav1.ConditionFalse, + Reason: string(gatewayv1alpha3.BackendTLSPolicyReasonNoValidCACertificate), + } + + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, acceptedCond) + }) + + t.Run("BackendTLSPolicy with a single invalid CACertificateRef has a ResolvedRefs Condition with status False and Reason InvalidKind", func(t *testing.T) { + resolvedRefsCond := metav1.Condition{ + Type: string(gatewayv1alpha3.BackendTLSPolicyConditionResolvedRefs), + Status: metav1.ConditionFalse, + Reason: string(gatewayv1alpha3.BackendTLSPolicyReasonInvalidKind), + } + + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, resolvedRefsCond) + }) + + t.Run("HTTP Request to backend targeted by an invalid BackendTLSPolicy receive a 5xx", func(t *testing.T) { + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendtlspolicy-" + policyNN.Name, + }, + Response: h.Response{ + StatusCodes: []int{500, 502, 503}, + }, + }) + }) + }, +} diff --git a/conformance/tests/backendtlspolicy-invalid-kind.yaml b/conformance/tests/backendtlspolicy-invalid-kind.yaml new file mode 100644 index 0000000000..a7eaeb5d5c --- /dev/null +++ b/conformance/tests/backendtlspolicy-invalid-kind.yaml @@ -0,0 +1,51 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: backendtlspolicy-invalid-kind-test + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + namespace: gateway-conformance-infra + hostnames: + - abc.example.com + rules: + - backendRefs: + - name: backendtlspolicy-invalid-kind-test + port: 443 + matches: + - path: + type: Exact + value: /backendtlspolicy-invalid-kind +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-invalid-kind-test + namespace: gateway-conformance-infra +spec: + selector: + app: tls-backend + ports: + - name: "https" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: invalid-kind + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-invalid-kind-test" + validation: + caCertificateRefs: + - group: invalid.io + kind: InvalidKind + name: "invalid-kind" + hostname: "abc.example.com" diff --git a/conformance/tests/backendtlspolicy-observed-generation-bump.go b/conformance/tests/backendtlspolicy-observed-generation-bump.go new file mode 100644 index 0000000000..a3cd4000bd --- /dev/null +++ b/conformance/tests/backendtlspolicy-observed-generation-bump.go @@ -0,0 +1,88 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "sigs.k8s.io/controller-runtime/pkg/client" + + "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/gateway-api/apis/v1alpha3" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, BackendTLSPolicyObservedGenerationBump) +} + +var BackendTLSPolicyObservedGenerationBump = suite.ConformanceTest{ + ShortName: "BackendTLSPolicyObservedGenerationBump", + Description: "A BackendTLSPolicy in the gateway-conformance-infra namespace should update the observedGeneration in all of it's Status.Conditions after an update to the spec", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportBackendTLSPolicy, + }, + Manifests: []string{"tests/backendtlspolicy-observed-generation-bump.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + policyNN := types.NamespacedName{Name: "observed-generation-bump", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + + t.Run("observedGeneration should increment", func(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), suite.TimeoutConfig.LatestObservedGenerationSet) + defer cancel() + + namespaces := []string{"gateway-conformance-infra"} + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, namespaces) + + original := &v1alpha3.BackendTLSPolicy{} + err := suite.Client.Get(ctx, policyNN, original) + require.NoError(t, err, "error getting HTTPRoute") + + // Sanity check + kubernetes.BackendTLSPolicyMustHaveLatestConditions(t, original) + + mutate := original.DeepCopy() + mutate.Spec.Validation.Hostname = "foo.example.com" + err = suite.Client.Patch(ctx, mutate, client.MergeFrom(original)) + require.NoError(t, err, "error patching the BackendTLSPolicy") + + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, metav1.Condition{ + Type: string(v1alpha2.PolicyConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "", // any reason + }) + + updated := &v1alpha3.BackendTLSPolicy{} + err = suite.Client.Get(ctx, policyNN, updated) + require.NoError(t, err, "error getting BackendTLSPolicy") + + // Sanity check + kubernetes.BackendTLSPolicyMustHaveLatestConditions(t, updated) + + require.NotEqual(t, original.Generation, updated.Generation, "generation should change after an update") + }) + }, +} diff --git a/conformance/tests/backendtlspolicy-observed-generation-bump.yaml b/conformance/tests/backendtlspolicy-observed-generation-bump.yaml new file mode 100644 index 0000000000..c21bd45bbc --- /dev/null +++ b/conformance/tests/backendtlspolicy-observed-generation-bump.yaml @@ -0,0 +1,45 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: backendtlspolicy-observed-generation-bump + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - backendRefs: + - name: observed-generation-bump-test + port: 443 +--- +apiVersion: v1 +kind: Service +metadata: + name: observed-generation-bump-test + namespace: gateway-conformance-infra +spec: + selector: + app: observed-generation-bump-test + ports: + - name: "https" + protocol: TCP + port: 443 + targetPort: 8443 +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: observed-generation-bump + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "observed-generation-bump-test" + sectionName: "https" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This ConfigMap is generated dynamically by the test suite. + name: "backend-tls-checks-certificate" + hostname: "abc.example.com" diff --git a/conformance/tests/backendtlspolicy-san.go b/conformance/tests/backendtlspolicy-san.go new file mode 100644 index 0000000000..38e7a2b43a --- /dev/null +++ b/conformance/tests/backendtlspolicy-san.go @@ -0,0 +1,163 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/apis/v1alpha2" + h "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, BackendTLSPolicySANValidation) +} + +var BackendTLSPolicySANValidation = suite.ConformanceTest{ + ShortName: "BackendTLSPolicySANValidation", + Description: "BackendTLSPolicySANValidation extend BackendTLSPolicy with SubjectAltNames validation", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportBackendTLSPolicy, + features.SupportBackendTLSPolicySANValidation, + }, + Manifests: []string{"tests/backendtlspolicy-san.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "route-backendtlspolicy-san-test", Namespace: ns} + gwNN := types.NamespacedName{Name: "gateway-backendtlspolicy", Namespace: ns} + + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN) + kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) + + policyCond := metav1.Condition{ + Type: string(v1alpha2.PolicyConditionAccepted), + Status: metav1.ConditionTrue, + Reason: string(v1alpha2.PolicyReasonAccepted), + } + + serverStr := "abc.example.com" + + // Verify that the request sent to Service with valid BackendTLSPolicy containing dns SAN should succeed. + t.Run("HTTP request sent to Service with valid BackendTLSPolicy containing dns SAN should succeed", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-san-dns", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSSanDns", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that the request sent to a Service targeted by a BackendTLSPolicy with mismatched dns SAN should fail. + t.Run("HTTP request sent to Service targeted by BackendTLSPolicy with mismatched dns SAN should return an HTTP error", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-san-dns-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSSanDnsMismatch", + SNI: serverStr, + }, + }) + }) + + // Verify that the request sent to Service with valid BackendTLSPolicy containing uri SAN should succeed. + t.Run("HTTP request sent to Service with valid BackendTLSPolicy containing uri SAN should succeed", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-san-uri", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSSanUri", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that the request sent to a Service targeted by a BackendTLSPolicy with mismatched uri SAN should fail. + t.Run("HTTP request sent to Service targeted by BackendTLSPolicy with mismatched uri SAN should return an HTTP error", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-san-uri-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSSanUriMismatch", + SNI: serverStr, + }, + }) + }) + + // Verify that the request sent to Service with valid BackendTLSPolicy containing multi SANs should succeed. + t.Run("HTTP request sent to Service with valid BackendTLSPolicy containing multi SAN should succeed", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-multiple-sans", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSMultiSans", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that the request sent to a Service targeted by a BackendTLSPolicy with mismatched multi SAN should fail. + t.Run("HTTP request sent to Service targeted by BackendTLSPolicy with mismatched multi SAN should return an HTTP error", func(t *testing.T) { + policyNN := types.NamespacedName{Name: "backendtlspolicy-multiple-mismatch-sans", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, policyNN, gwNN, policyCond) + + h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSMultiMismatchSans", + SNI: serverStr, + }, + }) + }) + }, +} diff --git a/conformance/tests/backendtlspolicy-san.yaml b/conformance/tests/backendtlspolicy-san.yaml new file mode 100644 index 0000000000..e3e0f79bf0 --- /dev/null +++ b/conformance/tests/backendtlspolicy-san.yaml @@ -0,0 +1,341 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: route-backendtlspolicy-san-test + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: gateway-backendtlspolicy + namespace: gateway-conformance-infra + hostnames: + - abc.example.com + rules: + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-dns-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSanDns + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-dns-mismatch-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSanDnsMismatch + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-uri-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSanUri + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-uri-mismatch-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSanUriMismatch + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-multiple-sans-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSMultiSans + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-multiple-mismatch-sans-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSMultiMismatchSans +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-san-dns-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-san-dns-mismatch-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-san-uri-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-san-uri-mismatch-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-multiple-sans-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-multiple-mismatch-sans-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-san-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backendtlspolicy-san-test + namespace: gateway-conformance-infra + labels: + app: backendtlspolicy-san-test +spec: + replicas: 1 + selector: + matchLabels: + app: backendtlspolicy-san-test + template: + metadata: + labels: + app: backendtlspolicy-san-test + spec: + containers: + - name: backendtlspolicy-san-test + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd + volumeMounts: + - name: secret-volume + mountPath: /etc/secret-volume + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: TLS_SERVER_CERT + value: /etc/secret-volume/crt + - name: TLS_SERVER_PRIVKEY + value: /etc/secret-volume/key + resources: + requests: + cpu: 10m + volumes: + - name: secret-volume + secret: + # This secret is generated dynamically by the test suite. + secretName: tls-with-san-certificate + items: + - key: tls.crt + path: crt + - key: tls.key + path: key +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-san-dns + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-dns-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "Hostname" + hostname: "abc.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-san-dns-mismatch + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-dns-mismatch-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "Hostname" + hostname: "dce.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-san-uri + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-uri-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "URI" + uri: "spiffe://abc.example.com/test-identity" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-san-uri-mismatch + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-uri-mismatch-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "URI" + uri: "spiffe://def.example.com/test-identity" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-multiple-sans + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-multiple-sans-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "URI" + uri: "spiffe://abc.example.com/test-identity" + - type: "Hostname" + hostname: "abc.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-multiple-mismatch-sans + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: backendtlspolicy-multiple-mismatch-sans-test + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-with-san-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: "URI" + uri: "spiffe://def.example.com/test-identity" + - type: "Hostname" + hostname: "def.example.com" diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go new file mode 100644 index 0000000000..62ed54c4af --- /dev/null +++ b/conformance/tests/backendtlspolicy.go @@ -0,0 +1,142 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/gateway-api/apis/v1alpha3" + h "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/conformance/utils/tls" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, BackendTLSPolicy) +} + +var BackendTLSPolicy = suite.ConformanceTest{ + ShortName: "BackendTLSPolicy", + Description: "BackendTLSPolicy must be used to configure TLS connection between gateway and backend", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportBackendTLSPolicy, + }, + Manifests: []string{"tests/backendtlspolicy.yaml"}, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: ns} + gwNN := types.NamespacedName{Name: "gateway-backendtlspolicy", Namespace: ns} + + kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN) + kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) + + acceptedCond := metav1.Condition{ + Type: string(v1alpha2.PolicyConditionAccepted), + Status: metav1.ConditionTrue, + Reason: string(v1alpha2.PolicyReasonAccepted), + } + resolvedRefsCond := metav1.Condition{ + Type: string(v1alpha3.BackendTLSPolicyConditionResolvedRefs), + Status: metav1.ConditionTrue, + Reason: string(v1alpha3.BackendTLSPolicyReasonResolvedRefs), + } + + validPolicyNN := types.NamespacedName{Name: "normative-test-backendtlspolicy", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, acceptedCond) + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, resolvedRefsCond) + + serverStr := "abc.example.com" + + // Verify that the request sent to Service with valid BackendTLSPolicy should succeed. + t.Run("HTTP request sent to Service with valid BackendTLSPolicy should succeed", func(t *testing.T) { + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLS", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // For the re-encrypt case, we need to use the cert for the frontend tls listener. + certNN := types.NamespacedName{Name: "tls-checks-certificate", Namespace: ns} + cPem, keyPem, err := GetTLSSecret(suite.Client, certNN) + if err != nil { + t.Fatalf("unexpected error finding TLS secret: %v", err) + } + // Verify that the request to a re-encrypted call to /backendTLS should succeed. + t.Run("Re-encrypt HTTPS request sent to Service with valid BackendTLSPolicy should succeed", func(t *testing.T) { + tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, serverStr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLS", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that the request sent to a Service targeted by a BackendTLSPolicy with mismatched host will fail. + t.Run("HTTP request sent to Service targeted by BackendTLSPolicy with mismatched hostname should return an HTTP error", func(t *testing.T) { + invalidPolicyNN := types.NamespacedName{Name: "backendtlspolicy-host-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidPolicyNN, gwNN, acceptedCond) + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidPolicyNN, gwNN, resolvedRefsCond) + + h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSHostMismatch", + SNI: serverStr, + }, + }) + }) + + // Verify that request sent to Service targeted by BackendTLSPolicy with mismatched cert should failed. + t.Run("HTTP request send to Service targeted by BackendTLSPolicy with mismatched cert should return HTTP error", func(t *testing.T) { + invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, acceptedCond) + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, resolvedRefsCond) + + h.MakeRequestAndExpectFailure(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSCertMismatch", + SNI: serverStr, + }, + }) + }) + }, +} diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml new file mode 100644 index 0000000000..6d0cab8e3f --- /dev/null +++ b/conformance/tests/backendtlspolicy.yaml @@ -0,0 +1,206 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: gateway-conformance-infra-test + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: gateway-backendtlspolicy + namespace: gateway-conformance-infra + hostnames: + - abc.example.com + rules: + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLS + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-host-mismatch-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSHostMismatch + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-cert-mismatch-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSCertMismatch +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-test + ports: + - name: "btls" + protocol: TCP + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-host-mismatch-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-cert-mismatch-test + namespace: gateway-conformance-infra +spec: + selector: + app: backendtlspolicy-test + ports: + - name: "btls" + protocol: TCP + appProtocol: HTTPS + port: 443 + targetPort: 8443 +--- +# Deployment must not be applied until after the secret is generated. +apiVersion: apps/v1 +kind: Deployment +metadata: + name: backendtlspolicy-test + namespace: gateway-conformance-infra + labels: + app: backendtlspolicy-test +spec: + replicas: 1 + selector: + matchLabels: + app: backendtlspolicy-test + template: + metadata: + labels: + app: backendtlspolicy-test + spec: + containers: + - name: backendtlspolicy-test + image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd + volumeMounts: + - name: ca-volume + mountPath: /etc/ca-volume + - name: secret-volume + mountPath: /etc/secret-volume + env: + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + - name: CA_CERT + value: /etc/ca-volume/crt + - name: CA_CERT_KEY + value: /etc/ca-volume/key + - name: TLS_SERVER_CERT + value: /etc/secret-volume/crt + - name: TLS_SERVER_PRIVKEY + value: /etc/secret-volume/key + resources: + requests: + cpu: 10m + volumes: + - name: ca-volume + configMap: + # This configMap is generated dynamically by the test suite. + name: backend-tls-checks-certificate + items: + - key: ca.crt + path: crt + - key: key.crt + path: key + - name: secret-volume + secret: + # This secret is generated dynamically by the test suite. + secretName: tls-checks-certificate + items: + - key: tls.crt + path: crt + - key: tls.key + path: key +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: normative-test-backendtlspolicy + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-test" + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-checks-certificate" + hostname: "abc.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-host-mismatch + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-host-mismatch-test" + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-checks-certificate" + hostname: "mismatch.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-cert-mismatch + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-cert-mismatch-test" + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-mismatch-certificate" + hostname: "abc.example.com" diff --git a/conformance/tests/cors-allow-credentials-behavior.go b/conformance/tests/cors-allow-credentials-behavior.go new file mode 100644 index 0000000000..391b3cee80 --- /dev/null +++ b/conformance/tests/cors-allow-credentials-behavior.go @@ -0,0 +1,100 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, CORSAllowCredentialsBehavior) +} + +var CORSAllowCredentialsBehavior = suite.ConformanceTest{ + ShortName: "CORSAllowCredentialsBehavior", + Description: "Validate ACA-Credentials responses", + Manifests: []string{"tests/cors-allow-credentials-behavior.yaml"}, + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportHTTPRouteCORS, + }, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "cors-allow-credentials", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) + + origin := "https://app.example" + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Method: "GET", + Path: "/cors-behavior-creds-false", + Headers: map[string]string{ + "Origin": origin, + "Cookie": "sid=abc123", + "Authorization": "Bearer test", + }, + }, + Response: http.Response{ + StatusCode: 200, + AbsentHeaders: []string{"Access-Control-Allow-Credentials"}, + }, + Namespace: ns, + }, + { + Request: http.Request{ + Method: "GET", + Path: "/cors-behavior-creds-true", + Headers: map[string]string{ + "Origin": origin, + "Cookie": "sid=abc123", + "Authorization": "Bearer test", + }, + }, + Response: http.Response{ + StatusCode: 200, + Headers: map[string]string{ + "Access-Control-Allow-Credentials": "true", + "Access-Control-Allow-Origin": origin, + }, + }, + Namespace: ns, + }, + } + + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) + }) + } + }, +} diff --git a/conformance/tests/cors-allow-credentials-behavior.yaml b/conformance/tests/cors-allow-credentials-behavior.yaml new file mode 100644 index 0000000000..13992e28f4 --- /dev/null +++ b/conformance/tests/cors-allow-credentials-behavior.yaml @@ -0,0 +1,32 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: cors-allow-credentials + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - matches: + - path: + type: PathPrefix + value: /cors-behavior-creds-false + backendRefs: + - name: infra-backend-v1 + port: 8080 + filters: + - cors: + allowCredentials: false + type: CORS + - matches: + - path: + type: PathPrefix + value: /cors-behavior-creds-true + backendRefs: + - name: infra-backend-v1 + port: 8080 + filters: + - cors: + allowCredentials: true + type: CORS + diff --git a/conformance/tests/gateway-optional-address-value.go b/conformance/tests/gateway-optional-address-value.go new file mode 100644 index 0000000000..78a59d687e --- /dev/null +++ b/conformance/tests/gateway-optional-address-value.go @@ -0,0 +1,70 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "context" + "testing" + + "github.com/stretchr/testify/require" + "k8s.io/apimachinery/pkg/types" + + v1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, GatewayOptionalAddressValue) +} + +var GatewayOptionalAddressValue = suite.ConformanceTest{ + ShortName: "GatewayOptionalAddressValue", + Description: "Check Gateway Support for GatewayAddressEmpty feature", + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportGatewayAddressEmpty, + }, + Provisional: true, + Manifests: []string{ + "tests/gateway-optional-address-value.yaml", + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + + kubernetes.NamespacesMustBeReady(t, s.Client, s.TimeoutConfig, []string{ns}) + + gwNN := types.NamespacedName{ + Name: "gateway-without-address-value", + Namespace: "gateway-conformance-infra", + } + ctx, cancel := context.WithTimeout(context.Background(), s.TimeoutConfig.DefaultTestTimeout) + defer cancel() + + t.Logf("waiting for Gateway %s to be ready for testing", gwNN.Name) + kubernetes.GatewayMustHaveLatestConditions(t, s.Client, s.TimeoutConfig, gwNN) + + t.Logf("retrieving Gateway %s/%s", gwNN.Namespace, gwNN.Name) + currentGW := &v1.Gateway{} + err := s.Client.Get(ctx, gwNN, currentGW) + require.NoError(t, err, "error getting Gateway: %v", err) + t.Logf("verifying that the Gateway %s/%s is accepted", gwNN.Namespace, gwNN.Name) + _, err = kubernetes.WaitForGatewayAddress(t, s.Client, s.TimeoutConfig, kubernetes.NewGatewayRef(gwNN, "http")) + require.NoError(t, err, "timed out waiting for Gateway address to be assigned") + }, +} diff --git a/conformance/tests/gateway-optional-address-value.yaml b/conformance/tests/gateway-optional-address-value.yaml new file mode 100644 index 0000000000..48e7ffdc32 --- /dev/null +++ b/conformance/tests/gateway-optional-address-value.yaml @@ -0,0 +1,13 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: gateway-without-address-value + namespace: gateway-conformance-infra +spec: + gatewayClassName: "{GATEWAY_CLASS_NAME}" + addresses: + - type: "IPAddress" + listeners: + - name: http + port: 8080 + protocol: HTTP diff --git a/conformance/tests/grpcroute-exact-method-matching.go b/conformance/tests/grpcroute-exact-method-matching.go index 384cf3ae02..c70c034b6c 100644 --- a/conformance/tests/grpcroute-exact-method-matching.go +++ b/conformance/tests/grpcroute-exact-method-matching.go @@ -46,7 +46,7 @@ var GRPCExactMethodMatching = suite.ConformanceTest{ ns := "gateway-conformance-infra" routeNN := types.NamespacedName{Name: "exact-matching", Namespace: ns} gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} - gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, routeNN) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN) testCases := []grpc.ExpectedResponse{ { diff --git a/conformance/tests/grpcroute-header-matching.go b/conformance/tests/grpcroute-header-matching.go index 48b6e0da66..2db1819d3e 100644 --- a/conformance/tests/grpcroute-header-matching.go +++ b/conformance/tests/grpcroute-header-matching.go @@ -46,7 +46,7 @@ var GRPCRouteHeaderMatching = suite.ConformanceTest{ ns := "gateway-conformance-infra" routeNN := types.NamespacedName{Name: "grpc-header-matching", Namespace: ns} gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} - gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, routeNN) + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN) testCases := []grpc.ExpectedResponse{{ EchoRequest: &pb.EchoRequest{}, diff --git a/conformance/tests/grpcroute-listener-hostname-matching.go b/conformance/tests/grpcroute-listener-hostname-matching.go index 0e0492e764..ba8ee64226 100644 --- a/conformance/tests/grpcroute-listener-hostname-matching.go +++ b/conformance/tests/grpcroute-listener-hostname-matching.go @@ -52,15 +52,15 @@ var GRPCRouteListenerHostnameMatching = suite.ConformanceTest{ gwNN := types.NamespacedName{Name: "grpcroute-listener-hostname-matching", Namespace: ns} _ = kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, - kubernetes.NewGatewayRef(gwNN, "listener-1"), &v1.GRPCRoute{}, + kubernetes.NewGatewayRef(gwNN, "listener-1"), &v1.GRPCRoute{}, true, types.NamespacedName{Namespace: ns, Name: "backend-v1"}, ) _ = kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, - kubernetes.NewGatewayRef(gwNN, "listener-2"), &v1.GRPCRoute{}, + kubernetes.NewGatewayRef(gwNN, "listener-2"), &v1.GRPCRoute{}, true, types.NamespacedName{Namespace: ns, Name: "backend-v2"}, ) gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, - kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"), &v1.GRPCRoute{}, + kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"), &v1.GRPCRoute{}, true, types.NamespacedName{Namespace: ns, Name: "backend-v3"}, ) diff --git a/conformance/tests/grpcroute-named-rule.go b/conformance/tests/grpcroute-named-rule.go new file mode 100644 index 0000000000..2c738a5660 --- /dev/null +++ b/conformance/tests/grpcroute-named-rule.go @@ -0,0 +1,72 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + + v1 "sigs.k8s.io/gateway-api/apis/v1" + pb "sigs.k8s.io/gateway-api/conformance/echo-basic/grpcechoserver" + "sigs.k8s.io/gateway-api/conformance/utils/grpc" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, GRPCRouteNamedRule) +} + +var GRPCRouteNamedRule = suite.ConformanceTest{ + ShortName: "GRPCRouteNamedRule", + Description: "An GRPCRoute with a named GRPCRouteRule", + Manifests: []string{"tests/grpcroute-named-rule.yaml"}, + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportGRPCRoute, + features.SupportGRPCRouteNamedRouteRule, + }, + Provisional: true, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "grpc-named-rules", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN) + + testCases := []grpc.ExpectedResponse{ + { + EchoRequest: &pb.EchoRequest{}, + Backend: "grpc-infra-backend-v1", + Namespace: ns, + }, { + EchoTwoRequest: &pb.EchoRequest{}, + Backend: "grpc-infra-backend-v2", + Namespace: ns, + }, + } + + for i := range testCases { + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + grpc.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.GRPCClient, suite.TimeoutConfig, gwAddr, tc) + }) + } + }, +} diff --git a/conformance/tests/grpcroute-named-rule.yaml b/conformance/tests/grpcroute-named-rule.yaml new file mode 100644 index 0000000000..fac94dbe2c --- /dev/null +++ b/conformance/tests/grpcroute-named-rule.yaml @@ -0,0 +1,24 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: GRPCRoute +metadata: + name: grpc-named-rules + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - name: named-rule + matches: + - method: + service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho + method: Echo + backendRefs: + - name: grpc-infra-backend-v1 + port: 8080 + - matches: + - method: + service: gateway_api_conformance.echo_basic.grpcecho.GrpcEcho + method: EchoTwo + backendRefs: + - name: grpc-infra-backend-v2 + port: 8080 diff --git a/conformance/tests/httproute-named-rule.go b/conformance/tests/httproute-named-rule.go new file mode 100644 index 0000000000..77cdccc567 --- /dev/null +++ b/conformance/tests/httproute-named-rule.go @@ -0,0 +1,71 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/kubernetes" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + ConformanceTests = append(ConformanceTests, HTTPRouteNamedRule) +} + +var HTTPRouteNamedRule = suite.ConformanceTest{ + ShortName: "HTTPRouteNamedRule", + Description: "An HTTPRoute with a named HTTPRouteRule", + Manifests: []string{"tests/httproute-named-rule.yaml"}, + Features: []features.FeatureName{ + features.SupportGateway, + features.SupportHTTPRoute, + features.SupportHTTPRouteNamedRouteRule, + }, + Provisional: true, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-infra" + routeNN := types.NamespacedName{Name: "http-named-rules", Namespace: ns} + gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns} + gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routeNN) + kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{Path: "/named"}, + Response: http.Response{StatusCode: 200}, + Namespace: ns, + }, { + Request: http.Request{Path: "/unnamed"}, + Response: http.Response{StatusCode: 200}, + Namespace: ns, + }, + } + + for i := range testCases { + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) + }) + } + }, +} diff --git a/conformance/tests/httproute-named-rule.yaml b/conformance/tests/httproute-named-rule.yaml new file mode 100644 index 0000000000..eb95c2cf03 --- /dev/null +++ b/conformance/tests/httproute-named-rule.yaml @@ -0,0 +1,24 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-named-rules + namespace: gateway-conformance-infra +spec: + parentRefs: + - name: same-namespace + rules: + - name: named-rule + matches: + - path: + type: PathPrefix + value: /named + backendRefs: + - name: infra-backend-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /unnamed + backendRefs: + - name: infra-backend-v2 + port: 8080 diff --git a/conformance/tests/httproute-weight.go b/conformance/tests/httproute-weight.go index 2a3e21afee..bafd768ad8 100644 --- a/conformance/tests/httproute-weight.go +++ b/conformance/tests/httproute-weight.go @@ -59,8 +59,10 @@ var HTTPRouteWeight = suite.ConformanceTest{ t.Run("Requests should have a distribution that matches the weight", func(t *testing.T) { expected := http.ExpectedResponse{ - Request: http.Request{Path: "/"}, - Response: http.Response{StatusCode: 200}, + Request: http.Request{Path: "/"}, + Response: http.Response{ + StatusCodes: []int{200}, + }, Namespace: "gateway-conformance-infra", } @@ -91,7 +93,6 @@ func testDistribution(t *testing.T, suite *suite.ConformanceTestSuite, gwAddr st g errgroup.Group seenMutex sync.Mutex seen = make(map[string]float64, 3 /* number of backends */) - req = http.MakeRequest(t, &expected, gwAddr, "HTTP", "http") expectedWeights = map[string]float64{ "infra-backend-v1": 0.7, "infra-backend-v2": 0.3, @@ -101,11 +102,16 @@ func testDistribution(t *testing.T, suite *suite.ConformanceTestSuite, gwAddr st g.SetLimit(concurrentRequests) for i := 0.0; i < totalRequests; i++ { g.Go(func() error { + uniqueExpected := expected + if err := http.AddEntropy(&uniqueExpected); err != nil { + return fmt.Errorf("error adding entropy: %w", err) + } + req := http.MakeRequest(t, &uniqueExpected, gwAddr, "HTTP", "http") cReq, cRes, err := roundTripper.CaptureRoundTrip(req) if err != nil { return fmt.Errorf("failed to roundtrip request: %w", err) } - if err := http.CompareRequest(t, &req, cReq, cRes, expected); err != nil { + if err := http.CompareRoundTrip(t, &req, cReq, cRes, expected); err != nil { return fmt.Errorf("response expectation failed for request: %w", err) } diff --git a/conformance/tests/main.go b/conformance/tests/main.go index 7cbcebc27f..4dc3775b27 100644 --- a/conformance/tests/main.go +++ b/conformance/tests/main.go @@ -16,6 +16,10 @@ limitations under the License. package tests -import "sigs.k8s.io/gateway-api/conformance/utils/suite" +import ( + "slices" -var ConformanceTests []suite.ConformanceTest + meshtests "sigs.k8s.io/gateway-api/conformance/tests/mesh" +) + +var ConformanceTests = slices.Clone(meshtests.MeshConformanceTests) diff --git a/conformance/tests/mesh/httproute-matching.go b/conformance/tests/mesh/httproute-matching.go new file mode 100644 index 0000000000..e0673c3a1d --- /dev/null +++ b/conformance/tests/mesh/httproute-matching.go @@ -0,0 +1,93 @@ +/* +Copyright 2022 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteMatching) +} + +var MeshHTTPRouteMatching = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteMatching", + Description: "A single HTTPRoute with path and header matching for different backends", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + }, + Manifests: []string{"tests/mesh/httproute-matching.yaml"}, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{{ + Request: http.Request{Path: "/"}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/example"}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/", Headers: map[string]string{"Version": "one"}}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/v2"}, + Backend: "echo-v2", + Namespace: ns, + }, { + Request: http.Request{Path: "/v2/example"}, + Backend: "echo-v2", + Namespace: ns, + }, { + Request: http.Request{Path: "/", Headers: map[string]string{"Version": "two"}}, + Backend: "echo-v2", + Namespace: ns, + }, { + Request: http.Request{Path: "/v2/"}, + Backend: "echo-v2", + Namespace: ns, + }, { + // Not a path segment prefix so should not match /v2. + Request: http.Request{Path: "/v2example"}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/foo/v2/example"}, + Backend: "echo-v1", + Namespace: ns, + }} + + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-matching.yaml b/conformance/tests/mesh/httproute-matching.yaml new file mode 100644 index 0000000000..fceec95b85 --- /dev/null +++ b/conformance/tests/mesh/httproute-matching.yaml @@ -0,0 +1,32 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-matching + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: / + - headers: + - name: version + value: one + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /v2 + - headers: + - name: version + value: two + backendRefs: + - name: echo-v2 + port: 8080 diff --git a/conformance/tests/mesh/httproute-named-rule.go b/conformance/tests/mesh/httproute-named-rule.go new file mode 100644 index 0000000000..9c7faf122e --- /dev/null +++ b/conformance/tests/mesh/httproute-named-rule.go @@ -0,0 +1,68 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteNamedRule) +} + +var MeshHTTPRouteNamedRule = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteNamedRule", + Description: "An HTTPRoute with a named HTTPRouteRule", + Manifests: []string{"tests/mesh/httproute-named-rule.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteNamedRouteRule, + }, + Provisional: true, + Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, suite, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{Path: "/named"}, + ExpectedRequest: &http.ExpectedRequest{Request: http.Request{Path: "/named"}}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/unnamed"}, + ExpectedRequest: &http.ExpectedRequest{Request: http.Request{Path: "/named"}}, + Backend: "echo-v2", + Namespace: ns, + }, + } + + for i := range testCases { + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, suite.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-named-rule.yaml b/conformance/tests/mesh/httproute-named-rule.yaml new file mode 100644 index 0000000000..9075968512 --- /dev/null +++ b/conformance/tests/mesh/httproute-named-rule.yaml @@ -0,0 +1,27 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-http-named-rules + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - name: named-rule + matches: + - path: + type: PathPrefix + value: /named + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /unnamed + backendRefs: + - name: echo-v2 + port: 8080 diff --git a/conformance/tests/mesh/httproute-query-param-matching.go b/conformance/tests/mesh/httproute-query-param-matching.go new file mode 100644 index 0000000000..53316d9bc8 --- /dev/null +++ b/conformance/tests/mesh/httproute-query-param-matching.go @@ -0,0 +1,135 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteQueryParamMatching) +} + +var MeshHTTPRouteQueryParamMatching = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteQueryParamMatching", + Description: "A single HTTPRoute with query param matching for different backends", + Manifests: []string{"tests/mesh/httproute-query-param-matching.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteQueryParamMatching, + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{{ + Request: http.Request{Path: "/?animal=whale"}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/?animal=dolphin"}, + Backend: "echo-v2", + Namespace: ns, + }, { + Request: http.Request{Path: "/?animal=whale&otherparam=irrelevant"}, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{Path: "/?animal=dolphin&color=yellow"}, + Backend: "echo-v2", + Namespace: ns, + }, { + Request: http.Request{Path: "/?color=blue"}, + Response: http.Response{StatusCode: 404}, + }, { + Request: http.Request{Path: "/?animal=dog"}, + Response: http.Response{StatusCode: 404}, + }, { + Request: http.Request{Path: "/?animal=whaledolphin"}, + Response: http.Response{StatusCode: 404}, + }, { + Request: http.Request{Path: "/"}, + Response: http.Response{StatusCode: 404}, + }} + + // Combinations of query param matching with other core matches. + testCases = append(testCases, []http.ExpectedResponse{ + { + Request: http.Request{Path: "/path1?animal=whale"}, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{Headers: map[string]string{"version": "one"}, Path: "/?animal=whale"}, + Backend: "echo-v2", + Namespace: ns, + }, + }...) + + // Ensure that combinations of matches which are OR'd together match + // even if only one of them is used in the request. + testCases = append(testCases, []http.ExpectedResponse{ + { + Request: http.Request{Path: "/path3?animal=shark"}, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{Headers: map[string]string{"version": "three"}, Path: "/path4?animal=kraken"}, + Backend: "echo-v1", + Namespace: ns, + }, + }...) + + // Ensure that combinations of match types which are ANDed together do not match + // when only a subset of match types is used in the request. + testCases = append(testCases, []http.ExpectedResponse{ + { + Request: http.Request{Path: "/?animal=shark"}, + Response: http.Response{StatusCode: 404}, + }, + { + Request: http.Request{Path: "/path4?animal=kraken"}, + Response: http.Response{StatusCode: 404}, + }, + }...) + + // For requests that satisfy multiple matches, ensure precedence order + // defined by the Gateway API spec is maintained. + testCases = append(testCases, []http.ExpectedResponse{ + { + Request: http.Request{Path: "/path5?animal=hydra"}, + Backend: "echo-v1", + Namespace: ns, + }, + }...) + + for i := range testCases { + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-query-param-matching.yaml b/conformance/tests/mesh/httproute-query-param-matching.yaml new file mode 100644 index 0000000000..0dd5ee4a80 --- /dev/null +++ b/conformance/tests/mesh/httproute-query-param-matching.yaml @@ -0,0 +1,85 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-query-param-matching + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - queryParams: + - name: animal + value: whale + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - queryParams: + - name: animal + value: dolphin + backendRefs: + - name: echo-v2 + port: 8080 + + # Combinations with core match types. + - matches: + - path: + type: PathPrefix + value: /path1 + queryParams: + - name: animal + value: whale + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - headers: + - name: version + value: one + queryParams: + - name: animal + value: whale + backendRefs: + - name: echo-v2 + port: 8080 + + # Match of the form (cond1 AND cond2) OR (cond3 AND cond4 AND cond5) + - matches: + - path: + type: PathPrefix + value: /path3 + queryParams: + - name: animal + value: shark + - path: + type: PathPrefix + value: /path4 + headers: + - name: version + value: three + queryParams: + - name: animal + value: kraken + backendRefs: + - name: echo-v1 + port: 8080 + + # Matches for checking precedence. + - matches: + - path: + type: PathPrefix + value: /path5 + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - queryParams: + - name: animal + value: hydra + backendRefs: + - name: echo-v2 + port: 8080 diff --git a/conformance/tests/mesh/httproute-redirect-host-and-status.go b/conformance/tests/mesh/httproute-redirect-host-and-status.go new file mode 100644 index 0000000000..055b70a256 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-host-and-status.go @@ -0,0 +1,84 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/roundtripper" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRedirectHostAndStatus) +} + +var MeshHTTPRouteRedirectHostAndStatus = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteRedirectHostAndStatus", + Description: "An HTTPRoute with hostname and statusCode redirect filters", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + }, + Manifests: []string{"tests/mesh/httproute-redirect-host-and-status.yaml"}, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Host: "echo", + Path: "/hostname-redirect", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/host-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 301, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + }, + Namespace: ns, + }, + } + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-redirect-host-and-status.yaml b/conformance/tests/mesh/httproute-redirect-host-and-status.yaml new file mode 100644 index 0000000000..8bb2779800 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-host-and-status.yaml @@ -0,0 +1,30 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-redirect-host-and-status + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /hostname-redirect + filters: + - type: RequestRedirect + requestRedirect: + hostname: example.org + - matches: + - path: + type: PathPrefix + value: /host-and-status + filters: + - type: RequestRedirect + requestRedirect: + statusCode: 301 + hostname: example.org + diff --git a/conformance/tests/mesh/httproute-redirect-path.go b/conformance/tests/mesh/httproute-redirect-path.go new file mode 100644 index 0000000000..bc4731e7a0 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-path.go @@ -0,0 +1,139 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/roundtripper" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRedirectPath) +} + +var MeshHTTPRouteRedirectPath = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteRedirectPath", + Description: "An HTTPRoute with scheme redirect filter", + Manifests: []string{"tests/mesh/httproute-redirect-path.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteRedirectPath, + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Host: "echo", + Path: "/original-prefix/lemon", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Path: "/replacement-prefix/lemon", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/full/path/original", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Path: "/full-path-replacement", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/path-and-host", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + Path: "/replacement-prefix", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/path-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 301, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Path: "/replacement-prefix", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/full-path-and-host", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + Path: "/replacement-full", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/full-path-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 301, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Path: "/replacement-full", + }, + Namespace: ns, + }, + } + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-redirect-path.yaml b/conformance/tests/mesh/httproute-redirect-path.yaml new file mode 100644 index 0000000000..05975f32a3 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-path.yaml @@ -0,0 +1,76 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-redirect-path + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /original-prefix + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplacePrefixMatch + replacePrefixMatch: /replacement-prefix + - matches: + - path: + type: PathPrefix + value: /full + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplaceFullPath + replaceFullPath: /full-path-replacement + - matches: + - path: + type: PathPrefix + value: /path-and-host + filters: + - type: RequestRedirect + requestRedirect: + hostname: example.org + path: + type: ReplacePrefixMatch + replacePrefixMatch: /replacement-prefix + - matches: + - path: + type: PathPrefix + value: /path-and-status + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplacePrefixMatch + replacePrefixMatch: /replacement-prefix + statusCode: 301 + - matches: + - path: + type: PathPrefix + value: /full-path-and-host + filters: + - type: RequestRedirect + requestRedirect: + hostname: example.org + path: + type: ReplaceFullPath + replaceFullPath: /replacement-full + - matches: + - path: + type: PathPrefix + value: /full-path-and-status + filters: + - type: RequestRedirect + requestRedirect: + path: + type: ReplaceFullPath + replaceFullPath: /replacement-full + statusCode: 301 diff --git a/conformance/tests/mesh/httproute-redirect-port.go b/conformance/tests/mesh/httproute-redirect-port.go new file mode 100644 index 0000000000..cae14c230e --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-port.go @@ -0,0 +1,113 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/roundtripper" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRedirectPort) +} + +var MeshHTTPRouteRedirectPort = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteRedirectPort", + Description: "An HTTPRoute with a port redirect filter", + Manifests: []string{"tests/mesh/httproute-redirect-port.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteRedirectPort, + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Host: "echo", + Path: "/port", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Port: "8083", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/port-and-host", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + Port: "8083", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/port-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 301, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Port: "8083", + }, + Namespace: ns, + }, { + Request: http.Request{ + Host: "echo", + Path: "/port-and-host-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Port: "8083", + Host: "example.org", + }, + Namespace: ns, + }, + } + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-redirect-port.yaml b/conformance/tests/mesh/httproute-redirect-port.yaml new file mode 100644 index 0000000000..522d67327e --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-port.yaml @@ -0,0 +1,48 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-redirect-port + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /port + filters: + - type: RequestRedirect + requestRedirect: + port: 8083 + - matches: + - path: + type: PathPrefix + value: /port-and-host + filters: + - type: RequestRedirect + requestRedirect: + hostname: example.org + port: 8083 + - matches: + - path: + type: PathPrefix + value: /port-and-status + filters: + - type: RequestRedirect + requestRedirect: + port: 8083 + statusCode: 301 + - matches: + - path: + type: PathPrefix + value: /port-and-host-and-status + filters: + - type: RequestRedirect + requestRedirect: + port: 8083 + hostname: example.org + statusCode: 302 diff --git a/conformance/tests/mesh/httproute-redirect-scheme.go b/conformance/tests/mesh/httproute-redirect-scheme.go new file mode 100644 index 0000000000..e241730914 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-scheme.go @@ -0,0 +1,116 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/roundtripper" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteSchemeRedirect) +} + +var MeshHTTPRouteSchemeRedirect = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteSchemeRedirect", + Description: "An HTTPRoute with a scheme redirect filter", + Manifests: []string{"tests/mesh/httproute-redirect-scheme.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteSchemeRedirect, + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Host: "echo", + Path: "/scheme", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Scheme: "https", + }, + Namespace: ns, + }, + { + Request: http.Request{ + Host: "echo", + Path: "/scheme-and-host", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Host: "example.org", + Scheme: "https", + }, + Namespace: ns, + }, + { + Request: http.Request{ + Host: "echo", + Path: "/scheme-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 301, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Scheme: "https", + }, + Namespace: ns, + }, + { + Request: http.Request{ + Host: "echo", + Path: "/scheme-and-host-and-status", + UnfollowRedirect: true, + }, + Response: http.Response{ + StatusCode: 302, + }, + RedirectRequest: &roundtripper.RedirectRequest{ + Scheme: "https", + Host: "example.org", + }, + Namespace: ns, + }, + } + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-redirect-scheme.yaml b/conformance/tests/mesh/httproute-redirect-scheme.yaml new file mode 100644 index 0000000000..b5f4628cd9 --- /dev/null +++ b/conformance/tests/mesh/httproute-redirect-scheme.yaml @@ -0,0 +1,49 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-redirect-scheme + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /scheme + filters: + - type: RequestRedirect + requestRedirect: + scheme: "https" + - matches: + - path: + type: PathPrefix + value: /scheme-and-host + filters: + - type: RequestRedirect + requestRedirect: + hostname: example.org + scheme: "https" + - matches: + - path: + type: PathPrefix + value: /scheme-and-status + filters: + - type: RequestRedirect + requestRedirect: + scheme: "https" + statusCode: 301 + - matches: + - path: + type: PathPrefix + value: /scheme-and-host-and-status + filters: + - type: RequestRedirect + requestRedirect: + scheme: "https" + statusCode: 302 + hostname: example.org + diff --git a/conformance/tests/mesh/httproute-request-header-modifier-backend.yaml b/conformance/tests/mesh/httproute-request-header-modifier-backend.yaml new file mode 100644 index 0000000000..4ce7dfbbd0 --- /dev/null +++ b/conformance/tests/mesh/httproute-request-header-modifier-backend.yaml @@ -0,0 +1,93 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-request-header-modifier + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /set + backendRefs: + - name: echo-v1 + port: 8080 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: set-overwrites-values + - matches: + - path: + type: PathPrefix + value: /add + backendRefs: + - name: echo-v1 + port: 8080 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + add: + - name: X-Header-Add + value: add-appends-values + - matches: + - path: + type: PathPrefix + value: /remove + backendRefs: + - name: echo-v1 + port: 8080 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + remove: + - X-Header-Remove + - matches: + - path: + type: PathPrefix + value: /multiple + backendRefs: + - name: echo-v1 + port: 8080 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set-1 + value: header-set-1 + - name: X-Header-Set-2 + value: header-set-2 + add: + - name: X-Header-Add-1 + value: header-add-1 + - name: X-Header-Add-2 + value: header-add-2 + - name: X-Header-Add-3 + value: header-add-3 + remove: + - X-Header-Remove-1 + - X-Header-Remove-2 + - matches: + - path: + type: PathPrefix + value: /case-insensitivity + backendRefs: + - name: echo-v1 + port: 8080 + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: header-set + add: + - name: X-Header-Add + value: header-add + remove: + - X-Header-Remove diff --git a/conformance/tests/mesh/httproute-request-header-modifier.go b/conformance/tests/mesh/httproute-request-header-modifier.go new file mode 100644 index 0000000000..8c7abb83fb --- /dev/null +++ b/conformance/tests/mesh/httproute-request-header-modifier.go @@ -0,0 +1,213 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, + MeshHTTPRouteRequestHeaderModifier, + MeshHTTPRouteBackendRequestHeaderModifier, + ) +} + +var MeshHTTPRouteBackendRequestHeaderModifier = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteBackendRequestHeaderModifier", + Description: "An HTTPRoute backend has request header modifier filters applied correctly", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteBackendRequestHeaderModification, + }, + Manifests: []string{"tests/mesh/httproute-request-header-modifier-backend.yaml"}, + Test: MeshHTTPRouteRequestHeaderModifier.Test, +} + +var MeshHTTPRouteRequestHeaderModifier = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteRequestHeaderModifier", + Description: "An HTTPRoute has request header modifier filters applied correctly", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + }, + Manifests: []string{"tests/mesh/httproute-request-header-modifier.yaml"}, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + testCases := []http.ExpectedResponse{ + { + Request: http.Request{ + Path: "/set", + Headers: map[string]string{ + "Some-Other-Header": "val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/set", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Set": "set-overwrites-values", + }, + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/set", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Set": "some-other-value", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/set", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Set": "set-overwrites-values", + }, + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/add", + Headers: map[string]string{ + "Some-Other-Header": "val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/add", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Add": "add-appends-values", + }, + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/add", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Add": "some-other-value", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/add", + Headers: map[string]string{ + "Some-Other-Header": "val", + "X-Header-Add": "some-other-value,add-appends-values", + }, + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/remove", + Headers: map[string]string{ + "X-Header-Remove": "val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/remove", + }, + AbsentHeaders: []string{"X-Header-Remove"}, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/multiple", + Headers: map[string]string{ + "X-Header-Set-2": "set-val-2", + "X-Header-Add-2": "add-val-2", + "X-Header-Remove-2": "remove-val-2", + "Another-Header": "another-header-val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/multiple", + Headers: map[string]string{ + "X-Header-Set-1": "header-set-1", + "X-Header-Set-2": "header-set-2", + "X-Header-Add-1": "header-add-1", + "X-Header-Add-2": "add-val-2,header-add-2", + "X-Header-Add-3": "header-add-3", + "Another-Header": "another-header-val", + }, + }, + AbsentHeaders: []string{"X-Header-Remove-1", "X-Header-Remove-2"}, + }, + Backend: "echo-v1", + Namespace: ns, + }, { + Request: http.Request{ + Path: "/case-insensitivity", + // The filter uses canonicalized header names, + // the request uses lowercase names. + Headers: map[string]string{ + "x-header-set": "original-val-set", + "x-header-add": "original-val-add", + "x-header-remove": "original-val-remove", + "Another-Header": "another-header-val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/case-insensitivity", + Headers: map[string]string{ + "X-Header-Set": "header-set", + "X-Header-Add": "original-val-add,header-add", + "Another-Header": "another-header-val", + }, + }, + AbsentHeaders: []string{"x-header-remove", "X-Header-Remove"}, + }, + Backend: "echo-v1", + Namespace: ns, + }, + } + + for i := range testCases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := testCases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + t.Parallel() + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-request-header-modifier.yaml b/conformance/tests/mesh/httproute-request-header-modifier.yaml new file mode 100644 index 0000000000..377ab22422 --- /dev/null +++ b/conformance/tests/mesh/httproute-request-header-modifier.yaml @@ -0,0 +1,93 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-request-header-modifier + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /set + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: set-overwrites-values + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /add + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + add: + - name: X-Header-Add + value: add-appends-values + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /remove + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + remove: + - X-Header-Remove + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /multiple + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set-1 + value: header-set-1 + - name: X-Header-Set-2 + value: header-set-2 + add: + - name: X-Header-Add-1 + value: header-add-1 + - name: X-Header-Add-2 + value: header-add-2 + - name: X-Header-Add-3 + value: header-add-3 + remove: + - X-Header-Remove-1 + - X-Header-Remove-2 + backendRefs: + - name: echo-v1 + port: 8080 + - matches: + - path: + type: PathPrefix + value: /case-insensitivity + filters: + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: header-set + add: + - name: X-Header-Add + value: header-add + remove: + - X-Header-Remove + backendRefs: + - name: echo-v1 + port: 8080 diff --git a/conformance/tests/mesh/httproute-rewrite-path.go b/conformance/tests/mesh/httproute-rewrite-path.go new file mode 100644 index 0000000000..22f8ae66a3 --- /dev/null +++ b/conformance/tests/mesh/httproute-rewrite-path.go @@ -0,0 +1,155 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteRewritePath) +} + +var MeshHTTPRouteRewritePath = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteRewritePath", + Description: "An HTTPRoute with path rewrite filter", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + features.SupportMeshHTTPRouteRewritePath, + }, + Manifests: []string{"tests/mesh/httproute-rewrite-path.yaml"}, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + cases := []http.ExpectedResponse{ + { + Request: http.Request{ + Path: "/prefix/one/two", + Host: "echo", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/one/two", + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/strip-prefix/three", + Host: "echo", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/three", + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/strip-prefix", + Host: "echo", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/", + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{ + Path: "/full/one/two", + Host: "echo", + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/one", + }, + }, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{ + Host: "echo", + Path: "/full/rewrite-path-and-modify-headers/test", + Headers: map[string]string{ + "X-Header-Remove": "remove-val", + "X-Header-Add-Append": "append-val-1", + "X-Header-Set": "set-val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/test", + Headers: map[string]string{ + "X-Header-Add": "header-val-1", + "X-Header-Add-Append": "append-val-1,header-val-2", + "X-Header-Set": "set-overwrites-values", + }, + }, + AbsentHeaders: []string{"X-Header-Remove"}, + }, + Backend: "echo-v1", + Namespace: ns, + }, + { + Request: http.Request{ + Host: "echo", + Path: "/prefix/rewrite-path-and-modify-headers/one", + Headers: map[string]string{ + "X-Header-Remove": "remove-val", + "X-Header-Add-Append": "append-val-1", + "X-Header-Set": "set-val", + }, + }, + ExpectedRequest: &http.ExpectedRequest{ + Request: http.Request{ + Path: "/prefix/one", + Headers: map[string]string{ + "X-Header-Add": "header-val-1", + "X-Header-Add-Append": "append-val-1,header-val-2", + "X-Header-Set": "set-overwrites-values", + }, + }, + AbsentHeaders: []string{"X-Header-Remove"}, + }, + Backend: "echo-v1", + Namespace: ns, + }, + } + for i := range cases { + // Declare tc here to avoid loop variable + // reuse issues across parallel tests. + tc := cases[i] + t.Run(tc.GetTestCaseName(i), func(t *testing.T) { + client.MakeRequestAndExpectEventuallyConsistentResponse(t, tc, s.TimeoutConfig) + }) + } + }, +} diff --git a/conformance/tests/mesh/httproute-rewrite-path.yaml b/conformance/tests/mesh/httproute-rewrite-path.yaml new file mode 100644 index 0000000000..8186746f39 --- /dev/null +++ b/conformance/tests/mesh/httproute-rewrite-path.yaml @@ -0,0 +1,101 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-rewrite-path + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - matches: + - path: + type: PathPrefix + value: /prefix/one + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: /one + backendRefs: + - name: echo-v1 + port: 80 + - matches: + - path: + type: PathPrefix + value: /strip-prefix + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: / + backendRefs: + - name: echo-v1 + port: 80 + - matches: + - path: + type: PathPrefix + value: /full/one + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplaceFullPath + replaceFullPath: /one + backendRefs: + - name: echo-v1 + port: 80 + - matches: + - path: + type: PathPrefix + value: /full/rewrite-path-and-modify-headers + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplaceFullPath + replaceFullPath: /test + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: set-overwrites-values + add: + - name: X-Header-Add + value: header-val-1 + - name: X-Header-Add-Append + value: header-val-2 + remove: + - X-Header-Remove + backendRefs: + - name: echo-v1 + port: 80 + - matches: + - path: + type: PathPrefix + value: /prefix/rewrite-path-and-modify-headers + filters: + - type: URLRewrite + urlRewrite: + path: + type: ReplacePrefixMatch + replacePrefixMatch: /prefix + - type: RequestHeaderModifier + requestHeaderModifier: + set: + - name: X-Header-Set + value: set-overwrites-values + add: + - name: X-Header-Add + value: header-val-1 + - name: X-Header-Add-Append + value: header-val-2 + remove: + - X-Header-Remove + backendRefs: + - name: echo-v1 + port: 80 diff --git a/conformance/tests/mesh/httproute-simple-same-namespace.go b/conformance/tests/mesh/httproute-simple-same-namespace.go new file mode 100644 index 0000000000..77813f29af --- /dev/null +++ b/conformance/tests/mesh/httproute-simple-same-namespace.go @@ -0,0 +1,52 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "testing" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteSimpleSameNamespace) +} + +var MeshHTTPRouteSimpleSameNamespace = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteSimpleSameNamespace", + Description: "A single HTTPRoute in the gateway-conformance-mesh namespace attaches to a Service in the same namespace", + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + }, + Manifests: []string{"tests/mesh/httproute-simple-same-namespace.yaml"}, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + ns := "gateway-conformance-mesh" + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + t.Run("Simple HTTP request should reach infra-backend", func(t *testing.T) { + client.MakeRequestAndExpectEventuallyConsistentResponse(t, http.ExpectedResponse{ + Request: http.Request{Path: "/", Host: "echo"}, + Response: http.Response{StatusCode: 200}, + Backend: "echo-v1", + Namespace: ns, + }, s.TimeoutConfig) + }) + }, +} diff --git a/conformance/tests/mesh/httproute-simple-same-namespace.yaml b/conformance/tests/mesh/httproute-simple-same-namespace.yaml new file mode 100644 index 0000000000..974d819d92 --- /dev/null +++ b/conformance/tests/mesh/httproute-simple-same-namespace.yaml @@ -0,0 +1,15 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: gateway-conformance-mesh-test + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - backendRefs: + - name: echo-v1 + port: 8080 diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go new file mode 100644 index 0000000000..844d5471e7 --- /dev/null +++ b/conformance/tests/mesh/httproute-weight.go @@ -0,0 +1,147 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import ( + "cmp" + "errors" + "fmt" + "math" + "slices" + "strings" + "sync" + "testing" + + "golang.org/x/sync/errgroup" + + "sigs.k8s.io/gateway-api/conformance/utils/echo" + "sigs.k8s.io/gateway-api/conformance/utils/http" + "sigs.k8s.io/gateway-api/conformance/utils/suite" + "sigs.k8s.io/gateway-api/pkg/features" +) + +func init() { + MeshConformanceTests = append(MeshConformanceTests, MeshHTTPRouteWeight) +} + +var MeshHTTPRouteWeight = suite.ConformanceTest{ + ShortName: "MeshHTTPRouteWeight", + Description: "An HTTPRoute with weighted backends", + Manifests: []string{"tests/mesh/httproute-weight.yaml"}, + Features: []features.FeatureName{ + features.SupportMesh, + features.SupportHTTPRoute, + }, + Test: func(t *testing.T, s *suite.ConformanceTestSuite) { + client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) + + t.Run("Requests should have a distribution that matches the weight", func(t *testing.T) { + host := "echo" + expected := http.ExpectedResponse{ + Request: http.Request{Path: "/", Host: host}, + Response: http.Response{StatusCode: 200}, + Namespace: "gateway-conformance-mesh", + } + + // Assert request succeeds before doing our distribution check + client.MakeRequestAndExpectEventuallyConsistentResponse(t, expected, s.TimeoutConfig) + for i := 0; i < 10; i++ { + if err := testDistribution(t, client, expected); err != nil { + t.Logf("Traffic distribution test failed (%d/10): %s", i+1, err) + } else { + return + } + } + t.Fatal("Weighted distribution tests failed") + }) + }, +} + +func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedResponse) error { + const ( + concurrentRequests = 10 + tolerancePercentage = 0.05 + totalRequests = 500.0 + ) + var ( + g errgroup.Group + seenMutex sync.Mutex + seen = make(map[string]float64, 2 /* number of backends */) + expectedWeights = map[string]float64{ + "echo-v1": 0.7, + "echo-v2": 0.3, + } + ) + g.SetLimit(concurrentRequests) + for i := 0.0; i < totalRequests; i++ { + g.Go(func() error { + uniqueExpected := expected + if err := http.AddEntropy(&uniqueExpected); err != nil { + return fmt.Errorf("error adding entropy: %w", err) + } + _, cRes, err := client.CaptureRequestResponseAndCompare(t, uniqueExpected) + if err != nil { + return fmt.Errorf("failed: %w", err) + } + + seenMutex.Lock() + defer seenMutex.Unlock() + + for expectedBackend := range expectedWeights { + if strings.HasPrefix(cRes.Hostname, expectedBackend) { + seen[expectedBackend]++ + return nil + } + } + + return fmt.Errorf("request was handled by an unexpected pod %q", cRes.Hostname) + }) + } + + if err := g.Wait(); err != nil { + return fmt.Errorf("error while sending requests: %w", err) + } + + var errs []error + if len(seen) != 2 { + errs = append(errs, fmt.Errorf("expected only two backends to receive traffic")) + } + + for wantBackend, wantPercent := range expectedWeights { + gotCount, ok := seen[wantBackend] + + if !ok && wantPercent != 0.0 { + errs = append(errs, fmt.Errorf("expect traffic to hit backend %q - but none was received", wantBackend)) + continue + } + + gotPercent := gotCount / totalRequests + + if math.Abs(gotPercent-wantPercent) > tolerancePercentage { + errs = append(errs, fmt.Errorf("backend %q weighted traffic of %v not within tolerance %v (+/-%f)", + wantBackend, + gotPercent, + wantPercent, + tolerancePercentage, + )) + } + } + slices.SortFunc(errs, func(a, b error) int { + return cmp.Compare(a.Error(), b.Error()) + }) + return errors.Join(errs...) +} diff --git a/conformance/tests/mesh/httproute-weight.yaml b/conformance/tests/mesh/httproute-weight.yaml new file mode 100644 index 0000000000..870c8a41dd --- /dev/null +++ b/conformance/tests/mesh/httproute-weight.yaml @@ -0,0 +1,19 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: mesh-weighted-backends + namespace: gateway-conformance-mesh +spec: + parentRefs: + - group: "" + kind: Service + name: echo + port: 80 + rules: + - backendRefs: + - name: echo-v1 + port: 8080 + weight: 70 + - name: echo-v2 + port: 8080 + weight: 30 diff --git a/conformance/tests/mesh/main.go b/conformance/tests/mesh/main.go new file mode 100644 index 0000000000..9e9c87bd58 --- /dev/null +++ b/conformance/tests/mesh/main.go @@ -0,0 +1,21 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package meshtests + +import "sigs.k8s.io/gateway-api/conformance/utils/suite" + +var MeshConformanceTests []suite.ConformanceTest diff --git a/conformance/tests/mesh-basic.go b/conformance/tests/mesh/mesh-basic.go similarity index 95% rename from conformance/tests/mesh-basic.go rename to conformance/tests/mesh/mesh-basic.go index ad878f3a48..377adce34e 100644 --- a/conformance/tests/mesh-basic.go +++ b/conformance/tests/mesh/mesh-basic.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshBasic) + MeshConformanceTests = append(MeshConformanceTests, MeshBasic) } var MeshBasic = suite.ConformanceTest{ diff --git a/conformance/tests/mesh-consumer-route.go b/conformance/tests/mesh/mesh-consumer-route.go similarity index 94% rename from conformance/tests/mesh-consumer-route.go rename to conformance/tests/mesh/mesh-consumer-route.go index 0bc4cfe522..e072ec1d27 100644 --- a/conformance/tests/mesh-consumer-route.go +++ b/conformance/tests/mesh/mesh-consumer-route.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshConsumerRoute) + MeshConformanceTests = append(MeshConformanceTests, MeshConsumerRoute) } var MeshConsumerRoute = suite.ConformanceTest{ @@ -38,7 +38,7 @@ var MeshConsumerRoute = suite.ConformanceTest{ features.SupportHTTPRoute, features.SupportHTTPRouteResponseHeaderModification, }, - Manifests: []string{"tests/mesh-consumer-route.yaml"}, + Manifests: []string{"tests/mesh/mesh-consumer-route.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { consumerClient := echo.ConnectToAppInNamespace(t, s, echo.MeshAppEchoV1, "gateway-conformance-mesh-consumer") consumerCases := []http.ExpectedResponse{ diff --git a/conformance/tests/mesh-consumer-route.yaml b/conformance/tests/mesh/mesh-consumer-route.yaml similarity index 100% rename from conformance/tests/mesh-consumer-route.yaml rename to conformance/tests/mesh/mesh-consumer-route.yaml diff --git a/conformance/tests/mesh-frontend-hostname.go b/conformance/tests/mesh/mesh-frontend-hostname.go similarity index 94% rename from conformance/tests/mesh-frontend-hostname.go rename to conformance/tests/mesh/mesh-frontend-hostname.go index 5d5e825e8a..097d3556dc 100644 --- a/conformance/tests/mesh-frontend-hostname.go +++ b/conformance/tests/mesh/mesh-frontend-hostname.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshFrontendHostname) + MeshConformanceTests = append(MeshConformanceTests, MeshFrontendHostname) } var MeshFrontendHostname = suite.ConformanceTest{ @@ -38,7 +38,7 @@ var MeshFrontendHostname = suite.ConformanceTest{ features.SupportHTTPRoute, features.SupportHTTPRouteResponseHeaderModification, }, - Manifests: []string{"tests/mesh-frontend.yaml"}, + Manifests: []string{"tests/mesh/mesh-frontend.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) cases := []http.ExpectedResponse{ diff --git a/conformance/tests/mesh-frontend.go b/conformance/tests/mesh/mesh-frontend.go similarity index 94% rename from conformance/tests/mesh-frontend.go rename to conformance/tests/mesh/mesh-frontend.go index 87b3c3437b..eb6c715243 100644 --- a/conformance/tests/mesh-frontend.go +++ b/conformance/tests/mesh/mesh-frontend.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshFrontend) + MeshConformanceTests = append(MeshConformanceTests, MeshFrontend) } var MeshFrontend = suite.ConformanceTest{ @@ -37,7 +37,7 @@ var MeshFrontend = suite.ConformanceTest{ features.SupportHTTPRoute, features.SupportHTTPRouteResponseHeaderModification, }, - Manifests: []string{"tests/mesh-frontend.yaml"}, + Manifests: []string{"tests/mesh/mesh-frontend.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) v2 := echo.ConnectToApp(t, s, echo.MeshAppEchoV2) diff --git a/conformance/tests/mesh-frontend.yaml b/conformance/tests/mesh/mesh-frontend.yaml similarity index 100% rename from conformance/tests/mesh-frontend.yaml rename to conformance/tests/mesh/mesh-frontend.yaml diff --git a/conformance/tests/mesh-ports.go b/conformance/tests/mesh/mesh-ports.go similarity index 95% rename from conformance/tests/mesh-ports.go rename to conformance/tests/mesh/mesh-ports.go index 67ebc21cef..2dfde3285e 100644 --- a/conformance/tests/mesh-ports.go +++ b/conformance/tests/mesh/mesh-ports.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshPorts) + MeshConformanceTests = append(MeshConformanceTests, MeshPorts) } var MeshPorts = suite.ConformanceTest{ @@ -38,7 +38,7 @@ var MeshPorts = suite.ConformanceTest{ features.SupportHTTPRouteParentRefPort, features.SupportHTTPRouteResponseHeaderModification, }, - Manifests: []string{"tests/mesh-ports.yaml"}, + Manifests: []string{"tests/mesh/mesh-ports.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) cases := []http.ExpectedResponse{ diff --git a/conformance/tests/mesh-ports.yaml b/conformance/tests/mesh/mesh-ports.yaml similarity index 100% rename from conformance/tests/mesh-ports.yaml rename to conformance/tests/mesh/mesh-ports.yaml diff --git a/conformance/tests/mesh-split.go b/conformance/tests/mesh/mesh-split.go similarity index 93% rename from conformance/tests/mesh-split.go rename to conformance/tests/mesh/mesh-split.go index 0864bbe378..dcb80ef90f 100644 --- a/conformance/tests/mesh-split.go +++ b/conformance/tests/mesh/mesh-split.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package tests +package meshtests import ( "testing" @@ -26,7 +26,7 @@ import ( ) func init() { - ConformanceTests = append(ConformanceTests, MeshTrafficSplit) + MeshConformanceTests = append(MeshConformanceTests, MeshTrafficSplit) } var MeshTrafficSplit = suite.ConformanceTest{ @@ -36,7 +36,7 @@ var MeshTrafficSplit = suite.ConformanceTest{ features.SupportMesh, features.SupportHTTPRoute, }, - Manifests: []string{"tests/mesh-split.yaml"}, + Manifests: []string{"tests/mesh/mesh-split.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { client := echo.ConnectToApp(t, s, echo.MeshAppEchoV1) cases := []http.ExpectedResponse{ diff --git a/conformance/tests/mesh-split.yaml b/conformance/tests/mesh/mesh-split.yaml similarity index 100% rename from conformance/tests/mesh-split.yaml rename to conformance/tests/mesh/mesh-split.yaml diff --git a/conformance/tests/tlsroute-simple-same-namespace.go b/conformance/tests/tlsroute-simple-same-namespace.go index 51db62aeff..b8704c4b8b 100644 --- a/conformance/tests/tlsroute-simple-same-namespace.go +++ b/conformance/tests/tlsroute-simple-same-namespace.go @@ -49,7 +49,7 @@ var TLSRouteSimpleSameNamespace = suite.ConformanceTest{ ns := "gateway-conformance-infra" routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: ns} gwNN := types.NamespacedName{Name: "gateway-tlsroute", Namespace: ns} - certNN := types.NamespacedName{Name: "tls-passthrough-checks-certificate", Namespace: ns} + certNN := types.NamespacedName{Name: "tls-checks-certificate", Namespace: ns} kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) diff --git a/conformance/utils/echo/parse.go b/conformance/utils/echo/parse.go index a175df926c..edabded67b 100644 --- a/conformance/utils/echo/parse.go +++ b/conformance/utils/echo/parse.go @@ -184,9 +184,8 @@ func ParseResponse(output string) Response { if len(sl) != 2 { continue } - out.RequestHeaders.Set(sl[0], sl[1]) + out.RequestHeaders.Add(sl[0], sl[1]) } - matches = responseHeaderFieldRegex.FindAllStringSubmatch(output, -1) for _, kv := range matches { sl := strings.SplitN(kv[1], ":", 2) diff --git a/conformance/utils/echo/pod.go b/conformance/utils/echo/pod.go index f61d843744..dff03ed5fa 100644 --- a/conformance/utils/echo/pod.go +++ b/conformance/utils/echo/pod.go @@ -20,6 +20,8 @@ import ( "bytes" "context" "fmt" + "slices" + "strconv" "strings" "testing" "time" @@ -58,7 +60,7 @@ func (m *MeshPod) MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, t.Helper() http.AwaitConvergence(t, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency, func(elapsed time.Duration) bool { - req := makeRequest(t, exp.Request) + req := makeRequest(t, &exp) resp, err := m.request(req) if err != nil { @@ -76,7 +78,25 @@ func (m *MeshPod) MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, tlog.Logf(t, "Request passed") } -func makeRequest(t *testing.T, r http.Request) []string { +func makeRequest(t *testing.T, exp *http.ExpectedResponse) []string { + if exp.Request.Host == "" { + exp.Request.Host = "echo" + } + if exp.Request.Method == "" { + exp.Request.Method = "GET" + } + + // if the deprecated field StatusCode is set, append it to StatusCodes for backwards compatibility + //nolint:staticcheck + if exp.Response.StatusCode != 0 { + exp.Response.StatusCodes = append(exp.Response.StatusCodes, exp.Response.StatusCode) + } + + if len(exp.Response.StatusCodes) == 0 { + exp.Response.StatusCodes = []int{200} + } + + r := exp.Request protocol := strings.ToLower(r.Protocol) if protocol == "" { protocol = "http" @@ -87,22 +107,60 @@ func makeRequest(t *testing.T, r http.Request) []string { args = append(args, "--method="+r.Method) } for k, v := range r.Headers { - args = append(args, "-H", fmt.Sprintf("%v: %v", k, v)) + args = append(args, "-H", fmt.Sprintf("%v:%v", k, v)) } return args } func compareRequest(exp http.ExpectedResponse, resp Response) error { - want := exp.Response - if fmt.Sprint(want.StatusCode) != resp.Code { - return fmt.Errorf("wanted status code %v, got %v", want.StatusCode, resp.Code) + if exp.ExpectedRequest == nil { + exp.ExpectedRequest = &http.ExpectedRequest{} } - for _, name := range want.AbsentHeaders { + wantReq := exp.ExpectedRequest + wantResp := exp.Response + statusCode, err := strconv.Atoi(resp.Code) + if err != nil { + return fmt.Errorf("invalid status code '%v': %v", resp.Code, err) + } + if !slices.Contains(wantResp.StatusCodes, statusCode) { + return fmt.Errorf("wanted status code to be one of %v, got %d", wantResp.StatusCodes, statusCode) + } + if wantReq.Headers != nil { + if resp.RequestHeaders == nil { + return fmt.Errorf("no headers captured, expected %v", len(wantReq.Headers)) + } + for name, val := range resp.RequestHeaders { + resp.RequestHeaders[strings.ToLower(name)] = val + } + for name, expectedVal := range wantReq.Headers { + actualVal, ok := resp.RequestHeaders[strings.ToLower(name)] + if !ok { + return fmt.Errorf("expected %s header to be set, actual headers: %v", name, resp.RequestHeaders) + } + if strings.Join(actualVal, ",") != expectedVal { + return fmt.Errorf("expected %s header to be set to %s, got %s", name, expectedVal, strings.Join(actualVal, ",")) + } + } + } + if len(wantReq.AbsentHeaders) > 0 { + for name, val := range resp.RequestHeaders { + resp.RequestHeaders[strings.ToLower(name)] = val + } + + for _, name := range wantReq.AbsentHeaders { + val, ok := resp.RequestHeaders[strings.ToLower(name)] + if ok { + return fmt.Errorf("expected %s header to not be set, got %s", name, val) + } + } + } + + for _, name := range wantResp.AbsentHeaders { if v := resp.ResponseHeaders.Values(name); len(v) != 0 { return fmt.Errorf("expected no header %q, got %v", name, v) } } - for k, v := range want.Headers { + for k, v := range wantResp.Headers { if got := resp.ResponseHeaders.Get(k); got != v { return fmt.Errorf("expected header %v=%v, got %v", k, v, got) } @@ -177,3 +235,19 @@ func ConnectToAppInNamespace(t *testing.T, s *suite.ConformanceTestSuite, app Me rcfg: s.RestConfig, } } + +func (m *MeshPod) CaptureRequestResponseAndCompare(t *testing.T, exp http.ExpectedResponse) ([]string, Response, error) { + req := makeRequest(t, &exp) + + resp, err := m.request(req) + if err != nil { + tlog.Logf(t, "Request %v failed, not ready yet: %v", req, err.Error()) + return []string{}, Response{}, err + } + tlog.Logf(t, "Got resp %v", resp) + if err := compareRequest(exp, resp); err != nil { + tlog.Logf(t, "Response expectation failed for request: %v not ready yet: %v", req, err) + return []string{}, Response{}, err + } + return req, resp, nil +} diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go index 7866790321..6cd68dd084 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -17,9 +17,12 @@ limitations under the License. package http import ( + "crypto/rand" "fmt" + "math/big" "net" "net/url" + "slices" "strings" "testing" "time" @@ -58,6 +61,10 @@ type ExpectedResponse struct { // User Given TestCase name TestCaseName string + + // ServerName indicates the hostname to which the client attempts to connect, + // and which is seen by the backend. + ServerName string } // Request can be used as both the request to make and a means to verify @@ -70,6 +77,8 @@ type Request struct { Headers map[string]string UnfollowRedirect bool Protocol string + Body string + SNI string } // ExpectedRequest defines expected properties of a request that reaches a backend. @@ -83,9 +92,12 @@ type ExpectedRequest struct { // Response defines expected properties of a response from a backend. type Response struct { + // Deprecated: Use StatusCodes instead, which supports matching against multiple status codes. StatusCode int + StatusCodes []int Headers map[string]string AbsentHeaders []string + Protocol string } type BackendRef struct { @@ -111,6 +123,17 @@ func MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, r roundtripp WaitForConsistentResponse(t, r, req, expected, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency) } +// MakeRequestAndExpectFailure makes a request with the given parameters. +// This function needs to ensure that after the system is stable the Request is +// not returning http 200 StatusCode. +func MakeRequestAndExpectFailure(t *testing.T, r roundtripper.RoundTripper, timeoutConfig config.TimeoutConfig, gwAddr string, expected ExpectedResponse) { + t.Helper() + + req := MakeRequest(t, &expected, gwAddr, "HTTP", "http") + + WaitForConsistentFailureResponse(t, r, req, 5, timeoutConfig.MaxTimeToConsistency) +} + func MakeRequest(t *testing.T, expected *ExpectedResponse, gwAddr, protocol, scheme string) roundtripper.Request { t.Helper() @@ -118,8 +141,13 @@ func MakeRequest(t *testing.T, expected *ExpectedResponse, gwAddr, protocol, sch expected.Request.Method = "GET" } - if expected.Response.StatusCode == 0 { - expected.Response.StatusCode = 200 + // if the deprecated field StatusCode is set, append it to StatusCodes for backwards compatibility + if expected.Response.StatusCode != 0 { + expected.Response.StatusCodes = append(expected.Response.StatusCodes, expected.Response.StatusCode) + } + + if len(expected.Response.StatusCodes) == 0 { + expected.Response.StatusCodes = []int{200} } if expected.Request.Protocol == "" { @@ -129,7 +157,7 @@ func MakeRequest(t *testing.T, expected *ExpectedResponse, gwAddr, protocol, sch path, query, _ := strings.Cut(expected.Request.Path, "?") reqURL := url.URL{Scheme: scheme, Host: CalculateHost(t, gwAddr, scheme), Path: path, RawQuery: query} - tlog.Logf(t, "Making %s request to %s", expected.Request.Method, reqURL.String()) + tlog.Logf(t, "Making %s request to host %s via %s", expected.Request.Method, expected.Request.Host, reqURL.String()) req := roundtripper.Request{ T: t, @@ -139,6 +167,7 @@ func MakeRequest(t *testing.T, expected *ExpectedResponse, gwAddr, protocol, sch Protocol: expected.Request.Protocol, Headers: map[string][]string{}, UnfollowRedirect: expected.Request.UnfollowRedirect, + Body: expected.Request.Body, } if expected.Request.Headers != nil { @@ -170,7 +199,10 @@ func CalculateHost(t *testing.T, gwAddr, scheme string) string { host, port, err = net.SplitHostPort(gwAddr) } if err != nil { - tlog.Logf(t, "Failed to parse host %q: %v", gwAddr, err) + // An address without a port causes an error, but it's fine for some cases. + if !strings.Contains(err.Error(), "missing port in address") { + tlog.Logf(t, "Failed to parse host %q: %v", gwAddr, err) + } return gwAddr } if strings.ToLower(scheme) == "http" && port == "80" { @@ -241,7 +273,7 @@ func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req ro return false } - if err := CompareRequest(t, &req, cReq, cRes, expected); err != nil { + if err := CompareRoundTrip(t, &req, cReq, cRes, expected); err != nil { tlog.Logf(t, "Response expectation failed for request: %+v not ready yet: %v (after %v)", req, err, elapsed) return false } @@ -251,15 +283,44 @@ func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req ro tlog.Logf(t, "Request passed") } -func CompareRequest(t *testing.T, req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected ExpectedResponse) error { +// WaitForConsistentFailureResponse repeats the provided request for the given +// period of time and ensures an error is returned each time. This function fails +// when HTTP Status OK (200) is returned. +func WaitForConsistentFailureResponse(t *testing.T, r roundtripper.RoundTripper, req roundtripper.Request, threshold int, maxTimeToConsistency time.Duration) { + AwaitConvergence(t, threshold, maxTimeToConsistency, func(elapsed time.Duration) bool { + _, cRes, err := r.CaptureRoundTrip(req) + if err != nil { + tlog.Logf(t, "Request failed, not ready yet: %v (after %v)", err.Error(), elapsed) + return false + } + if roundtripper.IsTimeoutError(cRes.StatusCode) { + tlog.Logf(t, "Response expectation failed for request: %+v not ready yet: %v (after %v)", req, cRes.StatusCode, elapsed) + return false + } + if cRes.StatusCode == 200 { // http:StatusCode OK + t.Fatalf("Request %+v should failed, returned HTTP Status OK (200) instead", req) + return false + } + return true + }) + tlog.Logf(t, "Expectation for failing Request are met") +} + +func CompareRoundTrip(t *testing.T, req *roundtripper.Request, cReq *roundtripper.CapturedRequest, cRes *roundtripper.CapturedResponse, expected ExpectedResponse) error { if roundtripper.IsTimeoutError(cRes.StatusCode) { - if roundtripper.IsTimeoutError(expected.Response.StatusCode) { - return nil + for _, statusCode := range expected.Response.StatusCodes { + if roundtripper.IsTimeoutError(statusCode) { + return nil + } } } - if expected.Response.StatusCode != cRes.StatusCode { - return fmt.Errorf("expected status code to be %d, got %d", expected.Response.StatusCode, cRes.StatusCode) + if !slices.Contains(expected.Response.StatusCodes, cRes.StatusCode) { + return fmt.Errorf("expected status code to be one of %v, got %d. CRes: %v", expected.Response.StatusCodes, cRes.StatusCode, cRes) + } + if expected.Response.Protocol != "" && expected.Response.Protocol != cRes.Protocol { + return fmt.Errorf("expected protocol to be %s, got %s", expected.Response.Protocol, cRes.Protocol) } + if cRes.StatusCode == 200 { // The request expected to arrive at the backend is // the same as the request made, unless otherwise @@ -351,6 +412,10 @@ func CompareRequest(t *testing.T, req *roundtripper.Request, cReq *roundtripper. if !strings.HasPrefix(cReq.Pod, expected.Backend) { return fmt.Errorf("expected pod name to start with %s, got %s", expected.Backend, cReq.Pod) } + + if expected.ExpectedRequest.SNI != "" && expected.ExpectedRequest.SNI != cReq.TLS.ServerName { + return fmt.Errorf("expected SNI %q to be equal to %q", cReq.TLS.ServerName, expected.ExpectedRequest.SNI) + } } else if roundtripper.IsRedirect(cRes.StatusCode) { if expected.RedirectRequest == nil { return nil @@ -412,7 +477,8 @@ func (er *ExpectedResponse) GetTestCaseName(i int) string { if er.Backend != "" { return fmt.Sprintf("%s should go to %s", reqStr, er.Backend) } - return fmt.Sprintf("%s should receive a %d", reqStr, er.Response.StatusCode) + + return fmt.Sprintf("%s should receive one of %v", reqStr, er.Response.StatusCodes) } func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.CapturedResponse, expected *ExpectedResponse) { @@ -430,3 +496,54 @@ func setRedirectRequestDefaults(req *roundtripper.Request, cRes *roundtripper.Ca expected.RedirectRequest.Path = req.URL.Path } } + +// addEntropy adds jitter to the request by adding either a delay up to 1 second, or a random header value, or both. +func AddEntropy(exp *ExpectedResponse) error { + randomNumber := func(limit int64) (*int64, error) { + number, err := rand.Int(rand.Reader, big.NewInt(limit)) + if err != nil { + return nil, err + } + n := number.Int64() + return &n, nil + } + + // adds a delay + delay := func(limit int64) error { + randomSleepDuration, err := randomNumber(limit) + if err != nil { + return err + } + time.Sleep(time.Duration(*randomSleepDuration) * time.Millisecond) + return nil + } + // adds random header value + randomHeader := func(limit int64) error { + randomHeaderValue, err := randomNumber(limit) + if err != nil { + return err + } + exp.Request.Headers = make(map[string]string) + exp.Request.Headers["X-Jitter"] = fmt.Sprintf("%d", *randomHeaderValue) + return nil + } + + random, err := randomNumber(3) + if err != nil { + return err + } + + switch *random { + case 0: + return delay(1000) + case 1: + return randomHeader(10000) + case 2: + if err := delay(1000); err != nil { + return err + } + return randomHeader(10000) + default: + return fmt.Errorf("invalid random value: %d", *random) + } +} diff --git a/conformance/utils/kubernetes/certificate.go b/conformance/utils/kubernetes/certificate.go index a0f70ddd14..1b2ee3af85 100644 --- a/conformance/utils/kubernetes/certificate.go +++ b/conformance/utils/kubernetes/certificate.go @@ -27,12 +27,15 @@ import ( "io" "math/big" "net" + "net/url" + "strings" "testing" "time" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + kvalidation "k8s.io/apimachinery/pkg/util/validation" ) const ( @@ -46,8 +49,25 @@ func MustCreateSelfSignedCertSecret(t *testing.T, namespace, secretName string, var serverKey, serverCert bytes.Buffer - require.NoError(t, generateRSACert(hosts, &serverKey, &serverCert), "failed to generate RSA certificate") + require.NoError(t, generateRSACert(hosts, &serverKey, &serverCert, nil, nil), "failed to generate RSA certificate") + return formatSecret(serverCert, serverKey, namespace, secretName) +} + +// MustCreateCASignedCertSecret creates a CA-signed SSL certificate and stores it in a secret +func MustCreateCASignedCertSecret(t *testing.T, namespace, secretName string, hosts []string, ca *x509.Certificate, caPrivKey *rsa.PrivateKey) *corev1.Secret { + require.NotEmpty(t, hosts, "require a non-empty hosts for Subject Alternate Name values") + + var serverCert, serverKey bytes.Buffer + + require.NoError(t, generateRSACert(hosts, &serverKey, &serverCert, ca, caPrivKey), "failed to generate CA signed RSA certificate") + + return formatSecret(serverCert, serverKey, namespace, secretName) +} + +// formatSecret formats the server certificate, key, namespace, and secretName +// and converts it to a Kubernetes Secret object. +func formatSecret(serverCert bytes.Buffer, serverKey bytes.Buffer, namespace string, secretName string) *corev1.Secret { data := map[string][]byte{ corev1.TLSCertKey: serverCert.Bytes(), corev1.TLSPrivateKeyKey: serverKey.Bytes(), @@ -65,8 +85,9 @@ func MustCreateSelfSignedCertSecret(t *testing.T, namespace, secretName string, return newSecret } -// generateRSACert generates a basic self-signed certificate valid for a year -func generateRSACert(hosts []string, keyOut, certOut io.Writer) error { +// generateRSACert generates a basic self-signed certificate if ca and caPrivKey are nil, +// otherwise it creates CA-signed cert with ca and caPrivkey input. Certs are valid for a year. +func generateRSACert(hosts []string, keyOut, certOut io.Writer, ca *x509.Certificate, caPrivKey *rsa.PrivateKey) error { priv, err := rsa.GenerateKey(rand.Reader, rsaBits) if err != nil { return fmt.Errorf("failed to generate key: %w", err) @@ -97,12 +118,22 @@ func generateRSACert(hosts []string, keyOut, certOut io.Writer) error { for _, h := range hosts { if ip := net.ParseIP(h); ip != nil { template.IPAddresses = append(template.IPAddresses, ip) - } else { + } else if err = validateHost(h); err == nil { template.DNSNames = append(template.DNSNames, h) + } else if u, parseErr := url.Parse(h); parseErr == nil { + template.URIs = append(template.URIs, u) } } - derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if caPrivKey == nil { + caPrivKey = priv + } + // If ca is nil, we create a self-signed certificate, e.g. template is the parent. + if ca == nil { + ca = &template + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, ca, &priv.PublicKey, caPrivKey) if err != nil { return fmt.Errorf("failed to create certificate: %w", err) } @@ -117,3 +148,119 @@ func generateRSACert(hosts []string, keyOut, certOut io.Writer) error { return nil } + +// MustCreateCACertConfigMap will create a ConfigMap containing a CA Certificate, given a TLS Secret +// for that CA certificate. Also returns the CA certificate. +func MustCreateCACertConfigMap(t *testing.T, namespace, configMapName string, hosts []string) (*corev1.ConfigMap, *x509.Certificate, *rsa.PrivateKey) { + require.NotEmpty(t, hosts, "require a non-empty hosts for Subject Alternate Name values") + + var certData, keyData bytes.Buffer + + ca, caBytes, caPrivKey, err := generateCACert(hosts) + if err != nil { + t.Errorf("failed to generate CA certificate and key: %v", err) + return nil, nil, nil + } + + if err := pem.Encode(&certData, &pem.Block{Type: "CERTIFICATE", Bytes: caBytes}); err != nil { + t.Errorf("failed creating cert: %v", err) + return nil, nil, nil + } + + if err := pem.Encode(&keyData, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey)}); err != nil { + t.Errorf("failed creating key: %v", err) + return nil, nil, nil + } + + // Store the certificate in a ConfigMap. + caConfigMap := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: namespace, + Name: configMapName, + }, + Data: map[string]string{ + "ca.crt": certData.String(), + // Don't do this in production, this is just for conformance testing. + "key.crt": keyData.String(), + }, + } + return caConfigMap, ca, caPrivKey +} + +// generateCACert generates a CA and a CA-signed certificate valid for a year. +func generateCACert(hosts []string) (*x509.Certificate, []byte, *rsa.PrivateKey, error) { + var caBytes []byte + + // Create the CA certificate template. + ca := &x509.Certificate{ + SerialNumber: big.NewInt(2024), + Subject: pkix.Name{ + Organization: []string{"Kubernetes Gateway API"}, + Country: []string{"US"}, + CommonName: "gatewayapi", + }, + Issuer: pkix.Name{ + Organization: []string{"Kubernetes Gateway API"}, + Country: []string{"US"}, + CommonName: "kubernetes", + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(1, 0, 0), + IsCA: true, // Indicates this is a CA Certificate. + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + BasicConstraintsValid: true, + } + + // Ensure only valid hosts make it into the CA cert. + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + ca.IPAddresses = append(ca.IPAddresses, ip) + } else if err := validateHost(h); err == nil { + ca.DNSNames = append(ca.DNSNames, h) + } else if u, err := url.Parse(h); err == nil { + ca.URIs = append(ca.URIs, u) + } + } + + // Generate the private key to sign certificates. + caPrivKey, err := rsa.GenerateKey(rand.Reader, rsaBits) + if err != nil { + return nil, caBytes, caPrivKey, fmt.Errorf("error generating key for CA: %v", err) + } + + // Create the self-signed certificate using the CA certificate. + caBytes, err = x509.CreateCertificate(rand.Reader, ca, ca, &caPrivKey.PublicKey, caPrivKey) + if err != nil { + return nil, caBytes, caPrivKey, fmt.Errorf("error creating CA: %v", err) + } + + return ca, caBytes, caPrivKey, nil +} + +// validateHost ensures that the host name length is no more than 253 characters. +// The only characters allowed in host name are alphanumeric characters, '-' or '.', +// and it must start and end with an alphanumeric character. A trailing dot is NOT allowed. +// The host name must in addition consist of one or more labels, with each label no more +// than 63 characters from the character set described above, and each label must start and +// end with an alphanumeric character. Wildcards are handled specially. +// DO NOT USE for general validation purposes, this is just for the hostnames set up for +// conformance testing. +func validateHost(host string) error { + // Remove wildcard if present. + host, _ = strings.CutPrefix(host, "*.") + + errs := kvalidation.IsDNS1123Subdomain(host) + if len(errs) != 0 { + return fmt.Errorf("host %s must conform to DNS naming conventions: %v", host, errs) + } + + labels := strings.Split(host, ".") + for _, l := range labels { + errs := kvalidation.IsDNS1123Label(l) + if len(errs) != 0 { + return fmt.Errorf("label %s in host %s must conform to DNS naming conventions: %v", l, host, errs) + } + } + return nil +} diff --git a/conformance/utils/kubernetes/certificate_test.go b/conformance/utils/kubernetes/certificate_test.go new file mode 100644 index 0000000000..f6c78048a9 --- /dev/null +++ b/conformance/utils/kubernetes/certificate_test.go @@ -0,0 +1,101 @@ +/* +Copyright 2024 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package kubernetes + +import ( + "bytes" + "crypto/x509" + "encoding/pem" + "testing" + + "github.com/stretchr/testify/require" +) + +func Test_generateCACert(t *testing.T) { + tests := []struct { + name string + hosts []string + expectedErr []string + }{ + { + name: "one host generates cert with no host", + hosts: []string{}, + }, + { + name: "one host generates cert for same host", + hosts: []string{"abc.example.com"}, + }, + { + name: "wildcard generates cert for same host", + hosts: []string{"*.example.com"}, + }, + { + name: "two hosts generates cert for both hosts", + hosts: []string{"abc.example.com", "def.example.com"}, + }, + { + name: "bad host generates cert for no host", + hosts: []string{"--abc.example.com"}, + expectedErr: []string{"x509: certificate is not valid for any names, but wanted to match --abc.example.com"}, + }, + { + name: "one good host and one bad host generates cert for only good host", + hosts: []string{"---.example.com", "def.example.com"}, + expectedErr: []string{"x509: certificate is valid xxx for def.example.com, not ---.example.com", ""}, + }, + } + + var serverKey, serverCert bytes.Buffer + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + serverCert.Reset() + serverKey.Reset() + // Test the function generateCACert. We can only test normative function + // and hostnames, everything else is hardcoded. + _, caBytes, caPrivKey, err := generateCACert(tc.hosts) + require.NoError(t, err, "unexpected error generating RSA certificate") + + var certData bytes.Buffer + if err := pem.Encode(&certData, &pem.Block{Type: "CERTIFICATE", Bytes: caBytes}); err != nil { + require.NoError(t, err, "failed to create certificater") + } + + var keyData bytes.Buffer + if err := pem.Encode(&keyData, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(caPrivKey)}); err != nil { + require.NoError(t, err, "failed to create key") + } + + // Test that the CA certificate is decodable, parseable, and has the configured hostname/s. + block, _ := pem.Decode(certData.Bytes()) + if block == nil { + require.FailNow(t, "failed to decode PEM block containing cert") + } else if block.Type == "CERTIFICATE" { + cert, err := x509.ParseCertificate(block.Bytes) + require.NoError(t, err, "failed to parse certificate") + for idx, h := range tc.hosts { + err = cert.VerifyHostname(h) + if err != nil && len(tc.expectedErr) > 0 && tc.expectedErr[idx] == "" { + require.EqualValues(t, tc.expectedErr[idx], err.Error(), "certificate verification failed") + } else if err == nil && len(tc.expectedErr) > 0 && tc.expectedErr[idx] != "" { + require.EqualValues(t, tc.expectedErr[idx], err, "expected an error but certification verification succeeded") + } + } + } + }) + } +} diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index 2b43828c09..3309c8f29b 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -37,6 +37,7 @@ import ( gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/gateway-api/apis/v1alpha3" "sigs.k8s.io/gateway-api/conformance/utils/config" "sigs.k8s.io/gateway-api/conformance/utils/tlog" ) @@ -331,14 +332,22 @@ func MeshNamespacesMustBeReady(t *testing.T, c client.Client, timeoutConfig conf // - ListenerConditionProgrammed // // The test will fail if these conditions are not met before the timeouts. -func GatewayAndRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, controllerName string, gw GatewayRef, routeType any, routeNNs ...types.NamespacedName) string { +// Note that this also returns a Gateway address to use, but it takes the port +// from the first listener it finds. Set parameter `usePort` to false if there +// are multiple listeners, and true if there is only one listener. +func GatewayAndRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, controllerName string, gw GatewayRef, routeType any, usePort bool, routeNNs ...types.NamespacedName) string { t.Helper() RouteTypeMustHaveParentsField(t, routeType) gwAddr, err := WaitForGatewayAddress(t, c, timeoutConfig, gw) - require.NoErrorf(t, err, "timed out waiting for Gateway address to be assigned") + // If the Gateway has multiple listeners, get a portless gwAddr. + // Otherwise, you get the first listener's port, which might not be the one you want. + if !usePort { + gwAddr, _, _ = strings.Cut(gwAddr, ":") + } + ns := gatewayv1.Namespace(gw.Namespace) kind := gatewayv1.Kind("Gateway") @@ -401,7 +410,7 @@ func GatewayAndRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutConfig // // The test will fail if these conditions are not met before the timeouts. func GatewayAndHTTPRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, controllerName string, gw GatewayRef, routeNNs ...types.NamespacedName) string { - return GatewayAndRoutesMustBeAccepted(t, c, timeoutConfig, controllerName, gw, &gatewayv1.HTTPRoute{}, routeNNs...) + return GatewayAndRoutesMustBeAccepted(t, c, timeoutConfig, controllerName, gw, &gatewayv1.HTTPRoute{}, true, routeNNs...) } // GatewayAndUDPRoutesMustBeAccepted waits until the specified Gateway has an IP @@ -409,7 +418,7 @@ func GatewayAndHTTPRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutCo // Gateway. The test will fail if these conditions are not met before the // timeouts. func GatewayAndUDPRoutesMustBeAccepted(t *testing.T, c client.Client, timeoutConfig config.TimeoutConfig, controllerName string, gw GatewayRef, routeNNs ...types.NamespacedName) string { - return GatewayAndRoutesMustBeAccepted(t, c, timeoutConfig, controllerName, gw, &v1alpha2.UDPRoute{}, routeNNs...) + return GatewayAndRoutesMustBeAccepted(t, c, timeoutConfig, controllerName, gw, &v1alpha2.UDPRoute{}, true, routeNNs...) } // WaitForGatewayAddress waits until at least one IP Address has been set in the @@ -419,16 +428,10 @@ func WaitForGatewayAddress(t *testing.T, client client.Client, timeoutConfig con var ipAddr, port string waitErr := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, timeoutConfig.GatewayMustHaveAddress, true, func(ctx context.Context) (bool, error) { - gw := &gatewayv1.Gateway{} - err := client.Get(ctx, gwRef.NamespacedName, gw) - if err != nil { - tlog.Logf(t, "error fetching Gateway: %v", err) - return false, fmt.Errorf("error fetching Gateway: %w", err) - } - - if err := ConditionsHaveLatestObservedGeneration(gw, gw.Status.Conditions); err != nil { - tlog.Log(t, "Gateway", err) - return false, nil + gw, err := getGatewayStatus(ctx, t, client, gwRef) + if gw == nil { + // The returned error is nil if the Gateway conditions don't have the latest observed generation. + return false, err } listener := gw.Spec.Listeners[0] @@ -442,20 +445,34 @@ func WaitForGatewayAddress(t *testing.T, client client.Client, timeoutConfig con } } port = strconv.FormatInt(int64(listener.Port), 10) - for _, address := range gw.Status.Addresses { - if address.Type != nil && (*address.Type == gatewayv1.IPAddressType || *address.Type == v1alpha2.HostnameAddressType) { + if address.Type != nil { ipAddr = address.Value return true, nil } } - return false, nil }) require.NoErrorf(t, waitErr, "error waiting for Gateway to have at least one IP address in status") return net.JoinHostPort(ipAddr, port), waitErr } +func getGatewayStatus(ctx context.Context, t *testing.T, client client.Client, gwRef GatewayRef) (*gatewayv1.Gateway, error) { + gw := &gatewayv1.Gateway{} + err := client.Get(ctx, gwRef.NamespacedName, gw) + if err != nil { + tlog.Logf(t, "error fetching Gateway: %v", err) + return nil, fmt.Errorf("error fetching Gateway: %w", err) + } + + if err := ConditionsHaveLatestObservedGeneration(gw, gw.Status.Conditions); err != nil { + tlog.Log(t, "Gateway", err) + return nil, nil + } + + return gw, nil +} + // GatewayListenersMustHaveConditions checks if every listener of the specified gateway has all // the specified conditions. func GatewayListenersMustHaveConditions(t *testing.T, client client.Client, timeoutConfig config.TimeoutConfig, gwName types.NamespacedName, conditions []metav1.Condition) { @@ -977,3 +994,47 @@ func findPodConditionInList(t *testing.T, conditions []v1.PodCondition, condName tlog.Logf(t, "%s was not in conditions list", condName) return false } + +// BackendTLSPolicyMustHaveCondition checks that the created BackentTLSPolicy has the Condition, +// halting after the specified timeout is exceeded. +func BackendTLSPolicyMustHaveCondition(t *testing.T, client client.Client, timeoutConfig config.TimeoutConfig, policyNN, gwNN types.NamespacedName, condition metav1.Condition) { + t.Helper() + waitErr := wait.PollUntilContextTimeout(context.Background(), 1*time.Second, timeoutConfig.HTTPRouteMustHaveCondition, true, func(ctx context.Context) (bool, error) { + policy := &v1alpha3.BackendTLSPolicy{} + err := client.Get(ctx, policyNN, policy) + if err != nil { + return false, fmt.Errorf("error fetching BackendTLSPolicy %v err: %w", policyNN, err) + } + + for _, parent := range policy.Status.Ancestors { + if err := ConditionsHaveLatestObservedGeneration(policy, parent.Conditions); err != nil { + tlog.Logf(t, "BackendTLSPolicy %s (parentRef=%v) %v", + policyNN, parentRefToString(parent.AncestorRef), err, + ) + return false, nil + } + + if parent.AncestorRef.Name == gatewayv1.ObjectName(gwNN.Name) && (parent.AncestorRef.Namespace == nil || string(*parent.AncestorRef.Namespace) == gwNN.Namespace) { + if findConditionInList(t, parent.Conditions, condition.Type, string(condition.Status), condition.Reason) { + return true, nil + } + } + } + + return false, nil + }) + + require.NoErrorf(t, waitErr, "error waiting for BackendTLSPolicy %v status to have a Condition %v", policyNN, condition) +} + +// BackendTLSPolicyMustHaveLatestConditions will fail the test if there are +// conditions that were not updated +func BackendTLSPolicyMustHaveLatestConditions(t *testing.T, r *v1alpha3.BackendTLSPolicy) { + t.Helper() + + for _, ancestor := range r.Status.Ancestors { + if err := ConditionsHaveLatestObservedGeneration(r, ancestor.Conditions); err != nil { + tlog.Fatalf(t, "BackendTLSPolicy(controller=%v, ancestorRef=%#v) %v", ancestor.ControllerName, parentRefToString(ancestor.AncestorRef), err) + } + } +} diff --git a/conformance/utils/roundtripper/roundtripper.go b/conformance/utils/roundtripper/roundtripper.go index c37f4500aa..9490b648e2 100644 --- a/conformance/utils/roundtripper/roundtripper.go +++ b/conformance/utils/roundtripper/roundtripper.go @@ -29,6 +29,7 @@ import ( "net/http/httputil" "net/url" "regexp" + "strings" "testing" "golang.org/x/net/http2" @@ -59,6 +60,7 @@ type Request struct { CertPem []byte KeyPem []byte Server string + Body string } // String returns a printable version of Request for logging. Note that the @@ -86,6 +88,14 @@ type CapturedRequest struct { Namespace string `json:"namespace"` Pod string `json:"pod"` + TLS TLS `json:"tls"` +} + +type TLS struct { + Version string `json:"version"` + ServerName string `json:"serverName"` + NegotiatedProtocol string `json:"negotiatedProtocol"` + CipherSuite string `json:"cipherSuite"` } // RedirectRequest contains a follow up request metadata captured from a redirect @@ -194,7 +204,12 @@ func (d *DefaultRoundTripper) defaultRoundTrip(request Request, transport http.R ctx, cancel := context.WithTimeout(context.Background(), d.TimeoutConfig.RequestTimeout) defer cancel() ctx = withT(ctx, request.T) - req, err := http.NewRequestWithContext(ctx, method, request.URL.String(), nil) + + var reqBody io.Reader + if request.Body != "" { + reqBody = strings.NewReader(request.Body) + } + req, err := http.NewRequestWithContext(ctx, method, request.URL.String(), reqBody) if err != nil { return nil, nil, err } @@ -221,6 +236,18 @@ func (d *DefaultRoundTripper) defaultRoundTrip(request Request, transport http.R resp, err := client.Do(req) if err != nil { + if d.Debug { + var dump []byte + if resp != nil { + dump, err = httputil.DumpResponse(resp, true) + if err != nil { + return nil, nil, err + } + tlog.Logf(request.T, "Error sending request:\n%s\n\n", formatDump(dump, "< ")) + } else { + tlog.Logf(request.T, "Error sending request: %v (no response)\n", err) + } + } return nil, nil, err } defer resp.Body.Close() diff --git a/conformance/utils/suite/conformance.go b/conformance/utils/suite/conformance.go index 3bbbbc1c23..436b3ed2ce 100644 --- a/conformance/utils/suite/conformance.go +++ b/conformance/utils/suite/conformance.go @@ -21,8 +21,6 @@ import ( "strings" "testing" - "k8s.io/apimachinery/pkg/util/sets" - "sigs.k8s.io/gateway-api/conformance/utils/tlog" "sigs.k8s.io/gateway-api/pkg/features" ) @@ -70,7 +68,7 @@ func (test *ConformanceTest) Run(t *testing.T, suite *ConformanceTestSuite) { for _, manifestLocation := range test.Manifests { tlog.Logf(t, "Applying %s", manifestLocation) - suite.Applier.MustApplyWithCleanup(t, suite.Client, suite.TimeoutConfig, manifestLocation, true) + suite.Applier.MustApplyWithCleanup(t, suite.Client, suite.TimeoutConfig, manifestLocation, suite.Cleanup) } if featuresInfo != "" { @@ -81,11 +79,11 @@ func (test *ConformanceTest) Run(t *testing.T, suite *ConformanceTestSuite) { // ParseSupportedFeatures parses flag arguments and converts the string to // sets.Set[features.FeatureName] -func ParseSupportedFeatures(f string) sets.Set[features.FeatureName] { +func ParseSupportedFeatures(f string) FeaturesSet { if f == "" { return nil } - res := sets.Set[features.FeatureName]{} + res := FeaturesSet{} for _, value := range strings.Split(f, ",") { res.Insert(features.FeatureName(value)) } diff --git a/conformance/utils/suite/profiles.go b/conformance/utils/suite/profiles.go index 2f589ed4eb..996fe346dd 100644 --- a/conformance/utils/suite/profiles.go +++ b/conformance/utils/suite/profiles.go @@ -119,7 +119,6 @@ var ( ExtendedFeatures: sets.New[features.FeatureName](). Insert(features.SetsToNamesSet( features.MeshExtendedFeatures, - features.HTTPRouteExtendedFeatures, ).UnsortedList()...), } diff --git a/conformance/utils/suite/reports.go b/conformance/utils/suite/reports.go index 4b03d67733..4efcc4e77f 100644 --- a/conformance/utils/suite/reports.go +++ b/conformance/utils/suite/reports.go @@ -22,7 +22,6 @@ import ( "k8s.io/apimachinery/pkg/util/sets" confv1 "sigs.k8s.io/gateway-api/conformance/apis/v1" - "sigs.k8s.io/gateway-api/pkg/features" ) // ----------------------------------------------------------------------------- @@ -107,7 +106,7 @@ func (p profileReportsMap) list() (profileReports []confv1.ProfileReport) { return } -func (p profileReportsMap) compileResults(supportedFeaturesMap map[ConformanceProfileName]sets.Set[features.FeatureName], unsupportedFeaturesMap map[ConformanceProfileName]sets.Set[features.FeatureName]) { +func (p profileReportsMap) compileResults(supportedFeaturesMap map[ConformanceProfileName]FeaturesSet, unsupportedFeaturesMap map[ConformanceProfileName]FeaturesSet) { for key, report := range p { // report the overall result for core features switch { @@ -162,7 +161,8 @@ func (p profileReportsMap) compileResults(supportedFeaturesMap map[ConformancePr // isTestExtended determines if a provided test is considered to be supported // at an extended level of support given the provided conformance profile. // -// TODO: right now the tests themselves don't indicate the conformance +// TODO(#3759) Update this method to be based on Features inferred. +// Right now the tests themselves don't indicate the conformance // support level associated with them. The only way we have right now // in this prototype to know whether a test belongs to any particular // conformance level is to compare the features needed for the test to diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 53700d6c53..877c030f3c 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -31,11 +31,13 @@ import ( "github.com/stretchr/testify/require" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/sets" clientset "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "sigs.k8s.io/controller-runtime/pkg/client" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" "sigs.k8s.io/gateway-api/apis/v1beta1" confv1 "sigs.k8s.io/gateway-api/conformance/apis/v1" "sigs.k8s.io/gateway-api/conformance/utils/config" @@ -69,15 +71,21 @@ type ConformanceTestSuite struct { BaseManifests string MeshManifests string Applier kubernetes.Applier - SupportedFeatures sets.Set[features.FeatureName] + SupportedFeatures FeaturesSet TimeoutConfig config.TimeoutConfig SkipTests sets.Set[string] SkipProvisionalTests bool RunTest string + Hook func(t *testing.T, test ConformanceTest, suite *ConformanceTestSuite) ManifestFS []fs.FS UsableNetworkAddresses []v1beta1.GatewaySpecAddress UnusableNetworkAddresses []v1beta1.GatewaySpecAddress + // If SupportedFeatures are automatically determined from GWC Status. + // This will be required to report in future iterations as the passing + // will be determined based on this. + supportedFeaturesSource supportedFeaturesSource + // mode is the operating mode of the implementation. // The default value for it is "default". mode string @@ -121,7 +129,7 @@ type ConformanceTestSuite struct { lock sync.RWMutex } -// Options can be used to initialize a ConformanceTestSuite. +// ConformanceOptions can be used to initialize a ConformanceTestSuite. type ConformanceOptions struct { Client client.Client ClientOptions client.Options @@ -141,8 +149,8 @@ type ConformanceOptions struct { // CleanupBaseResources indicates whether or not the base test // resources such as Gateways should be cleaned up after the run. CleanupBaseResources bool - SupportedFeatures sets.Set[features.FeatureName] - ExemptFeatures sets.Set[features.FeatureName] + SupportedFeatures FeaturesSet + ExemptFeatures FeaturesSet EnableAllSupportedFeatures bool TimeoutConfig config.TimeoutConfig // SkipTests contains all the tests not to be run and can be used to opt out @@ -152,7 +160,8 @@ type ConformanceOptions struct { SkipProvisionalTests bool // RunTest is a single test to run, mostly for development/debugging convenience. RunTest string - + // Hook is an optional function that can be used to run custom logic after each test at suite level. + Hook func(t *testing.T, test ConformanceTest, suite *ConformanceTestSuite) ManifestFS []fs.FS // UsableNetworkAddresses is an optional pool of usable addresses for @@ -170,6 +179,8 @@ type ConformanceOptions struct { ConformanceProfiles sets.Set[ConformanceProfileName] } +type FeaturesSet = sets.Set[features.FeatureName] + const ( // undefinedKeyword is set in the ConformanceReport "GatewayAPIVersion" and // "GatewayAPIChannel" fields in case it's not possible to figure out the actual @@ -177,18 +188,43 @@ const ( undefinedKeyword = "UNDEFINED" ) +// SupportedFeaturesSource represents the source from which supported features are derived. +// It is used to distinguish between them being inferred from GWC Status or manually +// supplied for the conformance report. +type supportedFeaturesSource string + +const ( + supportedFeaturesSourceManual supportedFeaturesSource = "Manual" + supportedFeaturesSourceInferred supportedFeaturesSource = "Inferred" +) + // NewConformanceTestSuite is a helper to use for creating a new ConformanceTestSuite. func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, error) { - // test suite callers are required to provide either: - // - one conformance profile via the flag '-conformance-profiles' - // - a list of supported features via the flag '-supported-features' - // - an explicit test to run via the flag '-run-test' - // - all features are being tested via the flag '-all-features' - if options.SupportedFeatures.Len() == 0 && - options.ConformanceProfiles.Len() == 0 && - !options.EnableAllSupportedFeatures && - options.RunTest == "" { - return nil, fmt.Errorf("no conformance profile, supported features, explicit tests were provided so no tests could be selected") + supportedFeatures := options.SupportedFeatures.Difference(options.ExemptFeatures) + source := supportedFeaturesSourceManual + if options.EnableAllSupportedFeatures { + supportedFeatures = features.SetsToNamesSet(features.AllFeatures) + } else if shouldInferSupportedFeatures(&options) { + var err error + supportedFeatures, err = fetchSupportedFeatures(options.Client, options.GatewayClassName) + if err != nil { + return nil, fmt.Errorf("cannot infer supported features: %w", err) + } + + // If Mesh features are populated in the GatewayClass we remove them from the supported features set. + meshFeatureNames := features.SetsToNamesSet(features.MeshCoreFeatures, features.MeshExtendedFeatures) + for _, f := range supportedFeatures.UnsortedList() { + if meshFeatureNames.Has(f) { + supportedFeatures.Delete(f) + fmt.Printf("WARNING: Mesh feature %q should not be populated in GatewayClass, skipping...", f) + } + } + source = supportedFeaturesSourceInferred + } + + // If features were not inferred from Status, it's a GWC issue. + if source == supportedFeaturesSourceInferred && supportedFeatures.Len() == 0 { + return nil, fmt.Errorf("no supported features were determined for test suite") } config.SetupTimeoutConfig(&options.TimeoutConfig) @@ -222,19 +258,6 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, mode = options.Mode } - // test suite callers can potentially just run all tests by saying they - // cover all features, if they don't they'll need to have provided a - // conformance profile or at least some specific features they support. - if options.EnableAllSupportedFeatures { - options.SupportedFeatures = features.SetsToNamesSet(features.AllFeatures) - } else if options.SupportedFeatures == nil { - options.SupportedFeatures = sets.New[features.FeatureName]() - } - - for feature := range options.ExemptFeatures { - options.SupportedFeatures.Delete(feature) - } - suite := &ConformanceTestSuite{ Client: options.Client, ClientOptions: options.ClientOptions, @@ -252,7 +275,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, NamespaceAnnotations: options.NamespaceAnnotations, AddressType: options.AddressType, }, - SupportedFeatures: options.SupportedFeatures, + SupportedFeatures: supportedFeatures, TimeoutConfig: options.TimeoutConfig, SkipTests: sets.New(options.SkipTests...), RunTest: options.RunTest, @@ -268,6 +291,8 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, mode: mode, apiVersion: apiVersion, apiChannel: apiChannel, + supportedFeaturesSource: source, + Hook: options.Hook, } for _, conformanceProfileName := range options.ConformanceProfiles.UnsortedList() { @@ -285,12 +310,12 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, for _, f := range conformanceProfile.ExtendedFeatures.UnsortedList() { if options.SupportedFeatures.Has(f) { if suite.extendedSupportedFeatures[conformanceProfileName] == nil { - suite.extendedSupportedFeatures[conformanceProfileName] = sets.New[features.FeatureName]() + suite.extendedSupportedFeatures[conformanceProfileName] = FeaturesSet{} } suite.extendedSupportedFeatures[conformanceProfileName].Insert(f) } else { if suite.extendedUnsupportedFeatures[conformanceProfileName] == nil { - suite.extendedUnsupportedFeatures[conformanceProfileName] = sets.New[features.FeatureName]() + suite.extendedUnsupportedFeatures[conformanceProfileName] = FeaturesSet{} } suite.extendedUnsupportedFeatures[conformanceProfileName].Insert(f) } @@ -363,6 +388,17 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest) suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup) secret = kubernetes.MustCreateSelfSignedCertSecret(t, "gateway-conformance-app-backend", "tls-passthrough-checks-certificate", []string{"abc.example.com"}) suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup) + caConfigMapBST, _, _ := kubernetes.MustCreateCACertConfigMap(t, "gateway-conformance-infra", "backend-tls-mismatch-certificate", []string{"nex.example.com"}) + suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{caConfigMapBST}, suite.Cleanup) + caConfigMap, ca, caPrivKey := kubernetes.MustCreateCACertConfigMap(t, "gateway-conformance-infra", "backend-tls-checks-certificate", []string{"abc.example.com"}) + suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{caConfigMap}, suite.Cleanup) + secret = kubernetes.MustCreateCASignedCertSecret(t, "gateway-conformance-infra", "tls-checks-certificate", []string{"abc.example.com"}, ca, caPrivKey) + suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup) + // TODO(kl52752) Merge CA certificates for Backend TLS Policy and move Deployment to common file. + caConfigMap, ca, caPrivKey = kubernetes.MustCreateCACertConfigMap(t, "gateway-conformance-infra", "backend-tls-with-san-certificate", []string{"abc.example.com", "spiffe://abc.example.com/test-identity"}) + suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{caConfigMap}, suite.Cleanup) + secret = kubernetes.MustCreateCASignedCertSecret(t, "gateway-conformance-infra", "tls-with-san-certificate", []string{"abc.example.com", "spiffe://abc.example.com/test-identity"}, ca, caPrivKey) + suite.Applier.MustApplyObjectsWithCleanup(t, suite.Client, suite.TimeoutConfig, []client.Object{secret}, suite.Cleanup) tlog.Logf(t, "Test Setup: Ensuring Gateways and Pods from base manifests are ready") namespaces := []string{ @@ -437,6 +473,9 @@ func (suite *ConformanceTestSuite) Run(t *testing.T, tests []ConformanceTest) er sleepForTestIsolation := false for _, test := range tests { res := testSucceeded + if suite.RunTest != "" && test.ShortName != suite.RunTest { + res = testSkipped + } if suite.SkipTests.Has(test.ShortName) { res = testSkipped } @@ -470,6 +509,13 @@ func (suite *ConformanceTestSuite) Run(t *testing.T, tests []ConformanceTest) er if res == testSucceeded || res == testFailed { sleepForTestIsolation = true } + + // call the hook function if it was provided, + // this's useful for running custom logic after each test at suite level, + // such as collecting current state of the cluster for debugging. + if suite.Hook != nil { + suite.Hook(t, test, suite) + } } // now that the tests have completed, mark the test suite as not running @@ -563,6 +609,37 @@ func ParseConformanceProfiles(p string) sets.Set[ConformanceProfileName] { return res } +func fetchSupportedFeatures(client client.Client, gatewayClassName string) (FeaturesSet, error) { + if gatewayClassName == "" { + return nil, fmt.Errorf("GatewayClass name must be provided to fetch supported features") + } + gwc := &gatewayv1.GatewayClass{} + err := client.Get(context.TODO(), types.NamespacedName{Name: gatewayClassName}, gwc) + if err != nil { + return nil, fmt.Errorf("fetchSupportedFeatures(): %w", err) + } + + fs := FeaturesSet{} + for _, feature := range gwc.Status.SupportedFeatures { + fs.Insert(features.FeatureName(feature.Name)) + } + fmt.Printf("Supported features for GatewayClass %s: %v\n", gatewayClassName, fs.UnsortedList()) + return fs, nil +} + +// shouldInferSupportedFeatures checks if any flags were supplied for manually +// picking what to test. Inferred supported features are only used when no flags +// are set. +func shouldInferSupportedFeatures(opts *ConformanceOptions) bool { + if opts == nil { + return false + } + return !opts.EnableAllSupportedFeatures && + opts.SupportedFeatures.Len() == 0 && + opts.ExemptFeatures.Len() == 0 && + opts.RunTest == "" +} + // getAPIVersionAndChannel iterates over all the crds installed in the cluster and check the version and channel annotations. // In case the annotations are not found or there are crds with different versions or channels, an error is returned. func getAPIVersionAndChannel(crds []apiextensionsv1.CustomResourceDefinition) (version string, channel string, err error) { diff --git a/conformance/utils/suite/suite_test.go b/conformance/utils/suite/suite_test.go index 951571f7aa..778afa7180 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -23,8 +23,11 @@ import ( "github.com/stretchr/testify/assert" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/sets" + "sigs.k8s.io/controller-runtime/pkg/client/fake" + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" confv1 "sigs.k8s.io/gateway-api/conformance/apis/v1" "sigs.k8s.io/gateway-api/pkg/consts" "sigs.k8s.io/gateway-api/pkg/features" @@ -217,7 +220,7 @@ var ( func TestSuiteReport(t *testing.T) { testCases := []struct { name string - features sets.Set[features.FeatureName] + features FeaturesSet extendedSupportedFeatures map[ConformanceProfileName]sets.Set[features.FeatureName] profiles sets.Set[ConformanceProfileName] skipProvisionalTests bool @@ -407,3 +410,183 @@ func TestSuiteReport(t *testing.T) { }) } } + +var statusFeatureNames = []string{ + "Gateway", + "GatewayPort8080", + "HTTPRoute", + "HTTPRouteHostRewrite", + "HTTPRouteMethodMatching", + "HTTPRoutePathRewrite", + "TTPRouteQueryParamMatching", + "HTTPRouteResponseHeaderModification", + "ReferenceGrant", +} + +func TestInferSupportedFeatures(t *testing.T) { + testCases := []struct { + name string + allowAllFeatures bool + supportedFeatures FeaturesSet + exemptFeatures FeaturesSet + ConformanceProfile sets.Set[ConformanceProfileName] + expectedFeatures FeaturesSet + expectedSource supportedFeaturesSource + }{ + { + name: "properly infer supported features", + expectedFeatures: namesToFeatureSet(statusFeatureNames), + expectedSource: supportedFeaturesSourceInferred, + }, + { + name: "no features", + supportedFeatures: sets.New[features.FeatureName]("Gateway"), + expectedFeatures: sets.New[features.FeatureName]("Gateway"), + expectedSource: supportedFeaturesSourceManual, + }, + { + name: "remove exempt features", + supportedFeatures: sets.New[features.FeatureName]("Gateway", "HTTPRoute"), + exemptFeatures: sets.New[features.FeatureName]("HTTPRoute"), + expectedFeatures: sets.New[features.FeatureName]("Gateway"), + expectedSource: supportedFeaturesSourceManual, + }, + { + name: "allow all features", + allowAllFeatures: true, + expectedFeatures: features.SetsToNamesSet(features.AllFeatures), + expectedSource: supportedFeaturesSourceManual, + }, + { + name: "supports conformance profile - core", + ConformanceProfile: sets.New(GatewayHTTPConformanceProfileName), + expectedFeatures: namesToFeatureSet(statusFeatureNames), + expectedSource: supportedFeaturesSourceInferred, + }, + } + + gwcName := "ochopintre" + gwc := &gatewayv1.GatewayClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: gwcName, + }, + Spec: gatewayv1.GatewayClassSpec{ + ControllerName: "example.com/gateway-controller", + }, + Status: gatewayv1.GatewayClassStatus{ + Conditions: []metav1.Condition{ + { + Type: string(gatewayv1.GatewayConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "GatewayClass is accepted and ready for use", + }, + }, + SupportedFeatures: featureNamesToSet(statusFeatureNames), + }, + } + scheme := runtime.NewScheme() + scheme.AddKnownTypes(gatewayv1.SchemeGroupVersion, &gatewayv1.GatewayClass{}) + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(gwc). + WithLists(&apiextensionsv1.CustomResourceDefinitionList{}). + Build() + + gatewayv1.Install(fakeClient.Scheme()) + apiextensionsv1.AddToScheme(fakeClient.Scheme()) + + for _, tc := range testCases { + options := ConformanceOptions{ + AllowCRDsMismatch: true, + GatewayClassName: gwcName, + EnableAllSupportedFeatures: tc.allowAllFeatures, + SupportedFeatures: tc.supportedFeatures, + ExemptFeatures: tc.exemptFeatures, + ConformanceProfiles: tc.ConformanceProfile, + Client: fakeClient, + } + + t.Run(tc.name, func(t *testing.T) { + cSuite, err := NewConformanceTestSuite(options) + if err != nil { + t.Fatalf("error initializing conformance suite: %v", err) + } + + if cSuite.supportedFeaturesSource != tc.expectedSource { + t.Errorf("InferredSupportedFeatures mismatch: got %v, want %v", cSuite.supportedFeaturesSource, tc.expectedSource) + } + + if equal := cSuite.SupportedFeatures.Equal(tc.expectedFeatures); !equal { + t.Errorf("SupportedFeatures mismatch: got %v, want %v", cSuite.SupportedFeatures.UnsortedList(), tc.expectedFeatures.UnsortedList()) + } + }) + } +} + +func TestGWCPublishedMeshFeatures(t *testing.T) { + gwcName := "ochopintre" + gwc := &gatewayv1.GatewayClass{ + ObjectMeta: metav1.ObjectMeta{ + Name: gwcName, + }, + Spec: gatewayv1.GatewayClassSpec{ + ControllerName: "example.com/gateway-controller", + }, + Status: gatewayv1.GatewayClassStatus{ + Conditions: []metav1.Condition{ + { + Type: string(gatewayv1.GatewayConditionAccepted), + Status: metav1.ConditionTrue, + Reason: "Accepted", + Message: "GatewayClass is accepted and ready for use", + }, + }, + SupportedFeatures: featureNamesToSet([]string{ + string(features.SupportGateway), + string(features.SupportMesh), + string(features.SupportMeshClusterIPMatching), + }), + }, + } + scheme := runtime.NewScheme() + scheme.AddKnownTypes(gatewayv1.SchemeGroupVersion, &gatewayv1.GatewayClass{}) + fakeClient := fake.NewClientBuilder(). + WithScheme(scheme). + WithObjects(gwc). + WithLists(&apiextensionsv1.CustomResourceDefinitionList{}). + Build() + + gatewayv1.Install(fakeClient.Scheme()) + apiextensionsv1.AddToScheme(fakeClient.Scheme()) + + options := ConformanceOptions{ + AllowCRDsMismatch: true, + GatewayClassName: gwcName, + Client: fakeClient, + } + + suite, err := NewConformanceTestSuite(options) + if err != nil { + t.Fatalf("error initializing conformance suite: %v", err) + } + if suite.SupportedFeatures.HasAny(features.SetsToNamesSet(features.MeshCoreFeatures, features.MeshExtendedFeatures).UnsortedList()...) { + t.Errorf("Mesh features should be skipped, got: %v", suite.SupportedFeatures.UnsortedList()) + } +} + +func featureNamesToSet(set []string) []gatewayv1.SupportedFeature { + var features []gatewayv1.SupportedFeature + for _, feature := range set { + features = append(features, gatewayv1.SupportedFeature{Name: gatewayv1.FeatureName(feature)}) + } + return features +} + +func namesToFeatureSet(names []string) FeaturesSet { + featureSet := FeaturesSet{} + for _, name := range names { + featureSet.Insert(features.FeatureName(name)) + } + return featureSet +} diff --git a/conformance/utils/tls/tls.go b/conformance/utils/tls/tls.go index e27fab839b..809a4938a8 100644 --- a/conformance/utils/tls/tls.go +++ b/conformance/utils/tls/tls.go @@ -54,8 +54,9 @@ func WaitForConsistentTLSResponse(t *testing.T, r roundtripper.RoundTripper, req return false } - if err := http.CompareRequest(t, &req, cReq, cRes, expected); err != nil { + if err := http.CompareRoundTrip(t, &req, cReq, cRes, expected); err != nil { tlog.Logf(t, "Response expectation failed for request: %+v not ready yet: %v (after %v)", req, err, elapsed) + tlog.Logf(t, "Full response: %+v", cReq) return false } diff --git a/docker/Dockerfile.echo-basic b/docker/Dockerfile.echo-basic index ed6081fb33..55d9b47055 100644 --- a/docker/Dockerfile.echo-basic +++ b/docker/Dockerfile.echo-basic @@ -13,7 +13,7 @@ # limitations under the License. # Build -FROM golang:1.22.2 as builder +FROM golang:1.22.2 AS builder ENV CGO_ENABLED=0 @@ -23,9 +23,10 @@ COPY ./conformance/echo-basic ./ # If left as go.mod and go.sum in the external repo, these files would # interfere with the ability to use reuse the protobuf/gRPC generated code -# for the test client in the conformance tests. -RUN mv .go.mod go.mod -RUN mv .go.sum go.sum +# for the test client in the conformance tests. Add -f in case previous run +# is aborted and not cleaned up. +RUN mv -f .go.mod go.mod +RUN mv -f .go.sum go.sum RUN go build -trimpath -ldflags="-buildid= -s -w" -o echo-basic . diff --git a/examples/experimental/backend-tls.yaml b/examples/experimental/backend-tls.yaml new file mode 100644 index 0000000000..94b8be09c7 --- /dev/null +++ b/examples/experimental/backend-tls.yaml @@ -0,0 +1,18 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: backend-tls +spec: + gatewayClassName: acme-lb + tls: + backend: + clientCertificateRef: + kind: Secret + group: "" + name: foo-example-cert + listeners: + - name: foo-https + protocol: HTTP + port: 80 + hostname: foo.example.com +--- diff --git a/examples/experimental/frontend-cert-validation.yaml b/examples/experimental/frontend-cert-validation.yaml index 7f103aed8e..34ada262b4 100644 --- a/examples/experimental/frontend-cert-validation.yaml +++ b/examples/experimental/frontend-cert-validation.yaml @@ -4,6 +4,23 @@ metadata: name: client-validation-basic spec: gatewayClassName: acme-lb + tls: + frontend: + default: + validation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: foo-example-com-ca-cert + perPort: + - port: 8443 + tls: + validation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: foo-example-com-ca-cert + mode: "AllowInsecureFallback" listeners: - name: foo-https protocol: HTTPS @@ -14,10 +31,14 @@ spec: - kind: Secret group: "" name: foo-example-com-cert - frontendValidation: - caCertificateRefs: - - kind: ConfigMap - group: "" - name: foo-example-com-ca-cert + - name: bar-https + protocol: HTTPS + port: 8443 + hostname: bar.example.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: bar-example-com-cert --- diff --git a/examples/experimental/v1alpha2/tls-routing/gateway.yaml b/examples/experimental/v1alpha2/tls-routing/gateway.yaml new file mode 100644 index 0000000000..a02bd52ee5 --- /dev/null +++ b/examples/experimental/v1alpha2/tls-routing/gateway.yaml @@ -0,0 +1,12 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: example-gateway +spec: + gatewayClassName: example-gateway-class + listeners: + - name: tls + protocol: TLS + port: 443 + tls: + mode: Passthrough diff --git a/examples/experimental/v1alpha2/tls-routing/tls-route.yaml b/examples/experimental/v1alpha2/tls-routing/tls-route.yaml new file mode 100644 index 0000000000..dd2f8527d5 --- /dev/null +++ b/examples/experimental/v1alpha2/tls-routing/tls-route.yaml @@ -0,0 +1,12 @@ +apiVersion: gateway.networking.k8s.io/v1alpha2 +kind: TLSRoute +metadata: + name: example-route +spec: + parentRefs: + - name: example-gateway + sectionName: tls + rules: + - backendRefs: + - name: example-svc + port: 443 diff --git a/examples/experimental/v1alpha3/tls-routing/gateway.yaml b/examples/experimental/v1alpha3/tls-routing/gateway.yaml new file mode 100644 index 0000000000..a02bd52ee5 --- /dev/null +++ b/examples/experimental/v1alpha3/tls-routing/gateway.yaml @@ -0,0 +1,12 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: example-gateway +spec: + gatewayClassName: example-gateway-class + listeners: + - name: tls + protocol: TLS + port: 443 + tls: + mode: Passthrough diff --git a/examples/experimental/v1alpha3/tls-routing/tls-route.yaml b/examples/experimental/v1alpha3/tls-routing/tls-route.yaml new file mode 100644 index 0000000000..1679ba6ac4 --- /dev/null +++ b/examples/experimental/v1alpha3/tls-routing/tls-route.yaml @@ -0,0 +1,14 @@ +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: TLSRoute +metadata: + name: example-route +spec: + parentRefs: + - name: example-gateway + sectionName: tls + hostnames: + - "example.com" + rules: + - backendRefs: + - name: example-svc + port: 443 diff --git a/geps/gep-1324/index.md b/geps/gep-1324/index.md index a80d6c8615..5384beced3 100644 --- a/geps/gep-1324/index.md +++ b/geps/gep-1324/index.md @@ -33,7 +33,7 @@ Gateway API represents the next generation of traffic routing APIs in Kubernetes ## Versioning -Features or other modifications to the Gateway API spec that fall under this GEP will be subject to the same [versioning guidelines](../../concepts/versioning.md#graduation-criteria) as the rest of the Gateway API. For example, to move changes concerning a beta feature (e.g. HTTPRoute) from experimental to standard, all of the [beta criteria](../../concepts/versioning.md#experimental-standard) must be met (e.g. implemented by several implementations). +Features or other modifications to the Gateway API spec that fall under this GEP will be subject to the same [versioning guidelines](../../concepts/versioning.md#graduation-criteria) as the rest of the Gateway API. For example, to move changes concerning a beta feature (e.g. HTTPRoute) from experimental to standard, all of the [graduation criteria](../../concepts/versioning.md#graduation-criteria) must be met (e.g. implemented by several implementations). ## Use-Cases diff --git a/geps/gep-1494/index.md b/geps/gep-1494/index.md index 5d5991052f..0fc115292f 100644 --- a/geps/gep-1494/index.md +++ b/geps/gep-1494/index.md @@ -1,7 +1,7 @@ # GEP-1494: HTTP Auth in Gateway API * Issue: [#1494](https://github.com/kubernetes-sigs/gateway-api/issues/1494) -* Status: Provisional +* Status: Implementable (See [status definitions](../overview.md#gep-states).) @@ -115,7 +115,7 @@ This section lays out some examples (updates with extra examples we've missed ar |[traefik](https://doc.traefik.io/traefik/middlewares/http/forwardauth/)|[Custom(ForwardAuth middleware)](https://doc.traefik.io/traefik/middlewares/http/forwardauth/)|[Basic](https://doc.traefik.io/traefik/middlewares/http/basicauth/), [Digest Auth](https://doc.traefik.io/traefik/middlewares/http/digestauth/)| |[Ambassador](https://www.getambassador.io/docs/edge-stack/latest/howtos/ext-filters)|[Envoy](https://github.com/emissary-ingress/emissary) ([Basic](https://www.getambassador.io/docs/edge-stack/latest/howtos/ext-filters#2-configure-aesambassador-edge-stack-authentication))|[SSO(OAuth, OIDC)](https://www.getambassador.io/docs/edge-stack/latest/howtos/oauth-oidc-auth) | |[ingress-nginx](https://kubernetes.github.io/ingress-nginx/examples/customization/external-auth-headers/)|[httpbin](https://httpbin.org) ([Basic](https://kubernetes.github.io/ingress-nginx/examples/auth/external-auth/), [OAuth](https://kubernetes.github.io/ingress-nginx/examples/auth/oauth-external-auth/))|[Basic](https://kubernetes.github.io/ingress-nginx/examples/auth/basic/), [Client Certificate](https://kubernetes.github.io/ingress-nginx/examples/auth/client-certs/)| -|[Envoy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto)|[External Authorization server (ext_authz filter)](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authz/v3/ext_authz.proto) |[JWT](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto)| +|[Envoy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authzz/v3/ext_authzz.proto)|[External Authorization server (ext_authzz filter)](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authzz/v3/ext_authzz.proto) |[JWT](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/jwt_authn/v3/config.proto)| |[Contour](https://projectcontour.io/docs/1.24/config/client-authorization/)|[Envoy](https://projectcontour.io/docs/1.24/config/client-authorization/)|[Envoy(JWT)](https://projectcontour.io/docs/1.24/config/jwt-verification/)| |[Istio](https://istio.io/latest/docs/tasks/security/authorization/)|[mutual TLS ingress gateway](https://istio.io/latest/docs/tasks/traffic-management/ingress/secure-ingress/#configure-a-mutual-tls-ingress-gateway), [External Authorization](https://istio.io/latest/docs/tasks/security/authorization/authz-custom/)|[JWT (RequestAuthentication)](https://istio.io/latest/docs/reference/config/security/request_authentication/)| |[Envoy Gateway](https://gateway.envoyproxy.io/docs/tasks/security/ext-auth/)| [Envoy](https://gateway.envoyproxy.io/docs/tasks/security/ext-auth/#http-external-authorization-service) | [Envoy(JWT)](https://gateway.envoyproxy.io/docs/tasks/security/jwt-authentication/), [Basic](https://gateway.envoyproxy.io/docs/tasks/security/basic-auth/) | @@ -130,7 +130,363 @@ From @ongy, some additional goals to keep in mind: ## API -(... details, can point to PR with changes) +This GEP proposes a two-part solution to this problem: + +* We introduce a new HTTPRoute Filter, `ExternalAuth`, that allows the + specification of an external source to connect to using Envoy's `ext_authz` protocol. +* We introduce a new Policy object that can be targeted at either the + Gateway or HTTPRoute levels. In either of these cases, it _defaults_ the settings + for the HTTPRoute Filter across all HTTPRoute matches that roll up to the object. + +These two parts will be done in two separate changes - Filter first, then +Policy after. + +Both of these additions use the same underlying struct for the config, so that +changes or additions in one place add them in the other as well. + +This plan has some big things that need explaining before we get to the API details: + +* Why a Filter plus Policy approach? +* Why two changes? +* Why Envoy's `ext_authz`? + +### Why a Filter plus Policy approach? + +We have two main requirements: Ana needs to be able to configure auth at least at +the smallest possible scope, and Ana, Ian and Chihiro need to be able to configure +defaults at larger scopes. + +The smallest possible scope for this config is the HTTPRoute Rule level, where +you can match a single set of matchers - like a path, or a path and header +combination. + +At this level, the inline tool we have available to perform changes is the HTTPRoute +Filter, which also has the property that it's designed to _filter_ requests. This +matches the overall pattern here, which is to _filter_ some requests, allowing +or denying them based on the presence of Authentication and the passing of +Authorization checks. + +A Policy _can_ be targeted at this level, using the Route rule as a `sectionName`, +but that leaves aside that Filters are exactly designed to handle this use case. + +Policy attachment includes defaulting fields like Filters in its scope already, +so we are allowed to use a combination in this way. + +Using a Filter also has the advantage that, at the tightest possible scope (the +object being defaulted) you can _explicitly_ override any configured defaults. + +Using a Filter also includes ordering (because Filters are an ordered list), +although this exact behavior is currently underspecified. This change will also +need to clarify. Ordering is particularly important for Auth use cases, because +sometimes Auth will expect certain properties that may need to be introduced +by things like header modification. + +Lastly, using a Filter means that, for the simplest possible case, where Ana +wants to enable Auth* for a single path, then there is only a single object to +edit, and a single place to configure. + +Using a Policy for the simplest case immediately brings in all the discovery +problems that Policy entails. + +There are two important caveats here that must be addressed, however: +* Firstly, whatever is in the filter either must be accepted, or the rule + is not accepted. Overrides from anywhere else, including if we add an Override + Policy later, must not override explicit config - that would + violate one of the key declarative principles, that what is requested in the + spec is either what ends up in the state, or that config is rejected. +* Secondly, filter ordering is particularly important for Auth use cases, so we + must ensure that when we add Policy defaulting we have a way to indicate at + what position in a filter list the Auth policy should fit. + +### Why two phases? + +In short: In the interest of getting something, even if incomplete, into our +user's hands as quickly as possible. + +Policy design is complex, and needs to be done carefully. Doing a first +pass using only a Filter to get the basic config correct while we discuss +how to make the Policy handling work means that we can get some work out to the +community without needing to complete the whole design. + +In particular, the design for the Filter plus Policy will need to answer at +least the following questions: + +* How to set where in a list of Filters a defaulted Auth filter sits; + and what happens if no Filters are specified in a HTTPRoute? Does it go first, + last, or should there be a way to specify the order? +* What Policy types are possible? Defaults? (Definitely useful for setting a + baseline expectation for a cluster, which is desirable for security constructs + like Auth) Overrides? (Also very useful for ensuring that exceptions meet + certain requirements - like only allowing the disabling of Auth on `/healthz` + endpoints or similar use cases.) +* Should Policy have a way to describe rules around when it should take effect? + That's in addition to the usual hierarchical rules, should the Policy have ways + to include or exclude specific matches? This would require agreement in the + Policy Attachment spec as well. + +All of these changes have costs in complexity and troubleshooting difficulty, so +it's important to ensure that the design consciously makes these tradeoffs. + +In particular, the last two items in the above list seem likely to require a fair +amount of discussion, and including a Policy in the initial release of this +seems likely to make this change miss its current release window. + + +### Why Envoy's ext_authz? + +#### What is ext_authz? + +Envoy's External Authorization filter is a filter that calls out to an authorization +service to check if the incoming request is authorized or not. Note that, in +order to check _authorization_, it must also be able to determine _authentication_ - +this is one of the reasons why we've chosen this approach. + +Envoy's implementation of this filter allows both a +[gRPC, protobuf API](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/http/ext_authzz/v3/ext_authzz.proto) +and configuration of a HTTP based API (which, as it's not defined using a +specification like protobuf, requires more configuration). + +The important thing to remember here is that the actual authorization process +is delegated to the authorization service, and the authentication process _may +optionally_ also be delegated there - which is why the ext_authz approach allows +handling many Auth methods - most of the work is performed by external services +which implement various methods (like Basic Auth, OAuth, JWT validation, etc). + +#### Why use it over other options? + +The community discussed Auth extensively in-person at Kubecon London in early 2025, +and got broad agreement from multiple dataplanes that: + +* something like ext_authz was a good idea, because it's flexible and allows the + implementation of many types of Auth without specific protocol implementation + in upstream +* Envoy's ext_authz protocol has no major problems that would stop us using it +* Envoy-based implementations mostly already have support for it + +At that meeting, those present agreed that ext_authz was a good place to start. + +Most non-Envoy dataplanes also already have similar methods, so the maintainers +of projects using other dataplanes were okay with this idea. + +The alternative here would be to add a Filter type _per auth method_, which, given +the large number of options, could quickly become very complex. + +This GEP is, however, explicitly _not_ ruling out the possibility of adding +specific Filters for specific Auth methods in the future, if users of this API +find the overhead of running a compatible implementation to be too much. + +### API Design + +#### Phase 1: Adding a Filter + +This config mainly takes inspiration from Envoy's ext_authz filter config, while +also trying to maintain compatibility with other HTTP methods. + +This design is also trying to start with a minimum feature set, and add things +as required, rather than adding everything configurable in all implementations +immediately. + +There is some difference between data planes, based on the links above, but +these fields should be broadly supportable across all the listed implementations. + +Some design comments are included inline. + +The intent for Phase 2 is that this struct will be included in an eventual Policy +so that additions only need to be made in one place. + +Additionally, as per other added Filters, the config is included in HTTPRoute, +and is not an additional CRD. + +##### Go Structs + +```go + +// HTTPRouteExtAuthProtcol specifies what protocol should be used +// for communicating with an external authorization server. +// +// Valid values are supplied as constants below. +type HTTPRouteExtAuthProtocol string + +const ( + HTTPRouteExtAuthGRPCProtocol HTTPRouteExtAuthProtocol = "GRPC" + HTTPRouteExtAuthHTTPProtocol HTTPRouteExtAuthProtocol = "HTTP" +) +// HTTPExtAuthFilter defines a filter that modifies requests by sending +// request details to an external authorization server. +// +// Support: Extended +// Feature Name: HTTPRouteExtAuth +type HTTPExtAuthFilter struct { + + // ExtAuthProtocol describes which protocol to use when communicating with an + // ext_authz authorization server. + // + // When this is set to GRPC, each backend must use the Envoy ext_authz protocol + // on the port specified in `backendRefs`. Requests and responses are defined + // in the protobufs explained at: + // https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto + // + // When this is set to HTTP, each backend must respond with a `200` status + // code in on a successful authorization. Any other code is considered + // an authorization failure. + // + // Feature Names: + // GRPC Support - HTTPRouteExtAuthGRPC + // HTTP Support - HTTPRouteExtAuthHTTP + // + // +unionDiscriminator + // +kubebuilder:validation:Enum=HTTP;GRPC + ExtAuthProtocol HTTPRouteExtAuthProtocol `json:"protocol"` + + // BackendRefs is a reference to a backend to send authorization + // requests to. + // + // The backend must speak the selected protocol (GRPC or HTTP) on the + // referenced port. + // + // If the backend service requires TLS, use BackendTLSPolicy to tell the + // implementation to supply the TLS details to be used to connect to that + // backend. + // + BackendRef BackendObjectReference `json:"backendRef"` + + // GRPCAuthConfig contains configuration for communication with ext_authz + // protocol-speaking backends. + // + // If unset, implementations must assume the default behavior for each + // included field is intended. + // + // +optional + GRPCAuthConfig *GRPCAuthConfig `json:"grpc,omitempty"` + + // HTTPAuthConfig contains configuration for communication with HTTP-speaking + // backends. + // + // If unset, implementations must assume the default behavior for each + // included field is intended. + // + // +optional + HTTPAuthConfig *HTTPAuthConfig `json:"http,omitempty"` + + // ForwardBody controls if requests to the authorization server should include + // the body of the client request; and if so, how big that body is allowed + // to be. + // + // It is expected that implementations will buffer the request body up to + // `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a + // 4xx series error (413 or 403 are common examples), and fail processing + // of the filter. + // + // If unset, or `forwardBody.maxSize` is set to `0`, then the body will not + // be forwarded. + // + // Feature Name: HTTPRouteExtAuthForwardBody + // + // GEP Review Notes: + // Both Envoy and Traefik show support for this feature, but HAProxy and + // ingress-nginx do not. So this has a separate feature flag for it. + // + // +optional + ForwardBody *ForwardBodyConfig `json:"forwardBody,omitempty"` +} + +// GRPCAuthConfig contains configuration for communication with ext_authz +// protocol-speaking backends. +type GRPCAuthConfig struct { + + // AllowedRequestHeaders specifies what headers from the client request + // will be sent to the authorization server. + // + // If this list is empty, then the following headers must be sent: + // + // - `Authorization` + // - `Location` + // - `Proxy-Authenticate` + // - `Set-Cookie` + // - `WWW-Authenticate` + // + // If the list has entries, only those entries must be sent. + // + // +optional + // +kubebuilder:validation:MaxLength=64 + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` +} + +// HTTPAuthConfig contains configuration for communication with HTTP-speaking +// backends. +type HTTPAuthConfig struct { + // Path sets the prefix that paths from the client request will have added + // when forwarded to the authorization server. + // + // When empty or unspecified, no prefix is added. + // +optional + Path string `json:"path,omitempty"` + + // AllowedRequestHeaders specifies what additional headers from the client request + // will be sent to the authorization server. + // + // The following headers must always be sent to the authorization server, + // regardless of this setting: + // + // * `Host` + // * `Method` + // * `Path` + // * `Content-Length` + // * `Authorization` + // + // If this list is empty, then only those headers must be sent. + // + // Note that `Content-Length` has a special behavior, in that the length + // sent must be correct for the actual request to the external authorization + // server - that is, it must reflect the actual number of bytes sent in the + // body of the request to the authorization server. + // + // So if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set + // to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set + // to anything other than `0`, then the `Content-Length` of the authorization + // request must be set to the actual number of bytes forwarded. + // + // +optional + // +kubebuilder:validation:MaxLength=64 + AllowedRequestHeaders []string `json:"allowedHeaders,omitempty"` + + // AllowedResponseHeaders specifies what headers from the authorization response + // will be copied into the request to the backend. + // + // If this list is empty, then all headers from the authorization server + // except Authority or Host must be copied. + // + // +optional + // +kubebuilder:validation:MaxLength=64 + AllowedResponseHeaders []string `json:"allowedResponseHeaders,omitempty"` + +} + +// ForwardBody configures if requests to the authorization server should include +// the body of the client request; and if so, how big that body is allowed +// to be. +// +// If empty or unset, do not forward the body. +type ForwardBodyConfig struct { + + // MaxSize specifies how large in bytes the largest body that will be buffered + // and sent to the authorization server. If the body size is larger than + // `maxSize`, then the body sent to the authorization server must be + // truncated to `maxSize` bytes. + // + // If 0, the body will not be sent to the authorization server. + MaxSize uint16 `json:"maxSize,omitempty"` +} + +``` +#### YAML Examples + +Coming soon. + +#### Phase 2: Adding more complex configuration with Policy + +This phase is currently undefined until we reach agreement on the Filter + Policy +approach. ## Conformance Details @@ -138,12 +494,22 @@ From @ongy, some additional goals to keep in mind: #### Feature Names -Every feature should: +For this feature as a base: + +`HTTPRouteExtAuth` + +For supporting talking to ext_authz servers using the gRPC ext_authz protocol: + +`HTTPRouteExtAuthGRPC` + +For supporting talking to ext_authz servers using HTTP: + +`HTTPRouteExtAuthHTTP` + +For forwarding the body of the client request to the authorization server + +`HTTPRouteExtAuthForwardBody` -1. Start with the resource name. i.e HTTPRouteXXX -2. Follow the PascalCase convention. Note that the resource name in the string should come as is and not be converted to PascalCase, i.e HTTPRoutePortRedirect and not HttpRoutePortRedirect. -3. Not exceed 128 characters. -4. Contain only letters and numbers ### Conformance tests diff --git a/geps/gep-1494/metadata.yaml b/geps/gep-1494/metadata.yaml index 14161d8cb4..600aed9a6a 100644 --- a/geps/gep-1494/metadata.yaml +++ b/geps/gep-1494/metadata.yaml @@ -2,7 +2,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 1494 name: HTTP Auth in Gateway API -status: Provisional +status: Implementable # Any authors who contribute to the GEP in any way should be listed here using # their GitHub handle. authors: @@ -13,7 +13,13 @@ authors: references: {} # featureNames is a list of the feature names introduced by the GEP, if there # are any. This will allow us to track which feature was introduced by which GEP. -featureNames: {} +featureNames: + - HTTPRouteExtAuth + - HTTPRouteExtAuthGRPC + - HTTPRouteExtAuthHTTP + - HTTPRouteExtAuthForwardBody # changelog is a list of hyperlinks to PRs that make changes to the GEP, in # ascending date order. -changelog: {} +changelog: + - https://github.com/kubernetes-sigs/gateway-api/pull/3500 + - https://github.com/kubernetes-sigs/gateway-api/pull/3884 diff --git a/geps/gep-1619/index.md b/geps/gep-1619/index.md index 04451eb948..1abed57476 100644 --- a/geps/gep-1619/index.md +++ b/geps/gep-1619/index.md @@ -21,7 +21,7 @@ Before this GEP graduates to Implementable, we must fulfill the following criter - **Answer**: Yes. We adjusted the API to use `BackendLBPolicy`. See [API](#api) for more details. 2. Should we leave room for configuring different forms of Session Persistence? If so, what would that look like? - - **Answer**: Yes. See the [BackendLBPolicy API](#BackendLBPolicy-api) and [API Granularity](#api-granularity) + - **Answer**: Yes. See the [BackendLBPolicy API](#backendlbpolicy-api) and [API Granularity](#api-granularity) sections for more details. 3. What name appropriately describe the API responsible for configuring load-balancing options for backend traffic? - **Answer**: We decided on `BackendLBPolicy` since it is aligned with `BackendTLSPolicy`, describes configuration @@ -668,7 +668,7 @@ functionality of their applications. ### Prior Art -Referring to our [Implementations](#Implementations) table on session persistence, the majority of Gateway API +Referring to our [Implementations](#implementations) table on session persistence, the majority of Gateway API implementations designed session persistence in their APIs to be attached to a service or backends. This should be considered cautiously, as making associations to Gateway API's notion of Gateway, Route, and Service to other implementation's objects is hard to directly translate. The idea of a route in Gateway API is often not the same as a diff --git a/geps/gep-1686/index.md b/geps/gep-1686/index.md index e986ee619f..50e6e7a756 100644 --- a/geps/gep-1686/index.md +++ b/geps/gep-1686/index.md @@ -16,7 +16,7 @@ This testing plan specifies a new set of tests to define a "Mesh" [conformance p ## Focus Currently the GAMMA spec consists of two Gateway API GEPs [defining terminology and goals of Gateway API for service meshes](../gep-1324/index.md) -and specifically [how route resources work in a service mesh context](/geps/gep-1426/). +and specifically [how route resources work in a service mesh context](../gep-1294/index.md). The goal of the initial conformance testing is to check the essential behavior as defined by GEP-1426, as it differs from the wider Gateway API spec. This GEP focuses on using a `Service` object as an `xRoute` `parentRef` to control how the GAMMA implementation directs traffic to the endpoints specified by the `Services` in `backendRefs` and how the traffic is filtered and modified. ## Conformance Profile diff --git a/geps/gep-1709/index.md b/geps/gep-1709/index.md index b4e29acc92..b370805fc8 100644 --- a/geps/gep-1709/index.md +++ b/geps/gep-1709/index.md @@ -69,7 +69,7 @@ steps: 1. select a [profile](#profiles) 2. [integrate](#integration) tests in the downstream project -3. [report results and get certified](#certification) +3. [report results][#reporting-process] and get certified][#certification-process] The goal is to make selecting a conformance profile as simple and automatic of a process as feasible and support both the existing command line integration @@ -164,7 +164,7 @@ for i := 0; i < len(tests.ConformanceTests); i++ { > but when used in conjunction with `Profile` this will result in a report that > the profile is not valid for reporting. Implementations in this state may be > able to report themselves as "in progress", see the -> [certification section](#certification) for details. +> [certification section](#certification-process) for details. Alternatively for an `Extended` conformance profile where not all of the features are implemented (as described in the [profiles](#profiles) section @@ -234,7 +234,7 @@ support, or opt-out of the features you _don't_ support using `UnsupportedFeatures`. Once an implementation has integrated with the conformance test suite, they can -move on to [certification](#certification) to report the results. +move on to [certification](#certification-process) to report the results. [go-test]:https://go.dev/doc/tutorial/add-a-test [go]:https://go.dev diff --git a/geps/gep-1713/index.md b/geps/gep-1713/index.md index f51f044dda..c720b35794 100644 --- a/geps/gep-1713/index.md +++ b/geps/gep-1713/index.md @@ -36,8 +36,8 @@ Thus updating a single `Gateway` resource with this many certificates is a conte More broadly, large scale gateway users often expose `O(1000)` domains, but are currently limited by the maximum of 64 `listeners`. -The spec currently has language to indicate implementations `MAY` merge `Gateways` resources but does not define any specific requirements for how that should work. -https://github.com/kubernetes-sigs/gateway-api/blob/541e9fc2b3c2f62915cb58dc0ee5e43e4096b3e2/apis/v1beta1/gateway_types.go#L76-L78 +The [spec currently has language](https://github.com/kubernetes-sigs/gateway-api/blob/541e9fc2b3c2f62915cb58dc0ee5e43e4096b3e2/apis/v1beta1/gateway_types.go#L76-L78) to indicate implementations `MAY` merge `Gateways` resources but does not define any specific requirements for how that should work. + ## Feature Details @@ -163,16 +163,20 @@ type ListenerEntry struct { // Port is the network port. Multiple listeners may use the // same port, subject to the Listener compatibility rules. - // - // If the port is specified as zero, the implementation will assign + // + // If the port is not set or specified as zero, the implementation will assign // a unique port. If the implementation does not support dynamic port // assignment, it MUST set `Accepted` condition to `False` with the // `UnsupportedPort` reason. - // + // // Support: Core // // +optional - Port *PortNumber `json:"port,omitempty"` + // + // +kubebuilder:default=0 + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=65535 + Port PortNumber `json:"port,omitempty"` // Protocol specifies the network protocol this listener expects to receive. // @@ -385,8 +389,11 @@ spec: ``` ### ListenerEntry -`ListenerEntry` is currently a copy of the `Listener` struct with some changes -1. `Port` is now a pointer to allow for dynamic port assignment. +`ListenerEntry` is currently a copy of the `Listener` struct with some changes noted in the below sections + +#### Port + +`Port` is now optional to allow for dynamic port assignment. If the port is unspecified or set to zero, the implementation will assign a unique port. If the implementation does not support dynamic port assignment, it MUST set `Accepted` condition to `False` with the `UnsupportedPort` reason. ## Semantics @@ -399,7 +406,7 @@ When there are no listeners the `Gateway`'s `status.listeners` should be empty o Implementations, when creating a `Gateway`, may provision underlying infrastructure when there are no listeners present. The status conditions `Accepted` and `Programmed` conditions should reflect state of this provisioning. -### Gateway <> ListenerSet Handshake +### Gateway & ListenerSet Handshake By default a `Gateway` MUST NOT allow `ListenerSets` to be attached. Users can enable this behaviour by configuring their `Gateway` to allow `ListenerSet` attachment: @@ -413,7 +420,7 @@ spec: - from: Same ``` -### Route Attaching +### Route Attachment Routes MUST be able to specify a `ListenerSet` as a `parentRef`. Routes can use `sectionName`/`port` fields in `ParentReference` to help target a specific listener. If no listener is targeted (`sectionName`/`port` are unset) then the Route attaches to all the listeners in the `ListenerSet`. @@ -461,10 +468,36 @@ spec: sectionName: foo ``` +#### Optional Section Name + +If a `sectionName` in a Route's `parentRef` is not set then the Route MUST attach to only the listeners in the referenced parent. As an example given a `Gateway` and it's child `ListenerSets` a route attaching to the `Gateway` with an empty `sectionName` shall only attach to the listeners in the `Gateways` immediate `spec.listeners` list. In other words, the Route will not attach to any listeners in the `ListenerSets`. This is necessary because, for UX reasons, the `name` field does not have to be unique across all Listeners merged into a Gateway (see the section below for details). + +### Policy Attachment + +Policy attachment is [under discussion] in https://github.com/kubernetes-sigs/gateway-api/discussions/2927 + +Similar to Routes, `ListenerSet` can inherit policy from a Gateway. +Policies that attach to a `ListenerSet` apply to all listeners defined in that resource, but do not impact listeners in the parent `Gateway`. This allows `ListenerSets` attached to the same `Gateway` to have different policies. +If the implementation cannot apply the policy to only specific listeners, it should reject the policy. + +### ReferenceGrant Semantics + +When a `ReferenceGrant` is applied to a `Gateway` it MUST NOT be inherited by child `ListenerSets`. Thus a `ListenerSet` listener MUST NOT access secrets granted to the `Gateway` listeners. + +When a `ReferenceGrant` is applied to a `ListenerSet` it MUST NOT grant permission to the parent `Gateway`'s listeners. Thus a `Gateway` listener MUST NOT access secrets granted to the `ListenerSet` listeners. + +A `ListenerSet` must be able to reference a secret/backend in the same namespace as itself without a `ReferenceGrant`. + + ### Listener Validation -Implementations MUST treat the parent `Gateway`s as having the merged list of all listeners from itself and attached `ListenerSets`. See 'Listener Precedence' for more details on ordering. -Validation of this list of listeners MUST behave the same as if the list were part of a single `Gateway`. +Within a single resource such as a `Gateway` or `ListenerSet` the list of listeners MUST have unique names. Implementations MUST allow listeners from a child `ListenerSet` to be merged into a parent `Gateway` when listeners have the same name. Likewise implementations MUST allow sibling `ListenerSets` listeners with matching names to be merged into a parent `Gateway`. This allows for authors of Routes to simply attach to their desired parentRef and listener without having to worry about naming conflicts across resources. + +It is up to the implementations how unique names are generated internally. One example would be to hash the `ListenerSet` name+namespace and prepend it to the listener entry `name`. + +Implementations MUST treat the parent `Gateway`s as having the merged list of all listeners from itself and attached `ListenerSets` and validation of this list of listeners MUST behave the same as if the list were part of a single `Gateway` with the relaxed listener name constraints. + +Ordering will follow the semantics defined in [Listener Precedence](#listener-precedence). From the earlier example the above resources would be equivalent to a single `Gateway` where the listeners are collapsed into a single list. @@ -514,7 +547,7 @@ Listeners should be merged using the following precedence: Conflicts are covered in the section 'ListenerConditions within a ListenerSet' -### Gateway Conditions +### Gateway Conditions `Gateway`'s `Accepted` and `Programmed` top-level conditions remain unchanged and reflect the status of the local configuration. @@ -555,14 +588,6 @@ If a listener has a conflict, this should be reported in the `ListenerEntryStatu Implementations SHOULD be cautious about what information from the parent or siblings are reported to avoid accidentally leaking sensitive information that the child would not otherwise have access to. This can include contents of secrets etc. -### Policy Attachment - -Policy attachment is [under discussion] in https://github.com/kubernetes-sigs/gateway-api/discussions/2927 - -Similar to Routes, `ListenerSet` can inherit policy from a Gateway. -Policies that attach to a `ListenerSet` apply to all listeners defined in that resource, but do not impact listeners in the parent `Gateway`. This allows `ListenerSets` attached to the same `Gateway` to have different policies. -If the implementation cannot apply the policy to only specific listeners, it should reject the policy. - ## Alternatives ### Re-using Gateway Resource diff --git a/geps/gep-1762/index.md b/geps/gep-1762/index.md index e5f4ebf395..eb25e53859 100644 --- a/geps/gep-1762/index.md +++ b/geps/gep-1762/index.md @@ -59,6 +59,7 @@ With this configuration, an implementation: * MUST mark the Gateway as `Programmed` and provide an address in `Status.Addresses` where the Gateway can be reached on each configured port. * MUST label all generated resources (Service, Deployment, etc) with `gateway.networking.k8s.io/gateway-name: my-gateway` (where `my-gateway` is the name of the Gateway resource). +* SHOULD label all generated resources (Service, Deployment, etc) with `gateway.networking.k8s.io/gateway-class-name: my-gateway-class` (where `my-gateway-class` is the name of the GatewayClass resource). * MUST provision generated resources in the same namespace as the Gateway if they are namespace scoped resources. * Cluster scoped resources are not recommended. * SHOULD name all generated resources `my-gateway-example` (`-`). diff --git a/geps/gep-1767/index.md b/geps/gep-1767/index.md index 3f1018bdb1..14315e190c 100644 --- a/geps/gep-1767/index.md +++ b/geps/gep-1767/index.md @@ -129,16 +129,6 @@ If `HTTPCORSFilter` is set, then the gateway will generate the response of the " For the actual cross-origin request, the gateway will add CORS headers to the response before it is sent to the client. ```golang -// AllowCredentialsType describes valid value of config `AllowCredentials`. -// -// +kubebuilder:validation:Enum=true -type AllowCredentialsType string - -const ( - // The actual cross-origin request allows to include credentials. - AllowCredentials AllowCredentialsType = "true" -) - const ( // HTTPRouteFilterCORS can be used to add CORS headers to an // HTTP response before it is sent to the client. @@ -222,7 +212,7 @@ type HTTPCORSFilter struct { // Output: // // The `Access-Control-Allow-Origin` response header can only use `*` - // wildcard as value when the `AllowCredentials` field is unspecified. + // wildcard as value when the `AllowCredentials` field is false. // // Input: // Origin: https://foo.example @@ -233,7 +223,7 @@ type HTTPCORSFilter struct { // Output: // Access-Control-Allow-Origin: * // - // When the `AllowCredentials` field is specified and `AllowOrigins` + // When the `AllowCredentials` field is true and `AllowOrigins` // field specified with the `*` wildcard, the gateway must return a // single origin in the value of the `Access-Control-Allow-Origin` // response header, instead of specifying the `*` wildcard. The value @@ -259,8 +249,8 @@ type HTTPCORSFilter struct { // AllowCredentials indicates whether the actual cross-origin request // allows to include credentials. // - // The only valid value for the `Access-Control-Allow-Credentials` - // response header is true (case-sensitive). + // When set to true, the gateway will include the `Access-Control-Allow-Credentials` + // response header with value true (case-sensitive). // // Input: // Origin: https://foo.example @@ -272,14 +262,12 @@ type HTTPCORSFilter struct { // Access-Control-Allow-Origin: https://foo.example // Access-Control-Allow-Credentials: true // - // If the credentials are not allowed in cross-origin requests, - // the gateway will omit the header `Access-Control-Allow-Credentials` - // entirely rather than setting its value to false. + // When set to false, the gateway will omit the header + // `Access-Control-Allow-Credentials` entirely (this is the standard CORS + // behavior). // // Support: Extended - // - // +optional - AllowCredentials AllowCredentialsType `json:"allowCredentials,omitempty"` + AllowCredentials *bool `json:"allowCredentials,omitempty"` // AllowMethods indicates which HTTP methods are supported // for accessing the requested resource. @@ -317,7 +305,7 @@ type HTTPCORSFilter struct { // Access-Control-Allow-Methods: GET, POST, DELETE, PATCH, OPTIONS // // The `Access-Control-Allow-Methods` response header can only use `*` - // wildcard as value when the `AllowCredentials` field is unspecified. + // wildcard as value when the `AllowCredentials` field is false. // // Input: // Access-Control-Request-Method: PUT @@ -328,7 +316,7 @@ type HTTPCORSFilter struct { // Output: // Access-Control-Allow-Methods: * // - // When the `AllowCredentials` field is specified and `AllowMethods` + // When the `AllowCredentials` field is true and the `AllowMethods` // field specified with the `*` wildcard, the gateway must specify one // HTTP method in the value of the Access-Control-Allow-Methods response // header. The value of the header `Access-Control-Allow-Methods` is same @@ -386,7 +374,7 @@ type HTTPCORSFilter struct { // // A wildcard indicates that the requests with all HTTP headers are allowed. // The `Access-Control-Allow-Headers` response header can only use `*` wildcard - // as value when the `AllowCredentials` field is unspecified. + // as value when the `AllowCredentials` field is false. // // Input: // Access-Control-Request-Headers: Content-Type, Cache-Control @@ -397,8 +385,8 @@ type HTTPCORSFilter struct { // Output: // Access-Control-Allow-Headers: * // - // When the `AllowCredentials` field is specified and `AllowHeaders` field - // specified with the `*` wildcard, the gateway must specify one or more + // When the `AllowCredentials` field is true and the `AllowHeaders` field + // is specified with the `*` wildcard, the gateway must specify one or more // HTTP headers in the value of the `Access-Control-Allow-Headers` response // header. The value of the header `Access-Control-Allow-Headers` is same as // the `Access-Control-Request-Headers` header provided by the client. If @@ -456,7 +444,7 @@ type HTTPCORSFilter struct { // // A wildcard indicates that the responses with all HTTP headers are exposed // to clients. The `Access-Control-Expose-Headers` response header can only use - // `*` wildcard as value when the `AllowCredentials` field is unspecified. + // `*` wildcard as value when the `AllowCredentials` field is false. // // Config: // exposeHeaders: ["*"] @@ -528,7 +516,7 @@ spec: value: /resource/foo filters: - cors: - - allowOrigins: + allowOrigins: - * allowMethods: - GET @@ -587,10 +575,10 @@ spec: value: /resource/foo filters: - cors: - - allowOrigins: + allowOrigins: - https://foo.example - http://foo.example - allowCredentials: "true" + allowCredentials: true allowMethods: - GET - PUT @@ -656,6 +644,48 @@ Access-Control-Allow-Headers: DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Request Access-Control-Expose-Headers: Content-Security-Policy ``` +### Disabling credentials + +To disable credentials for cross-origin requests, simply don't set the +`allowCredentials` field at all. If you prefer to be explicit, you can +set it to `false`, although this will generally not be necessary: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: http-route-cors-no-credentials +spec: + hostnames: + - http.route.cors.com + parentRefs: + - group: gateway.networking.k8s.io + kind: Gateway + name: http-gateway + rules: + - backendRefs: + - kind: Service + name: http-route-cors + port: 80 + matches: + - path: + type: PathPrefix + value: /resource/bar + filters: + - cors: + allowOrigins: + - https://foo.example + allowCredentials: false + allowMethods: + - GET + - POST + type: CORS +``` + +Omitting the field, and setting it to `false` both mean `false`. In this +configuration the gateway will _not_ include the +`Access-Control-Allow-Credentials` header in responses. + ## Prior Art Some implementations already support CORS. diff --git a/geps/gep-1767/metadata.yaml b/geps/gep-1767/metadata.yaml index c7fe532b81..e319aacd1c 100644 --- a/geps/gep-1767/metadata.yaml +++ b/geps/gep-1767/metadata.yaml @@ -7,6 +7,7 @@ authors: - lianglli - robscott - EyalPazz + - shaneutt references: - https://github.com/kubernetes-sigs/gateway-api/pull/3435 - https://github.com/kubernetes-sigs/gateway-api/pull/3637 diff --git a/geps/gep-1867/index.md b/geps/gep-1867/index.md index cf66436290..eba4f6e24c 100644 --- a/geps/gep-1867/index.md +++ b/geps/gep-1867/index.md @@ -36,7 +36,7 @@ This has been previously discussed in [this issue](https://github.com/kubernetes As a cluster scoped resource, `GatewayClass` does not meet this requirement. This restricts customization use cases to either a few pre-provisioned classes by the admin, or running in an environment where the "Infrastructure Provider" and "Cluster Operator" are the same roles. -The distinction between these roles is explicitly called out on the [homepage](../../index.md#what-is-the-gateway-api). +The distinction between these roles is explicitly called out on the [homepage](../../index.md#personas). ### Custom Resource diff --git a/geps/gep-1897/images/mesh.png b/geps/gep-1897/images/mesh.png new file mode 100644 index 0000000000..c82ced3089 Binary files /dev/null and b/geps/gep-1897/images/mesh.png differ diff --git a/geps/gep-1897/index.md b/geps/gep-1897/index.md index 9f2a9918f9..149d6c649e 100644 --- a/geps/gep-1897/index.md +++ b/geps/gep-1897/index.md @@ -22,18 +22,15 @@ the service or backend owner wants to validate the clients connecting to it, two 1. The solution must satisfy the following use case: the backend pod has its own certificate and the gateway implementation client needs to know how to connect to the backend pod. (Use case #4 in [Gateway API TLS Use Cases](#references)) -2. In terms of the Gateway API personas, only the application developer persona applies in this -solution. The application developer should control the gateway to backend TLS settings, -not the cluster operator, as requiring a cluster operator to manage certificate renewals -and revocations would be extremely cumbersome. -3. The solution should consider client certificate settings used in the TLS handshake **from -Gateway to backend**, such as server name indication, trusted certificates, -and CA certificates. +2. In this GEP, only the application developer persona will have control over TLS settings. This does not preclude adding other personas in future GEPs. +3. The solution should consider client TLS settings used in the TLS handshake **from +Gateway to backend**, such as server name indication and trusted CA certificates. +4. Both Gateway and Mesh use cases may be supported, depending on the implementation, and will be covered by features in each case. ## Longer Term Goals These are worthy goals, but deserve a different GEP for proper attention. This GEP is concerned entirely with the -controlplane, i.e. the hop between gateway and backend. +the hop between gateway client and backend. 1. [TCPRoute](../../reference/spec.md#gateway.networking.k8s.io/v1alpha2.TCPRoute) and [GRPCRoute](../../reference/spec.md#gateway.networking.k8s.io/v1alpha2.GRPCRoute) use cases @@ -59,7 +56,16 @@ These are worthy goals, but will not be covered by this GEP. 6. Controlling certificates used by more than one workload (#6 in [Gateway API TLS Use Cases](#references)) 7. Client certificate settings used in TLS **from external clients to the Listener** (#7 in [Gateway API TLS Use Cases](#references)) -8. Providing a mechanism for the cluster operator to override gateway to backend TLS settings. +8. Service Mesh "mesh transport security". +9. Providing a mechanism for the cluster operator to override gateway to backend TLS settings. + +> It is very common for service mesh implementations to implement some form of transparent transport security, whether that is WireGuard, mTLS, or others. +> This is completely orthogonal to the use cases being tackled by this GEP. +> * The "mesh transport security" is something invisible to the user's application, and is simply used to secure communication between components in the mesh. +> * This proposal, instead, explicitly calls for sending TLS **to the user's application**. +> However, this does not mean service meshes are outside of scope for this proposal, merely that only the application-level TLS configuration is in scope. + +![](images/mesh.png "Mesh transport") ## Already Solved TLS Use Cases @@ -83,16 +89,16 @@ Gateway API is missing a mechanism for separately providing the details for the including (but not limited to): * intent to use TLS on the backend hop -* client certificate of the gateway -* system certificates to use in the absence of client certificates +* CA certificates to trust +* other properties of the TLS handshake, such as SNI and SAN validation +* client certificate of the gateway (outside of scope for this GEP) ## Purpose - why do we want to do this? This proposal is _very_ tightly scoped because we have tried and failed to address this well-known gap in the API specification. The lack of support for this fundamental concept is holding back -Gateway API adoption by users that require a solution to the use case. One of the recurring themes -that has held up the prior art has been interest related to service mesh, and as such this proposal -focuses explicitly on the ingress use case in the initial round. Another reason for the tight scope +Gateway API adoption by users that require a solution to the use case. +Another reason for the tight scope is that we have been too focused on a generic representation of everything that TLS can do, which covers too much ground to address in a single GEP. @@ -150,10 +156,10 @@ Because naming is hard, a new name may be substituted without blocking acceptance of the content of the API change. The selection of the applicable Gateway API persona is important in the design of BackendTLSPolicy, because it provides -a way to explicitly describe the _expectations_ of the connection to the application. BackendTLSPolicy is configured -by the application developer Gateway API persona to signal what the application developer _expects_ in connections to -the application, from a TLS perspective. Only the application developer can know what the application expects, so it is -important that this configuration be managed by that persona. +a way to explicitly describe the _expectations_ of the connection to the application. +In this GEP, BackendTLSPolicy will be configured only by the application developer Gateway API persona to tell gateway clients how to connect to +the application, from a TLS perspective. +Future iterations *may* expand this to additionally allow consumer overrides; see [Future plans](#future-plans). During the course of discussion of this proposal, we did consider allowing the cluster operator persona to have some access to Gateway cert validation, but as mentioned, BackendTLSPolicy is used primarily to signal what the application @@ -170,18 +176,14 @@ as a TLS Client: - An explicit signal that TLS should be used by this connection. - A hostname the Gateway should use to connect to the backend. -- A reference to one or more certificates to use in the TLS handshake, signed by a CA or self-signed. -- An indication that system certificates may be used. +- A reference to one or more CA certificates (which could include "system certificates") to validate the server's TLS certificates. BackendTLSPolicy is defined as a Direct Policy Attachment without defaults or overrides, applied to a Service that accesses the backend in question, where the BackendTLSPolicy resides in the same namespace as the Service it is -applied to. The BackendTLSPolicy and the Service must reside in the same namespace in order to prevent the -complications involved with sharing trust across namespace boundaries. We chose the Service resource as a target, +applied to. For now, the BackendTLSPolicy and the Service must reside in the same namespace in order to prevent the +complications involved with sharing trust across namespace boundaries (see [Future plans](#future-plans)). We chose the Service resource as a target, rather than the Route resource, so that we can reuse the same BackendTLSPolicy for all the different Routes that might point to this Service. -For the use case where certificates are stored in their own namespace, users may create Secrets and use ReferenceGrants -for a BackendTLSPolicy-to-Secret binding. Implementations must respect a ReferenceGrant for cross-namespace Secret -sharing to BackendTLSPolicy, even if they don't for other cross-namespace sharing. One of the areas of concern for this API is that we need to indicate how and when the API implementations should use the backend destination certificate authority. This solution proposes, as introduced in @@ -194,6 +196,8 @@ that is appropriate, such as one of the HTTP error codes: 400 (Bad Request), 401 other signal that makes the failure sufficiently clear to the requester without revealing too much about the transaction, based on established security requirements. +BackendTLSPolicy applies only to TCP traffic. If a policy explicitly attaches to a UDP port of a Service (that is, the `targetRef` has a `sectionName` specifying a single port or the service has only 1 port), the `Accepted: False` Condition with `Reason: Invalid` MUST be set. If the policy attaches to a mix of TCP and UDP ports, implementations SHOULD include a warning in the `Accepted` condition message (`ancestors.conditions`); the policy will only be effective for the TCP ports. + All policy resources must include `TargetRefs` with the fields specified in [PolicyTargetReference](https://github.com/kubernetes-sigs/gateway-api/blob/a33a934af9ec6997b34fd9b00d2ecd13d143e48b/apis/v1alpha2/policy_types.go#L24-L41). In an upcoming [extension](https://github.com/kubernetes-sigs/gateway-api/issues/2147) to TargetRefs, policy resources @@ -210,6 +214,13 @@ configuration. CACertificateRefs is an implementation-specific slice of named object references, each containing a single cert. We originally proposed to follow the convention established by the [CertificateRefs field on Gateway](https://github.com/kubernetes-sigs/gateway-api/blob/18e79909f7310aafc625ba7c862dfcc67b385250/apis/v1beta1/gateway_types.go#L340) , but the CertificateRef requires both a tls.key and tls.crt and a certificate reference only requires the tls.crt. +If any of the CACertificateRefs cannot be resolved (e.g., the referenced resource does not exist) or is misconfigured (e.g., ConfigMap does not contain a key named `ca.crt`), the `ResolvedRefs` status condition MUST be set to `False` with `Reason: InvalidCACertificateRef`. Connections using that CACertificateRef MUST fail, and the client MUST receive an HTTP 5xx error response. +References to objects with an unsupported Group and Kind are not valid, and MUST be rejected by the implementation with the `ResolvedRefs` status condition set to `False` and `Reason: InvalidKind`. +Implementations MAY perform further validation of the certificate content (i.e., checking expiry or enforcing specific formats). If they do, they MUST ensure that the `ResolvedRefs` Condition is `False` and use an implementation-specific `Reason`, like `ExpiredCertificate` or similar. +If `ResolvedRefs` Condition is `False` implementations SHOULD include a message specifying which references are invalid and explaining why. + +If all CertificateRefs cannot be resolved, the BackendTLSPolicy is considered invalid and the implementation MUST set the `Accepted` Condition to `False`, with a reason of `NoValidCACertificate` and a message explaining this. + WellKnownCACertificates is an optional enum that allows users to specify whether to use the set of CA certificates trusted by the Gateway (WellKnownCACertificates specified as "System"), or to use the existing CACertificateRefs (WellKnownCACertificates specified as ""). The use and definition of system certificates is implementation-dependent, and the intent is that @@ -218,8 +229,12 @@ references to Kubernetes objects that contain PEM-encoded TLS certificates, whic between the gateway and backend pod. References to a resource in a different namespace are invalid. If ClientCertificateRefs is unspecified, then WellKnownCACertificates must be set to "System" for a valid configuration. If WellKnownCACertificates is unspecified, then CACertificateRefs must be specified with at least one entry for a valid configuration. -If WellKnownCACertificates is set to "System" and there are no system trusted certificates or the implementation doesn't define system -trusted certificates, then the associated TLS connection must fail. +If an implementation does not support the WellKnownCACertificates, or the provided value is unsupported,the BackendTLSPolicy is considered invalid, and the implementation MUST set the `Accepted` Condition to `False`, with a reason of `Invalid` and a message explaining this. + +For an invalid BackendTLSPolicy, implementations MUST NOT fall back to unencrypted (plaintext) connections. +Instead, the corresponding TLS connection MUST fail, and the client MUST receive an HTTP 5xx error response. + +Implementations MUST NOT modify any status other than their own. Ownership of a status is determined by the `controllerName`, which identifies the responsible controller. The `Hostname` field is required and is to be used to configure the SNI the Gateway should use to connect to the backend. Implementations must validate that at least one name in the certificate served by the backend matches this field. @@ -238,35 +253,22 @@ Thus, the following additions would be made to the Gateway API: ## How a client behaves -This table describes the effect that a BackendTLSPolicy has on a Route. There are only two cases where the -BackendTLSPolicy will signal a Route to connect to a backend using TLS, an HTTPRoute with a backend that is targeted -by a BackendTLSPolicy, either with or without listener TLS configured. (There are a few other cases where it may be -possible, but is implementation dependent.) - -Every implementation that claims supports for BackendTLSPolicy should document for which Routes it is being implemented. - -| Route Type | Gateway Config | Backend is targeted by a BackendTLSPolicy? | Connect to backend with TLS? | -|------------|----------------------------|-----------------------------------------------|-------------------------------| -| HTTPRoute | Listener tls | Yes | **Yes** | -| HTTPRoute | No listener tls | Yes | **Yes** | -| HTTPRoute | Listener tls | No | No | -| HTTPRoute | No listener tls | No | No | -| TLSRoute | Listener Mode: Passthrough | Yes | No | -| TLSRoute | Listener Mode: Terminate | Yes | Implementation-dependent | -| TLSRoute | Listener Mode: Passthrough | No | No | -| TLSRoute | Listener Mode: Terminate | No | No | -| TCPRoute | Listener TLS | Yes | Implementation-dependent | -| TCPRoute | No listener TLS | Yes | Implementation-dependent | -| TCPRoute | Listener TLS | No | No | -| TCPRoute | No listener TLS | No | No | -| UDPRoute | Listener TLS | Yes | No | -| UDPRoute | No listener TLS | Yes | No | -| UDPRoute | Listener TLS | No | No | -| UDPRoute | No listener TLS | No | No | -| GRPCRoute | Listener TLS | Yes | Implementation-dependent | -| GRPCRoute | No Listener TLS | Yes | Implementation-dependent | -| GRPCRoute | Listener TLS | No | No | -| GRPCRoute | No Listener TLS | No | No | +The `BackendTLSPolicy` tells a client "Connect to this service using TLS". +This is unconditional to the type of traffic the gateway client is forwarding. + +For instance, the following will all have the gateway client add TLS if the backend is targeted by a BackendTLSPolicy: + +* A Gateway accepts traffic on an HTTP listener +* A Gateway accepts and terminates TLS on an HTTPS listener +* A Gateway accepts traffic on a TCP listener + +There is no need for a Gateway that accepts traffic with `Mode: Passthrough` to do anything differently here, but implementations MAY choose to treat TLS passthrough as a special case. Implementations that do this SHOULD clearly document their approach if BackendTLSPolicy is treated differently for TLS passthrough. + +Note that there are cases where these patterns may result in multiple layers of TLS on a single connection. +There may be even cases where the gateway implementation is unaware of this; for example, processing TCPRoute traffic -- the traffic may or may not be TLS, and the gateway would be unaware. +This is intentional to allow full fidelity of the API, as this is commonly desired for tunneling scenarios. +When users do not want this, they should ensure that the BackendTLSPolicy is not incorrectly applied to traffic that is already TLS. +The [Future Plans](#future-plans) include more controls over the API to make this easier to manage. ## Request Flow @@ -281,6 +283,23 @@ reverse proxy. This is shown as **bolded** additions in step 6 below. 6. Lastly, the reverse proxy **optionally performs a TLS handshake** and forwards the request to one or more objects, i.e. Service, in the cluster based on backendRefs rules of the HTTPRoute **and the TargetRefs of the BackendTLSPolicy**. +## Future plans + +In order to scope this GEP, some some changes are deferred to a near-future GEP. +This GEP intends to add the ability for additional control by gateway clients to override TLS settings, following previously established patterns of [consumer and producer policies]([glossary](https://gateway-api.sigs.k8s.io/concepts/glossary/?h=gloss#producer-route)). +Additionally, more contextual control over when to apply the policies will be explored, to enable use cases like "apply TLS only from this route" ([issue](https://github.com/kubernetes-sigs/gateway-api/issues/3856)). + +While the details of these plans are out of scope for this GEP it is important to be aware of the future plans for the API to ensure the immediate-term plans are future-proofed against the proposed plans. + +Implementations should plan for the existence of future fields that may be added that will control where the TLS policy applies. +These may include, but are not limited to: + +* `spec.targetRefs.namespace` +* `spec.targetRefs.from` +* `spec.mode` + +While in some cases adding new fields may be seen as a backwards compatibility risk, due to older implementations not knowing to respect the fields, these fields (or similar, should future GEPs decide on new names) are pre-approved to be added in a future release, should the GEPs to add them are approved in the first place. + ## Alternatives Most alternatives are enumerated in the section "The history of backend TLS". A couple of additional alternatives are also listed here. @@ -405,8 +424,6 @@ the implementation would be required to fully implement the policy or mark the b [GEP-713: Metaresources and PolicyAttachment](../gep-713/index.md) -[Policy Attachment](../../reference/policy-attachment.md#direct-policy-attachment) - [Gateway API TLS](../../guides/tls.md) [SIG-NET Gateway API: TLS to the K8s.Service/Backend](https://docs.google.com/document/d/1RTYh2brg_vLX9o3pTcrWxtZSsf8Y5NQvIG52lpFcZlo) diff --git a/geps/gep-1911/index.md b/geps/gep-1911/index.md index c26565ce07..fb6df21430 100644 --- a/geps/gep-1911/index.md +++ b/geps/gep-1911/index.md @@ -85,7 +85,6 @@ 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](../gep-1897/index.md) diff --git a/geps/gep-2162/index.md b/geps/gep-2162/index.md index 38b2dbf60e..25f3371c63 100644 --- a/geps/gep-2162/index.md +++ b/geps/gep-2162/index.md @@ -1,11 +1,11 @@ # GEP-2162: Supported features in GatewayClass Status * Issue: [#2162](https://github.com/kubernetes-sigs/gateway-api/issues/2162) -* Status: Experimental +* Status: Standard ## TLDR -This GEP proposes to enhance the [GatewayClassStatus](https://github.com/kubernetes-sigs/gateway-api/blob/f2cd9bb92b4ff392416c40d6148ff7f76b30e649/apis/v1beta1/gatewayclass_types.go#L185) to include a list of Gateway API features supported by the installed GatewayClass. +This GEP proposes to enhance the [GatewayClassStatus](https://github.com/kubernetes-sigs/gateway-api/blob/f2cd9bb92b4ff392416c40d6148ff7f76b30e649/apis/v1beta1/gatewayclass_types.go#L185) to include a list of Gateway API features supported by the installed GatewayClass. ## Goals @@ -17,16 +17,12 @@ This GEP proposes to enhance the [GatewayClassStatus](https://github.com/kuberne * Provide foundation for tools to block or warn when unsupported features are used. - ## Non-Goals * Validate correctness of supported features published by the implementation. - Meaning we don't intend to verify whether the supported features reported by - the implementation are indeed supported. + Meaning we don't intend to verify whether the supported features reported by the implementation are indeed supported. - However, the supported features in the status of the GatewayClass should - make it very easy for any individual to run conformance tests against the - GatewayClass using our conformance tooling. + However, the supported features in the status of the GatewayClass should make it easy for any individual to run conformance tests against the GatewayClass using our conformance tooling. ## Introduction @@ -45,7 +41,7 @@ Implementations **must** publish the supported features before Accepting the Gat Implementations are free to decide how they manage this information. A common approach could be to maintain static lists of supported features or using predefined sets. -Note: implementations must keep the published list sorted in ascending alphabetical order. +> Note: implementations must keep the published list sorted in ascending alphabetical order. ## API @@ -53,7 +49,6 @@ This GEP proposes API changes describes as follow: * Update the `GatewayClassStatus` struct to include a string-represented list of `SupportedFeatures`. - ```go // GatewayClassStatus is the current status for the GatewayClass. type GatewayClassStatus struct { @@ -106,6 +101,12 @@ status: - HTTPRouteQueryParamMatching ``` + +### SupportedFeatures Guidance in GatewayClass + +Only Gateway related features should be published on GatewayClass. The rest, i.e Mesh features should not be published under GatewayClass, and will likely to be published on the new Mesh resource CRD when it is ready [ref](https://github.com/kubernetes-sigs/gateway-api/pull/3950). +Mesh features published on GatewayClassStatus will be ignored by the conformance test suite along with a warning. + ## Standardize features and conformance tests names Before we add the supported features into our API, it is necessary to establish standardized naming and formatting conventions. @@ -116,20 +117,40 @@ Before we add the supported features into our API, it is necessary to establish Every feature should: -1. Start with the resource name. i.e HTTPRouteXXX +1. Start with the resource name. i.e HTTPRouteXXX. 2. Follow the PascalCase convention. Note that the resource name in the string should come as is and not be converted to PascalCase, i.e HTTPRoutePortRedirect and not HttpRoutePortRedirect. 3. Not exceed 128 characters. 4. Contain only letters and numbers #### Conformance test names -Conformance tests file names should try to follow the `pascal-case-name.go` format. +Conformance tests file names should try to follow the `kebab-case-name.go` format. For example for `HTTPRoutePortRedirect` - the test file would be `httproute-port-redirect.go`. We should treat this guidance as "best effort" because we might have test files that check the combination of several features and can't follow the same format. In any case, the conformance tests file names should be meaningful and easy to understand. +#### Conformance report + +In order for to verify that the list of features reported are indeed supported by GatewayClass tests will be run based on the features from the GatewayClassStatus. +If the source of Gateway features are not inferred and manually provided the conformance suite will block the report from being submitted. + +#### Reporting Mesh features + +As Mesh doesn't have a good place (yet) to populate SupportedFeatures, its features can be tested for compliance by using Conformance Profiles, or manually, providing features for test using `--supported-features` flag. +Until mesh features are posted on the Mesh resource CRD, the conformance suite will determine if conformance run is for [Mesh features](https://github.com/kubernetes-sigs/gateway-api/issues/3984) and will NOT block the report if provided manually. + +#### Staying Compliant + +SupportedFeatures will become available starting 1.4 release as a standard feature, which means that all Gateway implementations will be expected to define and populate SupportedFeatures in the GatewayClass' Status. +The conformance test suite will be based on inferring supported features from GatewayClassStatus, +meaning if you want to generate passing report, features should be populated there. +There will be a grace period until the 1.5 release, after which all Gateway Conformance Reports will need to be generated based on the SupportedFeatures field in GatewayClass status (with the exception of Mesh features described above). + +The core purpose of conformance tests for GatewayClass is to verify that reported features are truly supported. +While the community currently operates on a trust-based system for conformance reports, programmatically inferring features from the GatewayClass status field creates a strong, verifiable link between an implementation's claims and the test results. +Having this connection between supported features and conformance tests, helps improve the UX and make it easier for implementers to run the correct conformance tests. ## Followups @@ -137,14 +158,13 @@ Before we make the changes we need to; 1. Change the names of the supported features and conformance tests that don't conform with the formatting rules. - ## Alternatives ### Re-using ConformanceProfiles structs We could use the same structs as we do in conformance profile object, more specifically, the [ProfileReport](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/apis/v1alpha1/profilereport.go#LL24C6-L24C19) struct. -Though it would be nice to have only one place to update, these structs seems to include much more data relevant to the conformance report but not for our use case. +Though it would be nice to have only one place to update, these structs seems to include much more data relevant to the conformance report but not for our use case. That said, conformance profiles are still at experimental stage, we could explore the option to create a shared struct that will be used both for the conformance reports and for the GatewayClass status. @@ -158,8 +178,7 @@ However, having the supported features published in the GatewayClass Status adds * We could build a mechanism or a tool to block or warn when unsupported features are used. * Users will be able to select the GatewayClass that suits their needs without having to refer to documentation or conformance reports. -This does not cover a future piece of work we want to implement which is to warn/block users from applying a Gateway API object if the installed GWC doesn't support it. (originally suggested in [#1804](https://github.com/kubernetes-sigs/gateway-api/issues/1804)). - +This does not cover a future piece of work we want to implement which is to warn/block users from applying a Gateway API object if the installed GWC doesn't support it. (originally suggested in [#1804](https://github.com/kubernetes-sigs/gateway-api/issues/1804)). ## References @@ -169,6 +188,7 @@ This does not cover a future piece of work we want to implement which is to warn ## Future Work ### Research the development of an unsupported feature warning/blocking mechanism + Once the GatewayClass features support are is published into the status we could look into; 1. Using the supported features in the webhook to validate or block attempts to apply manifests with unsupported features. @@ -181,7 +201,7 @@ Once the GatewayClass features support are is published into the status we could We got some feedback that it will be useful to indicate which Gateway API version the implementation supports. So when we have supported features published in the GatewayClass Status, users will also be able to understand that those are the supported features for a specific Gateway API version. -This work is likely to require its own small GEP but ideally what this field would mean is that an implementation supports Max(vX.X). +This work is likely to require its own small GEP but ideally what this field would mean is that an implementation supports Max(vX.X). The value of it is to provide a better user experience and also more foundation for tools to be able to warn for example when a GatewayClass and CRDs have mismatched versions. diff --git a/geps/gep-2627/index.md b/geps/gep-2627/index.md new file mode 100644 index 0000000000..86a36152a8 --- /dev/null +++ b/geps/gep-2627/index.md @@ -0,0 +1,51 @@ +# GEP-2627: DNS configuration within Gateway API + +* Issue: [#2627](https://github.com/kubernetes-sigs/gateway-api/issues/2627) +* Status: Provisional + +## TLDR + +For gateway infrastructure to be valuable we need to be able to connect clients to these gateways. A common way to achieve this is to use domain names/hostnames and DNS. The guidelines for DNS configuration are a critical piece of service networking, but this is currently not expressible as part of Gateway API. Instead of leaving this unspecified and having implementations likely to do this in different ways, the purpose of this proposal is to provide a standard way to specify DNS for Gateways. + +## Goals +* Provide DNS specification for Gateway resources +* Support multiple DNS providers and a selection mechanism for Gateways +* Provide Gateway status to communicate the state of provisioned DNS +* Increase portability and supportability between Gateway API implementations and third party controllers offering DNS integration. + +## Non-Goals + +* Providing any upstream hostname validation mechanisms. We can provide status for validation failure, but implementations are responsible for validation. +* Multi-cluster DNS for multi-cluster ingress solutions (at least not as part of the initial API) + +## Use Cases + +As a cluster administrator, I manage a set of domains and a set of gateways. I would like to declaratively define which gateways should be used for provisioning DNS records, and, if necessary, which DNS provider to use to configure connectivity for clients accessing these domains and my gateway so that I can see and configure which DNS provider is being used. + +As a cluster administrator, I would like to have the DNS names automatically populated into my specified DNS zones as a set of records based on the assigned addresses of my gateways so that I do not have to undertake external automation or management of this essential task. + +As a cluster administrator I would have the status of the DNS records reported back to me, so that I can leverage existing kube based monitoring tools to know the status of the integration. + +As a cluster administrator, I would like the DNS records to be updated automatically if the `spec` of assigned gateways changes, whether those changes are for IP address or hostname. + +As a DNS administrator, I should be able to ensure that only approved External DNS controllers can make changes to DNS zone configuration. (This should in general be taken care of by DNS system <-> External DNS controller interactions like user credentials and operation status responses, but it is important to remember that it needs to happen). + +## API + +Initial draft will not offer an API yet until the use cases are agreed. Some thoughts worth thinking about: +- I think it is important that we try to move away from APIs based on annotations which, while convenient, are not a full API and suffer from several limitations. An example: I want to configure a listener with a domain I own that is in a different provider than the domains of the other listeners. I want to add a new option to configure a particular weighting and so on. Soon you end up with a large set of connected annotations that often grow in complexity that really should be expressed as an API. + +- It is also important that this API can be delegated to controllers other than the Gateway API provider/implementor. This is because there are existing solutions that may want to support whatever API decided upon. It should not **have** to be a gateway provider that has to integrate with many DNS providers. + +## Conformance Details + +TBD + +## Alternatives + +it is possible to use `external-dns` to manage dns based on HTTPRoutes and Gateways https://github.com/kubernetes-sigs/external-dns/blob/7f3c10d65297ec1c4bcc8dd6f88c189b7f3e80d0/docs/tutorials/gateway-api.md. The aim of this GEP is not remove this as an option, but instead provide a common API that could then be leveraged by something like external-dns. + + +## References + +The Kuadrant project, offers a [DNSPolicy API](https://docs.kuadrant.io/1.2.x/kuadrant-operator/doc/reference/dnspolicy/#dnspolicy) which in part was the basis and inspiration for opening this GEP. The DNSPolicy offered by Kuadrant goes beyond what is outlined here as it also handles multi-cluster ingress and offers common routing options such as GEO and Weighted responses. \ No newline at end of file diff --git a/geps/gep-2627/metadata.yaml b/geps/gep-2627/metadata.yaml new file mode 100644 index 0000000000..17dfb34248 --- /dev/null +++ b/geps/gep-2627/metadata.yaml @@ -0,0 +1,7 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 2627 +name: DNS configuration for Gateway API +status: Provisional +authors: + - maleck13 diff --git a/geps/gep-2722/index.md b/geps/gep-2722/index.md index 135e2c7670..fc6a609d20 100644 --- a/geps/gep-2722/index.md +++ b/geps/gep-2722/index.md @@ -387,7 +387,7 @@ distribution mechanisms will be provided: for visualizing data and presenting information in a visually appealing manner. * Evaluate how gwctl can be extended to support [Mesh use - cases](/concepts/gamma/#how-the-gateway-api-works-for-service-mesh) + cases](../../mesh/index.md) ## References diff --git a/geps/gep-3155/index.md b/geps/gep-3155/index.md index b75b64cccf..41477c2266 100644 --- a/geps/gep-3155/index.md +++ b/geps/gep-3155/index.md @@ -43,13 +43,20 @@ Specifying credentials at the gateway level is the default operation mode, where backends will be presented with a single gateway certificate. Per-service overrides are subject for consideration as the future work. -**1. Add a new `BackendTLS` field at the top level of Gateways** +**1. Add a new `BackendValidation` field at TLSConfig struct located in GatewayTLSConfig.Default field** ```go -type GatewaySpec struct { - // BackendTLS configures TLS settings for when this Gateway is connecting to - // backends with TLS. - BackendTLS GatewayBackendTLS `json:"backendTLS,omitempty"'` +// TLSConfig describes TLS configuration that can apply to multiple Listeners +// within this Gateway. +type TLSConfig struct { + ... + // GatewayBackendTLS describes TLS configuration for gateway when connecting + // to backends. + // Support: Core + // + // +optional + // + BackendValidation *GatewayBackendTLS `json:"backendValidation,omitempty"` } type GatewayBackendTLS struct { // ClientCertificateRef is a reference to an object that contains a Client diff --git a/geps/gep-3779/index.md b/geps/gep-3779/index.md new file mode 100644 index 0000000000..49464b16d6 --- /dev/null +++ b/geps/gep-3779/index.md @@ -0,0 +1,266 @@ +# GEP-3779: Identity Based Authz for East-West Traffic + +* Issue: [#3779](https://github.com/kubernetes-sigs/gateway-api/issues/3779) +* Status: Provisional + +(See [status definitions](../overview.md#gep-states).) + + +## TLDR + +Provide a method for configuring Gateway API Mesh implementations to enforce east-west identity-based Authorization controls. At the time of writing this we leave Authentication for specific implementation and outside of this proposal scope. + + +## Goals + +(Using the [Gateway API Personas](../../concepts/roles-and-personas.md)) + +* A way for Ana the Application Developer to configure a Gateway API for Mesh implementation to enforce authorization policy that **allows** or **denies** identity or multiple identities to talk with some set (could be namespace or more granualr) of the workloads she controls. + +* A way for both Ana and Chihiro to restrict the scope of the policies they deploy to specific ports. + +## TBD Goals + +* A way for Chihiro, the Cluster Admin, to configure a Gateway API for Mesh implementation to enforce non-overridable cluster-wide, authorization policies that **allows** or **denies** identity or multiple identities to talk with some set of the workloads in the cluster. + +* A way for Chihiro, the Cluster Admin, to configure a Gateway API for Mesh implementation to enforce default, overridable, cluster-wide, authorization policies that **allows** or **denies** identity or multiple identities to talk with some set of the workloads in the cluster. + +## Non-Goals + +* Support identity based authorization for north-south traffic or define the composition with this API. + +## Deferred Goals + +* (Potentially) Support enforcement on attributes beyond identities and ports. + + +## Introduction + +Authorization is positioned as one of core mesh values. Every mesh supports some kind of east/west authorization between the workloads it controls. + +Kubernetes core provides NetworkPolicies as one way to do it. Network Policies however falls short in many ways including: + +* Network policies leverage labels as identities. + * Labels are mutable at runtime. This opens a path for escalating privileges + * Most implementations of network policies translate labels to IPs, this involves an eventual consistency nature which can and has lea to over permissiveness in the past. + +* Scale. Network Policies are enforced using IPs (different selectors in the APIs get translated to IPs). This does not scale well with large clusters or beyond a single cluster + +An identity-based authorization API is essential because it provides a structured way to control authorization between identities within the cluster. + + +### State of the World + + +| Aspect | Istio | Linkerd | Cilium | +| ----- | ----- | ----- | ----- | +| **Policy CRDs** | `AuthorizationPolicy` (APIs `security.istio.io/v1`) | `AuthorizationPolicy` (CRD `policy.linkerd.io/v1alpha1`), plus supporting CRDs (`Server`, `HTTPRoute`, `MeshTLSAuthentication`) | `CiliumNetworkPolicy` and `CiliumClusterwideNetworkPolicy` (superset of K8s NetworkPolicy) | +| **Identity model** | Identities derived from mTLS peer certificates (bound to SA):
  • SPIFFE-like principal `/ns//sa/`.
  • ServiceAccount name
  • Namespaces

identity within JWT derived from `request.auth.principal`

IPBlocks and x-forwarded-for ipBlocks | Identities derived from mTLS peer certificates (bound to SA trust domain `identity.linkerd.cluster.local`. Policies reference service accounts or explicit mesh identities (e.g. `webapp.identity.linkerd.cluster.local`).

Policies use `requiredAuthenticationRefs` to reference the entities who get authorization. This is a list of targetRefs and it can include:
  • ServiceAccounts
  • `MeshTLSAuthentication` - which represents a set of mesh identities either with a mesh identities strings or reference to serviceAccounts
  • `NetworkAuthentication` - represents sets of IPs or subnets.
|Cilium service mesh can leverage SPIFFE identities in certs that are used for handshake. These SPIFFEE identities are mapped to CiliumIdentities. You can read more about cilium identities in [CiliumIdentity](#CiliumIdentity).

Policies target abstractions like service accounts in the form of labels, pod labels, namespace label, node selectors, CIDR blocks and Cilium predefined [entities](https://docs.cilium.io/en/stable/security/policy/language/#entities-based). All policy targeting is coalesced by Cilium into one or more Cilium Identities for translation into the BPF datapath| +| **Enforcement** | For Istio with sidecars - a proxy on each pod. For ambient, ztunnel node agent enforces mTLS based L4 authorization, L7 authorization is being enforced in waypoints if any.

Istio supports ALLOW, DENY, CUSTOM (often used for external authorization), and AUDIT. DENY policies in istio's context are used to enforce higher priority deny policies. The allow semantics is that whatever is not allowed explicitly (and assuming there is any policy for the same match) is implicitly denied | Linkerd data-plane proxy (injected into each pod). The proxy enforces policies via mTLS identity checks.

Linkerd supports AUDIT and ALLOW. There is not DENY policies, whats not allowed (and assuming there is any policy for the same match) is implicitly denied. | For L3/4 Ingress Rules, CiliumNetworkPolicy enforcement - an eBPF-based datapath in the Linux kernel on the destination node. If L7 http rules are specified, the packet is redirected for a node-local envoy for further enforcement.

Cilium supports ALLOW and DENY semantics - all policies generate audit logs.

Cilium service mesh also offers a kind of AuthN where a Cilium agent on the src node validates a workloads SPIFFE identity by talking to another agent on the destination node, performing the initial TLS handshake to do authentication.| +| **Request Match criteria** | Policies can target a group of pods using label selector, a Gateway/Service (this means targeting a waypoint proxy) or a GatewayClass - meaning all the gateways created from this class. Policies without a label selector in a namespace implies the whole namespace is targeted.

Fine-grained L7 and L4 matching: HTTP/gRPC methods, paths, headers, ports, SNI, etc.Policies use logical OR over rules.

All match criterias are inline in the policy. See https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-To and https://istio.io/latest/docs/reference/config/security/authorization-policy/#Rule-when | Policies can target:
  • A `Server` which describes a set of pods (using fancy label match expressions), and a single port on those pods.
  • A user can optionally restrict the authorization to a smaller subset of the traffic by targeting an HTTPRoute. (TODO: any plans to support sectionNames?)
  • A namespace - this indicates that the policy applies to all traffic to all Servers and HTTPRoutes defined in the namespace.
Note: We leave `ServerAuthorization` outside the scope as it planned to be deprecated (per linkerd website) | Policies can target groups of pods using label selector (`endpointSelector`), or by node-labels (`nodeSelector`). Cilium supports L7 via built-in HTTP parsing: rules can match HTTP methods, paths, etc. For example, a CiliumNetworkPolicy can allow only specific HTTP methods/paths on a port. | +| **Default policies and admin policies** | If **no** ALLOW policy matches, traffic is **allowed** by default. You can deploy an overridable - default deny by default by deploying an **allow-nothing** policy in either the namespace or istio-system

AuthorizationPolicies in the `istio-system` namespace apply to the whole mesh and take precedence. These are not overridable by namespace-level policies. | Default inbound policy can be set at install time using `proxy.defaultInboundPolicy`. Supported values are:
  • `all-unauthenticated:` allow all traffic. This is the default.
  • `all-authenticated:` allow traffic from meshed clients in the same or from a different cluster (with multi-cluster).
  • `cluster-authenticated:` allow traffic from meshed clients in the same cluster.
  • `cluster-unauthenticated:` allow traffic from both meshed and non-meshed clients in the same cluster.
  • `deny:` all traffic are denied.
  • `audit:` Same as all-unauthenticated but requests get flagged in logs and metrics.

Users can override the default policies for namespaces/pods or by setting the [config.linkerd.io/default-inbound-policy](http://config.linkerd.io/default-inbound-policy) annotation There is no support for admin, non overridable policies. | Follows Kubernetes NetworkPolicy semantics by default: if no `CiliumNetworkPolicy` allows the traffic, it is allowed (no implicit deny). Once at least one `CiliumNetworkPolicy` or `CiliumClusterwideNetworkPolicy` allows some traffic, all other traffic is implicitly denied. +

Operators must apply explicit deny rules or “default-deny” policies to block traffic in the absence of allow rules.

`CiliumClusterwideNetworkPolicy` exists for whole-cluster enforcement.)| + + +Every mesh vendor has their own API of such authorization. Below we describe brief UX for different implementations: + +#### Istio +For the full spec and sematics of Istio AuthorizationPolicy: [Istio authorization policy docs](https://istio.io/latest/docs/reference/config/security/authorization-policy/) + +Istio's AuthorizationPolicy can enforce access control by specifying allowed istio-formatted identities using the `source.principals` field, which matches authenticated service account identities via mTLS. You can also use other source constructs which are described in the table above and in https://istio.io/latest/docs/reference/config/security/authorization-policy/#Source. + +``` +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + selector: + matchLabels: + app: httpbin # The policy applies to pods with this label + action: ALLOW + rules: + - from: + - source: + principals: ["cluster.local/ns/default/sa/sleep"] +``` + +OR targeting a gateway for example. + +``` +apiVersion: security.istio.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + targetRefs: + - name: waypoint + kind: Gateway # note: supported target Refs are Gateway, GatewayClass, Service, and ServiceEntry + group: gateway.networking.k8s.io + action: ALLOW + rules: + - from: + - source: + principals: ["cluster.local/ns/default/sa/sleep"] +``` +#### Linkerd + +For the full spec and sematics of Linkerd AuthorizationPolicy: [Linkerd authorization policy docs](https://linkerd.io/2-edge/reference/authorization-policy/) + +In Linkerd, identity-based authorization is enforced using AuthorizationPolicy and MeshTLSAuthentication, where MeshTLSAuthentication specifies allowed ServiceAccounts or mTLS identities (e.g., sleep.default.serviceaccount.identity.linkerd.cluster.local), ensuring that only authenticated workloads can access a resource. + +Linkerd Policy can by applied to two different targets. + +##### Pod Labels with Server Resource + +``` +apiVersion: policy.linkerd.io/v1beta1 +kind: Server +metadata: + namespace: default + name: httpbin-server +spec: + podSelector: + matchLabels: + app: httpbin + port: 8080 + proxyProtocol: HTTP/2 + +---- +apiVersion: policy.linkerd.io/v1beta1 +kind: MeshTLSAuthentication +metadata: + name: sleep-authn + namespace: default +spec: + identities: + - sleep.default.serviceaccount.identity.linkerd.cluster.local +---- + +apiVersion: policy.linkerd.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep + namespace: default +spec: + targetRef: + group: policy.linkerd.io + kind: Server + name: httpbin-server + requiredAuthenticationRefs: + - name: sleep-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io/v1beta1 + +--- +``` + +##### HTTPRoutes + +``` +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: httpbin-route + namespace: default +spec: + parentRefs: + - name: httpbin + kind: Service + rules: + - matches: + - path: + type: PathPrefix + value: / + backendRefs: + - name: httpbin + port: 80 + +----- + +apiVersion: policy.linkerd.io/v1beta1 +kind: MeshTLSAuthentication +metadata: + name: sleep-authn + namespace: default +spec: + identities: + - sleep.default.serviceaccount.identity.linkerd.cluster.local +----- + +apiVersion: policy.linkerd.io/v1beta1 +kind: AuthorizationPolicy +metadata: + name: allow-sleep-http + namespace: default +spec: + targetRef: + group: gateway.networking.k8s.io + kind: HTTPRoute + name: httpbin-route + requiredAuthenticationRefs: + - name: sleep-authn + kind: MeshTLSAuthentication + group: policy.linkerd.io/v1beta1 +--- +``` + + +#### Cilium + +For the full spec and sematics of CiliumNetworkPolicy: https://docs.cilium.io/en/stable/network/kubernetes/policy/#ciliumnetworkpolicy & https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#cilium-s-ingress-config-and-ciliumnetworkpolicy + +Beyond what's explained in the table above, Cilium also automatically labels each pod with its associated service account using the label io.cilium.k8s.policy.serviceaccount. This label can be used in CiliumNetworkPolicy to enforce identity-based access controls using [ServiceAccounts Based Identities](https://docs.cilium.io/en/latest/security/policy/kubernetes/#serviceaccounts) within CiliumNetworkPolicy; + +See below for example. + +``` +apiVersion: "cilium.io/v2" +kind: CiliumNetworkPolicy +metadata: + name: "k8s-svc-account-policy" +spec: + endpointSelector: + matchLabels: + io.cilium.k8s.policy.serviceaccount: httpbin + ingress: + - fromEndpoints: + - matchLabels: + io.cilium.k8s.policy.serviceaccount: sleep + toPorts: + - ports: + - port: '80' + protocol: TCP + rules: + http: + - method: GET + path: "/" +``` + + +##### CiliumIdentity +Cilium has the concept of CiliumIdentity. Pods are assigned identities derived from their Kubernetes labels (namespace, app labels, etc.). Cilium’s policy matches based on these label-derived identities. The CiliumIdentity implementation maps an integer to a group of IP addresses (the pod IPs associated with a group of pods). This “integer” and its mapping to pod IP addresses represents the core identity primitive in Cilium. + +More on https://docs.cilium.io/en/stable/internals/security-identities/ & https://docs.cilium.io/en/stable/security/network/identity/ + + + +## API + + + +## Conformance Details + + +#### Feature Names + + +### Conformance tests + + +## Alternatives + + +## References \ No newline at end of file diff --git a/geps/gep-3779/metadata.yaml b/geps/gep-3779/metadata.yaml new file mode 100644 index 0000000000..3c5b9af7d2 --- /dev/null +++ b/geps/gep-3779/metadata.yaml @@ -0,0 +1,19 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3779 +name: Identity Based Authz for east-west traffic +status: Provisional +# Any authors who contribute to the GEP in any way should be listed here using +# their GitHub handle. +authors: + - liorlieberman + - aryan16 +# references is a list of hyperlinks to relevant external references. +# It's intended to be used for storing GitHub discussions, Google docs, etc. +references: {} +# featureNames is a list of the feature names introduced by the GEP, if there +# are any. This will allow us to track which feature was introduced by which GEP. +featureNames: {} +# changelog is a list of hyperlinks to PRs that make changes to the GEP, in +# ascending date order. +changelog: {} diff --git a/geps/gep-3792/index.md b/geps/gep-3792/index.md new file mode 100644 index 0000000000..2441074466 --- /dev/null +++ b/geps/gep-3792/index.md @@ -0,0 +1,264 @@ +# GEP-3792: Out-of-Cluster Gateways + +* Issue: [#3792](https://github.com/kubernetes-sigs/gateway-api/issues/3792) +* Status: Provisional + +(See [status definitions](../overview.md#gep-states).) + +## User Story + +**[Chihiro] and [Ian] want a way for out-of-cluster Gateways to be able to +usefully participate in a GAMMA-compliant in-cluster service mesh.** + +Historically, API gateways and ingress controllers have often been implemented +using a Service of type LoadBalancer fronting a Kubernetes pod running a +proxy. This is simple to reason about, easy to manage for sidecar meshes, and +will presumably be an important implementation mechanism for the foreseeable +future. Some cloud providers, though, are moving the proxy outside of the +cluster, for various reasons which are out of the scope of this GEP. Chihiro +and Ian want to be able to use these out-of-cluster proxies effectively and +safely, though they recognize that this may require additional configuration. + +[Chihiro]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro +[Ian]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian + +### Nomenclature and Background + +In this GEP: + +1. We will use _out-of-cluster Gateway_ (OCG) to refer to a conformant + implementation of Gateway API's `GATEWAY` profile that's running outside of + the cluster. This would most commonly be a managed implementation from a + cloud provider, but of course there are many other possibilities -- and in + fact it's worth noting that anything we define here to support OCGs could + also be used by workloads that run in-cluster but which, for whatever + reason, can't be brought into the mesh in the mesh's usual way. + +2. We'll also distinguish between _mTLS meshes_, which rely on standard mTLS + for secure communication (authentication, encryption, and integrity + checking) between workloads, and _non-mTLS meshes_, which do anything else. + We'll focus on mTLS meshes in this GEP; this isn't because of a desire to + exclude non-mTLS meshes, but because we'll have enough trouble just + wrangling the mTLS meshes! Supporting non-mTLS meshes will be a separate + GEP. + + **Note:** It's important to separate mTLS and HTTPS here. Saying that the + mTLS meshes use mTLS for secure communication does not preclude them from + using custom protocols on top of mTLS, and certainly does not mean that + they must use only HTTPS. + +3. _Authentication_ is the act of verifying the identity of some _principal_; + what the principal actually is depends on context. For this GEP we will + primarily be concerned with _workload authentication_, in which the + principal is a workload, as opposed to _user authentication_, in which the + principal is the human on whose behalf a piece of technology is acting. We + expect that the OCG will handle user auth, but of course meshed workloads + can't trust what the OCG says about the user unless the OCG successfully + authenticates itself as a workload. + + **Note:** A single workload will have only one identity, but in practice we + often see a single identity being used for multiple workloads (both because + multiple replicas of a single workload need to share the same identity, and + because some low-security workloads may be grouped together under a single + identity). + +4. Finally, we'll distinguish between _inbound_ and _outbound_ behaviors. + + Inbound behaviors are those that are applied to a request _arriving_ at a + given workload. Authorization and rate limiting are canonical examples + of inbound behaviors. + + Outbound behaviors are those that are applied to a request _leaving_ a + given workload. Load balancing, retries, and circuit breakers are canonical + examples of outbound behaviors. + +## Goals + +- Allow Chihiro and Ian to configure an OCG and a mesh such that the OCG can + usefully participate in the mesh, including: + + - The OCG must be able to securely communicate with meshed workloads in + the cluster, where "securely communicate" includes encryption, + authentication, and integrity checking. + + - The OCG must have a proper identity within the mesh, so that the mesh + can apply authorization policy to requests from the OCG. + + - Whatever credentials the OCG and the mesh use to authenticate each other + must be able to be properly maintained over time (for example, if they + use mTLS, certificates will need rotation over time). + + - The OCG must be able to distinguish meshed workloads from non-meshed + workloads, so that it can communicate appropriately with each. + +- Allow Ana to develop and operate meshed applications without needing to know + whether the Gateway she's using is an OCG or an in-cluster Gateway. + +- Define a basic set of requirements for OCGs and meshes that want to + interoperate with each other (for example, the OCG and the mesh will likely + need to agree on how workload authentication principals are represented). + +- Define how responsibility is shared between the OCG and the mesh for + outbound behaviors applied to requests leaving the OCG. (Note that "the OCG + has complete responsibility and authority over outbound behaviors for + requests leaving the OCG" is very much a valid definition.) + +## Non-Goals + +- Support multicluster operations. It may be the case that functional + multicluster (with, e.g., a single OCG fronting multiple clusters) ends up + falling out of this GEP, but it is not a goal. + +- Support meshes interoperating with each other. It's possible that this GEP + will lay a lot of groundwork in that direction, but it is not a goal. + +- Support non-mTLS meshes in Gateway API 1.4. We'll make every effort not to + rule out non-mTLS meshes, but since starting with the mTLS meshes should + tackle a large chunk of the industry with a single solution, that will be + the initial focus. + +- Solve the problem of extending a mesh to cover non-Kubernetes workloads (AKA + _mesh expansion_). In many ways, mesh expansion is adjacent to the OCG + situation, but the where the OCG is aware of the cluster and mesh, mesh + expansion deals with a non-Kubernetes workload that is largely not aware of + either. + +- Solve the problem of how to support an OCG doing mTLS directly to a + _non_-meshed workload (AKA the _backend TLS problem_). Backend TLS to + non-meshed workloads is also adjacent to the OCG situation, but its + configuration has different needs: backends terminating TLS on their own are + likely to need per-workload configuration of certificates, cipher suites, + etc., where the mesh as a whole should share a single configuration. + +- Prevent the OCG API from being used by an in-cluster workload. We're not + going to make in-cluster workloads a primary use case for this GEP, but + neither are we disallowing them. + +## Overview + +Making an OCG work with an in-cluster mesh at the most basic level doesn't +really require any special effort. As long as the OCG has IP connectivity to +pods in the cluster, and the mesh is configured with permissive security, the +OCG can simply forward traffic from clients directly to meshed pods, and +things will "function" in that requests from clients, through the OCG, can be +handled by workloads in the cluster. + +Of course, this sort of non-integration has obvious and terrible security +implications, since the traffic between the OCG and the application pods in +the cluster will be cleartext in the scenario above. The lack of encryption is +awful in its own right, but the fact that any mTLS mesh uses mTLS for +_authentication_ also means that the mesh loses any way to enforce +authorization policy around the OCG. Combined, these items amount to a major +problem. + +An additional concern is that the OCG needs to be able to implement features +(e.g. sticky sessions) which require it to speak directly to endpoint IPs, +which can limit what the mesh will be able to do. This is likely a more minor +concern since a conformant OCG should itself be able to provide advanced +functionality; however, at minimum it can create some friction in +configuration. + +### The Problems + +To allow the OCG to _usefully_ participate in the mesh, we need to solve at +least four significant problems. Thankfully, these are mostly problems for +Chihiro -- if we do our jobs correctly, Ana will never need to know. + +#### 1. The Trust Problem + +The _trust problem_ is fairly straightforward to articulate: the OCG and the +mesh both need access to whatever information will allow each of them to trust +the other. + +In the case of mTLS meshes, we are helped by the fact that basically every OCG +candidate already speaks mTLS, so the trust problem becomes "only" one of +setting things up for the OCG and the mesh to each include the other's CA +certificate in their trust bundle. (They may be using the same CA certificate, +but we shouldn't rely on that.) + +In the case of non-mTLS meshes, the trust problem is more complex; this is the +major reason that this GEP is focused on mTLS meshes. + +#### 2. The Protocol Problem + +The _protocol problem_ is that the data-plane elements of the mesh may assume +that they'll always be talking only to other mesh data-plane elements, which +the OCG will not be. If the mesh data-plane elements use a specific protocol, +then either the OCG will need to speak that protocol, or the mesh will need to +relax its requirements (perhaps on a separate port?) to accept requests +directly from the OCG. + +For example, Linkerd and Istio Legacy both use standard mTLS for +proxy-to-proxy communication -- however, both also use ALPN to negotiate +custom (and distinct!) "application" protocols during mTLS negotiation, and +depending on the negotiated protocol, both can require the sending proxy to +send additional information after mTLS is established, before any client data +is sent. (For example, Linkerd requires the originating proxy to send +transport metadata right after the TLS handshake, and it will reject a +connection which doesn't do that correctly.) + +#### 3. The Discovery Problem + +When using a mesh, not every workload in the cluster is required to be meshed +(for example, it's fairly common to have some namespaces meshed and other +namespaces not meshed, especially during migrations). The _discovery problem_ +here is that the OCG needs to be know which workloads are meshed, so that it +can choose appropriate communication methods for them. + +#### 4. The Outbound Behavior Problem + +The OCG will need to speak directly to endpoints in the cluster, as described +above. This will prevent most meshes from being able to tell which service was +originally requested, which makes it impossible for the mesh to apply outbound +behaviors. This is the _outbound behavior problem_: it implies that either the +OCG must be responsible for outbound behaviors for requests leaving the OCG +for a meshed workload, or that the OCG must supply the mesh with enough +information about the targeted service to allow the mesh to apply those +outbound behaviors (if that's even possible: sidecar meshes may very well +simply not be able to do this.) + +This is listed last because it shouldn't be a functional problem to simply +declare the OCG solely responsible for outbound behaviors for requests leaving +the OCG. It is a UX problem: if a given workload needs to be used by both the +OCG or other meshed workloads, you'll need to either provide two Routes with +the same configuration, or you'll need to provide a single Route with multiple +`parentRef`s. + +## API + +Most of the API work for this GEP is TBD at this point, but there are two +important points to note: + +First, Gateway API has never defined a Mesh resource because, to date, it's +never been clear what would go into it. This may be the first configuration +item that causes us to need a Mesh resource. + +Second, since the API should affect only Gateway API resources, it is not a +good candidate for policy attachment. It is likely to be much more reasonable +to simply provide whatever extra configuration we need inline in the Gateway +or Mesh resources. + +## Graduation Criteria + +In addition to the [general graduation +criteria](../concepts/versioning.md#graduation-criteria), this GEP must also +guarantee that **all four** of the problems listed above need resolutions, and +must have implementation from at least two different Gateways and two +different meshes. + +### Gateway for Ingress (North/South) + +### Gateway For Mesh (East/West) + +## Conformance Details + +#### Feature Names + +This GEP will use the feature name `MeshOffClusterGateway`, under the +assumption that we will indeed need a Mesh resource. + +### Conformance tests + +## Alternatives + +## References diff --git a/geps/gep-3792/metadata.yaml b/geps/gep-3792/metadata.yaml new file mode 100644 index 0000000000..4478b32b1e --- /dev/null +++ b/geps/gep-3792/metadata.yaml @@ -0,0 +1,33 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3792 +name: Out-of-Cluster Gateways +status: Provisional +# Any authors who contribute to the GEP in any way should be listed here using +# their GitHub handle. +authors: + - kflynn +relationships: + # obsoletes indicates that a GEP makes the linked GEP obsolete, and completely + # replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field + # set back to this GEP, and MUST be moved to Declined. + obsoletes: {} + obsoletedBy: {} + # extends indicates that a GEP extends the linked GEP, adding more detail + # or additional implementation. The extended GEP MUST have its extendedBy + # field set back to this GEP. + extends: {} + extendedBy: {} + # seeAlso indicates other GEPs that are relevant in some way without being + # covered by an existing relationship. + seeAlso: {} +# references is a list of hyperlinks to relevant external references. +# It's intended to be used for storing GitHub discussions, Google docs, etc. +references: {} +# featureNames is a list of the feature names introduced by the GEP, if there +# are any. This will allow us to track which feature was introduced by which GEP. +# This is the value added to supportedFeatures and the conformance tests, in string form. +featureNames: {} +# changelog is a list of hyperlinks to PRs that make changes to the GEP, in +# ascending date order. +changelog: {} diff --git a/geps/gep-3793/index.md b/geps/gep-3793/index.md new file mode 100644 index 0000000000..f0cad9a72d --- /dev/null +++ b/geps/gep-3793/index.md @@ -0,0 +1,656 @@ +# GEP-3793: Default Gateways + +* Issue: [#3793](https://github.com/kubernetes-sigs/gateway-api/issues/3793) +* Status: Implementable + +(See [status definitions](../overview.md#gep-states).) + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in BCP 14 ([RFC8174]) when, and +only when, they appear in all capitals, as shown here. + +[RFC8174]: https://www.rfc-editor.org/rfc/rfc8174 + +## User Story + +**[Ana] wants a concept of a default Gateway.** + +Gateway API currently requires every north/south Route object to explicitly +specify its parent Gateway. This is helpful in that it removes ambiguity, but +it's less helpful in that [Ana] is stuck constantly explicitly configuring a +thing that she probably doesn't care much about: in a great many cases, Ana +just wants to create a Route that "works from the outside world" and she +really doesn't care what the Gateway is called. + +Therefore, Ana would like a way to be able to rely on a default Gateway that +she doesn't have to explicitly name, and can simply trust to exist. Ana +recognizes that this will involve **giving up** a certain amount of control +over how requests reach her workloads. She's OK with that, and she understands +that it means that relying on a default Gateway is not always appropriate: for +example, if she needs to be sure that her Route is protected by specific +authorization policies, she should confer with Chihiro to make sure that she +explicitly specifies a Gateway that meets those requirements. + +In the future, it may also be important to distinguish different kinds of +default Gateways -- for example, a default ingress Gateway or a default egress +Gateway. This GEP deliberately defines only a single _scope_ of default +Gateway (`All`) but recognizes the need to at least consider the possibility +of multiple scopes in the future. + +## Definitions + +- **defaulted Route**: a Route that Ana creates without explicitly specifying + a Gateway + +- **default Gateway**: a Gateway that Chihiro has configured to accept + defaulted Routes + +- **default Gateway scope**: the scope within which a default Gateway is + applicable + +## Goals + +- Give Ana a way to use Gateway API without having to explicitly specify a + Gateway for every Route, ideally without mutating Routes. (In other words, + give Ana an easy way to create a defaulted Route.) + +- Give Ana an easy way to define the scope for a defaulted Route. + +- Give Ana an easy way to determine which default Gateways are present in the + cluster, if any, and which of her Routes are currently bound to these + Gateways. + +- Continue supporting multiple Gateways in a cluster, while allowing zero or + more of them to be configured as default Gateways. + +- Allow [Chihiro] to retain control over which Gateways accept defaulted + Routes, so that they can ensure that all Gateways meet their requirements + for security, performance, and other operational concerns. + +- Allow Chihiro to choose not to provide any default Gateways at all. + +- Allow Chihiro to define the scope of a default Gateway. + +- Allow Chihiro to rename, reconfigure, or replace any default Gateway at + runtime. + + - While Kubernetes does not allow renaming a resource, Chihiro MUST be able + to duplicate a default Gateway under a new name, then remove the old + default Gateway, without disrupting routing. Ana MUST NOT need to go + update all her Routes just because Chihiro is being indecisive about + naming. + + - Determine how (or if) to signal changes in functionality if a default + Gateway's implementation is changed. For example, suppose that Chihiro + switches a default Gateway from an implementation that supports the + `HTTPRoutePhaseOfTheMoon` filter to an implementation that does not. + + (Note that this problem is not unique to default Gateways; it affects + explicitly-named Gateways as well.) + +- Allow Chihiro to control which Routes may bind to a default Gateway, and to + enumerate which Routes are currently bound to a default Gateway. + +- Support easy interoperation with common CI/CD and GitOps workflows. + +- Define how (or if) listener and Gateway merging applies to a default + Gateway. + +## Non-Goals + +- Allow Ana to override Chihiro's choices for default Gateways for a given + Route without explicitly specifying the Gateway: a Route can either be + defaulted, or it MUST specify a Gateway explicitly. + +- Require that every possible routing use case be met by a Route using a + default Gateway. There will be a great many situations that require Ana to + explicitly choose a Gateway; the existence of a default Gateway is not a + guarantee that it will be correct for any given use case. + +- Allow for "default Gateway" functionality without a Gateway controller + installed. Just as with any other Gateway, a default Gateway requires an + implementation to be installed. + +## Overview + +Gateway API currently requires every north/south Route object to explicitly +specify its parent Gateway. This is a wonderful example of a fundamental +tension in Gateway API: + +- [Chihiro] and [Ian] value _explicit definition_ of everything, because it + makes it easier for them to reason about the system and ensure that it meets + the standards they set for it. + +- [Ana], on the other hand, values _simplicity_ and _ease of use_, because + she just wants to get her job done without having to think about every little + detail. + +At present, Gateway API is heavily weighted towards the point of view of +Chihiro and Ian. This causes friction for Ana: for example, she can't write +examples or documentation for her colleagues (or her counterparts at other +companies) without telling them that they'll need to be sure to edit the +Gateway name in every Route. Nor can she write a Helm chart that includes a +Route without requiring the person using the chart to know the specific name +for the Gateway to use. + +The root cause of this friction is a difference in perspective: to Chihiro and +Ian, the Gateway is a first-class thing that they think about regularly, while +to Ana, it's an implementation detail that she doesn't care about. Neither +point of view is wrong, but they are in tension with each other. + +In practice, the trick is to find a usable balance between explicitness and +simplicity, while managing ambiguity. A good example is the humble URL, where +the port number is not always explicit, but it _is_ always unambiguous. +Requiring everyone to type `:80` or `:443` at the end of the host portion of +every URL wouldn't actually help anyone, though allowing it to be specified +explicitly when needed definitely does help people. + +### Prior Art + +- **Ingress** + + The Ingress resource is the most obvious example of prior art: it permitted + specifying a default IngressClass, allowing users to create Ingress + resources that didn't specify the IngressClass explicitly. As with a great + many things in the Ingress API, this caused problems: + + 1. Ingress never defined how conflicts between multiple Ingress resources + should be handled. Many (most?) implementations merged conflicting + resources, which is arguably the worst possible choice. + + 2. Ingress also never defined a way to allow users to see which IngressClass + was being used by a given Ingress resource, which made it difficult for + users to understand what was going on if they were using the default + IngressClass. + + (Oddly enough, Ingress' general lack of attention to separation of concerns + wasn't really one of the problems here, since IngressClass was a separate + resource.) + +- **Emissary Mapping** + + Emissary-ingress turns this idea on its head: it assumes that app developers + will almost never care about which specific Emissary they're using, and will + instead only care about the hostnames and ports involved. + + In Emissary: + + - a Listener resource defines which ports and protocols are in play; + - a Host resource defines hostnames, TLS certificates, etc.; + - a Mapping resource is roughly analogous to a Route. + + The Listener resource has selectors to control which Hosts it will claim; + Mappings, though, are claimed by Hosts based on the hostname that the + Mapping specifies. In other words, Mappings are not bound to a Listener + explicitly, but rather are bound to a Listener implicitly based on the + hostname that the Mapping specifies. There is no way to _explicitly_ specify + which Listener a Mapping wants to be claimed by. + + This is obviously a very different model from Gateway API, shifting almost + all the work of controlling route binding away from the application + developer onto the cluster operator. + +- **Service** + + We could also consider a Service of `type: LoadBalancer` as a kind of prior + art: in many cases, Ana can directly create these Services and use them to + provide direct, completely unmediated access to a workload, without + worrying about the specifics of how her cluster provider implements them. + + Service's major disadvantages here are that it doesn't support Layer 7 + functionality, and that each Service of type `LoadBalancer` has direct + costs in many cases. In other words, Service allows Ana to rely on the + cluster provider to create the load balancer, while forcing Ana to shoulder + the burden of basically everything else. + +### Debugging and Visibility + +It's also critical to note that visibility is critical when debugging: if Ana +can't tell which Gateway is being used by a given Route, then her ability to +troubleshoot problems is _severely_ hampered. Of course, one of the major +strengths of Gateway API is that it _does_ provide visibility into what's +going on in the `status` stanzas of its resources: every Route already has a +`status` showing exactly which Gateways it is bound to. Making certain that +Ana has easy access to this information, and that it's clear enough for her to +understand, is clearly important for many more reasons than just default +Gateways. + +[Ana]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana +[Chihiro]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro +[Ian]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian + +## API + +The main challenge in the API design is to find a way to allow Ana to use +Routes without requiring her to specify the Gateway explicitly, while still +allowing Chihiro and Ian to retain control over Gateways and their +configurations. + +An additional concern is CD tools and GitOps workflows. In very broad terms, +these tools function by applying manifests from a Git repository to a +Kubernetes cluster, and then monitoring the cluster for changes. If a tool +like Argo CD or Flux detects a change to a resource in the cluster, it will +attempt to reconcile that change with the manifest in the Git repository -- +which means that changes to the `spec` of an HTTPRoute that are made by code +running in the cluster, rather than by a user with a Git commit, can +potentially trip up these tools. + +These tools generally ignore strict additions: if a field in `spec` is not +present in the manifest in Git, but is added by code running in the cluster, +the tools know to ignore it. So, for example, if `spec.parentRefs` is not +present at all in the manifest in Git, CD tools can probably tolerate having a +Gateway controller write a new `parentRefs` stanza to the resource. + +There has been (much!) [discussion] about whether the ideal API for this +feature will mutate the `parentRefs` of a Route using a default Gateway to +reflect the Gateway chosen, or whether it should not, relying instead on the +`status` stanza to carry this information. Ultimately, mutating the `spec` of +a Kubernetes resource introduces complexity which we should avoid if it's not +required. Since we can gracefully provide default-Gateway functionality +without mutating `parentRefs`, we will rely on `status` instead of mutating +`parentRefs`. + +[discussion]: https://github.com/kubernetes-sigs/gateway-api/pull/3852#discussion_r2140117567 + +### Gateway for Ingress (North/South) + +There are three main aspects to the API design for default Gateways: + +1. Giving Ana a way to indicate that a Route should be defaulted. + +2. Giving Chihiro a way to control which Gateways (if any) will accept + defaulted Routes. + +3. Give anyone with read access to Routes (Ana, Chihiro, or Ian) a way to + enumerate which Routes are bound to the default Gateways. + +We will describe each of these aspects in turn, laying out changes to Gateway +API behaviors and resources that are necessary to support them. **Any behavior +not explicitly discussed in this GEP is intended to remain unchanged;** the +GEP covers **all** intended changes to Gateway API behavior. + +#### 1. Creating a Defaulted Route + +Since Ana must be able to choose whether a Route is defaulted or not, marking +a Route as defaulted must be an active configuration step she takes, rather +than any kind of implicit behavior. To that end, the `CommonRouteSpec` +resource will gain a new field, `useDefaultGateway`, which defines the +_scope_ for the defaulted Route: + +```go +// GatewayDefaultScope defines the set of default scopes that a Gateway +// can claim. At present the only supported scope is "All". +type GatewayDefaultScope string + +const ( + // GatewayDefaultScopeAll indicates that a Gateway can claim absolutely + // any Route asking for a default Gateway. + GatewayDefaultScopeAll GatewayDefaultScope = "All" +) + +type CommonRouteSpec struct { + // ... other fields ... + useDefaultGateway GatewayDefaultScope `json:"useDefaultGateway,omitempty"` +} +``` + +For Ana to indicate that a Route should use a default Gateway, she MUST set +the Route's `spec.useDefaultGateway` to the desired scope: + +```yaml +... +spec: + useDefaultGateway: All +``` + +A defaulted Route MUST be accepted only by Gateways that have been configured +with a matching `spec.useDefaultGateway` scope. + +A Route MAY include explicit `parentRefs` in addition to setting +`spec.useDefaultGateway`. In this case, the Route will be a candidate for +being bound to default Gateways, but it will also be bound to its +explicitly-specified `parentRefs`. This allows Ana to create a single Route +that handles N/S traffic via the default Gateways and also handles E/W traffic +via a Service, for example. + +All other characteristics of a defaulted Route MUST behave the same as if all +default Gateways were explicitly specified in `parentRefs`. + +##### Examples + +**Simple N/S Route**: The following HTTPRoute would route _all_ HTTP traffic +arriving at any default Gateway to `my-service` on port 80: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: my-route +spec: + useDefaultGateway: All + rules: + - backendRefs: + - name: my-service + port: 80 +``` + +**N/S and E/W Route**: The following HTTPRoute would be bound to both any +default Gateways and to a Service named `face` in the `faces` namespace, +permitting a single Route to handle both N/S traffic (via the default Gateway) +and E/W traffic (via the Service): + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: ns-ew-route +spec: + useDefaultGateway: All + parentRefs: + - kind: Service + name: face + namespace: faces + rules: + - backendRefs: + - name: face + port: 80 +``` + +**Multiple Gateways**: A defaulted Route MAY both set `useDefaultGateway` and +name other Gateways in `parentRefs`, although this is not expected to be +common in practice: + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: multi-gateway-route +spec: + useDefaultGateway: All + parentRefs: + - kind: Gateway + name: my-gateway + namespace: default + rules: + - backendRefs: + - name: my-service + port: 80 +``` + +##### `status` for a Defaulted Route + +When a defaulted Route is claimed by a default Gateway, the Gateway MUST use +`status.parents` to announce that it has claimed the Route, for example: + +```yaml +status: + parents: + - name: my-default-gateway + namespace: default + controllerName: gateway.networking.k8s.io/some-gateway-controller + conditions: + - type: Accepted + status: "True" + lastTransitionTime: "2025-10-01T12:00:00Z" + message: "Route is bound to default Gateway" +``` + +##### Other Considerations + +A default Gateway MUST NOT modify the `parentRefs` of a defaulted Route to +indicate that the Route has been claimed by a default Gateway. This becomes +important if the set of default Gateways changes, or (in some situations) if +GitOps tools are in play. + +If there are no default Gateways in the cluster, `spec.useDefaultGateway` MUST +be treated as if it were set to `false` in all Routes, parallel to the +situation where a Route specifies a Gateway by name, but no Gateway of that +name exists in the cluster. + +#### 2. Controlling which Gateways accept Defaulted Routes + +Since Chihiro must be able to control which Gateways accept defaulted Routes, +configuring a Gateway to accept defaulted Routes must be an active +configuration step taken by Chihiro, rather than any kind of implicit +behavior. To that end, the Gateway resource will gain a new field, +`spec.defaultScope`: + +```go +type GatewaySpec struct { + // ... other fields ... + DefaultScope GatewayDefaultScope `json:"defaultScope,omitempty"` +} +``` + +Again, the only currently-defined scope is `All`. + +If `spec.defaultScope` is set, the Gateway MUST claim Routes that have set +`spec.useDefaultGateway` to a matching value (subject to the usual Gateway API +rules about which Routes may be bound to a Gateway), and it MUST update its +own `status` with a `condition` of type `DefaultGateway` and `status` true to +indicate that it is a default Gateway and what its scope is, for example: + +```yaml +status: + conditions: + - type: DefaultGateway + status: "True" + lastTransitionTime: "2025-10-01T12:00:00Z" + message: "Gateway has default scope All" +``` + +If `spec.defaultScope` is not present, the Gateway MUST NOT claim Routes that +do not name it specifically in `parentRefs`, and it MUST NOT set the +`DefaultGateway` condition in its `status`. + +##### Access to a Default Gateway + +The rules for which Routes may bind to a Gateway do not change for a default +Gateway. In particular, if a default Gateway should accept Routes from other +namespaces, then it MUST include the appropriate `AllowedRoutes` definition, +and without such an `AllowedRoutes`, a default Gateway MUST accept only Routes +from its own namespace. + +##### Behavior with No Default Gateway + +If no Gateway has `spec.defaultScope` set, then all Gateways MUST ignore +`spec.useDefaultGateway` in all Routes. A Route will be bound to only those Gateways that it specifically names in `parentRefs` entries. + +##### Deleting a Default Gateway + +Deleting a default Gateway MUST behave the same as deleting any other Gateway: +all Routes that were bound to that Gateway MUST be unbound, and the `Accepted` +conditions in the `status` of those Routes SHOULD be removed. + +##### Multiple Default Gateways + +Support for multiple default Gateways in a cluster was not one of the original +goals of this GEP. However, allowing Chihiro full control over which Gateways +accept defaulted Routes - including being able to change the set of default +Gateways at runtime, without requiring downtime - has always been a goal, and +this turns out to require support for multiple default Gateways. + +Kubernetes itself will not prevent setting `spec.defaultScope` on multiple +Gateways in a cluster, and it also doesn't support any atomic swap mechanisms. +If we want to enforce only a single default Gateway, the Gateway controllers +will have to implement that enforcement logic. There are three possible +options here. + +1. Don't bother with any enforcement logic. + + In this case, a Route that sets `spec.useDefaultGateway` would be bound to + _all_ Gateways that have `spec.defaultScope` set a matching scope. Since + Gateway API already allows a Route to be bound to multiple Gateways, and + the Route `status` is already designed for it, this should function + without difficulty. + +2. Treat multiple Gateways with `spec.defaultScope` set as if no Gateway has + `spec.defaultScope` set. + + If we assume that all Gateway controllers in a cluster can see all the + Gateways in the cluster, then detecting that multiple Gateways have + `spec.defaultScope` set is relatively straightforward. + + In this case, every Gateway with `spec.defaultScope` set would ignore it, + with the final effect being the same as if no Gateway had + `spec.defaultScope` set: all Gateways would ignore + `spec.useDefaultGateway` in all Routes, and each Gateway would only accept + Routes that explicitly named it in `parentRefs`. + + Each Gateway with `spec.defaultScope` set would also update its `status` + with a `condition` of type `DefaultGateway` and `status` false to indicate + that it is not the default Gateway, for example: + + ```yaml + status: + conditions: + - type: DefaultGateway + status: "False" + lastTransitionTime: "2025-10-01T12:00:00Z" + message: "Multiple Gateways are marked as default" + ``` + +3. Perform conflict resolution as with Routes. + + In this case, the oldest Gateway with `spec.defaultScope` set would be + considered the only default Gateway. That oldest Gateway would be the only + one that honors `spec.useDefaultGateway` in Routes, and all other Gateways + with `spec.defaultScope` set would ignore `spec.useDefaultGateway` in + every Route. + + The oldest default Gateway would update its `status` to reflect that it + the default Gateway; all other Gateways with `spec.defaultScope` set to + `true` will update their `status` as in Option 2. + +Unfortunately, option 2 will almost certainly cause downtime in any case where +Chihiro wants to change the implementation behind a default Gateway: + +- If Chihiro deletes the old Gateway resource before creating the new one, + then all routes using that Gateway will be unbound during the time between + deletion and recreation, resulting in errors for any requests using those + Routes. + +- If Chihiro creates the new Gateway resource before deleting the old one, + then all Routes using the old default Gateway will still be unbound during + the time that both Gateways exist. + +Option 3 gives Chihiro a way to change the default Gateway without downtime: +when they create the new default Gateway resource, it will not take effect +until the old default Gateway resource is deleted. However, it doesn't give +Chihiro any way to test the Routes through the new default Gateway before +deleting the old Gateway. + +Reluctantly, we must therefore conclude that option 1 is the only viable +choice. Therefore: Gateways MUST NOT attempt to enforce a single default +Gateway, and MUST allow Routes that set `spec.useDefaultGateway` to bind to +_all_ Gateways that have `spec.defaultScope` set a matching scope. This is +simplest to implement, it permits zero-downtime changes to the default +Gateway, it allows for testing of the new default Gateway before the old one +is deleted, and it doesn't cause trouble with respect to security posture +(since Ana already accepts that she's giving up some control over how her +Routes are handled when she's using default Gateways). + +##### Changes in Functionality + +If Chihiro changes a default Gateway to a different implementation that does +not support all the functionality of the previous default Gateway, then the +Routes that were bound to the previous default Gateway will no longer function +as expected. This is not a new problem: it already exists when Ana changes a +Route's `parentRefs`, or when Chihiro changes the implementation of a Gateway +that is explicitly specified in a Route's `parentRefs`. + +At present, we do not propose any solution to this problem, other than to note +that `gwctl` or similar tools SHOULD be able to show Ana not just the Gateways +to which a Route is bound, but also the features supported by those Gateways. +This will at least give Ana some visibility into whether she's trying to use +Gateways that don't support a feature that she needs. This is a definitely an +area for future work, and it is complicated by the fact that Ana may not have +access to read Gateway resources in the cluster at all. + +##### Listeners, ListenerSets, and Merging + +Setting `spec.defaultScope` on a Gateway affects which Routes will bind to the +Gateway, not where the Gateway listens for traffic. As such, setting +`spec.defaultScope` MUST NOT alter a Gateway's behavior with respect to +Listeners, ListenerSets, or merging. + +In the future, we may want to consider allowing default ListenerSets rather +than only default Gateways, but that is not in scope for this GEP. Even if it +is considered later, the guiding principle SHOULD be that `spec.defaultScope` +SHOULD NOT affect where a Gateway listens for traffic or whether it can be +merged with other Gateways. + +#### 4. Enumerating Routes Bound to Default Gateways + +To enumerate Routes bound to the default Gateways, any of Ana, Chihiro, or Ian +can look for Routes that set `spec.useDefaultGateway` to `true`, and then +check the `status.parents` of those Routes to see if the Route has been +claimed. Since this will also show _which_ Gateways have claimed a given +defaulted Route, it neatly solves the problem of allowing Ana to determine +which default Gateway(s) her Route is using even if she doesn't have RBAC to +query Gateway resources directly. + +While this is possible with `kubectl get -o yaml`, it's not exactly a friendly +user experience, so adding this functionality to a tool like `gwctl` would be +a dramatic improvement. In fact, looking at the `status` of a Route is very +much something that we should expect any user of Gateway API to do often, +whether or not default Gateways are in play; `gwctl` or something similar +SHOULD be able to show her which Routes are bound to which Gateways in every +case, not just with default Gateways. + +### Gateway For Mesh (East/West) + +Mesh traffic is defined by using a Service as a `parentRef` rather than a +Gateway. As such, there is no case where a default Gateway would be used for +mesh traffic. + +As noted above, a Route MAY both set `spec.useDefaultGateway` _and_ include a +`Service` `parentRef` entry, allowing a single Route to handle both N/S and +E/W traffic. In this case, the Route will be bound to both the default Gateway +and the mesh, and the `status` will show both parents. + +## Conformance Details + +#### Feature Names + +The default-gateway feature will be named `HTTPRouteDefaultGateway` and +`GRPCRouteDefaultGateway`. It is unlikely that an implementation would support +one of these Route types without the other, but `GatewayDefaultGateway` does +not seem like a good choice. + +### Conformance tests + +TBD. + +## Alternatives + +- A possible alternative API design is to modify the behavior of Listeners or + ListenerSets; rather than having a "default Gateway", perhaps we would have + "[default Listeners]". One challenge here is that the Route `status` doesn't + currently expose information about which Listener is being used, though it + does show which Gateway is being used. + +[default Listeners]: https://github.com/kubernetes-sigs/gateway-api/pull/3852#discussion_r2149056246 + +- We could define the default Gateway as a Gateway with a magic name, e.g. + "default". This doesn't actually make things that much simpler for Ana + (she'd still have to specify `parentRefs`), and it raises questions about + Chihiro's ability to control which Routes can bind to the default Gateway, + as well as how namespacing would work -- it's especially unhelpful for Ana + if she has to know the namespace of the default Gateway in order to use it. + + (Also, this is a breaking change if Chihiro has already created a + non-default Gateway with whatever name we choose to use for the convention.) + +- A default Gateway could overwrite a defaulted Route's `parentRefs` to point + to the default Gateway. The main challenge with this approach is that once + the `parentRefs` are overwritten, it's no longer possible to know what Ana + originally intended. Using the `status` to indicate that the Route is bound + to the default Gateway instead both preserves Ana's original intent and also + makes it possible to change the default Gateway without requiring Ana to + recreate all her Routes. + +## References + +TBD. diff --git a/geps/gep-3793/metadata.yaml b/geps/gep-3793/metadata.yaml new file mode 100644 index 0000000000..db611f5988 --- /dev/null +++ b/geps/gep-3793/metadata.yaml @@ -0,0 +1,33 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3793 +name: Default Gateways +status: Implementable +# Any authors who contribute to the GEP in any way should be listed here using +# their GitHub handle. +authors: + - kflynn +relationships: + # obsoletes indicates that a GEP makes the linked GEP obsolete, and completely + # replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field + # set back to this GEP, and MUST be moved to Declined. + obsoletes: {} + obsoletedBy: {} + # extends indicates that a GEP extends the linked GEP, adding more detail + # or additional implementation. The extended GEP MUST have its extendedBy + # field set back to this GEP. + extends: {} + extendedBy: {} + # seeAlso indicates other GEPs that are relevant in some way without being + # covered by an existing relationship. + seeAlso: {} +# references is a list of hyperlinks to relevant external references. +# It's intended to be used for storing GitHub discussions, Google docs, etc. +references: {} +# featureNames is a list of the feature names introduced by the GEP, if there +# are any. This will allow us to track which feature was introduced by which GEP. +# This is the value added to supportedFeatures and the conformance tests, in string form. +featureNames: {} +# changelog is a list of hyperlinks to PRs that make changes to the GEP, in +# ascending date order. +changelog: {} diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md new file mode 100644 index 0000000000..16080b1e8e --- /dev/null +++ b/geps/gep-3798/index.md @@ -0,0 +1,93 @@ +# GEP-3798: Client IP-Based Session Persistence + +* Issue: [#3798](https://github.com/kubernetes-sigs/gateway-api/issues/3798) +* Status: Deferred + +(See [status definitions](../overview.md#gep-states).) + +## Notes and Disclaimers + +* **DEFERRED**: This originally targeted release as `Experimental` in [v1.4.0]. + Notably (in [PR#3844]) there was concern that it may be difficult to get + multiple implementations to support this. During the release cycle, this GEP + was not able to meet the timeline requirements to progress, so it is now + considered deferred. If anyone is interested in picking this back up, it will + need to be re-submitted for consideration in a future release with a written + plan about how it will achieve implementation from multiple implementations. + If this remains in deferred state for a prolonged period, it may eventually + be moved to `Withdrawn`, or moved into the alternatives considered for + [GEP-1619]. + +[v1.4.0]:https://github.com/kubernetes-sigs/gateway-api/milestone/22 +[PR#3844]:https://github.com/kubernetes-sigs/gateway-api/pull/3844 +[GEP-1619]:https://gateway-api.sigs.k8s.io/geps/gep-1619/ + +## TLDR + +### What + This GEP proposes the addition of Client IP-based session persistence to the Gateway API. This feature will allow Gateway API implementations to ensure that requests originating from a specific client IP address (or a subnet defined by an IP mask) are consistently routed to the same backend endpoint for a configurable duration. This aims to provide a standardized and centralized mechanism for client IP persistence across various Gateway API implementations. + + As mentioned in the [GEP-1619](https://gateway-api.sigs.k8s.io/geps/gep-1619/#api), `SessionPersistence` can be applied via `BackendLBPolicy` and `RouteRule` API. Similar [edge case behaviour](https://gateway-api.sigs.k8s.io/geps/gep-1619/#edge-case-behavior) and [API Granularity](https://gateway-api.sigs.k8s.io/geps/gep-1619/#api-granularity) for ClientIP Persistence type should be applicable as well. + + An important addition/difference compared to [GEP-1619](https://gateway-api.sigs.k8s.io/geps/gep-1619) is that the identity of the backend assigned to a client (or a group of clients in the same subnet) is stored on the server (load balancer / gateway) side as opposed to the client side. + +## Goals + +* Define an API extension within Gateway API to enable client IP-based session persistence. + +* Allow configuration of a session duration for which a client IP should stick to a backend. + +* Provide an optional mechanism to specify an IP mask for subnet-based persistence, allowing multiple clients from the same subnet to be routed to the same backend. + +* Improve portability of applications requiring client IP persistence across different Gateway API implementations. + +## Non-Goals + +This GEP does not dictate the specific algorithm or implementation details for how an individual Gateway controller maintains the client IP-to-backend mapping (e.g., in-memory, distributed cache). + +## Introduction + +### Why: The Problem This Solves +Currently, achieving client IP-based session persistence within Kubernetes Gateway API environments often requires vendor-specific annotations or out-of-band configurations on the underlying load balancer or ingress controller. This approach has several drawbacks: + +* Inconsistent User Experience: Users have to learn different methods for configuring the same logical feature depending on their chosen Gateway API implementation. Configurations are not easily transferable between different Gateway API implementations, leading to vendor lock-in and increased operational overhead when migrating or using multiple controllers. + +* Reduced Visibility: The desired session persistence behavior is not explicitly declared within the Gateway API resources, making it harder to audit, manage, and understand the routing logic from a single source of truth. + +This GEP addresses these issues by providing a first-class API mechanism for client IP-based session persistence, enhancing the Gateway API's capabilities and promoting consistency and portability. + +### Who: Beneficiaries +* Application Developers: Can define session persistence requirements directly in their Gateway API configurations, ensuring consistent behavior regardless of the underlying Gateway implementation. This simplifies application deployment and management for stateful workloads. + +* Platform Operators/Administrators: Gain a standardized way to configure and manage client IP-based session persistence across their clusters, reducing the need for custom scripts or deep knowledge of individual controller implementations. This improves operational efficiency and consistency. + +* Gateway API Implementers: Receive a clear specification for implementing client IP-based session persistence, fostering interoperability and reducing divergent approaches. + +* Users with Stateful/Legacy Applications: Applications that rely on client IP Persistence (e.g., certain legacy applications, gaming servers, or applications with in-memory session stores) will directly benefit from a reliable and configurable persistence mechanism. + +## API + +TODO: when we get to the implementation iterations, we need to consider whether we can implement this using functionality established in [GEP-1619](https://gateway-api.sigs.k8s.io/geps/gep-1619). + +### Conformance tests + +NA + +## Alternatives + +Yet to do + +## References + +Below are references showing how ClientIP persistence is currently supported across some implementations: + +* [AVI](https://techdocs.broadcom.com/us/en/vmware-security-load-balancing/avi-load-balancer/avi-load-balancer/30-2/load-balancing-overview/persistence.html) +* [Native k8s](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) + +Below are some implementations of ClientIP persistence which allows configuring subnet Mask + +* [F5](https://techdocs.f5.com/content/kb/en-us/products/big-ip_ltm/manuals/product/ltm-concepts-11-5-1/11.html#:~:text=is%20persisted%20properly.-,Source%20address%20affinity%20persistence,-Source%20address%20affinity) +* [Fortinet](https://help.fortinet.com/fadc/4-8-0/olh/Content/FortiADC/handbook/slb_persistence.htm) +* [Huwaei](https://info.support.huawei.com/hedex/api/pages/EDOC1100149308/AEJ0713J/18/resources/cli/session_persistence.html) +* [NetScaler](https://docs.netscaler.com/en-us/citrix-adc/current-release/load-balancing/load-balancing-persistence/no-rule-persistence#:~:text=For%20IP%2Dbased%20persistence%2C%20you%20can%20also%20set%20the%20persistMask%20parameter) +* [AVI](https://techdocs.broadcom.com/us/en/vmware-security-load-balancing/avi-load-balancer/avi-load-balancer/30-2/load-balancing-overview/persistence/client-ip-persistence.html) diff --git a/geps/gep-3798/metadata.yaml b/geps/gep-3798/metadata.yaml new file mode 100644 index 0000000000..85a47289c0 --- /dev/null +++ b/geps/gep-3798/metadata.yaml @@ -0,0 +1,37 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3798 +name: Client IP-Based Session Persistence +status: Deferred +# Any authors who contribute to the GEP in any way should be listed here using +# their GitHub handle. +authors: + - arihantg +relationships: + # obsoletes indicates that a GEP makes the linked GEP obsolete, and completely + # replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field + # set back to this GEP, and MUST be moved to Declined. + obsoletes: {} + obsoletedBy: {} + # extends indicates that a GEP extends the linked GEP, adding more detail + # or additional implementation. The extended GEP MUST have its extendedBy + # field set back to this GEP. + extends: {} + extendedBy: {} + # seeAlso indicates other GEPs that are relevant in some way without being + # covered by an existing relationship. + seeAlso: + - number: 1619 + name: Session Persistence + description: Session Persistence via BackendLBPolicy + +# references is a list of hyperlinks to relevant external references. +# It's intended to be used for storing GitHub discussions, Google docs, etc. +references: {} +# featureNames is a list of the feature names introduced by the GEP, if there +# are any. This will allow us to track which feature was introduced by which GEP. +# This is the value added to supportedFeatures and the conformance tests, in string form. +featureNames: {} +# changelog is a list of hyperlinks to PRs that make changes to the GEP, in +# ascending date order. +changelog: {} diff --git a/geps/gep-3949/index.md b/geps/gep-3949/index.md new file mode 100644 index 0000000000..26f5f2056c --- /dev/null +++ b/geps/gep-3949/index.md @@ -0,0 +1,539 @@ +# GEP-3949: Mesh Resource + +* Issue: [#3949](https://github.com/kubernetes-sigs/gateway-api/issues/3949) +* Status: Implementable + +(See [status definitions](../overview.md#gep-states).) + +[Chihiro]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro +[Ian]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian +[Ana]: https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", +"SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this +document are to be interpreted as described in BCP 14 ([RFC8174]) when, and +only when, they appear in all capitals, as shown here. + +[RFC8174]: https://www.rfc-editor.org/rfc/rfc8174 + +## User Story + +**[Chihiro] and [Ian] would like a Mesh resource, +parallel to the Gateway resource, +that allows them to +supply mesh-wide configuration +and +shows what features +a given mesh implementation supports.** + +## Background + +Gateway API has long had a GatewayClass resource +that represents a class of Gateways +that can be instantiated in a cluster. +GatewayClass both +allows configuring the class as a whole +and provides a way for [Chihiro] and [Ian] to see +what features Gateways in that class support. +We have, +to date, +avoided such a resource for meshes, +but as we work on +improving mesh conformance tests and reports +and start work on +supporting Out-of-Cluster Gateways (OCGs), +we will need ways to +show what features a given mesh implementation supports +and represent mesh-wide configuration. + +This GEP therefore defines a Mesh resource +which represents a running instance of a service mesh, +allowing [Chihiro] and [Ian] to +supply mesh-wide configuration, +and allowing the mesh implementation +to indicate what features it supports. + +Unlike Gateways, we do not expect +multiple instances of meshes to be instantiated +in a single cluster. +This implies that a MeshClass resource is not needed; +instead, we will simply define a Mesh resource. + +## Goals + +- Define a Mesh resource + that allows for + mesh-wide configuration + and feature discovery. + +- Avoid making it more difficult for [Chihiro] and [Ian] + to adopt a mesh + (or to experiment with adopting a mesh). + +## Non-Goals + +- Support meshes interoperating with each other. + + As always, + we will not rule out future work + in this area, + but it is out of scope + for this GEP. + +- Support off-cluster gateways. + + This is covered in a separate GEP + and will not be discussed here. + +- Change GAMMA's position on + multiple meshes running simultaneously + in a single cluster. + + GAMMA has always taken the position + that multiple meshes running simultaneously + in a single cluster + is not an explicit goal, but neither is it forbidden. + This GEP does not change that position. + +## API + +The purpose +of the Mesh resource +is to support both +mesh-wide configuration +as well as feature discovery. +However, +as of the writing of this GEP, +there is +no mesh-wide configuration +that is portable across implementations. +Therefore, +the Mesh resource +is currently pretty simple: + +```yaml +apiVersion: gateway.networking.x-k8s.io/v1alpha1 +kind: XMesh +metadata: + name: one-mesh-to-mesh-them-all +spec: + # required, must be domain-prefixed + controllerName: one-mesh.example.com/one-mesh + parametersRef: + # optional ParametersReference + ... +``` + +- The Mesh resource is cluster-scoped, + so there is no `metadata.namespace` field. + +- Although we call this the Mesh resource, + as an experimental API + it must be named XMesh + in the `gateway.networking.x-k8s.io` API group. + + When the API graduates to standard, + it will be renamed to `Mesh` + in the `gateway.networking.k8s.io` API group. + +- The `controllerName` field + is analogous to + the `controllerName` field + in the GatewayClass resource: + it defines the name + of the mesh implementation + that is responsible for + this Mesh resource. + + A given mesh implementation will define its controller name + at build time. + It MUST be a domain-prefixed path, + for example `linkerd.io/linkerd` or `istio.io/istio`. + It MUST NOT be empty. + It MAY be configurable at runtime, + although this is not expected to be common. + + Although we expect + that there will be + only one mesh + in a given cluster, the + `controllerName` field + MUST be supplied, + and a given mesh implementation + MUST ignore + a Mesh resource + that does not have + a `controllerName` field + that matches its own name. + +- The `parametersRef` field + is analogous to + the `parametersRef` field + in the GatewayClass resource: + it allows optionally specifying + a reference to a resource + that contains configuration + specific to the mesh + implementation. + +### `status` + +The `status` stanza +of the Mesh resource +is used to indicate +whether the Mesh resource +has been accepted by +a mesh implementation, +whether the mesh is +ready to use, +and +what features +the mesh supports. + +```yaml +apiVersion: gateway.networking.x-k8s.io/v1alpha1 +kind: XMesh +metadata: + name: one-mesh-to-mesh-them-all +spec: + controllerName: one-mesh.example.com/one-mesh +status: + conditions: + # MUST include Accepted condition if the Mesh resource is active. + - type: Accepted # Becomes true when the controller accepts the Mesh resource + status: "True" + reason: Accepted + lastTransitionTime: "2023-10-01T12:00:00Z" + message: Mesh resource accepted by one-mesh v1.2.3 in namespace one-mesh + ... + supportedFeatures: + # List of SupportedFeature + - name: MeshHTTPRoute + - name: MeshConsumerRoute + - name: OffClusterGateway + ... +``` + +Although GAMMA does not fully support multiple meshes +running in the same cluster at the same time, +meshes still MUST provide +human-readable information +in the `Accepted` condition +about which mesh instance +has claimed a given Mesh resource. +This information is meant to be used +by [Chihiro] and [Ian] as confirmation +that the mesh instance +is doing what they expect it to do. + +Mesh implementations MUST +reject Mesh resources in which `spec.parametersRef` +references a resource that does not exist +or is not supported by the mesh implementation, +setting the `Reason` to `InvalidParameters`. + +The mesh implementation +MUST set `status.SupportedFeatures` +to indicate which features +the mesh supports. + +### Life Cycle + +One of the explicit goals of this GEP +is to avoid making it more difficult for [Chihiro] and [Ian] +to adopt a mesh. +In turn, this implies that we MUST NOT require [Chihiro] or [Ian] +to manually create a Mesh resource in order to use a mesh. + +The simplest way to achieve this is +for the mesh implementation to create a Mesh resource +when it starts up, +if one does not already exist +with a matching `controllerName` field. +This raises questions around +what the Mesh resource should be named, +and how the mesh implementation can avoid overwriting +any modifications [Chihiro] or [Ian] make +to the Mesh resource after it is created. + +To manage these concerns +while still minimizing added friction, +mesh implementations MUST define a default `metadata.name` +for the Mesh resource they will look for, +and SHOULD allow overriding this name at install time. +This default name SHOULD be +an obvious derivative of the mesh implementation name, +such as "linkerd" or "istio"; +its purpose is to make it easy for [Chihiro] and [Ian] +to find the Mesh resource +while also allowing for the possibility +that there will need to be more than one +Mesh resource in a cluster. + +At startup, then: + +- The mesh implementation MUST look for a Mesh resource + with the expected `metadata.name` field. + +- If no Mesh resource exists with the expected `metadata.name`, + the implementation MUST create a Mesh resource + with the expected `metadata.name` + and `spec.controllerName` fields. + + - The mesh MUST NOT set any other fields + in the `spec` of the Mesh resource + that it creates. + + In particular, the mesh MUST NOT set `parametersRef` + when it creates the Mesh resource. + +- Otherwise + (a Mesh resource already exists with the expected `metadata.name`), + the implementation MUST NOT modify the `spec` + of that Mesh resource + in **any way**. + Instead, it MUST check the `spec.controllerName` field: + + - If the Mesh resource has a matching `spec.controllerName` field: + + - The implementation MUST set the `status` stanza + of the Mesh resource + to indicate whether or not it has accepted the Mesh resource + and, if accepted, what features the mesh supports. + + - Otherwise + (the Mesh resource does not have + a matching `spec.controllerName` field): + + - The implementation MUST NOT modify the Mesh resource + in any way, + and it SHOULD warn the user + (in whatever way is appropriate for the mesh) + that there is a mismatch in the Mesh resource + +```mermaid +flowchart TD + Start{Does a Mesh resource with a matching name exist?} + Start -->|Yes| Match + Start -->|No| NoMatch + Match{Does the controllerName also match?} + Match -->|No| WarnNoModify + Match -->|Yes| UpdateStat + NoMatch[Create a new Mesh resource] --> CheckCreate + CheckCreate{Did creation succeed?} + CheckCreate -->|Yes| UpdateStat + CheckCreate -->|No| Warn + UpdateStat[Update status] + Warn[Warn] + WarnNoModify[Warn and don't modify] +``` + +If, at the end of this process, +there is no Mesh resource with both +a matching `metadata.name` and +a matching `spec.controllerName`, +the implementation MUST act as if +a Mesh resource was found with a empty `spec` +(other than the `controllerName` field). +Optional configuration MUST remain in its default state, +and features that require a Mesh resource +(such as OCG support) +MUST NOT be enabled. + +Obviously, if no matching Mesh resource exists, +the mesh will not be able to publish support features, +which may lead to assumptions +that the mesh does not support any features. + +The mesh implementation MUST NOT, +under any circumstances, +modify the `spec` of a Mesh resource +other than by creating a new Mesh resource +when one does not exist. + +Mesh implementations SHOULD +respond to changes in the Mesh resource +without requiring the mesh to be restarted. + +### API Type Definitions + +```go +// Mesh is a Cluster level resource. +type Mesh struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of Mesh. + Spec MeshSpec `json:"spec"` + + // Status defines the current state of Mesh. + // + // Implementations MUST populate status on all Mesh resources which + // specify their controller name. + // + // Defaults to Accepted condition with status Unknown and reason Pending. + Status MeshStatus `json:"status,omitempty"` +} + +// MeshSpec defines the desired state of a Mesh. +type MeshSpec struct { + // ControllerName is the name of the controller that is managing this + // Mesh. The value of this field MUST be a domain prefixed path. + // + // Example: "example.com/awesome-mesh". + // + // This field is not mutable and cannot be empty. + // + // Support: Core + // + // +kubebuilder:validation:XValidation:message="Value is immutable",rule="self == oldSelf" + ControllerName string `json:"controllerName"` + + // ParametersRef is an optional reference to a resource that contains + // implementation-specific for this Mesh. If no implementation-specific + // parameters are needed, this field MUST be omitted. + // + // ParametersRef can reference a standard Kubernetes resource, i.e. + // ConfigMap, or an implementation-specific custom resource. The resource + // can be cluster-scoped or namespace-scoped. + // + // If the referent cannot be found, refers to an unsupported kind, or when + // the data within that resource is malformed, the Mesh MUST be rejected + // with the "Accepted" status condition set to "False" and an + // "InvalidParameters" reason. + // + // Support: Implementation-specific + // + // +optional + ParametersRef *ParametersReference `json:"parametersRef,omitempty"` +} + +// MeshConditionType is the type for status conditions on Mesh resources. +// This type should be used with the MeshStatus.Conditions field. +type MeshConditionType string + +// MeshConditionReason defines the set of reasons that explain why a +// particular Mesh condition type has been raised. +type MeshConditionReason string + +const ( + // This condition indicates whether the Mesh has been accepted by the + // controller requested in the `spec.controller` field. + // + // This condition defaults to Unknown, and MUST be set by a controller + // when it sees a Mesh using its controller string. The status of this + // condition MUST be set to True if the controller will accept the Mesh + // resource. Otherwise, this status MUST be set to False. If the status + // is set to False, the controller MUST set a Message and Reason as an + // explanation. + // + // Possible reasons for this condition to be true are: + // + // * "Accepted" + // + // Possible reasons for this condition to be False are: + // + // * "InvalidParameters" + // + // Controllers should prefer to use the values of MeshConditionReason + // for the corresponding Reason, where appropriate. + MeshConditionStatusAccepted MeshConditionType = "Accepted" + + // This reason is used with the "Accepted" condition when the condition is + // true. + MeshConditionReasonAccepted MeshConditionReason = "Accepted" + + // This reason is used with the "Accepted" condition when the Mesh + // was not accepted because the parametersRef field refers to + // * a namespaced resource but the Namespace field is not set, or + // * a cluster-scoped resource but the Namespace field is set, or + // * a nonexistent object, or + // * an unsupported resource or kind, or + // * an existing resource but the data within that resource is malformed. + MeshConditionReasonInvalidParameters MeshConditionReason = "InvalidParameters" + + // This reason is used with the "Accepted" condition when the + // requested controller has not yet made a decision about whether + // to accept the Mesh. It is the default Reason on a new Mesh. + MeshConditionReasonPending MeshConditionReason = "Pending" +) + +// MeshStatus is the current status for the Mesh. +type MeshStatus struct { + // Conditions is the current status from the controller for + // this Mesh. + // + // Controllers should prefer to publish conditions using values + // of MeshConditionType for the type of each Condition. + // + // +optional + // +listType=map + // +listMapKey=type + // +kubebuilder:validation:MaxItems=8 + // Defaults to Accepted condition with status Unknown and reason Pending. + Conditions []metav1.Condition `json:"conditions,omitempty"` + + // SupportedFeatures is the set of features the Mesh support. + // It MUST be sorted in ascending alphabetical order by the Name key. + // +optional + // +listType=map + // +listMapKey=name + // + // +kubebuilder:validation:MaxItems=64 + SupportedFeatures []SupportedFeature `json:"supportedFeatures,omitempty"` +} + +// +kubebuilder:object:root=true + +// MeshList contains a list of Mesh +type MeshList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Mesh `json:"items"` +} +``` + +## Conformance Details + +TBA. + +#### Feature Names + +No feature name is defined +for the Mesh resource itself; +filling out the `status` stanza +of the Mesh resource +is a conformance requirement, +and is sufficient indication +that the Mesh resource is supported. + +### Conformance tests + +TBA. + +## Alternatives + +We did not find any +particularly compelling alternatives +to having a Mesh resource +to meet these needs. +We considered having both +MeshClass and Mesh resources, +but decided that +there was no clear need for both, +and that a Mesh resource +better served the use cases. + +If a MeshClass resource +is later defined, +the Mesh resource +will need to be updated. +One potential approach to such an update might be: + +- Add a `meshClassName` field to the Mesh resource; +- Deprecate the `controllerName` field; and +- Define that a Mesh resource with both fields set is invalid. + +## References + +TBA. diff --git a/geps/gep-3949/metadata.yaml b/geps/gep-3949/metadata.yaml new file mode 100644 index 0000000000..de9c3639e7 --- /dev/null +++ b/geps/gep-3949/metadata.yaml @@ -0,0 +1,34 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3949 +name: Mesh Resource +status: Implementable +# Any authors who contribute to the GEP in any way should be listed here using +# their GitHub handle. +authors: + - kflynn + - karthikbox +relationships: + # obsoletes indicates that a GEP makes the linked GEP obsolete, and completely + # replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field + # set back to this GEP, and MUST be moved to Declined. + obsoletes: {} + obsoletedBy: {} + # extends indicates that a GEP extends the linked GEP, adding more detail + # or additional implementation. The extended GEP MUST have its extendedBy + # field set back to this GEP. + extends: {} + extendedBy: {} + # seeAlso indicates other GEPs that are relevant in some way without being + # covered by an existing relationship. + seeAlso: {} +# references is a list of hyperlinks to relevant external references. +# It's intended to be used for storing GitHub discussions, Google docs, etc. +references: {} +# featureNames is a list of the feature names introduced by the GEP, if there +# are any. This will allow us to track which feature was introduced by which GEP. +# This is the value added to supportedFeatures and the conformance tests, in string form. +featureNames: {} +# changelog is a list of hyperlinks to PRs that make changes to the GEP, in +# ascending date order. +changelog: {} diff --git a/geps/gep-696/index.md b/geps/gep-696/index.md index bedcc6e658..6082b30907 100644 --- a/geps/gep-696/index.md +++ b/geps/gep-696/index.md @@ -1,7 +1,7 @@ # GEP-696: GEP template * Issue: [#696](https://github.com/kubernetes-sigs/gateway-api/issues/696) -* Status: Provisional|Implementable|Experimental|Standard|Deferred|Rejected|Withdrawn|Replaced +* Status: Provisional|Prototyping|Implementable|Experimental|Standard|Completed|Memorandum|Deferred|Declined|Withdrawn (See [status definitions](../overview.md#gep-states).) @@ -47,6 +47,8 @@ Every feature should: 3. Not exceed 128 characters. 4. Contain only letters and numbers +GEPs cannot move to Experimental without a Feature Name. + ### Conformance tests Conformance tests file names should try to follow the `pascal-case-name.go` format. diff --git a/geps/gep-696/metadata.yaml b/geps/gep-696/metadata.yaml index 0eedd6cabe..cc3c2ce20f 100644 --- a/geps/gep-696/metadata.yaml +++ b/geps/gep-696/metadata.yaml @@ -10,6 +10,7 @@ authors: - robscott - youngnick - dprotaso + - mlavacca relationships: # obsoletes indicates that a GEP makes the linked GEP obsolete, and completely # replaces that GEP. The obsoleted GEP MUST have its obsoletedBy field diff --git a/geps/gep-91/index.md b/geps/gep-91/index.md index 6fddddb59f..d71aef7650 100644 --- a/geps/gep-91/index.md +++ b/geps/gep-91/index.md @@ -1,4 +1,4 @@ -# GEP-91: Client Certificate Validation for TLS terminating at the Gateway Listener +# GEP-91: Client Certificate Validation for TLS terminating at the Gateway * Issue: [#91](https://github.com/kubernetes-sigs/gateway-api/issues/91) * Status: Implementable @@ -8,39 +8,46 @@ ## TLDR This GEP proposes a way to validate the TLS certificate presented by the frontend client to the server -(Gateway Listener in this case) during a [TLS Handshake Protocol][]. +(Gateway in this case) during a [TLS Handshake Protocol][]. + +## Connection coalescing security issue + +Gateway API standard defines a `Listener` as "the concept of a logical endpoint where a Gateway accepts network connections." This statement is incorrect because once the connection is established (this applies to both HTTP and TLS traffic) it can be reused across multiple listeners sharing the same port. This might lead to bypassing client certificate validation configuration for a given `Listener`. Those concerns were raised in [GEP-3567](). To provide the best experience for gateway users and secure their applications, client certificate configuration needs to be introduced with finer granularity per-port (binding to TCP connection). ## Goals -* Define an API field to specify the CA Certificate within the Gateway Listener configuration that can be used as a trust anchor to validate the certificates presented by the client. This use case has been highlighted in the [TLS Configuration GEP][] under segment 1 and in the [Gateway API TLS Use Cases][] document under point 7. +* Define an API field to specify the CA Certificate within the Gateway configuration that can be used as a trust anchor to validate the certificates presented by the client. +This use case has been highlighted in the [TLS Configuration GEP][] under segment 1 and in the [Gateway API TLS Use Cases][] document under point 7. +* Introduce explicit client certificate validation modes that reflect common TLS behaviors (e.g., optional vs. required client certs) +* Ensure the configuration mitigates the authentication bypass risks associated with HTTP/2 connection coalesing as described in [GEP-3567](https://gateway-api.sigs.k8s.io/geps/gep-3567/#interaction-with-client-cert-validation). ## Non-Goals * Define other fields that can be used to verify the client certificate such as the Certificate Hash. -## Existing support in Implementations +### API -This feature is widely supported in implementations that support Gateway API. -This table highlights the support. Please feel free to add any missing implementations not mentioned below. +* Introduce new structs: `GatewayTLSConfig`, `TLSConfig`, `TLSPortConfig`, `FrontendTLSValidation` allowing for the definition of certificate validation used to authenticate the peer (frontend) in a TLS connection. A new `tls` field with gateway tls configuration will be added to the gateway object. +* `TLSConfig` will allow defining client certificate validation per port which will be applied to all Listeners matching this port. We might want to extend this struct with other tls configurations. +* `TLSPortConfig` will allow defining client certificate validation per port which will be applied to all Listeners matching this port. +* `GatewayTLSConfig` struct contains default and (optional) per port configuration. Default configuration will apply to all Listeners which are not matching per port override. +* This new field is separate from the existing [BackendTLSPolicy][] configuration. [BackendTLSPolicy][] controls TLS certificate validation for connections *from* the Gateway to the backend service. +This proposal adds the ability to validate the TLS certificate presented by the *client* connecting to the Gateway (the frontend). +These two validation mechanisms operate independently and can be used simultaneously. +* Introduce a `caCertificateRefs` field within `FrontendTLSValidation` that can be used to specify a list of CA Certificates that can be used as a trust anchor to validate the certificates presented by the client. +* Add a new `FrontendValidationModeType` enum within `FrontendTLSValidation` indicating how gateway should validate client certificates. As for now we support following values but it might change in the future: + 1) `AllowValidOnly` (Core Support) + 2) `AllowInsecureFallback` (Extended Support) -| Implementation | Support | -|----------------|------------| -| Apache APISIX | [ApisixTls.Client.CASecret](https://apisix.apache.org/docs/ingress-controller/tutorials/mtls/#mutual-authentication) | -| Contour | [HTTPProxy.Spec.VirtualHost.Tls.ClientValidation.CASecret](https://projectcontour.io/docs/v1.17.1/config/tls-termination/) | -| Emissary Ingress| [TlSContext.Spec.Secret](https://www.getambassador.io/docs/emissary/latest/topics/running/tls/mtls) | -| Gloo Edge | [VirtualService.Spec.SSLConfig.SecretRef](https://docs.solo.io/gloo-edge/latest/guides/security/tls/server_tls/#configuring-downstream-mtls-in-a-virtual-service) | -| Istio | [Gateway.Spec.Servers.TLS.Mode](https://istio.io/latest/docs/tasks/traffic-management/ingress/secure-ingress/#configure-a-mutual-tls-ingress-gateway) | -| Kong | [mTLS Plugin](https://docs.konghq.com/hub/kong-inc/mtls-auth/) | -| Traefik | [TLSOption.Spec.ClientAuth](https://doc.traefik.io/traefik/https/tls/#client-authentication-mtls) | -| NGINX Ingress Controller | [ingressMTLS](https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#ingressmtls) | + `AllowInsecureFallback` mode indicates the gateway will accept connections even if the client certificate is not presented or fails verification. + This approach delegates client authorization to the backend and introduce a significant security risk. It should be used in testing environments or + on a temporary basis in non-testing environments. + When `FrontendValidationModeType` is changed from `AllowValidOnly` to `AllowInsecureFallback` the `InsecureFrontendValidationMode` condition MUST be set to `True` with Reason `ConfigurationChanged` on gateway. +* Introduce a `ObjectReference` structure that can be used to specify `caCertificateRefs` references. -### API +### Impact on listeners -* Introduce a `FrontendValidation` field of type `FrontendTLSValidation` within [GatewayTLSConfig][] that can be used to validate the peer (frontend) with which the TLS connection is being made. -* Introduce a `caCertificateRefs` field within `FrontendTLSValidation` that can be used to specify a list of CA Certificates that can be used as a trust anchor to validate the certificates presented by the client. -* This new field is separate from the existing [BackendTLSPolicy][] configuration. [BackendTLSPolicy][] controls TLS certificate validation for connections *from* the - Gateway to the backend service. This proposal adds the ability to validate the TLS certificate presented by the *client* connecting to the Gateway (the - frontend). These two validation mechanisms operate independently and can be used simultaneously. -* Also introduce a `ObjectReference` structure that can be used to specify `caCertificateRefs` references. +This proposal removes frontendTLSValidation from Listener's TLS configuration and introduces gateways level per port configuration. This is a breaking change for exisitng implementation which uses this feature from Experimental API. + Once gateway level TLS is configured (either by default or for a specific port), the TLS settings will apply to all existing and newly created Listeners serving HTTPS that match the configuration. #### GO @@ -78,50 +85,142 @@ type ObjectReference struct { Namespace *Namespace `json:"namespace,omitempty"` } +// GatewayTLSConfig specifies frontend tls configuration for gateway. type GatewayTLSConfig struct { - ...... - // FrontendValidation holds configuration information for validating the frontend (client). - // Setting this field will require clients to send a client certificate - // required for validation during the TLS handshake. In browsers this may result in a dialog appearing - // that requests a user to specify the client certificate. - // The maximum depth of a certificate chain accepted in verification is Implementation specific. - FrontendValidation *FrontendTLSValidation `json:"frontendValidation,omitempty"` + // default specifies the default client certificate validation configuration + // for all Listeners handling HTTPS traffic, unless a per-port configuration + // is defined. + // + // support: Core + // + // +required + // + Default FrontendTLSValidation `json:"default"` + + // PerPort specifies tls configuration assigned per port. + // Per port configuration is optional. Once set this configuration overrides + // the default configuration for all Listeners handling HTTPS traffic + // that match this port. + // Each override port requires a unique TLS configuration. + // + // support: Core + // + PerPort []TLSConfig `json:"PerPort,omitempty"` +} + +// TLSConfig describes a TLS configuration. Currently, it stores only the client +// certificate validation configuration, but this may be extended in the future. +type TLSConfig struct { + // FrontendValidation holds configuration information for validating the frontend (client). + // Setting this field will result in mutual authentication when connecting to the gateway. + // In browsers this may result in a dialog appearing + // that requests a user to specify the client certificate. + // The maximum depth of a certificate chain accepted in verification is Implementation specific. + // + // Support: Extended + // + // +required + // + FrontendValidation FrontendTLSValidation `json:"frontendValidation"` +} + +type TLSPortConfig struct { + // The Port indicates the Port Number to which the TLS configuration will be + // applied. This configuration will be applied to all Listeners handling HTTPS + // traffic that match this port. + // + // Support: Core + // + // +required + // + Port PortNumber `json:"port"` + // TLS store the configuration that will be applied to all Listeners handling + // HTTPS traffic and matching given port. + TLS TLSConfig `json:"tls"` } // FrontendTLSValidation holds configuration information that can be used to validate // the frontend initiating the TLS connection type FrontendTLSValidation struct { - // CACertificateRefs contains one or more references to - // Kubernetes objects that contain TLS certificates of - // the Certificate Authorities that can be used - // as a trust anchor to validate the certificates presented by the client. - // - // A single CA certificate reference to a Kubernetes ConfigMap - // has "Core" support. - // Implementations MAY choose to support attaching multiple CA certificates to - // a Listener, but this behavior is implementation-specific. - // - // Support: Core - A single reference to a Kubernetes ConfigMap - // with the CA certificate in a key named `ca.crt`. - // - // Support: Implementation-specific (More than one reference, or other kinds - // of resources). - // - // References to a resource in a different namespace are invalid UNLESS there - // is a ReferenceGrant in the target namespace that allows the certificate - // to be attached. If a ReferenceGrant does not allow this reference, the - // "ResolvedRefs" condition MUST be set to False for this listener with the - // "RefNotPermitted" reason. - // - // +kubebuilder:validation:MaxItems=8 - // +kubebuilder:validation:MinItems=1 - CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"` + // CACertificateRefs contains one or more references to + // Kubernetes objects that contain TLS certificates of + // the Certificate Authorities that can be used + // as a trust anchor to validate the certificates presented by the client. + // + // A single CA certificate reference to a Kubernetes ConfigMap + // has "Core" support. + // Implementations MAY choose to support attaching multiple CA certificates to + // a Listener, but this behavior is implementation-specific. + // + // Support: Core - A single reference to a Kubernetes ConfigMap + // with the CA certificate in a key named `ca.crt`. + // + // Support: Implementation-specific (More than one certificate in a ConfigMap with different keys or more than one reference, or other kinds of resources). + // + // References to a resource in a different namespace are invalid UNLESS there + // is a ReferenceGrant in the target namespace that allows the certificate + // to be attached. If a ReferenceGrant does not allow this reference, the + // "ResolvedRefs" condition MUST be set to False for this listener with the + // "RefNotPermitted" reason. + // + // +kubebuilder:validation:MaxItems=8 + // +kubebuilder:validation:MinItems=1 + CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"` + + // FrontendValidationMode defines the mode for validating the client certificate. + // There are two possible modes: + // + // - AllowValidOnly: In this mode, the gateway will accept connections only if + // the client presents a valid certificate. This certificate must successfully + // pass validation against the CA certificates specified in `CACertificateRefs`. + // - AllowInsecureFallback: In this mode, the gateway will accept connections + // even if the client certificate is not presented or fails verification. + // + // This approach delegates client authorization to the backend and introduce + // a significant security risk. It should be used in testing environments or + // on a temporary basis in non-testing environments. + // + // Defaults to AllowValidOnly. + // + // Support: Core + // + // +optional + // +kubebuilder:default=AllowValidOnly + Mode FrontendValidationModeType `json:"mode,omitempty"` +} + +// FrontendValidationModeType type defines how a Gateway validates client certificates. +// +// +kubebuilder:validation:Enum=AllowValidOnly;AllowInsecureFallback +type FrontendValidationModeType string + +const ( + // AllowValidOnly indicates that a client certificate is required + // during the TLS handshake and MUST pass validation. + AllowValidOnly FrontendValidationModeType = "AllowValidOnly" + + // AllowInsecureFallback indicates that a client certificate may not be + // presented during the handshake or the validation against CA certificates may fail. + AllowInsecureFallback FrontendValidationModeType = "AllowInsecureFallback" +) + +type GatewaySpec struct { + ... + // GatewayTLSConfig specifies frontend tls configuration for gateway. + // + // Support: Core + // + // +optional + // + TLS *GatewayTLSConfig `json:"tls,omitempty"` } ``` #### YAML +1. Setting default `frontendValidation` config. + ```yaml apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway @@ -129,6 +228,13 @@ metadata: name: client-validation-basic spec: gatewayClassName: acme-lb + tls: + default: + frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: default-cert listeners: - name: foo-https protocol: HTTPS @@ -139,11 +245,60 @@ spec: - kind: Secret group: "" name: foo-example-com-cert + - name: bar-https + protocol: HTTPS + port: 8443 + hostname: bar.example.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: bar-example-com-cert +``` + +2. Setting default and per port `frontendValidation` configs. + +```yaml +apiVersion: gateway.networking.k8s.io/v1beta1 +kind: Gateway +metadata: + name: client-validation-basic +spec: + gatewayClassName: acme-lb + tls: + default: frontendValidation: caCertificateRefs: - - kind: ConfigMap - group: "" - name: foo-example-com-ca-cert + - kind: ConfigMap + group: "" + name: default-cert + mode: AllowInsecureFallback + perPort: + - port: 443 + frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: foo-example-com-ca-cert + listeners: + - name: foo-https + protocol: HTTPS + port: 443 + hostname: foo.example.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: foo-example-com-cert + - name: bar-https + protocol: HTTPS + port: 8443 + hostname: bar.example.com + tls: + certificateRefs: + - kind: Secret + group: "" + name: bar-example-com-cert ``` ## Deferred @@ -151,16 +306,56 @@ spec: This section highlights use cases that may be covered in a future iteration of this GEP * Using system CA certificates as the trust anchor to validate the certificates presented by the frontend client. -* Supporting a mode where validating client certificates is optional, useful for debugging and migrating to strict TLS. * Supporting an optional `subjectAltNames` field within `FrontendTLSValidation` that can be used to specify one or more alternate names to verify the subject identity in the certificate presented by the client. This field falls under Authorization, the initial focus here is on Client Authentication and will be revisited when Authorization is tackled as a whole in the project. * Specifying the verification depth in the client certificate chain. This is being deferred because the default verification depth differs across implementations. +## Existing support in Implementations + +This feature is already widely supported by implementations that conform to the Gateway API. +The table below summarizes current support. Please feel free to add any implementations that are missing. +This GEP aims to standardize this behavior as an official part of the upstream specification. + +| Implementation | Support | Granularity | Inline vs Policy | +|------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------|------------------| +| Acnodal EPIC | | | | +| Airlock Microgateway | [SidecarGateway.spec.applications[].downstream.tls.clientCertificate](https://docs.airlock.com/microgateway/latest/index/api/crds/sidecar-gateway/v1alpha1/index.html#sidecargatewayspecapplicationsdownstreamtls) | Per Listener | Inline | +| Amazon Elastic Kubernetes Service | | | | +| Apache APISIX | [ApisixTls.Client.CASecret](https://apisix.apache.org/docs/ingress-controller/tutorials/mtls/#mutual-authentication) | Per SNI | | +| Avi Kubernetes Operator | | | | +| Azure Application Gateway for Containers | [FrontendTLSPolicy](https://learn.microsoft.com/en-us/azure/application-gateway/for-containers/api-specification-kubernetes#alb.networking.azure.io/v1.FrontendTLSPolicy) | Per Gateway & Per Listener | Policy | +| Cilium | | | | +| Contour | [HTTPProxy.Spec.VirtualHost.Tls.ClientValidation.CASecret](https://projectcontour.io/docs/v1.17.1/config/tls-termination/) | Per SNI | Inline | +| Easegress | | | | +| Emissary Ingress | [TlSContext.Spec.CASecret](https://www.getambassador.io/docs/emissary/latest/howtos/client-cert-validation) | Per SNI | Policy | +| Envoy Gateway | [ClientTrafficPolicy.Spec.TLS.ClientValidation](https://gateway.envoyproxy.io/docs/api/extension_types/#clientvalidationcontext) | Per Gateway & Per Listener | Policy | +| Flomesh Service Mesh | | | | +| Gloo Gateway | [VirtualService.Spec.SSLConfig.SecretRef](https://docs.solo.io/gloo-edge/latest/guides/security/tls/server_tls/#configuring-downstream-mtls-in-a-virtual-service) | Per SNI | Inline | +| Google Cloud Service Mesh | | | | +| Google Kubernetes Engine | | | | +| HAProxy Ingress | | | | +| HAProxy Kubernetes Ingress Controller | [ca-file](https://www.haproxy.com/documentation/haproxy-configuration-tutorials/security/authentication/client-certificate-authentication/#sidebar) | Per SNI | Inline | +| HashiCorp Consul | [file-system-certificate](https://developer.hashicorp.com/consul/docs/north-south/api-gateway/secure-traffic/encrypt) | Per Listener | Policy | +| Istio | [Gateway.Spec.Servers.TLS.Mode](https://istio.io/latest/docs/tasks/traffic-management/ingress/secure-ingress/#configure-a-mutual-tls-ingress-gateway) | Per Server | Inline | +| kgateway | | | | +| Kong Kubernetes Ingress Controller | [mTLS Plugin](https://docs.konghq.com/hub/kong-inc/mtls-auth/) | Per HTTP Proxy (Host/Port) | Policy | +| Kong Gateway Operator | [mTLS Plugin](https://docs.konghq.com/hub/kong-inc/mtls-auth/) | Per HTTP Proxy (Host/Port) | Policy | +| Kuma | | | | +| Linkerd | | | | +| LiteSpeed Ingress Controller | | | | +| LoxiLB | | | | +| NGINX Gateway Fabric | [ingressMTLS](https://docs.nginx.com/nginx-ingress-controller/configuration/policy-resource/#ingressmtls) | Per Listener | Policy | +| ngrok Kubernetes Operator | [TrafficPolicy.Terminate-TLS.Config.MutualTLSCertificateAuthorities](https://ngrok.com/docs/traffic-policy/actions/terminate-tls/#configuration-reference) | Per Endpoint (Host:Port) | Policy | +| STUNner | | | | +| Traefik Proxy | [TLSOption.Spec.ClientAuth](https://doc.traefik.io/traefik/https/tls/#client-authentication-mtls) | Per EntryPoint | Inline | +| Tyk | [Enable Client Certificate](https://tyk.io/docs/basic-config-and-security/security/mutual-tls/client-mtls/#why-use-mutual-tls) | Per Gateway | Policy | +| WSO2 APK | [Authentication.Spec.Default.AuthTypes.MTLS](https://apk.docs.wso2.com/en/latest/catalogs/crds/authentication_types/#dp.wso2.com/v1alpha2.MutualSSLConfig) | Per API | Policy | +| Ingress-NGINX | [nginx.ingress.kubernetes.io/auth-tls-verify-client](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#client-certificate-authentication) | Per Ingress | Inline | ## References [TLS Handshake Protocol]: https://www.rfc-editor.org/rfc/rfc5246#section-7.4 [Certificate Path Validation]: https://www.rfc-editor.org/rfc/rfc5280#section-6 -[GatewayTLSConfig]: /references/spec/#gateway.networking.k8s.io/v1.GatewayTLSConfig [BackendTLSPolicy]: ../../api-types/backendtlspolicy.md [TLS Configuration GEP]: ../gep-2907/index.md [Gateway API TLS Use Cases]: https://docs.google.com/document/d/17sctu2uMJtHmJTGtBi_awGB0YzoCLodtR6rUNmKMCs8/edit?pli=1#heading=h.cxuq8vo8pcxm +[GEP-3567]: https://gateway-api.sigs.k8s.io/geps/gep-3567/ diff --git a/geps/gep-995/index.md b/geps/gep-995/index.md index 6236d1a279..25c40c747f 100644 --- a/geps/gep-995/index.md +++ b/geps/gep-995/index.md @@ -1,7 +1,7 @@ # GEP-995: Named route rules * Issue: [#995](https://github.com/kubernetes-sigs/gateway-api/issues/995) -* Status: Experimental +* Status: Standard ## TLDR @@ -9,7 +9,7 @@ Add a new optional `name` field to the route rule types ([GRPCRouteRule](../../r ## Goals -* Support referencing individual route rules by name from other resources, such as from metaresources ([GEP-2648](../gep-2648/index.md#apply-policies-to-sections-of-a-resource).) +* Support referencing individual route rules by name from other resources, such as from metaresources ([GEP-2648](../gep-2648/index.md#section-names).) * Support referencing individual route rules by name from condition messages propagated in the status stanza of route resources as suggested in https://github.com/kubernetes-sigs/gateway-api/issues/1696#issuecomment-1666258188. * Support referencing individual route rules by name at other observability and networking tools that are part of the ecosystem based on Gateway API. * Provide a rather intuitive API for users of Kubernetes who are familiar with the same pattern employed already by other kinds of resources where lists of complex elements can be declared – e.g. service [ports](https://kubernetes.io/docs/reference/kubernetes-api/service-resources/service-v1/#ServiceSpec), pod [containers](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#containers) and pod [volumes](https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#volumes). diff --git a/geps/gep-995/metadata.yaml b/geps/gep-995/metadata.yaml index 547d7bfdfa..2552744a95 100644 --- a/geps/gep-995/metadata.yaml +++ b/geps/gep-995/metadata.yaml @@ -2,7 +2,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 995 name: Named route rules -status: Experimental +status: Standard authors: - guicassolato changelog: diff --git a/geps/overview.md b/geps/overview.md index 808cdb0a80..d270e820a7 100644 --- a/geps/overview.md +++ b/geps/overview.md @@ -151,6 +151,8 @@ use the `experimental` Golang build tag to denote experimental functionality. Some other requirements must be met before marking a GEP `Experimental`: - the graduation criteria to reach `Standard` MUST be filled out +- the GEP must have at least one Feature Name for features described inside that + will need to be tested by conformance tests. - a proposed probationary period (see next section) must be included in the GEP and approved by maintainers. diff --git a/go.mod b/go.mod index 46c6618d28..bd1a6d9147 100644 --- a/go.mod +++ b/go.mod @@ -3,49 +3,48 @@ module sigs.k8s.io/gateway-api go 1.24.0 require ( - github.com/elastic/crd-ref-docs v0.1.0 - github.com/miekg/dns v1.1.65 - github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.39.0 - golang.org/x/sync v0.13.0 - google.golang.org/grpc v1.71.1 + github.com/elastic/crd-ref-docs v0.2.0 + github.com/miekg/dns v1.1.68 + github.com/stretchr/testify v1.11.0 + golang.org/x/net v0.43.0 + golang.org/x/sync v0.16.0 + google.golang.org/grpc v1.75.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 - google.golang.org/protobuf v1.36.6 - k8s.io/api v0.32.3 - k8s.io/apiextensions-apiserver v0.32.3 - k8s.io/apimachinery v0.32.3 - k8s.io/client-go v0.32.3 - k8s.io/code-generator v0.32.3 - k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f + google.golang.org/protobuf v1.36.7 + k8s.io/api v0.33.4 + k8s.io/apiextensions-apiserver v0.33.4 + k8s.io/apimachinery v0.33.4 + k8s.io/client-go v0.33.4 + k8s.io/code-generator v0.33.4 + k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 - sigs.k8s.io/controller-runtime v0.20.4 - sigs.k8s.io/controller-tools v0.17.3 + sigs.k8s.io/controller-runtime v0.21.0 + sigs.k8s.io/controller-tools v0.18.0 sigs.k8s.io/structured-merge-diff/v4 v4.7.0 - sigs.k8s.io/yaml v1.4.0 + sigs.k8s.io/yaml v1.5.0 ) require ( github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/emicklei/go-restful/v3 v3.12.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fatih/color v1.18.0 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect - github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/logr v1.4.3 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/gobuffalo/flect v1.0.3 // indirect - github.com/goccy/go-yaml v1.11.3 // indirect + github.com/goccy/go-yaml v1.18.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect - github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect - github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.1 // indirect + github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect github.com/huandu/xstrings v1.3.3 // indirect github.com/imdario/mergo v0.3.11 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect @@ -68,21 +67,23 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.37.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/oauth2 v0.25.0 // indirect - golang.org/x/sys v0.32.0 // indirect - golang.org/x/term v0.31.0 // indirect - golang.org/x/text v0.24.0 // indirect - golang.org/x/time v0.7.0 // indirect - golang.org/x/tools v0.30.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect + go.yaml.in/yaml/v2 v2.4.2 // indirect + golang.org/x/crypto v0.41.0 // indirect + golang.org/x/mod v0.26.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sys v0.35.0 // indirect + golang.org/x/term v0.34.0 // indirect + golang.org/x/text v0.28.0 // indirect + golang.org/x/time v0.9.0 // indirect + golang.org/x/tools v0.35.0 // indirect + golang.org/x/tools/go/expect v0.1.1-deprecated // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 // indirect + k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 // indirect k8s.io/klog/v2 v2.130.1 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect ) diff --git a/go.sum b/go.sum index 6c92e7ba96..4120b93f2a 100644 --- a/go.sum +++ b/go.sum @@ -6,13 +6,19 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/elastic/crd-ref-docs v0.1.0 h1:Cr5kz89QB3Iuuj7dhAfLMApCrChEGAaIBTxGk/xuRKw= -github.com/elastic/crd-ref-docs v0.1.0/go.mod h1:X83mMBdJt05heJUYiS3T0yJ/JkCuliuhSUNav5Gjo/U= +github.com/elastic/crd-ref-docs v0.2.0 h1:U17MyGX71j4qfKTvYxbR4qZGoA1hc2thy7kseGYmP+o= +github.com/elastic/crd-ref-docs v0.2.0/go.mod h1:0bklkJhTG7nC6AVsdDi0wt5bGoqvzdZSzMMQkilZ6XM= github.com/emicklei/go-restful/v3 v3.12.0 h1:y2DdzBAURM29NFF94q6RaY4vjIH1rtwDapwQtU84iWk= github.com/emicklei/go-restful/v3 v3.12.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/evanphx/json-patch/v5 v5.9.11 h1:/8HVnzMq13/3x9TPvjG08wUGqBTmZBsCWzjTM0wiaDU= @@ -23,8 +29,8 @@ github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nos github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= -github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= -github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/zapr v1.3.0 h1:XGdV8XW8zdwFiwOA2Dryh1gj2KRQyOOoNmBy4EplIcQ= @@ -35,36 +41,28 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE= github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE= -github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/gobuffalo/flect v1.0.3 h1:xeWBM2nui+qnVvNM4S3foBhCAL2XgPU+a7FdpelbTq4= github.com/gobuffalo/flect v1.0.3/go.mod h1:A5msMlrHtLqh9umBSnvabjsMrCcCpAyzglnDvkbYKHs= -github.com/goccy/go-yaml v1.11.3 h1:B3W9IdWbvrUu2OYQGwvU1nZtvMQJPBKgBUuweJjLj6I= -github.com/goccy/go-yaml v1.11.3/go.mod h1:wKnAMd44+9JAAnGQpWVEgBzGt3YuTaQ4uXoHvE4m7WU= +github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw= +github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= -github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo= +github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA= github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4= github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/imdario/mergo v0.3.11 h1:3tnifQM4i+fbajXKBHXWEH+KvNHqojZ778UH75j3bGA= @@ -81,8 +79,6 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= @@ -90,8 +86,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/miekg/dns v1.1.65 h1:0+tIPHzUW0GCge7IiK3guGP57VAw7hoPDfApjkMD1Fc= -github.com/miekg/dns v1.1.65/go.mod h1:Dzw9769uoKVaLuODMDZz9M6ynFU6Em65csPuoi8G0ck= +github.com/miekg/dns v1.1.68 h1:jsSRkNozw7G/mnmXULynzMNIsgY2dHC8LO6U6Ij2JEA= +github.com/miekg/dns v1.1.68/go.mod h1:fujopn7TB3Pu3JM69XaawiU0wqjpL9/8xGop5UrTPps= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= @@ -113,15 +109,23 @@ github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8= -github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY= +github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y= +github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q= +github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io= +github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= @@ -130,91 +134,103 @@ github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= -github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.11.0 h1:ib4sjIrwZKxE5u/Japgo/7SJV3PvgjGiRNAvTVGqQl8= +github.com/stretchr/testify v1.11.0/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= -go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= -go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= -go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= -go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= -go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= -go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= -go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= -go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= -go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= -go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI= +go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg= +go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc= +go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= +go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI= +go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU= +go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE= +go.yaml.in/yaml/v3 v3.0.3/go.mod h1:tBHosrYAkRZjRAOREWbDnBXUf08JOwYq++0QNwQiWzI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= +golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= -golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= -golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70= -golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= +golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= -golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= -golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI= +golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= +golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= +golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= +golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= +golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0= +golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw= +golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM= +golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM= +golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= -golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50= -google.golang.org/grpc v1.71.1 h1:ffsFWr7ygTUscGPI0KKK6TLrGz0476KUvvsbqWK0rPI= -google.golang.org/grpc v1.71.1/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= +gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= +gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7 h1:pFyd6EwwL2TqFf8emdthzeX+gZE1ElRq3iM8pui4KBY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250707201910-8d1bb00bc6a7/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.75.0 h1:+TW+dqTd2Biwe6KKfhE5JpiYIBWq865PhKGSXiivqt4= +google.golang.org/grpc v1.75.0/go.mod h1:JtPAzKiq4v1xcAB2hydNlWI2RnF85XXcV0mhKXr2ecQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 h1:F29+wU6Ee6qgu9TddPgooOdaqsxTMunOoj8KA5yuS5A= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1/go.mod h1:5KF+wpkbTSbGcR9zteSqZV6fqFOWBl4Yde8En8MryZA= -google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= -google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= +google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= @@ -230,33 +246,35 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= -k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= -k8s.io/apiextensions-apiserver v0.32.3 h1:4D8vy+9GWerlErCwVIbcQjsWunF9SUGNu7O7hiQTyPY= -k8s.io/apiextensions-apiserver v0.32.3/go.mod h1:8YwcvVRMVzw0r1Stc7XfGAzB/SIVLunqApySV5V7Dss= -k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= -k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= -k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= -k8s.io/code-generator v0.32.3 h1:31p2TVzC9+hVdSkAFruAk3JY+iSfzrJ83Qij1yZutyw= -k8s.io/code-generator v0.32.3/go.mod h1:+mbiYID5NLsBuqxjQTygKM/DAdKpAjvBzrJd64NU1G8= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9 h1:si3PfKm8dDYxgfbeA6orqrtLkvvIeH8UqffFJDl0bz4= -k8s.io/gengo/v2 v2.0.0-20240911193312-2b36238f13e9/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= +k8s.io/api v0.33.4 h1:oTzrFVNPXBjMu0IlpA2eDDIU49jsuEorGHB4cvKupkk= +k8s.io/api v0.33.4/go.mod h1:VHQZ4cuxQ9sCUMESJV5+Fe8bGnqAARZ08tSTdHWfeAc= +k8s.io/apiextensions-apiserver v0.33.4 h1:rtq5SeXiDbXmSwxsF0MLe2Mtv3SwprA6wp+5qh/CrOU= +k8s.io/apiextensions-apiserver v0.33.4/go.mod h1:mWXcZQkQV1GQyxeIjYApuqsn/081hhXPZwZ2URuJeSs= +k8s.io/apimachinery v0.33.4 h1:SOf/JW33TP0eppJMkIgQ+L6atlDiP/090oaX0y9pd9s= +k8s.io/apimachinery v0.33.4/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.4 h1:TNH+CSu8EmXfitntjUPwaKVPN0AYMbc9F1bBS8/ABpw= +k8s.io/client-go v0.33.4/go.mod h1:LsA0+hBG2DPwovjd931L/AoaezMPX9CmBgyVyBZmbCY= +k8s.io/code-generator v0.33.4 h1:DiA801QxqApRIBh3OWULasVAUA237XnYvFNMh+E34Y8= +k8s.io/code-generator v0.33.4/go.mod h1:ifWxKWhEl/Z1K7WmWAyOBEf3ex/i546ingCzLC8YVIY= +k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7 h1:2OX19X59HxDprNCVrWi6jb7LW1PoqTlYqEq5H2oetog= +k8s.io/gengo/v2 v2.0.0-20250207200755-1244d31929d7/go.mod h1:EJykeLsmFC60UQbYJezXkEsG2FLrt0GPNkU5iK5GWxU= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= -k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4= +k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff/go.mod h1:5jIi+8yX4RIb8wk3XwBo5Pq2ccx4FP10ohkbSKCZoK8= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.20.4 h1:X3c+Odnxz+iPTRobG4tp092+CvBU9UK0t/bRf+n0DGU= -sigs.k8s.io/controller-runtime v0.20.4/go.mod h1:xg2XB0K5ShQzAgsoujxuKN4LNXR2LfwwHsPj7Iaw+XY= -sigs.k8s.io/controller-tools v0.17.3 h1:lwFPLicpBKLgIepah+c8ikRBubFW5kOQyT88r3EwfNw= -sigs.k8s.io/controller-tools v0.17.3/go.mod h1:1ii+oXcYZkxcBXzwv3YZBlzjt1fvkrCGjVF73blosJI= +sigs.k8s.io/controller-runtime v0.21.0 h1:CYfjpEuicjUecRk+KAeyYh+ouUBn4llGyDYytIGcJS8= +sigs.k8s.io/controller-runtime v0.21.0/go.mod h1:OSg14+F65eWqIu4DceX7k/+QRAbTTvxeQSNSOQpukWM= +sigs.k8s.io/controller-tools v0.18.0 h1:rGxGZCZTV2wJreeRgqVoWab/mfcumTMmSwKzoM9xrsE= +sigs.k8s.io/controller-tools v0.18.0/go.mod h1:gLKoiGBriyNh+x1rWtUQnakUYEujErjXs9pf+x/8n1U= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016 h1:kXv6kKdoEtedwuqMmkqhbkgvYKeycVbC8+iPCP9j5kQ= sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= +sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU= +sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI= sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps= -sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= +sigs.k8s.io/yaml v1.5.0 h1:M10b2U7aEUY6hRtU870n2VTPgR5RZiL/I6Lcc2F4NUQ= +sigs.k8s.io/yaml v1.5.0/go.mod h1:wZs27Rbxoai4C0f8/9urLZtZtF3avA3gKvGyPdDqTO4= diff --git a/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-bad-http-path.yaml b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-bad-http-path.yaml new file mode 100644 index 0000000000..93ad3c98c9 --- /dev/null +++ b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-bad-http-path.yaml @@ -0,0 +1,12 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: invalid-filter-externalauth-empty +spec: + rules: + - filters: + - type: ExternalAuth + externalAuth: + protocol: HTTP + http: + path: /[] diff --git a/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-empty.yaml b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-empty.yaml new file mode 100644 index 0000000000..cba0c2b2bc --- /dev/null +++ b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-empty.yaml @@ -0,0 +1,8 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: invalid-filter-externalauth-empty +spec: + rules: + - filters: + - type: ExternalAuth diff --git a/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-no-protocol.yaml b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-no-protocol.yaml new file mode 100644 index 0000000000..96cc047e95 --- /dev/null +++ b/hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-no-protocol.yaml @@ -0,0 +1,9 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: HTTPRoute +metadata: + name: invalid-filter-externalauth-empty +spec: + rules: + - filters: + - type: ExternalAuth + externalAuth: {} diff --git a/hack/invalid-examples/experimental/tlsroute/no-hostname.yaml b/hack/invalid-examples/experimental/tlsroute/no-hostname.yaml new file mode 100644 index 0000000000..a2c137467d --- /dev/null +++ b/hack/invalid-examples/experimental/tlsroute/no-hostname.yaml @@ -0,0 +1,8 @@ +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: TLSRoute +metadata: + name: no-hostname +spec: + rules: + - backendRefs: + - name: foo diff --git a/hack/mkdocs-generate-conformance.py b/hack/mkdocs-generate-conformance.py index f24832af57..bec9ecdef1 100644 --- a/hack/mkdocs-generate-conformance.py +++ b/hack/mkdocs-generate-conformance.py @@ -21,10 +21,21 @@ from fnmatch import fnmatch import glob import os +import re log = logging.getLogger(f'mkdocs.plugins.{__name__}') +def process_feature_name(feature): + """ + Process feature names by splitting camelCase into space-separated words + """ + # Split camelCase + words = re.findall(r'HTTPRoute|[A-Z]+(?=[A-Z][a-z])|[A-Z][a-z]+|[A-Z\d]+', feature) + # Join words with spaces + return ' '.join(words) + + @plugins.event_priority(100) def on_files(files, config, **kwargs): log.info("generating conformance") @@ -47,6 +58,10 @@ def on_files(files, config, **kwargs): # Add the generated file to the site files.append(file) + # Write the generated file to the site-src directory + with open(os.path.join("site-src", file.src_uri), "w") as f: + f.write(file.content_string) + return files @@ -151,7 +166,9 @@ def generate_profiles_report(reports, route,version): for row in http_table.itertuples(): if type(row._4) is list: for feat in row._4: - http_table.loc[row.Index, feat] = ':white_check_mark:' + # Process feature name before using it as a column + processed_feat = process_feature_name(feat) + http_table.loc[row.Index, processed_feat] = ':white_check_mark:' http_table = http_table.fillna(':x:') http_table = http_table.drop(['extended.supportedFeatures'], axis=1) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 6164a48242..940b186b39 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -10,14 +10,14 @@ MarkupSafe==3.0.2 mkdocs==1.6.1 mkdocs-awesome-pages-plugin==2.10.1 mkdocs-macros-plugin==1.3.7 -mkdocs-material==9.6.11 +mkdocs-material==9.6.18 mkdocs-redirects==1.2.2 mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 pep562==1.1 -Pygments==2.19.1 -pymdown-extensions==10.14.3 +Pygments==2.19.2 +pymdown-extensions==10.16.1 PyYAML==6.0.2 six==1.17.0 tabulate==0.9.0 -tornado==6.4.2 \ No newline at end of file +tornado==6.5.2 \ No newline at end of file diff --git a/hack/test-crds-validation.sh b/hack/test-crds-validation.sh deleted file mode 100755 index 8f3da81db0..0000000000 --- a/hack/test-crds-validation.sh +++ /dev/null @@ -1,152 +0,0 @@ -#!/bin/bash - -# Copyright 2020 The Kubernetes Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -set -o nounset -set -o pipefail - -readonly GO111MODULE="on" -readonly GOFLAGS="-mod=readonly" -readonly GOPATH="$(mktemp -d)" -readonly CLUSTER_NAME="verify-gateway-api" - -export KUBECONFIG="${GOPATH}/.kubeconfig" -export GOFLAGS GO111MODULE GOPATH -export PATH="${GOPATH}/bin:${PATH}" - -# Cleanup logic for cleanup on exit -CLEANED_UP=false -cleanup() { - if [ "$CLEANED_UP" = "true" ]; then - return - fi - - if [ "${KIND_CREATE_ATTEMPTED:-}" = true ]; then - kind delete cluster --name "${CLUSTER_NAME}" || true - fi - CLEANED_UP=true -} - -trap cleanup INT TERM EXIT - -# TODO(mlavacca): find a good way to keep this dependency up to date. -KIND_VERSION="v0.26.0" - -# list of kind images taken from https://github.com/kubernetes-sigs/kind/releases/tag/v0.26.0. -# they need to be updated when kind is updated. -KIND_IMAGES=( - "kindest/node:v1.28.15@sha256:a7c05c7ae043a0b8c818f5a06188bc2c4098f6cb59ca7d1856df00375d839251" - "kindest/node:v1.29.12@sha256:62c0672ba99a4afd7396512848d6fc382906b8f33349ae68fb1dbfe549f70dec" - "kindest/node:v1.30.8@sha256:17cd608b3971338d9180b00776cb766c50d0a0b6b904ab4ff52fd3fc5c6369bf" - "kindest/node:v1.31.4@sha256:2cb39f7295fe7eafee0842b1052a599a4fb0f8bcf3f83d96c7f4864c357c6c30" - "kindest/node:v1.32.0@sha256:2458b423d635d7b01637cac2d6de7e1c1dca1148a2ba2e90975e214ca849e7cb" -) - -if [ "$#" -gt 1 ]; then - echo "Error: Too many arguments provided. Only 1 argument is allowed." - exit 1 -fi - -DEFAULT_INDEX=$((1)) - -if [ "$#" -eq 1 ]; then - # Check if the argument is a valid number between 1 and 5 - if ! [[ "$1" =~ ^[1-5] ]]; then - echo "Error: Argument is not a valid integer between 1 and 5." - exit 1 - fi - INDEX=$(($1)) -else - INDEX=$((DEFAULT_INDEX)) -fi - -K8S_IMAGE=${KIND_IMAGES[$((INDEX-1))]} -echo "Using Kubernetes image: ${K8S_IMAGE}" - -# For exit code -res=0 - -# Install kind -(cd "${GOPATH}" && go install sigs.k8s.io/kind@${KIND_VERSION}) || res=$? - -# Create cluster -KIND_CREATE_ATTEMPTED=true -kind create cluster --name "${CLUSTER_NAME}" --image "${K8S_IMAGE}" || res=$? - -# Verify CEL validation -for CHANNEL in experimental standard; do - # Install CRDs. - kubectl apply -f "config/crd/${CHANNEL}/gateway*.yaml" - - # Run tests. - go test -v -timeout=120s -count=1 --tags ${CHANNEL} sigs.k8s.io/gateway-api/pkg/test/cel || res=$? - - # Delete CRDs to reset environment. - kubectl delete -f "config/crd/${CHANNEL}/gateway*.yaml" -done - -# Temporary workaround for https://github.com/kubernetes/kubernetes/issues/104090 -sleep 8 - -## Validate example YAMLs for each channel - -for CHANNEL in experimental standard; do - ##### Test valid CRD apply and that invalid examples are invalid. - # Install CRDs - kubectl apply -f "config/crd/${CHANNEL}/gateway*.yaml" || res=$? - - # Temporary workaround for https://github.com/kubernetes/kubernetes/issues/104090 - sleep 8 - - kubectl apply --recursive -f examples/standard || res=$? - - # Install all experimental example gateway-api resources when experimental mode is enabled - if [[ "${CHANNEL}" == "experimental" ]]; then - echo "Experimental mode enabled: deploying experimental examples" - kubectl apply --recursive -f examples/experimental || res=$? - fi - - # Find all our invalid examples and check them one by one. - # This lets us check the output in a cleaner way than a grep pipeline. - for file in $(find hack/invalid-examples -name "*.yaml"); do - # Don't check alpha resources in Standard checks - if [[ "$file" =~ "experimental" && "$CHANNEL" == "standard" ]]; then - continue - fi - - KUBECTL_OUTPUT=$(kubectl apply -f "$file" 2>&1) - - if [[ \ - ! ("$KUBECTL_OUTPUT" =~ "is invalid") && \ - ! ("$KUBECTL_OUTPUT" =~ "missing required field") && \ - ! ("$KUBECTL_OUTPUT" =~ "denied the request") && \ - ! ("$KUBECTL_OUTPUT" =~ "Invalid value") \ - ]]; then - res=2 - cat< ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -3012,6 +3068,26 @@ func schema_sigsk8sio_gateway_api_apis_v1_CookieConfig(ref common.ReferenceCallb } } +func schema_sigsk8sio_gateway_api_apis_v1_ForwardBodyConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "ForwardBody configures if requests to the authorization server should include the body of the client request; and if so, how big that body is allowed to be.\n\nIf empty or unset, do not forward the body.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "maxSize": { + SchemaProps: spec.SchemaProps{ + Description: "MaxSize specifies how large in bytes the largest body that will be buffered and sent to the authorization server. If the body size is larger than `maxSize`, then the body sent to the authorization server must be truncated to `maxSize` bytes.\n\nExperimental note: This behavior needs to be checked against various dataplanes; it may need to be changed. See https://github.com/kubernetes-sigs/gateway-api/pull/4001#discussion_r2291405746 for more.\n\nIf 0, the body will not be sent to the authorization server.", + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + }, + }, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3038,6 +3114,51 @@ func schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref common.ReferenceCallback) } } +func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "FrontendTLSConfig specifies frontend tls configuration for gateway.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "default": { + SchemaProps: spec.SchemaProps{ + Description: "Default specifies the default client certificate validation configuration for all Listeners handling HTTPS traffic, unless a per-port configuration is defined.\n\nsupport: Core\n\n", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.TLSConfig"), + }, + }, + "perPort": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-map-keys": []interface{}{ + "port", + }, + "x-kubernetes-list-type": "map", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "PerPort specifies tls configuration assigned per port. Per port configuration is optional. Once set this configuration overrides the default configuration for all Listeners handling HTTPS traffic that match this port. Each override port requires a unique TLS configuration.\n\nsupport: Core\n\n", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig"), + }, + }, + }, + }, + }, + }, + Required: []string{"default"}, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.TLSConfig", "sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig"}, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3046,8 +3167,13 @@ func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.Refer Type: []string{"object"}, Properties: map[string]spec.Schema{ "caCertificateRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "CACertificateRefs contains one or more references to Kubernetes objects that contain TLS certificates of the Certificate Authorities that can be used as a trust anchor to validate the certificates presented by the client.\n\nA single CA certificate reference to a Kubernetes ConfigMap has \"Core\" support. Implementations MAY choose to support attaching multiple CA certificates to a Listener, but this behavior is implementation-specific.\n\nSupport: Core - A single reference to a Kubernetes ConfigMap with the CA certificate in a key named `ca.crt`.\n\nSupport: Implementation-specific (More than one reference, or other kinds of resources).\n\nReferences to a resource in a different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.", + Description: "CACertificateRefs contains one or more references to Kubernetes objects that contain TLS certificates of the Certificate Authorities that can be used as a trust anchor to validate the certificates presented by the client.\n\nA single CA certificate reference to a Kubernetes ConfigMap has \"Core\" support. Implementations MAY choose to support attaching multiple CA certificates to a Listener, but this behavior is implementation-specific.\n\nSupport: Core - A single reference to a Kubernetes ConfigMap with the CA certificate in a key named `ca.crt`.\n\nSupport: Implementation-specific (More than one certificate in a ConfigMap with different keys or more than one reference, or other kinds of resources).\n\nReferences to a resource in a different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3059,7 +3185,15 @@ func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.Refer }, }, }, + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "FrontendValidationMode defines the mode for validating the client certificate. There are two possible modes:\n\n- AllowValidOnly: In this mode, the gateway will accept connections only if\n the client presents a valid certificate. This certificate must successfully\n pass validation against the CA certificates specified in `CACertificateRefs`.\n- AllowInsecureFallback: In this mode, the gateway will accept connections\n even if the client certificate is not presented or fails verification.\n\n This approach delegates client authorization to the backend and introduce\n a significant security risk. It should be used in testing environments or\n on a temporary basis in non-testing environments.\n\nDefaults to AllowValidOnly.\n\nSupport: Core", + Type: []string{"string"}, + Format: "", + }, + }, }, + Required: []string{"caCertificateRefs"}, }, }, Dependencies: []string{ @@ -3067,6 +3201,39 @@ func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.Refer } } +func schema_sigsk8sio_gateway_api_apis_v1_GRPCAuthConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "GRPCAuthConfig contains configuration for communication with Auth server backends that speak Envoy's ext_authz gRPC protocol.\n\nRequests and responses are defined in the protobufs explained at: https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "allowedHeaders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "AllowedRequestHeaders specifies what headers from the client request will be sent to the authorization server.\n\nIf this list is empty, then the following headers must be sent:\n\n- `Authorization` - `Location` - `Proxy-Authenticate` - `Set-Cookie` - `WWW-Authenticate`\n\nIf the list has entries, only those entries must be sent.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_GRPCBackendRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -3118,6 +3285,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCBackendRef(ref common.ReferenceCal }, }, "filters": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Filters defined at this level MUST be executed if and only if the request is being forwarded to the backend defined here.\n\nSupport: Implementation-specific (For broader support of filters, use the Filters field in GRPCRouteRule.)", Type: []string{"array"}, @@ -3253,6 +3425,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRoute(ref common.ReferenceCallback }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ @@ -3409,12 +3582,17 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteRule(ref common.ReferenceCall Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "Name is the name of the route rule. This name MUST be unique within a Route if it is set.\n\nSupport: Extended ", + Description: "Name is the name of the route rule. This name MUST be unique within a Route if it is set.\n\nSupport: Extended", Type: []string{"string"}, Format: "", }, }, "matches": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Matches define conditions used for matching the rule against incoming gRPC requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied.\n\nFor example, take the following matches configuration:\n\n``` matches: - method:\n service: foo.bar\n headers:\n values:\n version: 2\n- method:\n service: foo.bar.v2\n```\n\nFor a request to match against this rule, it MUST satisfy EITHER of the two conditions:\n\n- service of foo.bar AND contains the header `version: 2` - service of foo.bar.v2\n\nSee the documentation for GRPCRouteMatch on how to specify multiple match conditions to be ANDed together.\n\nIf no matches are specified, the implementation MUST match every gRPC request.\n\nProxy or Load Balancer routing configuration generated from GRPCRoutes MUST prioritize rules based on the following criteria, continuing on ties. Merging MUST not be done between GRPCRoutes and HTTPRoutes. Precedence MUST be given to the rule with the largest number of:\n\n* Characters in a matching non-wildcard hostname. * Characters in a matching hostname. * Characters in a matching service. * Characters in a matching method. * Header matches.\n\nIf ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties:\n\n* The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by\n \"{namespace}/{name}\".\n\nIf ties still exist within the Route that has been given precedence, matching precedence MUST be granted to the first matching rule meeting the above criteria.", Type: []string{"array"}, @@ -3429,6 +3607,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteRule(ref common.ReferenceCall }, }, "filters": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Filters define the filters that are applied to requests that match this rule.\n\nThe effects of ordering of multiple behaviors are currently unspecified. This can change in the future based on feedback during the alpha stage.\n\nConformance-levels at this level are defined based on the type of filter:\n\n- ALL core filters MUST be supported by all implementations that support\n GRPCRoute.\n- Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across\n implementations.\n\nSpecifying the same filter multiple times is not supported unless explicitly indicated in the filter.\n\nIf an implementation cannot support a combination of filters, it must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to be set to status `False`, implementations may use the `IncompatibleFilters` reason to specify this configuration error.\n\nSupport: Core", Type: []string{"array"}, @@ -3443,6 +3626,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteRule(ref common.ReferenceCall }, }, "backendRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "BackendRefs defines the backend(s) where matching requests should be sent.\n\nFailure behavior here depends on how many BackendRefs are specified and how many are invalid.\n\nIf *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive an `UNAVAILABLE` status.\n\nSee the GRPCBackendRef definition for the rules about what makes a single GRPCBackendRef invalid.\n\nWhen a GRPCBackendRef is invalid, `UNAVAILABLE` statuses MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive an `UNAVAILABLE` status.\n\nFor example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic MUST receive an `UNAVAILABLE` status. Implementations may choose how that 50 percent is determined.\n\nSupport: Core for Kubernetes Service\n\nSupport: Implementation-specific for any other resource\n\nSupport for weight: Core", Type: []string{"array"}, @@ -3478,6 +3666,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteSpec(ref common.ReferenceCall Type: []string{"object"}, Properties: map[string]spec.Schema{ "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -3492,6 +3685,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteSpec(ref common.ReferenceCall }, }, "hostnames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Hostnames defines a set of hostnames to match against the GRPC Host header to select a GRPCRoute to process the request. This matches the RFC 1123 definition of a hostname with 2 notable exceptions:\n\n1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard\n label MUST appear by itself as the first label.\n\nIf a hostname is specified by both the Listener and GRPCRoute, there MUST be at least one intersecting hostname for the GRPCRoute to be attached to the Listener. For example:\n\n* A Listener with `test.example.com` as the hostname matches GRPCRoutes\n that have either not specified any hostnames, or have specified at\n least one of `test.example.com` or `*.example.com`.\n* A Listener with `*.example.com` as the hostname matches GRPCRoutes\n that have either not specified any hostnames or have specified at least\n one hostname that matches the Listener hostname. For example,\n `test.example.com` and `*.example.com` would both match. On the other\n hand, `example.com` and `test.example.net` would not match.\n\nHostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`.\n\nIf both the Listener and GRPCRoute have specified hostnames, any GRPCRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the GRPCRoute specified `test.example.com` and `test.example.net`, `test.example.net` MUST NOT be considered for a match.\n\nIf both the Listener and GRPCRoute have specified hostnames, and none match with the criteria above, then the GRPCRoute MUST NOT be accepted by the implementation. The implementation MUST raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus.\n\nIf a Route (A) of type HTTPRoute or GRPCRoute is attached to a Listener and that listener already has another Route (B) of the other type attached and the intersection of the hostnames of A and B is non-empty, then the implementation MUST accept exactly one of these two routes, determined by the following criteria, in order:\n\n* The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by\n \"{namespace}/{name}\".\n\nThe rejected Route MUST raise an 'Accepted' condition with a status of 'False' in the corresponding RouteParentStatus.\n\nSupport: Core", Type: []string{"array"}, @@ -3507,6 +3705,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteSpec(ref common.ReferenceCall }, }, "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Rules are a list of GRPC matchers, filters and actions.\n\n", Type: []string{"array"}, @@ -3536,8 +3739,13 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteStatus(ref common.ReferenceCa Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3617,7 +3825,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayBackendTLS(ref common.Reference Properties: map[string]spec.Schema{ "clientCertificateRef": { SchemaProps: spec.SchemaProps{ - Description: "ClientCertificateRef is a reference to an object that contains a Client Certificate and the associated private key.\n\nReferences to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.\n\nClientCertificateRef can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources.\n\nThis setting can be overridden on the service level by use of BackendTLSPolicy.\n\nSupport: Core\n\n", + Description: "ClientCertificateRef is a reference to an object that contains a Client Certificate and the associated private key.\n\nReferences to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.\n\nClientCertificateRef can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources.\n\nSupport: Core\n\n", Ref: ref("sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"), }, }, @@ -3782,7 +3990,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayClassStatus(ref common.Referenc }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions is the current status from the controller for this GatewayClass.\n\nControllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition.", + Description: "Conditions is the current status from the controller for this GatewayClass.\n\nControllers should prefer to publish conditions using values of GatewayClassConditionType for the type of each Condition.\n\n Notes for implementors:\n\nConditions are a listType `map`, which means that they function like a map with a key of the `type` field _in the k8s apiserver_.\n\nThis means that implementations must obey some rules when updating this section.\n\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n* Implementations MUST NOT remove or reorder Conditions that they are not\n directly responsible for. For example, if an implementation sees a Condition\n with type `special.io/SomeField`, it MUST NOT remove, change or update that\n Condition.\n* Implementations MUST always _merge_ changes into Conditions of the same Type,\n rather than creating more than one Condition of the same Type.\n* Implementations MUST always update the `observedGeneration` field of the\n Condition to the `metadata.generation` of the Gateway at the time of update creation.\n* If the `observedGeneration` of a Condition is _greater than_ the value the\n implementation knows about, then it MUST NOT perform the update on that Condition,\n but must wait for a future reconciliation and status update. (The assumption is that\n the implementation's copy of the object is stale and an update will be re-triggered\n if relevant.)\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -3963,6 +4171,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpec(ref common.ReferenceCallba }, }, "addresses": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Addresses requested for this Gateway. This is optional and behavior can depend on the implementation. If a value is set in the spec and the requested address is invalid or unavailable, the implementation MUST indicate this in the associated entry in GatewayStatus.Addresses.\n\nThe Addresses field represents a request for the address(es) on the \"outside of the Gateway\", that traffic bound for this Gateway will use. This could be the IP address or hostname of an external load balancer or other networking infrastructure, or some other address that traffic will be sent to.\n\nIf no Addresses are specified, the implementation MAY schedule the Gateway in an implementation-specific manner, assigning an appropriate set of Addresses.\n\nThe implementation MUST bind all Listeners to every GatewayAddress that it assigns to the Gateway and add a corresponding entry in GatewayStatus.Addresses.\n\nSupport: Extended\n\n", Type: []string{"array"}, @@ -3982,24 +4195,24 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpec(ref common.ReferenceCallba Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayInfrastructure"), }, }, - "backendTLS": { - SchemaProps: spec.SchemaProps{ - Description: "BackendTLS configures TLS settings for when this Gateway is connecting to backends with TLS.\n\nSupport: Core\n\n", - Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayBackendTLS"), - }, - }, "allowedListeners": { SchemaProps: spec.SchemaProps{ Description: "AllowedListeners defines which ListenerSets can be attached to this Gateway. While this feature is experimental, the default value is to allow no ListenerSets.\n\n", Ref: ref("sigs.k8s.io/gateway-api/apis/v1.AllowedListeners"), }, }, + "tls": { + SchemaProps: spec.SchemaProps{ + Description: "TLS specifies frontend and backend tls configuration for entire gateway.\n\nSupport: Extended\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig"), + }, + }, }, Required: []string{"gatewayClassName", "listeners"}, }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.AllowedListeners", "sigs.k8s.io/gateway-api/apis/v1.GatewayBackendTLS", "sigs.k8s.io/gateway-api/apis/v1.GatewayInfrastructure", "sigs.k8s.io/gateway-api/apis/v1.GatewaySpecAddress", "sigs.k8s.io/gateway-api/apis/v1.Listener"}, + "sigs.k8s.io/gateway-api/apis/v1.AllowedListeners", "sigs.k8s.io/gateway-api/apis/v1.GatewayInfrastructure", "sigs.k8s.io/gateway-api/apis/v1.GatewaySpecAddress", "sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig", "sigs.k8s.io/gateway-api/apis/v1.Listener"}, } } @@ -4007,7 +4220,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpecAddress(ref common.Referenc return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "GatewayAddress describes an address that can be bound to a Gateway.", + Description: "GatewaySpecAddress describes an address that can be bound to a Gateway.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "type": { @@ -4038,6 +4251,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayStatus(ref common.ReferenceCall Type: []string{"object"}, Properties: map[string]spec.Schema{ "addresses": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Addresses lists the network addresses that have been bound to the Gateway.\n\nThis list may differ from the addresses provided in the spec under some conditions:\n\n * no addresses are specified, all addresses are dynamically assigned\n * a combination of specified and dynamic addresses are assigned\n * a specified address was unusable (e.g. already in use)\n\n", Type: []string{"array"}, @@ -4061,7 +4279,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayStatus(ref common.ReferenceCall }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions describe the current conditions of the Gateway.\n\nImplementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state.\n\nKnown condition types are:\n\n* \"Accepted\" * \"Programmed\" * \"Ready\"", + Description: "Conditions describe the current conditions of the Gateway.\n\nImplementations should prefer to express Gateway conditions using the `GatewayConditionType` and `GatewayConditionReason` constants so that operators and tools can converge on a common vocabulary to describe Gateway state.\n\nKnown condition types are:\n\n* \"Accepted\" * \"Programmed\" * \"Ready\"\n\n Notes for implementors:\n\nConditions are a listType `map`, which means that they function like a map with a key of the `type` field _in the k8s apiserver_.\n\nThis means that implementations must obey some rules when updating this section.\n\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n* Implementations MUST NOT remove or reorder Conditions that they are not\n directly responsible for. For example, if an implementation sees a Condition\n with type `special.io/SomeField`, it MUST NOT remove, change or update that\n Condition.\n* Implementations MUST always _merge_ changes into Conditions of the same Type,\n rather than creating more than one Condition of the same Type.\n* Implementations MUST always update the `observedGeneration` field of the\n Condition to the `metadata.generation` of the Gateway at the time of update creation.\n* If the `observedGeneration` of a Condition is _greater than_ the value the\n implementation knows about, then it MUST NOT perform the update on that Condition,\n but must wait for a future reconciliation and status update. (The assumption is that\n the implementation's copy of the object is stale and an update will be re-triggered\n if relevant.)\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4136,41 +4354,73 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref common.ReferenceC return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Type: []string{"object"}, + Description: "GatewayTLSConfig specifies frontend and backend tls configuration for gateway.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "mode": { + "backend": { SchemaProps: spec.SchemaProps{ - Description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes:\n\n- Terminate: The TLS session between the downstream client and the\n Gateway is terminated at the Gateway. This mode requires certificates\n to be specified in some way, such as populating the certificateRefs\n field.\n- Passthrough: The TLS session is NOT terminated by the Gateway. This\n implies that the Gateway can't decipher the TLS stream except for\n the ClientHello message of the TLS protocol. The certificateRefs field\n is ignored in this mode.\n\nSupport: Core", + Description: "Backend describes TLS configuration for gateway when connecting to backends.\n\nNote that this contains only details for the Gateway as a TLS client, and does _not_ imply behavior about how to choose which backend should get a TLS connection. That is determined by the presence of a BackendTLSPolicy.\n\nSupport: Core\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayBackendTLS"), + }, + }, + "frontend": { + SchemaProps: spec.SchemaProps{ + Description: "Frontend describes TLS config when client connects to Gateway. Support: Core\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.FrontendTLSConfig"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSConfig", "sigs.k8s.io/gateway-api/apis/v1.GatewayBackendTLS"}, + } +} + +func schema_sigsk8sio_gateway_api_apis_v1_HTTPAuthConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HTTPAuthConfig contains configuration for communication with HTTP-speaking backends.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "path": { + SchemaProps: spec.SchemaProps{ + Description: "Path sets the prefix that paths from the client request will have added when forwarded to the authorization server.\n\nWhen empty or unspecified, no prefix is added.\n\nValid values are the same as the \"value\" regex for path values in the `match` stanza, and the validation regex will screen out invalid paths in the same way. Even with the validation, implementations MUST sanitize this input before using it directly.", Type: []string{"string"}, Format: "", }, }, - "certificateRefs": { + "allowedHeaders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener.\n\nA single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific.\n\nReferences to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.\n\nThis field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise.\n\nCertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources.\n\nSupport: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls\n\nSupport: Implementation-specific (More than one reference or other resource types)", + Description: "AllowedRequestHeaders specifies what additional headers from the client request will be sent to the authorization server.\n\nThe following headers must always be sent to the authorization server, regardless of this setting:\n\n* `Host` * `Method` * `Path` * `Content-Length` * `Authorization`\n\nIf this list is empty, then only those headers must be sent.\n\nNote that `Content-Length` has a special behavior, in that the length sent must be correct for the actual request to the external authorization server - that is, it must reflect the actual number of bytes sent in the body of the request to the authorization server.\n\nSo if the `forwardBody` stanza is unset, or `forwardBody.maxSize` is set to `0`, then `Content-Length` must be `0`. If `forwardBody.maxSize` is set to anything other than `0`, then the `Content-Length` of the authorization request must be set to the actual number of bytes forwarded.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ - Default: map[string]interface{}{}, - Ref: ref("sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"), + Default: "", + Type: []string{"string"}, + Format: "", }, }, }, }, }, - "frontendValidation": { - SchemaProps: spec.SchemaProps{ - Description: "FrontendValidation holds configuration information for validating the frontend (client). Setting this field will require clients to send a client certificate required for validation during the TLS handshake. In browsers this may result in a dialog appearing that requests a user to specify the client certificate. The maximum depth of a certificate chain accepted in verification is Implementation specific.\n\nSupport: Extended\n\n", - Ref: ref("sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation"), + "allowedResponseHeaders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, }, - }, - "options": { SchemaProps: spec.SchemaProps{ - Description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites.\n\nA set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API.\n\nSupport: Implementation-specific", - Type: []string{"object"}, - AdditionalProperties: &spec.SchemaOrBool{ - Allows: true, + Description: "AllowedResponseHeaders specifies what headers from the authorization response will be copied into the request to the backend.\n\nIf this list is empty, then all headers from the authorization server except Authority or Host must be copied.", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ SchemaProps: spec.SchemaProps{ Default: "", @@ -4184,8 +4434,6 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref common.ReferenceC }, }, }, - Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation", "sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"}, } } @@ -4240,6 +4488,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPBackendRef(ref common.ReferenceCal }, }, "filters": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Filters defined at this level should be executed if and only if the request is being forwarded to the backend defined here.\n\nSupport: Implementation-specific (For broader support of filters, use the Filters field in HTTPRouteRule.)", Type: []string{"array"}, @@ -4276,7 +4529,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "AllowOrigins indicates whether the response can be shared with requested resource from the given `Origin`.\n\nThe `Origin` consists of a scheme and a host, with an optional port, and takes the form `://(:)`.\n\nValid values for scheme are: `http` and `https`.\n\nValid values for port are any integer between 1 and 65535 (the list of available TCP/UDP ports). Note that, if not included, port `80` is assumed for `http` scheme origins, and port `443` is assumed for `https` origins. This may affect origin matching.\n\nThe host part of the origin may contain the wildcard character `*`. These wildcard characters behave as follows:\n\n* `*` is a greedy match to the _left_, including any number of\n DNS labels to the left of its position. This also means that\n `*` will include any number of period `.` characters to the\n left of its position.\n* A wildcard by itself matches all hosts.\n\nAn origin value that includes _only_ the `*` character indicates requests from all `Origin`s are allowed.\n\nWhen the `AllowOrigins` field is configured with multiple origins, it means the server supports clients from multiple origins. If the request `Origin` matches the configured allowed origins, the gateway must return the given `Origin` and sets value of the header `Access-Control-Allow-Origin` same as the `Origin` header provided by the client.\n\nThe status code of a successful response to a \"preflight\" request is always an OK status (i.e., 204 or 200).\n\nIf the request `Origin` does not match the configured allowed origins, the gateway returns 204/200 response but doesn't set the relevant cross-origin response headers. Alternatively, the gateway responds with 403 status to the \"preflight\" request is denied, coupled with omitting the CORS headers. The cross-origin request fails on the client side. Therefore, the client doesn't attempt the actual cross-origin request.\n\nThe `Access-Control-Allow-Origin` response header can only use `*` wildcard as value when the `AllowCredentials` field is unspecified.\n\nWhen the `AllowCredentials` field is specified and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header `Access-Control-Allow-Origin` is same as the `Origin` header provided by the client.\n\nSupport: Extended", + Description: "AllowOrigins indicates whether the response can be shared with requested resource from the given `Origin`.\n\nThe `Origin` consists of a scheme and a host, with an optional port, and takes the form `://(:)`.\n\nValid values for scheme are: `http` and `https`.\n\nValid values for port are any integer between 1 and 65535 (the list of available TCP/UDP ports). Note that, if not included, port `80` is assumed for `http` scheme origins, and port `443` is assumed for `https` origins. This may affect origin matching.\n\nThe host part of the origin may contain the wildcard character `*`. These wildcard characters behave as follows:\n\n* `*` is a greedy match to the _left_, including any number of\n DNS labels to the left of its position. This also means that\n `*` will include any number of period `.` characters to the\n left of its position.\n* A wildcard by itself matches all hosts.\n\nAn origin value that includes _only_ the `*` character indicates requests from all `Origin`s are allowed.\n\nWhen the `AllowOrigins` field is configured with multiple origins, it means the server supports clients from multiple origins. If the request `Origin` matches the configured allowed origins, the gateway must return the given `Origin` and sets value of the header `Access-Control-Allow-Origin` same as the `Origin` header provided by the client.\n\nThe status code of a successful response to a \"preflight\" request is always an OK status (i.e., 204 or 200).\n\nIf the request `Origin` does not match the configured allowed origins, the gateway returns 204/200 response but doesn't set the relevant cross-origin response headers. Alternatively, the gateway responds with 403 status to the \"preflight\" request is denied, coupled with omitting the CORS headers. The cross-origin request fails on the client side. Therefore, the client doesn't attempt the actual cross-origin request.\n\nThe `Access-Control-Allow-Origin` response header can only use `*` wildcard as value when the `AllowCredentials` field is false or omitted.\n\nWhen the `AllowCredentials` field is true and `AllowOrigins` field specified with the `*` wildcard, the gateway must return a single origin in the value of the `Access-Control-Allow-Origin` response header, instead of specifying the `*` wildcard. The value of the header `Access-Control-Allow-Origin` is same as the `Origin` header provided by the client.\n\nSupport: Extended", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4291,7 +4544,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal }, "allowCredentials": { SchemaProps: spec.SchemaProps{ - Description: "AllowCredentials indicates whether the actual cross-origin request allows to include credentials.\n\nThe only valid value for the `Access-Control-Allow-Credentials` response header is true (case-sensitive).\n\nIf the credentials are not allowed in cross-origin requests, the gateway will omit the header `Access-Control-Allow-Credentials` entirely rather than setting its value to false.\n\nSupport: Extended", + Description: "AllowCredentials indicates whether the actual cross-origin request allows to include credentials.\n\nWhen set to true, the gateway will include the `Access-Control-Allow-Credentials` response header with value true (case-sensitive).\n\nWhen set to false or omitted the gateway will omit the header `Access-Control-Allow-Credentials` entirely (this is the standard CORS behavior).\n\nSupport: Extended", Type: []string{"boolean"}, Format: "", }, @@ -4303,7 +4556,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "AllowMethods indicates which HTTP methods are supported for accessing the requested resource.\n\nValid values are any method defined by RFC9110, along with the special value `*`, which represents all HTTP methods are allowed.\n\nMethod names are case sensitive, so these values are also case-sensitive. (See https://www.rfc-editor.org/rfc/rfc2616#section-5.1.1)\n\nMultiple method names in the value of the `Access-Control-Allow-Methods` response header are separated by a comma (\",\").\n\nA CORS-safelisted method is a method that is `GET`, `HEAD`, or `POST`. (See https://fetch.spec.whatwg.org/#cors-safelisted-method) The CORS-safelisted methods are always allowed, regardless of whether they are specified in the `AllowMethods` field.\n\nWhen the `AllowMethods` field is configured with one or more methods, the gateway must return the `Access-Control-Allow-Methods` response header which value is present in the `AllowMethods` field.\n\nIf the HTTP method of the `Access-Control-Request-Method` request header is not included in the list of methods specified by the response header `Access-Control-Allow-Methods`, it will present an error on the client side.\n\nThe `Access-Control-Allow-Methods` response header can only use `*` wildcard as value when the `AllowCredentials` field is unspecified.\n\nWhen the `AllowCredentials` field is specified and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the `Access-Control-Request-Method` header provided by the client. If the header `Access-Control-Request-Method` is not included in the request, the gateway will omit the `Access-Control-Allow-Methods` response header, instead of specifying the `*` wildcard. A Gateway implementation may choose to add implementation-specific default methods.\n\nSupport: Extended", + Description: "AllowMethods indicates which HTTP methods are supported for accessing the requested resource.\n\nValid values are any method defined by RFC9110, along with the special value `*`, which represents all HTTP methods are allowed.\n\nMethod names are case sensitive, so these values are also case-sensitive. (See https://www.rfc-editor.org/rfc/rfc2616#section-5.1.1)\n\nMultiple method names in the value of the `Access-Control-Allow-Methods` response header are separated by a comma (\",\").\n\nA CORS-safelisted method is a method that is `GET`, `HEAD`, or `POST`. (See https://fetch.spec.whatwg.org/#cors-safelisted-method) The CORS-safelisted methods are always allowed, regardless of whether they are specified in the `AllowMethods` field.\n\nWhen the `AllowMethods` field is configured with one or more methods, the gateway must return the `Access-Control-Allow-Methods` response header which value is present in the `AllowMethods` field.\n\nIf the HTTP method of the `Access-Control-Request-Method` request header is not included in the list of methods specified by the response header `Access-Control-Allow-Methods`, it will present an error on the client side.\n\nThe `Access-Control-Allow-Methods` response header can only use `*` wildcard as value when the `AllowCredentials` field is false or omitted.\n\nWhen the `AllowCredentials` field is true and `AllowMethods` field specified with the `*` wildcard, the gateway must specify one HTTP method in the value of the Access-Control-Allow-Methods response header. The value of the header `Access-Control-Allow-Methods` is same as the `Access-Control-Request-Method` header provided by the client. If the header `Access-Control-Request-Method` is not included in the request, the gateway will omit the `Access-Control-Allow-Methods` response header, instead of specifying the `*` wildcard. A Gateway implementation may choose to add implementation-specific default methods.\n\nSupport: Extended", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4323,7 +4576,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "AllowHeaders indicates which HTTP request headers are supported for accessing the requested resource.\n\nHeader names are not case sensitive.\n\nMultiple header names in the value of the `Access-Control-Allow-Headers` response header are separated by a comma (\",\").\n\nWhen the `AllowHeaders` field is configured with one or more headers, the gateway must return the `Access-Control-Allow-Headers` response header which value is present in the `AllowHeaders` field.\n\nIf any header name in the `Access-Control-Request-Headers` request header is not included in the list of header names specified by the response header `Access-Control-Allow-Headers`, it will present an error on the client side.\n\nIf any header name in the `Access-Control-Allow-Headers` response header does not recognize by the client, it will also occur an error on the client side.\n\nA wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` wildcard as value when the `AllowCredentials` field is unspecified.\n\nWhen the `AllowCredentials` field is specified and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as the `Access-Control-Request-Headers` header provided by the client. If the header `Access-Control-Request-Headers` is not included in the request, the gateway will omit the `Access-Control-Allow-Headers` response header, instead of specifying the `*` wildcard. A Gateway implementation may choose to add implementation-specific default headers.\n\nSupport: Extended", + Description: "AllowHeaders indicates which HTTP request headers are supported for accessing the requested resource.\n\nHeader names are not case sensitive.\n\nMultiple header names in the value of the `Access-Control-Allow-Headers` response header are separated by a comma (\",\").\n\nWhen the `AllowHeaders` field is configured with one or more headers, the gateway must return the `Access-Control-Allow-Headers` response header which value is present in the `AllowHeaders` field.\n\nIf any header name in the `Access-Control-Request-Headers` request header is not included in the list of header names specified by the response header `Access-Control-Allow-Headers`, it will present an error on the client side.\n\nIf any header name in the `Access-Control-Allow-Headers` response header does not recognize by the client, it will also occur an error on the client side.\n\nA wildcard indicates that the requests with all HTTP headers are allowed. The `Access-Control-Allow-Headers` response header can only use `*` wildcard as value when the `AllowCredentials` field is false or omitted.\n\nWhen the `AllowCredentials` field is true and `AllowHeaders` field specified with the `*` wildcard, the gateway must specify one or more HTTP headers in the value of the `Access-Control-Allow-Headers` response header. The value of the header `Access-Control-Allow-Headers` is same as the `Access-Control-Request-Headers` header provided by the client. If the header `Access-Control-Request-Headers` is not included in the request, the gateway will omit the `Access-Control-Allow-Headers` response header, instead of specifying the `*` wildcard. A Gateway implementation may choose to add implementation-specific default headers.\n\nSupport: Extended", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4343,7 +4596,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "ExposeHeaders indicates which HTTP response headers can be exposed to client-side scripts in response to a cross-origin request.\n\nA CORS-safelisted response header is an HTTP header in a CORS response that it is considered safe to expose to the client scripts. The CORS-safelisted response headers include the following headers: `Cache-Control` `Content-Language` `Content-Length` `Content-Type` `Expires` `Last-Modified` `Pragma` (See https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name) The CORS-safelisted response headers are exposed to client by default.\n\nWhen an HTTP header name is specified using the `ExposeHeaders` field, this additional header will be exposed as part of the response to the client.\n\nHeader names are not case sensitive.\n\nMultiple header names in the value of the `Access-Control-Expose-Headers` response header are separated by a comma (\",\").\n\nA wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only use `*` wildcard as value when the `AllowCredentials` field is unspecified.\n\nSupport: Extended", + Description: "ExposeHeaders indicates which HTTP response headers can be exposed to client-side scripts in response to a cross-origin request.\n\nA CORS-safelisted response header is an HTTP header in a CORS response that it is considered safe to expose to the client scripts. The CORS-safelisted response headers include the following headers: `Cache-Control` `Content-Language` `Content-Length` `Content-Type` `Expires` `Last-Modified` `Pragma` (See https://fetch.spec.whatwg.org/#cors-safelisted-response-header-name) The CORS-safelisted response headers are exposed to client by default.\n\nWhen an HTTP header name is specified using the `ExposeHeaders` field, this additional header will be exposed as part of the response to the client.\n\nHeader names are not case sensitive.\n\nMultiple header names in the value of the `Access-Control-Expose-Headers` response header are separated by a comma (\",\").\n\nA wildcard indicates that the responses with all HTTP headers are exposed to clients. The `Access-Control-Expose-Headers` response header can only use `*` wildcard as value when the `AllowCredentials` field is false or omitted.\n\nSupport: Extended", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -4369,11 +4622,59 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal } } -func schema_sigsk8sio_gateway_api_apis_v1_HTTPHeader(ref common.ReferenceCallback) common.OpenAPIDefinition { +func schema_sigsk8sio_gateway_api_apis_v1_HTTPExternalAuthFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "HTTPHeader represents an HTTP Header name and value as defined by RFC 7230.", + Description: "HTTPExternalAuthFilter defines a filter that modifies requests by sending request details to an external authorization server.\n\nSupport: Extended Feature Name: HTTPRouteExternalAuth", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "protocol": { + SchemaProps: spec.SchemaProps{ + Description: "ExternalAuthProtocol describes which protocol to use when communicating with an ext_authz authorization server.\n\nWhen this is set to GRPC, each backend must use the Envoy ext_authz protocol on the port specified in `backendRefs`. Requests and responses are defined in the protobufs explained at: https://www.envoyproxy.io/docs/envoy/latest/api-v3/service/auth/v3/external_auth.proto\n\nWhen this is set to HTTP, each backend must respond with a `200` status code in on a successful authorization. Any other code is considered an authorization failure.\n\nFeature Names: GRPC Support - HTTPRouteExternalAuthGRPC HTTP Support - HTTPRouteExternalAuthHTTP", + Type: []string{"string"}, + Format: "", + }, + }, + "backendRef": { + SchemaProps: spec.SchemaProps{ + Description: "BackendRef is a reference to a backend to send authorization requests to.\n\nThe backend must speak the selected protocol (GRPC or HTTP) on the referenced port.\n\nIf the backend service requires TLS, use BackendTLSPolicy to tell the implementation to supply the TLS details to be used to connect to that backend.", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference"), + }, + }, + "grpc": { + SchemaProps: spec.SchemaProps{ + Description: "GRPCAuthConfig contains configuration for communication with ext_authz protocol-speaking backends.\n\nIf unset, implementations must assume the default behavior for each included field is intended.", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GRPCAuthConfig"), + }, + }, + "http": { + SchemaProps: spec.SchemaProps{ + Description: "HTTPAuthConfig contains configuration for communication with HTTP-speaking backends.\n\nIf unset, implementations must assume the default behavior for each included field is intended.", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.HTTPAuthConfig"), + }, + }, + "forwardBody": { + SchemaProps: spec.SchemaProps{ + Description: "ForwardBody controls if requests to the authorization server should include the body of the client request; and if so, how big that body is allowed to be.\n\nIt is expected that implementations will buffer the request body up to `forwardBody.maxSize` bytes. Bodies over that size must be rejected with a 4xx series error (413 or 403 are common examples), and fail processing of the filter.\n\nIf unset, or `forwardBody.maxSize` is set to `0`, then the body will not be forwarded.\n\nFeature Name: HTTPRouteExternalAuthForwardBody", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.ForwardBodyConfig"), + }, + }, + }, + Required: []string{"protocol", "backendRef"}, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.BackendObjectReference", "sigs.k8s.io/gateway-api/apis/v1.ForwardBodyConfig", "sigs.k8s.io/gateway-api/apis/v1.GRPCAuthConfig", "sigs.k8s.io/gateway-api/apis/v1.HTTPAuthConfig"}, + } +} + +func schema_sigsk8sio_gateway_api_apis_v1_HTTPHeader(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "HTTPHeader represents an HTTP Header name and value as defined by RFC 7230.", Type: []string{"object"}, Properties: map[string]spec.Schema{ "name": { @@ -4759,7 +5060,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteFilter(ref common.ReferenceCa Properties: map[string]spec.Schema{ "type": { SchemaProps: spec.SchemaProps{ - Description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels:\n\n- Core: Filter types and their corresponding configuration defined by\n \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All\n implementations must support core filters.\n\n- Extended: Filter types and their corresponding configuration defined by\n \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers\n are encouraged to support extended filters.\n\n- Implementation-specific: Filters that are defined and supported by\n specific vendors.\n In the future, filters showing convergence in behavior across multiple\n implementations will be considered for inclusion in extended or core\n conformance levels. Filter-specific configuration for such filters\n is specified using the ExtensionRef field. `Type` should be set to\n \"ExtensionRef\" for custom filters.\n\nImplementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior.\n\nIf a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response.\n\nNote that values may be added to this enum, implementations must ensure that unknown values will not cause a crash.\n\nUnknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`.\n\n", + Description: "Type identifies the type of filter to apply. As with other API fields, types are classified into three conformance levels:\n\n- Core: Filter types and their corresponding configuration defined by\n \"Support: Core\" in this package, e.g. \"RequestHeaderModifier\". All\n implementations must support core filters.\n\n- Extended: Filter types and their corresponding configuration defined by\n \"Support: Extended\" in this package, e.g. \"RequestMirror\". Implementers\n are encouraged to support extended filters.\n\n- Implementation-specific: Filters that are defined and supported by\n specific vendors.\n In the future, filters showing convergence in behavior across multiple\n implementations will be considered for inclusion in extended or core\n conformance levels. Filter-specific configuration for such filters\n is specified using the ExtensionRef field. `Type` should be set to\n \"ExtensionRef\" for custom filters.\n\nImplementers are encouraged to define custom implementation types to extend the core API with implementation-specific behavior.\n\nIf a reference to a custom filter type cannot be resolved, the filter MUST NOT be skipped. Instead, requests that would have been processed by that filter MUST receive a HTTP error response.\n\nNote that values may be added to this enum, implementations must ensure that unknown values will not cause a crash.\n\nUnknown values here must result in the implementation setting the Accepted Condition for the Route to `status: False`, with a Reason of `UnsupportedValue`.\n\n", Default: "", Type: []string{"string"}, Format: "", @@ -4801,6 +5102,12 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteFilter(ref common.ReferenceCa Ref: ref("sigs.k8s.io/gateway-api/apis/v1.HTTPCORSFilter"), }, }, + "externalAuth": { + SchemaProps: spec.SchemaProps{ + Description: "ExternalAuth configures settings related to sending request details to an external auth service. The external service MUST authenticate the request, and MAY authorize the request as well.\n\nIf there is any problem communicating with the external service, this filter MUST fail closed.\n\nSupport: Extended\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.HTTPExternalAuthFilter"), + }, + }, "extensionRef": { SchemaProps: spec.SchemaProps{ Description: "ExtensionRef is an optional, implementation-specific extension to the \"filter\" behavior. For example, resource \"myroutefilter\" in group \"networking.example.net\"). ExtensionRef MUST NOT be used for core and extended filters.\n\nThis filter can be used multiple times within the same rule.\n\nSupport: Implementation-specific", @@ -4812,7 +5119,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteFilter(ref common.ReferenceCa }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.HTTPCORSFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPHeaderFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPRequestMirrorFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPRequestRedirectFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPURLRewriteFilter", "sigs.k8s.io/gateway-api/apis/v1.LocalObjectReference"}, + "sigs.k8s.io/gateway-api/apis/v1.HTTPCORSFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPExternalAuthFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPHeaderFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPRequestMirrorFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPRequestRedirectFilter", "sigs.k8s.io/gateway-api/apis/v1.HTTPURLRewriteFilter", "sigs.k8s.io/gateway-api/apis/v1.LocalObjectReference"}, } } @@ -4945,6 +5252,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteRetry(ref common.ReferenceCal Type: []string{"object"}, Properties: map[string]spec.Schema{ "codes": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Codes defines the HTTP response status codes for which a backend request should be retried.\n\nSupport: Extended", Type: []string{"array"}, @@ -4988,12 +5300,17 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteRule(ref common.ReferenceCall Properties: map[string]spec.Schema{ "name": { SchemaProps: spec.SchemaProps{ - Description: "Name is the name of the route rule. This name MUST be unique within a Route if it is set.\n\nSupport: Extended ", + Description: "Name is the name of the route rule. This name MUST be unique within a Route if it is set.\n\nSupport: Extended", Type: []string{"string"}, Format: "", }, }, "matches": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Matches define conditions used for matching the rule against incoming HTTP requests. Each match is independent, i.e. this rule will be matched if **any** one of the matches is satisfied.\n\nFor example, take the following matches configuration:\n\n``` matches: - path:\n value: \"/foo\"\n headers:\n - name: \"version\"\n value: \"v2\"\n- path:\n value: \"/v2/foo\"\n```\n\nFor a request to match against this rule, a request must satisfy EITHER of the two conditions:\n\n- path prefixed with `/foo` AND contains the header `version: v2` - path prefix of `/v2/foo`\n\nSee the documentation for HTTPRouteMatch on how to specify multiple match conditions that should be ANDed together.\n\nIf no matches are specified, the default is a prefix path match on \"/\", which has the effect of matching every HTTP request.\n\nProxy or Load Balancer routing configuration generated from HTTPRoutes MUST prioritize matches based on the following criteria, continuing on ties. Across all rules specified on applicable Routes, precedence must be given to the match having:\n\n* \"Exact\" path match. * \"Prefix\" path match with largest number of characters. * Method match. * Largest number of header matches. * Largest number of query param matches.\n\nNote: The precedence of RegularExpression path matches are implementation-specific.\n\nIf ties still exist across multiple Routes, matching precedence MUST be determined in order of the following criteria, continuing on ties:\n\n* The oldest Route based on creation timestamp. * The Route appearing first in alphabetical order by\n \"{namespace}/{name}\".\n\nIf ties still exist within an HTTPRoute, matching precedence MUST be granted to the FIRST matching rule (in list order) with a match meeting the above criteria.\n\nWhen no rules matching a request have been successfully attached to the parent a request is coming from, a HTTP 404 status code MUST be returned.", Type: []string{"array"}, @@ -5008,6 +5325,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteRule(ref common.ReferenceCall }, }, "filters": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Filters define the filters that are applied to requests that match this rule.\n\nWherever possible, implementations SHOULD implement filters in the order they are specified.\n\nImplementations MAY choose to implement this ordering strictly, rejecting any combination or order of filters that cannot be supported. If implementations choose a strict interpretation of filter ordering, they MUST clearly document that behavior.\n\nTo reject an invalid combination or order of filters, implementations SHOULD consider the Route Rules with this configuration invalid. If all Route Rules in a Route are invalid, the entire Route would be considered invalid. If only a portion of Route Rules are invalid, implementations MUST set the \"PartiallyInvalid\" condition for the Route.\n\nConformance-levels at this level are defined based on the type of filter:\n\n- ALL core filters MUST be supported by all implementations. - Implementers are encouraged to support extended filters. - Implementation-specific custom filters have no API guarantees across\n implementations.\n\nSpecifying the same filter multiple times is not supported unless explicitly indicated in the filter.\n\nAll filters are expected to be compatible with each other except for the URLRewrite and RequestRedirect filters, which may not be combined. If an implementation cannot support other combinations of filters, they must clearly document that limitation. In cases where incompatible or unsupported filters are specified and cause the `Accepted` condition to be set to status `False`, implementations may use the `IncompatibleFilters` reason to specify this configuration error.\n\nSupport: Core", Type: []string{"array"}, @@ -5022,6 +5344,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteRule(ref common.ReferenceCall }, }, "backendRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "BackendRefs defines the backend(s) where matching requests should be sent.\n\nFailure behavior here depends on how many BackendRefs are specified and how many are invalid.\n\nIf *all* entries in BackendRefs are invalid, and there are also no filters specified in this route rule, *all* traffic which matches this rule MUST receive a 500 status code.\n\nSee the HTTPBackendRef definition for the rules about what makes a single HTTPBackendRef invalid.\n\nWhen a HTTPBackendRef is invalid, 500 status codes MUST be returned for requests that would have otherwise been routed to an invalid backend. If multiple backends are specified, and some are invalid, the proportion of requests that would otherwise have been routed to an invalid backend MUST receive a 500 status code.\n\nFor example, if two backends are specified with equal weights, and one is invalid, 50 percent of traffic must receive a 500. Implementations may choose how that 50 percent is determined.\n\nWhen a HTTPBackendRef refers to a Service that has no ready endpoints, implementations SHOULD return a 503 for requests to that backend instead. If an implementation chooses to do this, all of the above rules for 500 responses MUST also apply for responses that return a 503.\n\nSupport: Core for Kubernetes Service\n\nSupport: Extended for Kubernetes ServiceImport\n\nSupport: Implementation-specific for any other resource\n\nSupport for weight: Core", Type: []string{"array"}, @@ -5069,6 +5396,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteSpec(ref common.ReferenceCall Type: []string{"object"}, Properties: map[string]spec.Schema{ "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -5083,6 +5415,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteSpec(ref common.ReferenceCall }, }, "hostnames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Hostnames defines a set of hostnames that should match against the HTTP Host header to select a HTTPRoute used to process the request. Implementations MUST ignore any port value specified in the HTTP Host header while performing a match and (absent of any applicable header modification configuration) MUST forward this header unmodified to the backend.\n\nValid values for Hostnames are determined by RFC 1123 definition of a hostname with 2 notable exceptions:\n\n1. IPs are not allowed. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard\n label must appear by itself as the first label.\n\nIf a hostname is specified by both the Listener and HTTPRoute, there must be at least one intersecting hostname for the HTTPRoute to be attached to the Listener. For example:\n\n* A Listener with `test.example.com` as the hostname matches HTTPRoutes\n that have either not specified any hostnames, or have specified at\n least one of `test.example.com` or `*.example.com`.\n* A Listener with `*.example.com` as the hostname matches HTTPRoutes\n that have either not specified any hostnames or have specified at least\n one hostname that matches the Listener hostname. For example,\n `*.example.com`, `test.example.com`, and `foo.test.example.com` would\n all match. On the other hand, `example.com` and `test.example.net` would\n not match.\n\nHostnames that are prefixed with a wildcard label (`*.`) are interpreted as a suffix match. That means that a match for `*.example.com` would match both `test.example.com`, and `foo.test.example.com`, but not `example.com`.\n\nIf both the Listener and HTTPRoute have specified hostnames, any HTTPRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the HTTPRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match.\n\nIf both the Listener and HTTPRoute have specified hostnames, and none match with the criteria above, then the HTTPRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus.\n\nIn the event that multiple HTTPRoutes specify intersecting hostnames (e.g. overlapping wildcard matching and exact matching hostnames), precedence must be given to rules from the HTTPRoute with the largest number of:\n\n* Characters in a matching non-wildcard hostname. * Characters in a matching hostname.\n\nIf ties exist across multiple Routes, the matching precedence rules for HTTPRouteMatches takes over.\n\nSupport: Core", Type: []string{"array"}, @@ -5098,6 +5435,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteSpec(ref common.ReferenceCall }, }, "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Rules are a list of HTTP matchers, filters and actions.\n\n", Type: []string{"array"}, @@ -5127,8 +5469,13 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteStatus(ref common.ReferenceCa Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5244,8 +5591,8 @@ func schema_sigsk8sio_gateway_api_apis_v1_Listener(ref common.ReferenceCallback) }, "tls": { SchemaProps: spec.SchemaProps{ - Description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\".\n\nThe association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener.\n\nThe GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake.\n\nSupport: Core", - Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig"), + Description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\".\n\nThe association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener.\n\nThe GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake.\n\nSupport: Core", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.ListenerTLSConfig"), }, }, "allowedRoutes": { @@ -5259,7 +5606,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_Listener(ref common.ReferenceCallback) }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.AllowedRoutes", "sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig"}, + "sigs.k8s.io/gateway-api/apis/v1.AllowedRoutes", "sigs.k8s.io/gateway-api/apis/v1.ListenerTLSConfig"}, } } @@ -5307,6 +5654,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_ListenerStatus(ref common.ReferenceCal }, }, "supportedKinds": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration.\n\nIf kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified.", Type: []string{"array"}, @@ -5338,7 +5690,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_ListenerStatus(ref common.ReferenceCal }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions describe the current condition of this listener.", + Description: "Conditions describe the current condition of this listener.\n\n Notes for implementors:\n\nConditions are a listType `map`, which means that they function like a map with a key of the `type` field _in the k8s apiserver_.\n\nThis means that implementations must obey some rules when updating this section.\n\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n* Implementations MUST NOT remove or reorder Conditions that they are not\n directly responsible for. For example, if an implementation sees a Condition\n with type `special.io/SomeField`, it MUST NOT remove, change or update that\n Condition.\n* Implementations MUST always _merge_ changes into Conditions of the same Type,\n rather than creating more than one Condition of the same Type.\n* Implementations MUST always update the `observedGeneration` field of the\n Condition to the `metadata.generation` of the Gateway at the time of update creation.\n* If the `observedGeneration` of a Condition is _greater than_ the value the\n implementation knows about, then it MUST NOT perform the update on that Condition,\n but must wait for a future reconciliation and status update. (The assumption is that\n the implementation's copy of the object is stale and an update will be re-triggered\n if relevant.)\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5359,6 +5711,62 @@ func schema_sigsk8sio_gateway_api_apis_v1_ListenerStatus(ref common.ReferenceCal } } +func schema_sigsk8sio_gateway_api_apis_v1_ListenerTLSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "mode": { + SchemaProps: spec.SchemaProps{ + Description: "Mode defines the TLS behavior for the TLS session initiated by the client. There are two possible modes:\n\n- Terminate: The TLS session between the downstream client and the\n Gateway is terminated at the Gateway. This mode requires certificates\n to be specified in some way, such as populating the certificateRefs\n field.\n- Passthrough: The TLS session is NOT terminated by the Gateway. This\n implies that the Gateway can't decipher the TLS stream except for\n the ClientHello message of the TLS protocol. The certificateRefs field\n is ignored in this mode.\n\nSupport: Core", + Type: []string{"string"}, + Format: "", + }, + }, + "certificateRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "CertificateRefs contains a series of references to Kubernetes objects that contains TLS certificates and private keys. These certificates are used to establish a TLS handshake for requests that match the hostname of the associated listener.\n\nA single CertificateRef to a Kubernetes Secret has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a Listener, but this behavior is implementation-specific.\n\nReferences to a resource in different namespace are invalid UNLESS there is a ReferenceGrant in the target namespace that allows the certificate to be attached. If a ReferenceGrant does not allow this reference, the \"ResolvedRefs\" condition MUST be set to False for this listener with the \"RefNotPermitted\" reason.\n\nThis field is required to have at least one element when the mode is set to \"Terminate\" (default) and is optional otherwise.\n\nCertificateRefs can reference to standard Kubernetes resources, i.e. Secret, or implementation-specific custom resources.\n\nSupport: Core - A single reference to a Kubernetes Secret of type kubernetes.io/tls\n\nSupport: Implementation-specific (More than one reference or other resource types)", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"), + }, + }, + }, + }, + }, + "options": { + SchemaProps: spec.SchemaProps{ + Description: "Options are a list of key/value pairs to enable extended TLS configuration for each implementation. For example, configuring the minimum TLS version or supported cipher suites.\n\nA set of common keys MAY be defined by the API in the future. To avoid any ambiguity, implementation-specific definitions MUST use domain-prefixed names, such as `example.com/my-custom-option`. Un-prefixed names are reserved for key names defined by Gateway API.\n\nSupport: Implementation-specific", + Type: []string{"object"}, + AdditionalProperties: &spec.SchemaOrBool{ + Allows: true, + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"}, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_LocalObjectReference(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -5670,7 +6078,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_RouteParentStatus(ref common.Reference }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status.\n\nIf the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why.\n\nA Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway.\n\nThere are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when:\n\n* The Route refers to a nonexistent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to.", + Description: "Conditions describes the status of the route with respect to the Gateway. Note that the route's availability is also subject to the Gateway's own status conditions and listener status.\n\nIf the Route's ParentRef specifies an existing Gateway that supports Routes of this kind AND that Gateway's controller has sufficient access, then that Gateway's controller MUST set the \"Accepted\" condition on the Route, to indicate whether the route has been accepted or rejected by the Gateway, and why.\n\nA Route MUST be considered \"Accepted\" if at least one of the Route's rules is implemented by the Gateway.\n\nThere are a number of cases where the \"Accepted\" condition may not be set due to lack of controller visibility, that includes when:\n\n* The Route refers to a nonexistent parent. * The Route is of a type that the controller does not support. * The Route is in a namespace the controller does not have access to.\n\n\n\nNotes for implementors:\n\nConditions are a listType `map`, which means that they function like a map with a key of the `type` field _in the k8s apiserver_.\n\nThis means that implementations must obey some rules when updating this section.\n\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n* Implementations MUST NOT remove or reorder Conditions that they are not\n directly responsible for. For example, if an implementation sees a Condition\n with type `special.io/SomeField`, it MUST NOT remove, change or update that\n Condition.\n* Implementations MUST always _merge_ changes into Conditions of the same Type,\n rather than creating more than one Condition of the same Type.\n* Implementations MUST always update the `observedGeneration` field of the\n Condition to the `metadata.generation` of the Gateway at the time of update creation.\n* If the `observedGeneration` of a Condition is _greater than_ the value the\n implementation knows about, then it MUST NOT perform the update on that Condition,\n but must wait for a future reconciliation and status update. (The assumption is that\n the implementation's copy of the object is stale and an update will be re-triggered\n if relevant.)\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5683,7 +6091,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_RouteParentStatus(ref common.Reference }, }, }, - Required: []string{"parentRef", "controllerName"}, + Required: []string{"parentRef", "controllerName", "conditions"}, }, }, Dependencies: []string{ @@ -5699,8 +6107,13 @@ func schema_sigsk8sio_gateway_api_apis_v1_RouteStatus(ref common.ReferenceCallba Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -5832,6 +6245,57 @@ func schema_sigsk8sio_gateway_api_apis_v1_SupportedFeature(ref common.ReferenceC } } +func schema_sigsk8sio_gateway_api_apis_v1_TLSConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSConfig describes TLS configuration that can apply to multiple Listeners within this Gateway. Currently, it stores only the client certificate validation configuration, but this may be extended in the future.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "validation": { + SchemaProps: spec.SchemaProps{ + Description: "Validation holds configuration information for validating the frontend (client). Setting this field will result in mutual authentication when connecting to the gateway. In browsers this may result in a dialog appearing that requests a user to specify the client certificate. The maximum depth of a certificate chain accepted in verification is Implementation specific.\n\nSupport: Core\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation"), + }, + }, + }, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation"}, + } +} + +func schema_sigsk8sio_gateway_api_apis_v1_TLSPortConfig(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "port": { + SchemaProps: spec.SchemaProps{ + Description: "The Port indicates the Port Number to which the TLS configuration will be applied. This configuration will be applied to all Listeners handling HTTPS traffic that match this port.\n\nSupport: Core\n\n", + Default: 0, + Type: []string{"integer"}, + Format: "int32", + }, + }, + "tls": { + SchemaProps: spec.SchemaProps{ + Description: "TLS store the configuration that will be applied to all Listeners handling HTTPS traffic and matching given port.\n\nSupport: Core\n\n", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.TLSConfig"), + }, + }, + }, + Required: []string{"port", "tls"}, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.TLSConfig"}, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_supportedFeatureInternal(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -5894,6 +6358,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_GRPCRoute(ref common.ReferenceCa }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ @@ -6108,7 +6573,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_PolicyAncestorStatus(ref common. }, }, SchemaProps: spec.SchemaProps{ - Description: "Conditions describes the status of the Policy with respect to the given Ancestor.", + Description: "Conditions describes the status of the Policy with respect to the given Ancestor.\n\n\n\nNotes for implementors:\n\nConditions are a listType `map`, which means that they function like a map with a key of the `type` field _in the k8s apiserver_.\n\nThis means that implementations must obey some rules when updating this section.\n\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n* Implementations MUST NOT remove or reorder Conditions that they are not\n directly responsible for. For example, if an implementation sees a Condition\n with type `special.io/SomeField`, it MUST NOT remove, change or update that\n Condition.\n* Implementations MUST always _merge_ changes into Conditions of the same Type,\n rather than creating more than one Condition of the same Type.\n* Implementations MUST always update the `observedGeneration` field of the\n Condition to the `metadata.generation` of the Gateway at the time of update creation.\n* If the `observedGeneration` of a Condition is _greater than_ the value the\n implementation knows about, then it MUST NOT perform the update on that Condition,\n but must wait for a future reconciliation and status update. (The assumption is that\n the implementation's copy of the object is stale and an update will be re-triggered\n if relevant.)\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6121,7 +6586,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_PolicyAncestorStatus(ref common. }, }, }, - Required: []string{"ancestorRef", "controllerName"}, + Required: []string{"ancestorRef", "controllerName", "conditions"}, }, }, Dependencies: []string{ @@ -6136,6 +6601,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_PolicyStatus(ref common.Referenc Type: []string{"object"}, Properties: map[string]spec.Schema{ "ancestors": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Ancestors is a list of ancestor resources (usually Gateways) that are associated with the policy, and the status of the policy with respect to each ancestor. When this policy attaches to a parent, the controller that manages the parent and the ancestors MUST add an entry to this list when the controller first sees the policy and SHOULD update the entry as appropriate when the relevant ancestor is modified.\n\nNote that choosing the relevant ancestor is left to the Policy designers; an important part of Policy design is designing the right object level at which to namespace this status.\n\nNote also that implementations MUST ONLY populate ancestor status for the Ancestor resources they are responsible for. Implementations MUST use the ControllerName field to uniquely identify the entries in this list that they are responsible for.\n\nNote that to achieve this, the list of PolicyAncestorStatus structs MUST be treated as a map with a composite key, made up of the AncestorRef and ControllerName fields combined.\n\nA maximum of 16 ancestors will be represented in this list. An empty list means the Policy is not relevant for any ancestors.\n\nIf this slice is full, implementations MUST NOT add further entries. Instead they MUST consider the policy unimplementable and signal that on any related resources such as the ancestor that would be referenced here. For example, if this list was full on BackendTLSPolicy, no additional Gateways would be able to reference the Service targeted by the BackendTLSPolicy.", Type: []string{"array"}, @@ -6363,6 +6833,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteRule(ref common.Referenc }, }, "backendRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a nonexistent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Connection rejections must respect weight; if an invalid backend is requested to have 80% of connections, then 80% of connections must be rejected instead.\n\nSupport: Core for Kubernetes Service\n\nSupport: Extended for Kubernetes ServiceImport\n\nSupport: Implementation-specific for any other resource\n\nSupport for weight: Extended", Type: []string{"array"}, @@ -6377,6 +6852,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ @@ -6392,6 +6868,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteSpec(ref common.Referenc Type: []string{"object"}, Properties: map[string]spec.Schema{ "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -6406,6 +6887,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteSpec(ref common.Referenc }, }, "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Rules are a list of TCP matchers and actions.\n\n", Type: []string{"array"}, @@ -6436,8 +6922,13 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteStatus(ref common.Refere Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6572,6 +7063,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteRule(ref common.Referenc }, }, "backendRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a nonexistent resource or a Service with no endpoints), the rule performs no forwarding; if no filters are specified that would result in a response being sent, the underlying implementation must actively reject request attempts to this backend, by rejecting the connection or returning a 500 status code. Request rejections must respect weight; if an invalid backend is requested to have 80% of requests, then 80% of requests must be rejected instead.\n\nSupport: Core for Kubernetes Service\n\nSupport: Extended for Kubernetes ServiceImport\n\nSupport: Implementation-specific for any other resource\n\nSupport for weight: Extended", Type: []string{"array"}, @@ -6586,6 +7082,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ @@ -6601,6 +7098,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteSpec(ref common.Referenc Type: []string{"object"}, Properties: map[string]spec.Schema{ "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -6615,6 +7117,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteSpec(ref common.Referenc }, }, "hostnames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Hostnames defines a set of SNI names that should match against the SNI attribute of TLS ClientHello message in TLS handshake. This matches the RFC 1123 definition of a hostname with 2 notable exceptions:\n\n1. IPs are not allowed in SNI names per RFC 6066. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard\n label must appear by itself as the first label.\n\nIf a hostname is specified by both the Listener and TLSRoute, there must be at least one intersecting hostname for the TLSRoute to be attached to the Listener. For example:\n\n* A Listener with `test.example.com` as the hostname matches TLSRoutes\n that have either not specified any hostnames, or have specified at\n least one of `test.example.com` or `*.example.com`.\n* A Listener with `*.example.com` as the hostname matches TLSRoutes\n that have either not specified any hostnames or have specified at least\n one hostname that matches the Listener hostname. For example,\n `test.example.com` and `*.example.com` would both match. On the other\n hand, `example.com` and `test.example.net` would not match.\n\nIf both the Listener and TLSRoute have specified hostnames, any TLSRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the TLSRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match.\n\nIf both the Listener and TLSRoute have specified hostnames, and none match with the criteria above, then the TLSRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus.\n\nSupport: Core", Type: []string{"array"}, @@ -6630,6 +7137,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteSpec(ref common.Referenc }, }, "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Rules are a list of TLS matchers and actions.\n\n", Type: []string{"array"}, @@ -6660,8 +7172,13 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteStatus(ref common.Refere Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6796,6 +7313,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteRule(ref common.Referenc }, }, "backendRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "BackendRefs defines the backend(s) where matching requests should be sent. If unspecified or invalid (refers to a nonexistent resource or a Service with no endpoints), the underlying implementation MUST actively reject connection attempts to this backend. Packet drops must respect weight; if an invalid backend is requested to have 80% of the packets, then 80% of packets must be dropped instead.\n\nSupport: Core for Kubernetes Service\n\nSupport: Extended for Kubernetes ServiceImport\n\nSupport: Implementation-specific for any other resource\n\nSupport for weight: Extended", Type: []string{"array"}, @@ -6810,6 +7332,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ @@ -6825,6 +7348,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteSpec(ref common.Referenc Type: []string{"object"}, Properties: map[string]spec.Schema{ "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", Type: []string{"array"}, @@ -6839,6 +7367,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteSpec(ref common.Referenc }, }, "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Rules are a list of UDP matchers and actions.\n\n", Type: []string{"array"}, @@ -6869,8 +7402,13 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteStatus(ref common.Refere Type: []string{"object"}, Properties: map[string]spec.Schema{ "parents": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.", + Description: "Parents is a list of parent resources (usually Gateways) that are associated with the route, and the status of the route with respect to each parent. When this route attaches to a parent, the controller that manages the parent must add an entry to this list when the controller first sees the route and should update the entry as appropriate when the route or gateway is modified.\n\nNote that parent references that cannot be resolved by an implementation of this API will not be added to this list. Implementations of this API can only populate Route status for the Gateways/parent resources they are responsible for.\n\nA maximum of 32 Gateways will be represented in this list. An empty list means the route has not been attached to any Gateway.\n\n Notes for implementors:\n\nWhile parents is not a listType `map`, this is due to the fact that the list key is not scalar, and Kubernetes is unable to represent this.\n\nParent status MUST be considered to be namespaced by the combination of the parentRef and controllerName fields, and implementations should keep the following rules in mind when updating this status:\n\n* Implementations MUST update only entries that have a matching value of\n `controllerName` for that implementation.\n* Implementations MUST NOT update entries with non-matching `controllerName`\n fields.\n* Implementations MUST treat each `parentRef`` in the Route separately and\n update its status based on the relationship with that parent.\n* Implementations MUST perform a read-modify-write cycle on this field\n before modifying it. That is, when modifying this field, implementations\n must be confident they have fetched the most recent version of this field,\n and ensure that changes they make are on that recent version.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -6998,6 +7536,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicySpec(ref common. Type: []string{"object"}, Properties: map[string]spec.Schema{ "targetRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "TargetRefs identifies an API object to apply the policy to. Only Services have Extended support. Implementations MAY support additional objects, with Implementation Specific support. Note that this config applies to the entire referenced resource by default, but this default may change in the future to provide a more granular application of the policy.\n\nTargetRefs must be _distinct_. This means either that:\n\n* They select different targets. If this is the case, then targetRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, and `name` must\n be unique across all targetRef entries in the BackendTLSPolicy.\n* They select different sectionNames in the same target.\n\nSupport: Extended for Kubernetes Service\n\nSupport: Implementation-specific for any other resource", Type: []string{"array"}, @@ -7051,8 +7594,13 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c Type: []string{"object"}, Properties: map[string]spec.Schema{ "caCertificateRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "CACertificateRefs contains one or more references to Kubernetes objects that contain a PEM-encoded TLS CA certificate bundle, which is used to validate a TLS handshake between the Gateway and backend Pod.\n\nIf CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified, not both. If CACertificateRefs is empty or unspecified, the configuration for WellKnownCACertificates MUST be honored instead if supported by the implementation.\n\nReferences to a resource in a different namespace are invalid for the moment, although we will revisit this in the future.\n\nA single CACertificateRef to a Kubernetes ConfigMap kind has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a backend, but this behavior is implementation-specific.\n\nSupport: Core - An optional single reference to a Kubernetes ConfigMap, with the CA certificate in a key named `ca.crt`.\n\nSupport: Implementation-specific (More than one reference, or other kinds of resources).", + Description: "CACertificateRefs contains one or more references to Kubernetes objects that contain a PEM-encoded TLS CA certificate bundle, which is used to validate a TLS handshake between the Gateway and backend Pod.\n\nIf CACertificateRefs is empty or unspecified, then WellKnownCACertificates must be specified. Only one of CACertificateRefs or WellKnownCACertificates may be specified, not both. If CACertificateRefs is empty or unspecified, the configuration for WellKnownCACertificates MUST be honored instead if supported by the implementation.\n\nA CACertificateRef is invalid if:\n\n* It refers to a resource that cannot be resolved (e.g., the referenced resource\n does not exist) or is misconfigured (e.g., a ConfigMap does not contain a key\n named `ca.crt`). In this case, the Reason must be set to `InvalidCACertificateRef`\n and the Message of the Condition must indicate which reference is invalid and why.\n\n* It refers to an unknown or unsupported kind of resource. In this case, the Reason\n must be set to `InvalidKind` and the Message of the Condition must explain which\n kind of resource is unknown or unsupported.\n\n* It refers to a resource in another namespace. This may change in future\n spec updates.\n\nImplementations MAY choose to perform further validation of the certificate content (e.g., checking expiry or enforcing specific formats). In such cases, an implementation-specific Reason and Message must be set for the invalid reference.\n\nIn all cases, the implementation MUST ensure the `ResolvedRefs` Condition on the BackendTLSPolicy is set to `status: False`, with a Reason and Message that indicate the cause of the error. Connections using an invalid CACertificateRef MUST fail, and the client MUST receive an HTTP 5xx error response. If ALL CACertificateRefs are invalid, the implementation MUST also ensure the `Accepted` Condition on the BackendTLSPolicy is set to `status: False`, with a Reason `NoValidCACertificate`.\n\nA single CACertificateRef to a Kubernetes ConfigMap kind has \"Core\" support. Implementations MAY choose to support attaching multiple certificates to a backend, but this behavior is implementation-specific.\n\nSupport: Core - An optional single reference to a Kubernetes ConfigMap, with the CA certificate in a key named `ca.crt`.\n\nSupport: Implementation-specific - More than one reference, other kinds of resources, or a single reference that includes multiple certificates.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -7065,21 +7613,31 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c }, }, "wellKnownCACertificates": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ - Description: "WellKnownCACertificates specifies whether system CA certificates may be used in the TLS handshake between the gateway and backend pod.\n\nIf WellKnownCACertificates is unspecified or empty (\"\"), then CACertificateRefs must be specified with at least one entry for a valid configuration. Only one of CACertificateRefs or WellKnownCACertificates may be specified, not both. If an implementation does not support the WellKnownCACertificates field or the value supplied is not supported, the Status Conditions on the Policy MUST be updated to include an Accepted: False Condition with Reason: Invalid.\n\nSupport: Implementation-specific", + Description: "WellKnownCACertificates specifies whether system CA certificates may be used in the TLS handshake between the gateway and backend pod.\n\nIf WellKnownCACertificates is unspecified or empty (\"\"), then CACertificateRefs must be specified with at least one entry for a valid configuration. Only one of CACertificateRefs or WellKnownCACertificates may be specified, not both. If an implementation does not support the WellKnownCACertificates field, or the supplied value is not recognized, the implementation MUST ensure the `Accepted` Condition on the BackendTLSPolicy is set to `status: False`, with a Reason `Invalid`.\n\nSupport: Implementation-specific", Type: []string{"string"}, Format: "", }, }, "hostname": { SchemaProps: spec.SchemaProps{ - Description: "Hostname is used for two purposes in the connection between Gateways and backends:\n\n1. Hostname MUST be used as the SNI to connect to the backend (RFC 6066). 2. Hostname MUST be used for authentication and MUST match the certificate served by the matching backend, unless SubjectAltNames is specified.\n authentication and MUST match the certificate served by the matching\n backend.\n\nSupport: Core", + Description: "Hostname is used for two purposes in the connection between Gateways and backends:\n\n1. Hostname MUST be used as the SNI to connect to the backend (RFC 6066). 2. Hostname MUST be used for authentication and MUST match the certificate served by the matching backend, unless SubjectAltNames is specified.\n\nSupport: Core", Default: "", Type: []string{"string"}, Format: "", }, }, "subjectAltNames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "SubjectAltNames contains one or more Subject Alternative Names. When specified the certificate served from the backend MUST have at least one Subject Alternate Name matching one of the specified SubjectAltNames.\n\nSupport: Extended", Type: []string{"array"}, @@ -7138,6 +7696,179 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_SubjectAltName(ref common.Refere } } +func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRoute(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "The TLSRoute resource is similar to TCPRoute, but can be configured to match against TLS-specific metadata. This allows more flexibility in matching streams for a given TLS listener.\n\nIf you need to forward traffic to a single target for a TLS listener, you could choose to use a TCPRoute with a TLS listener.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta"), + }, + }, + "spec": { + SchemaProps: spec.SchemaProps{ + Description: "Spec defines the desired state of TLSRoute.", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRouteSpec"), + }, + }, + "status": { + SchemaProps: spec.SchemaProps{ + Description: "Status defines the current state of TLSRoute.", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1alpha2.TLSRouteStatus"), + }, + }, + }, + Required: []string{"spec"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta", "sigs.k8s.io/gateway-api/apis/v1alpha2.TLSRouteStatus", "sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRouteSpec"}, + } +} + +func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteList(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSRouteList contains a list of TLSRoute", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources", + Type: []string{"string"}, + Format: "", + }, + }, + "metadata": { + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta"), + }, + }, + "items": { + SchemaProps: spec.SchemaProps{ + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRoute"), + }, + }, + }, + }, + }, + }, + Required: []string{"items"}, + }, + }, + Dependencies: []string{ + "k8s.io/apimachinery/pkg/apis/meta/v1.ListMeta", "sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRoute"}, + } +} + +func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteSpec(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "TLSRouteSpec defines the desired state of a TLSRoute resource.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "parentRefs": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "ParentRefs references the resources (usually Gateways) that a Route wants to be attached to. Note that the referenced parent resource needs to allow this for the attachment to be complete. For Gateways, that means the Gateway needs to allow attachment from Routes of this kind and namespace. For Services, that means the Service must either be in the same namespace for a \"producer\" route, or the mesh implementation must support and allow \"consumer\" routes for the referenced Service. ReferenceGrant is not applicable for governing ParentRefs to Services - it is not possible to create a \"producer\" route for a Service in a different namespace from the Route.\n\nThere are two kinds of parent resources with \"Core\" support:\n\n* Gateway (Gateway conformance profile) * Service (Mesh conformance profile, ClusterIP Services only)\n\nThis API may be extended in the future to support additional kinds of parent resources.\n\nParentRefs must be _distinct_. This means either that:\n\n* They select different objects. If this is the case, then parentRef\n entries are distinct. In terms of fields, this means that the\n multi-part key defined by `group`, `kind`, `namespace`, and `name` must\n be unique across all parentRef entries in the Route.\n* They do not select different objects, but for each optional field used,\n each ParentRef that selects the same object must set the same set of\n optional fields to different values. If one ParentRef sets a\n combination of optional fields, all must set the same combination.\n\nSome examples:\n\n* If one ParentRef sets `sectionName`, all ParentRefs referencing the\n same object must also set `sectionName`.\n* If one ParentRef sets `port`, all ParentRefs referencing the same\n object must also set `port`.\n* If one ParentRef sets `sectionName` and `port`, all ParentRefs\n referencing the same object must also set `sectionName` and `port`.\n\nIt is possible to separately reference multiple distinct objects that may be collapsed by an implementation. For example, some implementations may choose to merge compatible Gateway Listeners together. If that is the case, the list of routes attached to those resources should also be merged.\n\nNote that for ParentRefs that cross namespace boundaries, there are specific rules. Cross-namespace references are only valid if they are explicitly allowed by something in the namespace they are referring to. For example, Gateway has the AllowedRoutes field, and ReferenceGrant provides a generic way to enable other kinds of cross-namespace reference.\n\n ParentRefs from a Route to a Service in the same namespace are \"producer\" routes, which apply default routing rules to inbound connections from any namespace to the Service.\n\nParentRefs from a Route to a Service in a different namespace are \"consumer\" routes, and these routing rules are only applied to outbound connections originating from the same namespace as the Route, for which the intended destination of the connections are a Service targeted as a ParentRef of the Route. \n\n ", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.ParentReference"), + }, + }, + }, + }, + }, + "hostnames": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Hostnames defines a set of SNI hostnames that should match against the SNI attribute of TLS ClientHello message in TLS handshake. This matches the RFC 1123 definition of a hostname with 2 notable exceptions:\n\n1. IPs are not allowed in SNI hostnames per RFC 6066. 2. A hostname may be prefixed with a wildcard label (`*.`). The wildcard\n label must appear by itself as the first label.\n\nIf a hostname is specified by both the Listener and TLSRoute, there must be at least one intersecting hostname for the TLSRoute to be attached to the Listener. For example:\n\n* A Listener with `test.example.com` as the hostname matches TLSRoutes\n that have specified at least one of `test.example.com` or\n `*.example.com`.\n* A Listener with `*.example.com` as the hostname matches TLSRoutes\n that have specified at least one hostname that matches the Listener\n hostname. For example, `test.example.com` and `*.example.com` would both\n match. On the other hand, `example.com` and `test.example.net` would not\n match.\n\nIf both the Listener and TLSRoute have specified hostnames, any TLSRoute hostnames that do not match the Listener hostname MUST be ignored. For example, if a Listener specified `*.example.com`, and the TLSRoute specified `test.example.com` and `test.example.net`, `test.example.net` must not be considered for a match.\n\nIf both the Listener and TLSRoute have specified hostnames, and none match with the criteria above, then the TLSRoute is not accepted. The implementation must raise an 'Accepted' Condition with a status of `False` in the corresponding RouteParentStatus.\n\nSupport: Core", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "rules": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, + SchemaProps: spec.SchemaProps{ + Description: "Rules are a list of actions.\n\n", + Type: []string{"array"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1alpha2.TLSRouteRule"), + }, + }, + }, + }, + }, + }, + Required: []string{"hostnames", "rules"}, + }, + }, + Dependencies: []string{ + "sigs.k8s.io/gateway-api/apis/v1.ParentReference", "sigs.k8s.io/gateway-api/apis/v1alpha2.TLSRouteRule"}, + } +} + func schema_sigsk8sio_gateway_api_apis_v1beta1_Gateway(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -7572,6 +8303,11 @@ func schema_sigsk8sio_gateway_api_apis_v1beta1_ReferenceGrantSpec(ref common.Ref Type: []string{"object"}, Properties: map[string]spec.Schema{ "from": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "From describes the trusted namespaces and kinds that can reference the resources described in \"To\". Each entry in this list MUST be considered to be an additional place that references can be valid from, or to put this another way, entries MUST be combined using OR.\n\nSupport: Core", Type: []string{"array"}, @@ -7586,6 +8322,11 @@ func schema_sigsk8sio_gateway_api_apis_v1beta1_ReferenceGrantSpec(ref common.Ref }, }, "to": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "To describes the resources that may be referenced by the resources described in \"From\". Each entry in this list MUST be considered to be an additional place that references can be valid to, or to put this another way, entries MUST be combined using OR.\n\nSupport: Core", Type: []string{"array"}, @@ -7747,8 +8488,7 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntry(ref common.Refere }, "port": { SchemaProps: spec.SchemaProps{ - Description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules.", - Default: 0, + Description: "Port is the network port. Multiple listeners may use the same port, subject to the Listener compatibility rules.\n\nIf the port is not set or specified as zero, the implementation will assign a unique port. If the implementation does not support dynamic port assignment, it MUST set `Accepted` condition to `False` with the `UnsupportedPort` reason.", Type: []string{"integer"}, Format: "int32", }, @@ -7763,8 +8503,8 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntry(ref common.Refere }, "tls": { SchemaProps: spec.SchemaProps{ - Description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\".\n\nThe association of SNIs to Certificate defined in GatewayTLSConfig is defined based on the Hostname field for this listener.\n\nThe GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake.", - Ref: ref("sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig"), + Description: "TLS is the TLS configuration for the Listener. This field is required if the Protocol field is \"HTTPS\" or \"TLS\". It is invalid to set this field if the Protocol field is \"HTTP\", \"TCP\", or \"UDP\".\n\nThe association of SNIs to Certificate defined in ListenerTLSConfig is defined based on the Hostname field for this listener.\n\nThe GatewayClass MUST use the longest matching SNI out of all available certificates for any TLS handshake.", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.ListenerTLSConfig"), }, }, "allowedRoutes": { @@ -7774,11 +8514,11 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntry(ref common.Refere }, }, }, - Required: []string{"name", "port", "protocol"}, + Required: []string{"name", "protocol"}, }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.AllowedRoutes", "sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig"}, + "sigs.k8s.io/gateway-api/apis/v1.AllowedRoutes", "sigs.k8s.io/gateway-api/apis/v1.ListenerTLSConfig"}, } } @@ -7806,6 +8546,11 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntryStatus(ref common. }, }, "supportedKinds": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "SupportedKinds is the list indicating the Kinds supported by this listener. This MUST represent the kinds an implementation supports for that Listener configuration.\n\nIf kinds are specified in Spec that are not supported, they MUST NOT appear in this list and an implementation MUST set the \"ResolvedRefs\" condition to \"False\" with the \"InvalidRouteKinds\" reason. If both valid and invalid Route kinds are specified, the implementation MUST reference the valid Route kinds that have been specified.", Type: []string{"array"}, @@ -7882,7 +8627,7 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerSetSpec(ref common.Refe }, }, SchemaProps: spec.SchemaProps{ - Description: "Listeners associated with this ListenerSet. Listeners define logical endpoints that are bound on this referenced parent Gateway's addresses.\n\nListeners in a `Gateway` and their attached `ListenerSets` are concatenated as a list when programming the underlying infrastructure. Each listener name does not need to be unique across the Gateway and ListenerSets. See ListenerEntry.Name for more details.\n\nImplementations MUST treat the parent Gateway as having the merged list of all listeners from itself and attached ListenerSets using the following precedence:\n\n1. \"parent\" Gateway 2. ListenerSet ordered by creation time (oldest first) 3. ListenerSet ordered alphabetically by “{namespace}/{name}”.\n\nAn implementation MAY reject listeners by setting the ListenerEntryStatus `Accepted`` condition to False with the Reason `TooManyListeners`\n\nIf a listener has a conflict, this will be reported in the Status.ListenerEntryStatus setting the `Conflicted` condition to True.\n\nImplementations SHOULD be cautious about what information from the parent or siblings are reported to avoid accidentally leaking sensitive information that the child would not otherwise have access to. This can include contents of secrets etc.", + Description: "Listeners associated with this ListenerSet. Listeners define logical endpoints that are bound on this referenced parent Gateway's addresses.\n\nListeners in a `Gateway` and their attached `ListenerSets` are concatenated as a list when programming the underlying infrastructure. Each listener name does not need to be unique across the Gateway and ListenerSets. See ListenerEntry.Name for more details.\n\nImplementations MUST treat the parent Gateway as having the merged list of all listeners from itself and attached ListenerSets using the following precedence:\n\n1. \"parent\" Gateway 2. ListenerSet ordered by creation time (oldest first) 3. ListenerSet ordered alphabetically by \"{namespace}/{name}\".\n\nAn implementation MAY reject listeners by setting the ListenerEntryStatus `Accepted` condition to False with the Reason `TooManyListeners`\n\nIf a listener has a conflict, this will be reported in the Status.ListenerEntryStatus setting the `Conflicted` condition to True.\n\nImplementations SHOULD be cautious about what information from the parent or siblings are reported to avoid accidentally leaking sensitive information that the child would not otherwise have access to. This can include contents of secrets etc.", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ @@ -8161,7 +8906,7 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_XListenerSet(ref common.Referen return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "XListenerSet defines a set of additional listeners to attach to an existing Gateway.", + Description: "XListenerSet defines a set of additional listeners to attach to an existing Gateway. This resource provides a mechanism to merge multiple listeners into a single Gateway.\n\nThe parent Gateway must explicitly allow ListenerSet attachment through its AllowedListeners configuration. By default, Gateways do not allow ListenerSet attachment.\n\nRoutes can attach to a ListenerSet by specifying it as a parentRef, and can optionally target specific listeners using the sectionName field.\n\nPolicy Attachment: - Policies that attach to a ListenerSet apply to all listeners defined in that resource - Policies do not impact listeners in the parent Gateway - Different ListenerSets attached to the same Gateway can have different policies - If an implementation cannot apply a policy to specific listeners, it should reject the policy\n\nReferenceGrant Semantics: - ReferenceGrants applied to a Gateway are not inherited by child ListenerSets - ReferenceGrants applied to a ListenerSet do not grant permission to the parent Gateway's listeners - A ListenerSet can reference secrets/backends in its own namespace without a ReferenceGrant\n\nGateway Integration: - The parent Gateway's status will include an \"AttachedListenerSets\" condition - This condition will be:\n - True: when AllowedListeners is set and at least one child ListenerSet is attached\n - False: when AllowedListeners is set but no valid listeners are attached, or when AllowedListeners is not set or false\n - Unknown: when no AllowedListeners config is present", Type: []string{"object"}, Properties: map[string]spec.Schema{ "kind": { diff --git a/pkg/generator/main.go b/pkg/generator/main.go index dc170b8823..1149e1a902 100644 --- a/pkg/generator/main.go +++ b/pkg/generator/main.go @@ -69,6 +69,8 @@ func main() { log.Fatalf("failed to register markers: %s", err) } + registerMarkerOverrides(parser.Collector.Registry) + crd.AddKnownTypes(parser) for _, r := range roots { parser.NeedPackage(r) diff --git a/pkg/generator/markers.go b/pkg/generator/markers.go new file mode 100644 index 0000000000..ab5f625aae --- /dev/null +++ b/pkg/generator/markers.go @@ -0,0 +1,66 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package main + +import ( + apiext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + "sigs.k8s.io/controller-tools/pkg/markers" +) + +type Minimum float64 + +func (m Minimum) Value() float64 { + return float64(m) +} + +//nolint:unparam +func (m Minimum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + val := m.Value() + schema.Minimum = &val + return nil +} + +type Maximum float64 + +func (m Maximum) Value() float64 { + return float64(m) +} + +//nolint:unparam +func (m Maximum) ApplyToSchema(schema *apiext.JSONSchemaProps) error { + val := m.Value() + schema.Maximum = &val + return nil +} + +// kubebuilder Min Max markers are broken with type aliases +func registerMarkerOverrides(into *markers.Registry) { + minMarker, _ := markers.MakeDefinition( + "kubebuilder:validation:Minimum", + markers.DescribesField, + Minimum(0), + ) + + maxMarker, _ := markers.MakeDefinition( + "kubebuilder:validation:Maximum", + markers.DescribesField, + Maximum(0), + ) + + into.Register(minMarker) //nolint:errcheck + into.Register(maxMarker) //nolint:errcheck +} diff --git a/pkg/test/cel/gateway_test.go b/pkg/test/cel/gateway_test.go index 7f8d867642..ba85b50f2e 100644 --- a/pkg/test/cel/gateway_test.go +++ b/pkg/test/cel/gateway_test.go @@ -60,7 +60,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("http"), Protocol: gatewayv1.HTTPProtocolType, Port: gatewayv1.PortNumber(8080), - TLS: &gatewayv1.GatewayTLSConfig{}, + TLS: &gatewayv1.ListenerTLSConfig{}, }, } }, @@ -74,7 +74,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("https"), Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8080), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: ptrTo(gatewayv1.TLSModeType("Passthrough")), }, }, @@ -90,7 +90,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("https"), Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8080), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ CertificateRefs: []gatewayv1.SecretObjectReference{ {Name: gatewayv1.ObjectName("foo")}, }, @@ -107,7 +107,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("tcp"), Protocol: gatewayv1.TCPProtocolType, Port: gatewayv1.PortNumber(8080), - TLS: &gatewayv1.GatewayTLSConfig{}, + TLS: &gatewayv1.ListenerTLSConfig{}, }, } }, @@ -212,7 +212,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("https"), Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, }, }, @@ -229,7 +229,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("tls"), Protocol: gatewayv1.TLSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, }, }, @@ -246,7 +246,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("https"), Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, CertificateRefs: []gatewayv1.SecretObjectReference{ {Name: gatewayv1.ObjectName("foo")}, @@ -265,7 +265,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("tls"), Protocol: gatewayv1.TLSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, CertificateRefs: []gatewayv1.SecretObjectReference{ {Name: gatewayv1.ObjectName("foo")}, @@ -284,7 +284,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("https"), Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, Options: map[gatewayv1.AnnotationKey]gatewayv1.AnnotationValue{ "networking.example.com/tls-version": "1.2", @@ -303,7 +303,7 @@ func TestValidateGateway(t *testing.T) { Name: gatewayv1.SectionName("tls"), Protocol: gatewayv1.TLSProtocolType, Port: gatewayv1.PortNumber(8443), - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ Mode: &tlsMode, Options: map[gatewayv1.AnnotationKey]gatewayv1.AnnotationValue{ "networking.example.com/tls-version": "1.2", @@ -473,7 +473,7 @@ func TestValidateGateway(t *testing.T) { Protocol: gatewayv1.HTTPSProtocolType, Port: gatewayv1.PortNumber(8000), Hostname: &hostnameFoo, - TLS: &gatewayv1.GatewayTLSConfig{ + TLS: &gatewayv1.ListenerTLSConfig{ CertificateRefs: []gatewayv1.SecretObjectReference{ {Name: gatewayv1.ObjectName("foo")}, }, diff --git a/pkg/test/cel/httproute_experimental_test.go b/pkg/test/cel/httproute_experimental_test.go index f6ff0d455b..b9d2289e58 100644 --- a/pkg/test/cel/httproute_experimental_test.go +++ b/pkg/test/cel/httproute_experimental_test.go @@ -241,6 +241,135 @@ func toDuration(durationString string) *gatewayv1.Duration { return (*gatewayv1.Duration)(&durationString) } +func TestHTTPRouteCORS(t *testing.T) { + tests := []struct { + name string + wantErrors []string + corsfilter *gatewayv1.HTTPCORSFilter + }{ + { + name: "Valid cors should be accepted", + wantErrors: nil, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "https://xpto.com", + "http://*.abcd.com", + "http://*.abcd.com:12345", + }, + }, + }, + { + name: "Using wildcard only is accepted", + wantErrors: nil, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "*", + }, + }, + }, + { + name: "Wildcard and other hosts on the same origin list should be denied", + wantErrors: []string{"AllowOrigins cannot contain '*' alongside other origins"}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "*", + "https://xpto.com", + }, + }, + }, + { + name: "An origin without the format scheme://host should be denied", + wantErrors: []string{"Invalid value: \"xpto.com\": spec.rules[0].filters[0].cors.allowOrigins[1] in body should match"}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "https://xpto.com", + "xpto.com", + }, + }, + }, + { + name: "An origin as http://*.com should be accepted", + wantErrors: nil, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "https://*.com", + }, + }, + }, + { + name: "An origin with an invalid port should be denied", + wantErrors: []string{"Invalid value: \"https://xpto.com:notaport\": spec.rules[0].filters[0].cors.allowOrigins[0] in body should match"}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "https://xpto.com:notaport", + }, + }, + }, + { + name: "An origin with an value before the scheme definition should be denied", + wantErrors: []string{"Invalid value: \"xpto/https://xpto.com\""}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowOrigins: []gatewayv1.CORSOrigin{ + "xpto/https://xpto.com", + }, + }, + }, + { + name: "Using an invalid HTTP method should be denied", + wantErrors: []string{"Unsupported value: \"BAZINGA\""}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowMethods: []gatewayv1.HTTPMethodWithWildcard{ + "BAZINGA", + }, + }, + }, + { + name: "Using wildcard and a valid method should be denied", + wantErrors: []string{"AllowMethods cannot contain '*' alongside other methods"}, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowMethods: []gatewayv1.HTTPMethodWithWildcard{ + "GET", + "*", + "POST", + }, + }, + }, + { + name: "Using an array of valid methods should be accepted", + wantErrors: nil, + corsfilter: &gatewayv1.HTTPCORSFilter{ + AllowMethods: []gatewayv1.HTTPMethodWithWildcard{ + "GET", + "OPTIONS", + "POST", + }, + }, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + route := &gatewayv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()), + Namespace: metav1.NamespaceDefault, + }, + Spec: gatewayv1.HTTPRouteSpec{Rules: []gatewayv1.HTTPRouteRule{ + { + Filters: []gatewayv1.HTTPRouteFilter{ + { + Type: gatewayv1.HTTPRouteFilterCORS, + CORS: tc.corsfilter, + }, + }, + }, + }}, + } + validateHTTPRoute(t, route, tc.wantErrors) + }) + } +} + func TestHTTPRouteTimeouts(t *testing.T) { tests := []struct { name string @@ -568,3 +697,49 @@ func TestHTTPRequestMirrorFilterExperimental(t *testing.T) { }) } } + +func TestHTTPExternalAuthFilterExperimental(t *testing.T) { + tests := []struct { + name string + wantErrors []string + rules []gatewayv1.HTTPRouteRule + }{ + { + name: "HTTPRoute - Invalid because protocol is GRPC without GRPC config", + wantErrors: []string{"grpc must be specified when protocol is set to 'GRPC'"}, + rules: []gatewayv1.HTTPRouteRule{{ + Filters: []gatewayv1.HTTPRouteFilter{{ + Type: gatewayv1.HTTPRouteFilterExternalAuth, + ExternalAuth: &gatewayv1.HTTPExternalAuthFilter{ + ExternalAuthProtocol: gatewayv1.HTTPRouteExternalAuthGRPCProtocol, + }, + }}, + }}, + }, + { + name: "HTTPRoute - Invalid because protocol is HTTP without HTTP config", + wantErrors: []string{"http must be specified when protocol is set to 'HTTP'"}, + rules: []gatewayv1.HTTPRouteRule{{ + Filters: []gatewayv1.HTTPRouteFilter{{ + Type: gatewayv1.HTTPRouteFilterExternalAuth, + ExternalAuth: &gatewayv1.HTTPExternalAuthFilter{ + ExternalAuthProtocol: gatewayv1.HTTPRouteExternalAuthHTTPProtocol, + }, + }}, + }}, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + route := &gatewayv1.HTTPRoute{ + ObjectMeta: metav1.ObjectMeta{ + Name: fmt.Sprintf("foo-%v", time.Now().UnixNano()), + Namespace: metav1.NamespaceDefault, + }, + Spec: gatewayv1.HTTPRouteSpec{Rules: tc.rules}, + } + validateHTTPRoute(t, route, tc.wantErrors) + }) + } + +} diff --git a/pkg/test/cel/main_test.go b/pkg/test/cel/main_test.go index 3ba7de1d20..e4c656f72e 100644 --- a/pkg/test/cel/main_test.go +++ b/pkg/test/cel/main_test.go @@ -19,7 +19,7 @@ package main import ( "fmt" "os" - "path" + "path/filepath" "strings" "testing" @@ -29,34 +29,84 @@ import ( "sigs.k8s.io/gateway-api/apis/v1beta1" apisxv1alpha1 "sigs.k8s.io/gateway-api/apisx/v1alpha1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/envtest" ) var k8sClient client.Client func TestMain(m *testing.M) { + scheme := runtime.NewScheme() + var restConfig *rest.Config + var testEnv *envtest.Environment + var err error + + v1alpha3.Install(scheme) + v1alpha2.Install(scheme) + v1beta1.Install(scheme) + v1.Install(scheme) + apisxv1alpha1.Install(scheme) + + // Add core APIs in case we refer secrets, services and configmaps + corev1.AddToScheme(scheme) + + // If one wants to use a local cluster, a KUBECONFIG envvar should be passed, + // otherwise testenv will be used kubeconfig := os.Getenv("KUBECONFIG") - if kubeconfig == "" { - kubeconfig = path.Join(os.Getenv("HOME"), ".kube/config") + if kubeconfig != "" { + restConfig, err = clientcmd.BuildConfigFromFlags("", kubeconfig) + if err != nil { + panic(fmt.Sprintf("Failed to get restConfig from BuildConfigFromFlags: %v", err)) + } + } else { + // The version used here MUST reflect the available versions at + // controller-runtime repo: https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/HEAD/envtest-releases.yaml + // If the envvar is not passed, the latest GA will be used + k8sVersion := os.Getenv("K8S_VERSION") + + crdChannel := "standard" + if requestedCRDChannel, ok := os.LookupEnv("CRD_CHANNEL"); ok { + crdChannel = requestedCRDChannel + } + + testEnv = &envtest.Environment{ + Scheme: scheme, + ErrorIfCRDPathMissing: true, + DownloadBinaryAssets: true, + DownloadBinaryAssetsVersion: k8sVersion, + CRDInstallOptions: envtest.CRDInstallOptions{ + Paths: []string{ + filepath.Join("..", "..", "..", "config", "crd", crdChannel), + }, + CleanUpAfterUse: true, + }, + } + + restConfig, err = testEnv.Start() + if err != nil { + panic(fmt.Sprintf("Error initializing test environment: %v", err)) + } } - restConfig, err := clientcmd.BuildConfigFromFlags("", kubeconfig) + k8sClient, err = client.New(restConfig, client.Options{ + Scheme: scheme, + }) if err != nil { - panic(fmt.Sprintf("Failed to get restConfig from BuildConfigFromFlags: %v", err)) + panic(fmt.Sprintf("Error initializing Kubernetes client: %v", err)) } - k8sClient, err = client.New(restConfig, client.Options{}) - if err != nil { - panic(fmt.Sprintf("Error initializing Kubernetes client: %v", err)) + rc := m.Run() + if testEnv != nil { + if err := testEnv.Stop(); err != nil { + panic(fmt.Sprintf("error stopping test environment: %v", err)) + } } - v1alpha3.Install(k8sClient.Scheme()) - v1alpha2.Install(k8sClient.Scheme()) - v1beta1.Install(k8sClient.Scheme()) - v1.Install(k8sClient.Scheme()) - apisxv1alpha1.Install(k8sClient.Scheme()) - os.Exit(m.Run()) + os.Exit(rc) } func ptrTo[T any](a T) *T { diff --git a/pkg/test/crd/crd_test.go b/pkg/test/crd/crd_test.go new file mode 100644 index 0000000000..9becc1aaf4 --- /dev/null +++ b/pkg/test/crd/crd_test.go @@ -0,0 +1,177 @@ +/* +Copyright 2025 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package crd_test + +import ( + "fmt" + "io/fs" + "os" + "os/exec" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/runtime" + "sigs.k8s.io/controller-runtime/pkg/envtest" + + v1 "sigs.k8s.io/gateway-api/apis/v1" + "sigs.k8s.io/gateway-api/apis/v1alpha2" + "sigs.k8s.io/gateway-api/apis/v1alpha3" + "sigs.k8s.io/gateway-api/apis/v1beta1" + apisxv1alpha1 "sigs.k8s.io/gateway-api/apisx/v1alpha1" +) + +// This test is a replacement for the previously existing tests inside +// tests-crds-validation.sh. +// Instead of relying on a KinD cluster, we can rely on an `envtest` which +// usually is faster to create and teardown the environment +func TestCRDValidation(t *testing.T) { + scheme := runtime.NewScheme() + var testEnv *envtest.Environment + var err error + + // We will extract these from envTest and create our own exec.Cmd to reproduce + // a user doing "kubectl" commands + var kubectlLocation, kubeconfigLocation string + + crdChannel := "standard" + + v1alpha3.Install(scheme) + v1alpha2.Install(scheme) + v1beta1.Install(scheme) + v1.Install(scheme) + apisxv1alpha1.Install(scheme) + + // Add core APIs in case we refer secrets, services and configmaps + corev1.AddToScheme(scheme) + + // The version used here MUST reflect the available versions at + // controller-runtime repo: https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/HEAD/envtest-releases.yaml + // If the envvar is not passed, the latest GA will be used + k8sVersion := os.Getenv("K8S_VERSION") + if requestedCRDChannel, ok := os.LookupEnv("CRD_CHANNEL"); ok { + crdChannel = requestedCRDChannel + } + + t.Run("should be able to start test environment", func(_ *testing.T) { + testEnv = &envtest.Environment{ + Scheme: scheme, + ErrorIfCRDPathMissing: true, + DownloadBinaryAssets: true, + DownloadBinaryAssetsVersion: k8sVersion, + CRDInstallOptions: envtest.CRDInstallOptions{ + Paths: []string{ + filepath.Join("..", "..", "..", "config", "crd", crdChannel), + }, + CleanUpAfterUse: true, + }, + } + + _, err = testEnv.Start() + if err != nil { + panic(fmt.Sprintf("Error initializing test environment: %v", err)) + } + }) + + t.Cleanup(func() { + require.NoError(t, testEnv.Stop()) + }) + + t.Run("should be able to set kubectl and kubeconfig and connect to the cluster", func(t *testing.T) { + kubectlLocation = testEnv.ControlPlane.KubectlPath + require.NotEmpty(t, kubectlLocation) + + kubeconfigLocation = fmt.Sprintf("%s/kubeconfig", filepath.Dir(kubectlLocation)) + require.NoError(t, os.WriteFile(kubeconfigLocation, testEnv.KubeConfig, 0o600)) + + apiResources, err := executeKubectlCommand(t, kubectlLocation, kubeconfigLocation, []string{"api-resources"}) + require.NoError(t, err) + require.Contains(t, apiResources, "gateway.networking.k8s.io/v1") + }) + + t.Run("should be able to install standard examples", func(t *testing.T) { + output, err := executeKubectlCommand(t, kubectlLocation, kubeconfigLocation, []string{"apply", "--recursive", "-f", filepath.Join("..", "..", "..", "examples", "standard")}) + assert.NoError(t, err, "output", output) + }) + + t.Run("should be able to install experimental examples", func(t *testing.T) { + if crdChannel != "experimental" { + t.Skipf("experimental channel not being tested") + } + output, err := executeKubectlCommand(t, kubectlLocation, kubeconfigLocation, []string{"apply", "--recursive", "-f", filepath.Join("..", "..", "..", "examples", "experimental")}) + assert.NoError(t, err, "output", output) + }) + + t.Run("should expect an error in case of validation failure", func(t *testing.T) { + files, err := getInvalidExamplesFiles(t, crdChannel) + require.NoError(t, err) + + for _, example := range files { + t.Run(fmt.Sprintf("validate example %s", example), func(t *testing.T) { + output, err := executeKubectlCommand(t, kubectlLocation, kubeconfigLocation, []string{"apply", "-f", example}) + require.Error(t, err) + assert.True(t, expectedValidationError(output), "output does not contain the expected error", output) + }) + } + }) +} + +func expectedValidationError(cmdoutput string) bool { + return strings.Contains(cmdoutput, "is invalid") || + strings.Contains(cmdoutput, "missing required field") || + strings.Contains(cmdoutput, "denied request") || + strings.Contains(cmdoutput, "Invalid value") +} + +func executeKubectlCommand(t *testing.T, kubectl, kubeconfig string, args []string) (string, error) { + t.Helper() + + cacheDir := filepath.Dir(kubeconfig) + args = append([]string{"--cache-dir", cacheDir}, args...) + + cmd := exec.Command(kubectl, args...) + cmd.Env = []string{ + fmt.Sprintf("KUBECONFIG=%s", kubeconfig), + } + + output, err := cmd.CombinedOutput() + return string(output), err +} + +func getInvalidExamplesFiles(t *testing.T, crdChannel string) ([]string, error) { + t.Helper() + + var files []string + err := filepath.WalkDir(filepath.Join("..", "..", "..", "hack", "invalid-examples"), func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if crdChannel == "standard" && strings.Contains(path, "experimental") { + return nil + } + + if !d.IsDir() && filepath.Ext(path) == ".yaml" { + files = append(files, path) + } + return nil + }) + return files, err +} diff --git a/site-src/api-types/backendtlspolicy.md b/site-src/api-types/backendtlspolicy.md index c0645d444b..ac57bd04ec 100644 --- a/site-src/api-types/backendtlspolicy.md +++ b/site-src/api-types/backendtlspolicy.md @@ -139,10 +139,10 @@ Status defines the observed state of the BackendTLSPolicy and is not user-config way you do for other Gateway API objects to verify correct operation. Note that the status in BackendTLSPolicy uses `PolicyAncestorStatus` to allow you to know which parentReference set that particular status. -[backendtlspolicy]: /references/spec/#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicy -[validation]: /references/spec/#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicy.Validation -[caCertificateRefs]: /references/spec/#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicyValidation.CACertificateRefs -[wellKnownCACertificates]: /references/spec/#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicyValidation.WellKnownCACertificates -[hostname]: /references/spec/#gateway.networking.k8s.io/v1.PreciseHostname +[backendtlspolicy]: ../reference/spec.md#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicy +[validation]: ../reference/spec.md#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicy.Validation +[caCertificateRefs]: ../reference/spec.md#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicyValidation.CACertificateRefs +[wellKnownCACertificates]: ../reference/spec.md#gateway.networking.k8s.io/v1alpha3.BackendTLSPolicyValidation.WellKnownCACertificates +[hostname]: ../reference/spec.md#gateway.networking.k8s.io/v1.PreciseHostname [rfc-3986]: https://tools.ietf.org/html/rfc3986 -[targetRefs]: /references/spec/#gateway.networking.k8s.io/v1alpha2.PolicyTargetReference +[targetRefs]: ../reference/spec.md#gateway.networking.k8s.io/v1alpha2.PolicyTargetReference diff --git a/site-src/api-types/backendtrafficpolicy.md b/site-src/api-types/backendtrafficpolicy.md index b64bc110ee..61dd645229 100644 --- a/site-src/api-types/backendtrafficpolicy.md +++ b/site-src/api-types/backendtrafficpolicy.md @@ -86,8 +86,8 @@ backendRef. TargetRefs is a required object reference, specifying a Backend via its Name, Kind, and Group. Currently, TargetRefs can not be scoped to specific ports on a service. -[backendtrafficpolicy]: /references/specx/#xbackendtrafficpolicy +[backendtrafficpolicy]: /references/specx.md#xbackendtrafficpolicy [localpolicytargetreference]: /references/spec/#gateway.networking.k8s.io/v1alpha2.LocalPolicyTargetReference -[retryConstraint]: /references/specx/#retryconstraint +[retryConstraint]: /references/specx.md#retryconstraint [sessionPersistence]: /references/spec/#gateway.networking.k8s.io/v1.SessionPersistence [httproute]: /references/spec/#https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1beta1.HTTPRoute diff --git a/site-src/api-types/grpcroute.md b/site-src/api-types/grpcroute.md index 69dcfb4082..2b6188ad47 100644 --- a/site-src/api-types/grpcroute.md +++ b/site-src/api-types/grpcroute.md @@ -225,7 +225,7 @@ on `weight` and other fields. For more information on release channels, refer to our [versioning guide](../concepts/versioning.md). -GRPCRoute Rules include an optional `name` field. The applications for the name of a route rule are implementation-specific. It can be used to reference individual route rules by name from other resources, such as in the `sectionName` field of metaresources ([GEP-2648](../geps/gep-2648/index.md#apply-policies-to-sections-of-a-resource)), in the status stanzas of resources related to the route object, to identify internal configuration objects generated by the implementation from GRPCRoute Rule, etc. +GRPCRoute Rules include an optional `name` field. The applications for the name of a route rule are implementation-specific. It can be used to reference individual route rules by name from other resources, such as in the `sectionName` field of metaresources ([GEP-2648](../geps/gep-2648/index.md#section-names)), in the status stanzas of resources related to the route object, to identify internal configuration objects generated by the implementation from GRPCRoute Rule, etc. If specified, the value of the name field must comply with the [`SectionName`](https://github.com/kubernetes-sigs/gateway-api/blob/v1.0.0/apis/v1/shared_types.go#L607-L624) type. diff --git a/site-src/api-types/httproute.md b/site-src/api-types/httproute.md index a1e051ab8a..0551a37c3d 100644 --- a/site-src/api-types/httproute.md +++ b/site-src/api-types/httproute.md @@ -271,7 +271,7 @@ Reference the [timeouts][timeouts] API documentation for additional details. For more information on release channels, refer to our [versioning guide](../concepts/versioning.md). -HTTPRoute Rules include an optional `name` field. The applications for the name of a route rule are implementation-specific. It can be used to reference individual route rules by name from other resources, such as in the `sectionName` field of metaresources ([GEP-2648](../geps/gep-2648/index.md#apply-policies-to-sections-of-a-resource)), in the status stanzas of resources related to the route object, to identify internal configuration objects generated by the implementation from HTTPRoute Rule, etc. +HTTPRoute Rules include an optional `name` field. The applications for the name of a route rule are implementation-specific. It can be used to reference individual route rules by name from other resources, such as in the `sectionName` field of metaresources ([GEP-2648](../geps/gep-2648/index.md#section-names)), in the status stanzas of resources related to the route object, to identify internal configuration objects generated by the implementation from HTTPRoute Rule, etc. If specified, the value of the name field must comply with the [`SectionName`](https://github.com/kubernetes-sigs/gateway-api/blob/v1.0.0/apis/v1/shared_types.go#L607-L624) type. @@ -322,7 +322,7 @@ metadata: ... status: parents: - - parentRefs: + - parentRef: name: gw-example namespace: gw-example-ns conditions: diff --git a/site-src/blog/2021/introducing-v1alpha2.md b/site-src/blog/2021/introducing-v1alpha2.md index fe231f9f40..55f5231efa 100644 --- a/site-src/blog/2021/introducing-v1alpha2.md +++ b/site-src/blog/2021/introducing-v1alpha2.md @@ -146,4 +146,4 @@ We still have lots more to work on. Some of our next items to discuss include: * L4 Route matching If these kinds of topics interest you, we'd love to have your input. Refer to -our [community page](/contributing/community) to see how you can get involved. +our [community page](../../contributing/index.md) to see how you can get involved. diff --git a/site-src/blog/2022/graduating-to-beta.md b/site-src/blog/2022/graduating-to-beta.md index 70064b7fc8..7b0e011560 100644 --- a/site-src/blog/2022/graduating-to-beta.md +++ b/site-src/blog/2022/graduating-to-beta.md @@ -70,12 +70,12 @@ page][community] which includes links to the Slack channel and community meeting [crd]:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ [concepts]:../../concepts/api-overview.md -[guides]:/guides/getting-started/ +[guides]:../../guides/index.md [impl]:../../implementations.md -[install-crds]:/guides/getting-started/#install-the-crds +[install-crds]:../../guides/index.md#installing-gateway-api [issue]:https://github.com/kubernetes-sigs/gateway-api/issues/new/choose [disc]:https://github.com/kubernetes-sigs/gateway-api/discussions -[community]:/contributing/community/ +[community]:../../contributing/index.md ## Release highlights @@ -128,7 +128,7 @@ For this release we've added the following experimental features: - [Routes can attach to Gateways by specifying port numbers](../../geps/gep-957/index.md) - [URL rewrites and path redirects](../../geps/gep-726/index.md) -[ch]:../../concepts/versioning.md#release-channels-eg-experimental-standard +[ch]:../../concepts/versioning.md#release-channels ### Other improvements @@ -146,12 +146,12 @@ possible integration. We are pleased to announce that the service mesh community, including representatives from Cilium Service Mesh, Consul, Istio, Kuma, Linkerd, NGINX Service Mesh and Open Service Mesh, is coming together to form the [GAMMA -Initiative](/concepts/gamma/), a dedicated +Initiative](../../mesh/index.md), a dedicated workstream within the Gateway API subproject focused on Gateway API for Mesh Management and Administration. This group will deliver [enhancement -proposals](/v1beta1/contributing/gep/) consisting +proposals](../../contributing/enhancement-requests.md) consisting of resources, additions, and modifications to the Gateway API specification for mesh and mesh-adjacent use-cases. @@ -169,11 +169,11 @@ As we continue to mature the API for production use cases, here are some of the - [Route delegation][pr1085] - Layer 4 API maturity: Graduating [TCPRoute][tcpr], [UDPRoute][udpr] and [TLSRoute][tlsr] to beta -- [GAMMA Initiative](/concepts/gamma/) - Gateway API for Service Mesh +- [GAMMA Initiative](../../mesh/index.md) - Gateway API for Service Mesh If there's something on this list you want to get involved in, or there's something not on this list that you want to advocate for to get on the roadmap -please join us in the #sig-network-gateway-api channel on Kubernetes Slack or our weekly [community calls](/contributing/community/#meetings). +please join us in the #sig-network-gateway-api channel on Kubernetes Slack or our weekly [community calls](../../contributing/index.md#meetings). [gep1016]:https://github.com/kubernetes-sigs/gateway-api/blob/master/geps/gep-1016.md [grpc]:https://grpc.io/ @@ -181,4 +181,4 @@ please join us in the #sig-network-gateway-api channel on Kubernetes Slack or ou [tcpr]:https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1alpha2/tcproute_types.go [udpr]:https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1alpha2/udproute_types.go [tlsr]:https://github.com/kubernetes-sigs/gateway-api/blob/main/apis/v1alpha2/tlsroute_types.go -[community]:/contributing/community/ +[community]:../../contributing/index.md diff --git a/site-src/blog/2023/0829-mesh-support.md b/site-src/blog/2023/0829-mesh-support.md index 6b79dc633a..7bc15c4429 100644 --- a/site-src/blog/2023/0829-mesh-support.md +++ b/site-src/blog/2023/0829-mesh-support.md @@ -185,21 +185,21 @@ Although these are [Experimental][status] patterns, note that they are available in the [`standard` release channel][ch], since the GAMMA initiative has not needed to introduce new resources or fields to date. -[gamma]:/concepts/gamma/ -[status]:../../geps/overview.md#status -[ch]:../../concepts/versioning.md#release-channels-eg-experimental-standard +[gamma]:../../mesh/index.md +[status]:../../geps/overview.md#gep-states +[ch]:../../concepts/versioning.md#release-channels [cel]:https://kubernetes.io/docs/reference/using-api/cel/ [crd]:https://kubernetes.io/docs/tasks/extend-kubernetes/custom-resources/custom-resource-definitions/ [concepts]:../../concepts/api-overview.md [geps]:../../contributing/enhancement-requests.md -[guides]:/guides/getting-started/ +[guides]:../../guides/index.md [impl]:../../implementations.md -[install-crds]:/guides/getting-started/#install-the-crds +[install-crds]:../../guides/index.md#installing-gateway-api [issue]:https://github.com/kubernetes-sigs/gateway-api/issues/new/choose [disc]:https://github.com/kubernetes-sigs/gateway-api/discussions -[community]:/contributing/community/ -[mesh-routing]:/concepts/gamma/#how-the-gateway-api-works-for-service-mesh -[GEP-1426]:/geps/gep-1426/ +[community]:../../contributing/index.md +[mesh-routing]:../../mesh/index.md +[GEP-1426]:../../geps/gep-1294/index.md [GEP-1324]:../../geps/gep-1324/index.md [GEP-1686]:../../geps/gep-1686/index.md [GEP-1709]:../../geps/gep-1709/index.md diff --git a/site-src/blog/index.md b/site-src/blog/index.md index 98f4bcb109..85027e3d40 100644 --- a/site-src/blog/index.md +++ b/site-src/blog/index.md @@ -17,7 +17,7 @@ your feedback! [:octicons-arrow-right-24: Continue reading][Gateway API: Introducing Service Mesh Support!] -[status]:../geps/overview.md#status +[status]:../geps/overview.md#gep-states [Gateway API: Introducing Service Mesh Support!]:2023/0829-mesh-support.md ## [Gateway API Graduates to Beta] diff --git a/site-src/concepts/api-overview.md b/site-src/concepts/api-overview.md index d04f893bf3..20db51b0ab 100644 --- a/site-src/concepts/api-overview.md +++ b/site-src/concepts/api-overview.md @@ -219,7 +219,7 @@ The following is required for a Route to be attached to a Gateway: The `Port` field described below is currently only included in the "Experimental" channel of Gateway API. For more information on release - channels, refer to the [related documentation](versioning.md#adding-experimental-fields). + channels, refer to the [related documentation](versioning.md#release-channels). A Route can reference a Gateway by specifying the namespace (optional if the Route and the Gateway are in the same namespace) and name of the Gateway in @@ -326,8 +326,8 @@ to any traffic directed to the Service. How and which Routes attach to a given Service is controlled by the Routes themselves (working with Kubernetes RBAC), as covered in the [GAMMA routing documentation]. -[GAMMA]:/concepts/gamma -[GAMMA routing documentation]:/concepts/gamma#gateway-api-for-mesh +[GAMMA]:../mesh/index.md +[GAMMA routing documentation]:../mesh/index.md#connecting-routes-and-services [service mesh]:glossary.md#service-mesh ## Extension points diff --git a/site-src/concepts/use-cases.md b/site-src/concepts/use-cases.md index dfe68d2aad..3199e0a62e 100644 --- a/site-src/concepts/use-cases.md +++ b/site-src/concepts/use-cases.md @@ -14,9 +14,9 @@ organizations, they all have distinct concerns that we need to consider separately.) [roles and personas]:roles-and-personas.md -[Ana]:roles-and-personas.md#ana -[Chihiro]:roles-and-personas.md#chihiro -[Ian]:roles-and-personas.md#ian +[Ana]:roles-and-personas.md#key-roles-and-personas +[Chihiro]:roles-and-personas.md#key-roles-and-personas +[Ian]:roles-and-personas.md#key-roles-and-personas ## The Use Cases @@ -148,7 +148,7 @@ advantage of the service mesh, with custom routing logic, without any bottlenecks in requests to Chihiro or Ian. [east/west]:glossary.md#eastwest-traffic -[GAMMA]:/concepts/gamma/ +[GAMMA]:../mesh/index.md [service mesh]:glossary.md#service-mesh ## Gateway and mesh use case diff --git a/site-src/contributing/devguide.md b/site-src/contributing/devguide.md index 6d3acfdfed..ee5e5bd4c2 100644 --- a/site-src/contributing/devguide.md +++ b/site-src/contributing/devguide.md @@ -36,7 +36,9 @@ command in PR and issue comments][issue-cmds]. For example, Before you start developing with Gateway API, we'd recommend having the following prerequisites installed: -* [Kind](https://kubernetes.io/docs/tasks/tools/#kind): This is a standalone local Kubernetes cluster. At least one container runtime is required. We recommend installing [Docker](https://docs.docker.com/engine/install/). While you can opt for alternatives like [Podman](https://podman.io/docs/installation), please be aware that doing so is at your own risk. +* [KinD](https://kubernetes.io/docs/tasks/tools/#kind): This is a standalone local Kubernetes cluster. At least one container runtime is required. +* [Docker](https://docs.docker.com/engine/install/): This is a prerequisite for running KinD. While you can opt for alternatives like [Podman](https://podman.io/docs/installation), please be aware that doing so is at your own risk. +* [BuildX](https://github.com/docker/buildx): Prerequisite for `make verify` to run. * [Kubectl](https://kubernetes.io/docs/tasks/tools/#kubectl): This is the Kubernetes command-line tool. * [Go](https://golang.org/doc/install): It is the main programming language in this project. Please check this [file](https://github.com/kubernetes-sigs/gateway-api/blob/main/go.mod#L3) to find out the least `Go` version otherwise you might encounter compilation errors. * [Digest::SHA](https://metacpan.org/pod/Digest::SHA): It is a required dependency. You can obtain it by installing the `perl-Digest-SHA` package. diff --git a/site-src/contributing/index.md b/site-src/contributing/index.md index 613b15decc..323fda8992 100644 --- a/site-src/contributing/index.md +++ b/site-src/contributing/index.md @@ -37,10 +37,9 @@ questions, discussions. ## Meetings -Gateway API community meetings happen on the first Tuesday of each month at -8am Pacific Time (15:00 UTC, [convert to your timezone][8am-pst-convert]) and -weekly on all subsequent weeks each month on Mondays at 3pm Pacific Time -(23:00 UTC, [convert to your timezone][3pm-pst-convert]): +Gateway API community meetings happen on alternating weeks: +- **Week A**: Mondays at 3pm Pacific Time (23:00 UTC, [convert to your timezone][3pm-pst-convert]) +- **Week B**: Tuesdays at 8am Pacific Time (16:00 UTC, [convert to your timezone][8am-pst-convert]) Being the main meeting for Gateway API, the topics can vary here and often this is where new topics and ideas are discussed, including both ingress and service @@ -102,13 +101,35 @@ service mesh use cases can be found in a separate | Date | Title | | |----------------|-------|----| -| November, 2019 | [Kubecon 2019 San Diego: Evolving the Kubernetes Ingress APIs to GA and Beyond][2019-kubecon-na-slides] | [slides][2019-kubecon-na-slides], [video][2019-kubecon-na-video]| +| Mar, 2024 | Kubecon 2024 Paris: Configuring Your Service Mesh with Gateway API | [video][2024-kubecon-video-1]| +| Mar, 2024 | Kubecon 2024 Paris: Gateway API: Beyond GA | [video][2024-kubecon-video-2]| +| Mar, 2024 | Kubecon 2024 Paris: Tutorial: Configuring Your Service Mesh with Gateway API | [video][2024-kubecon-video-3]| +| Oct, 2023 | Kubecon 2023 Chicago: Gateway API: The Most Collaborative API in Kubernetes History Is GA | [video][2023-kubecon-video-3]| +| May, 2023 | Kubecon 2023 Amsterdam: Emissary-Ingress: Self-Service APIs and the Kubernetes Gateway API | [video][2023-kubecon-video-1]| +| May, 2023 | Kubecon 2023 Amsterdam: Exiting Ingress 201: A Primer on Extension Mechanisms in Gateway API | [video][2023-kubecon-video-2]| +| Oct, 2022 | Kubecon 2022 Detroit: One API To Rule Them All? What the Gateway API Means For Service Meshes | [video][2022-kubecon-video-4]| +| Oct, 2022 | Kubecon 2022 Detroit: Exiting Ingress With the Gateway API | [video][2022-kubecon-video-3]| +| Oct, 2022 | Kubecon 2022 Detroit: Flagger, Linkerd, And Gateway API: Oh My! | [video][2022-kubecon-video-2]| +| May, 2022 | Kubecon 2022 Valencia: Gateway API: Beta to GA | [video][2022-kubecon-video-1]| +| May, 2021 | Kubecon 2021 Virtual: Google Cloud - Multi-cluster, Blue-green Traffic Splitting with the Gateway API | [video][2021-kubecon-video-2]| +| May, 2021 | Kubecon 2021 Virtual: Gateway API: A New Set of Kubernetes APIs for Advanced Traffic Routing | [video][2021-kubecon-video-1]| +| November, 2019 | Kubecon 2019 San Diego: Evolving the Kubernetes Ingress APIs to GA and Beyond | [video][2019-kubecon-na-video]| | November, 2019 | Kubecon 2019 San Diego: SIG-NETWORK Service/Ingress Evolution Discussion | [slides][2019-kubecon-na-community-slides] | | May, 2019 | [Kubecon 2019 Barcelona: Ingress V2 and Multicluster Services][2019-kubecon-eu] | [slides][2019-kubecon-eu-slides], [video][2019-kubecon-eu-video]| | March, 2018 | SIG-NETWORK: Ingress user survey | [data][survey-data], [slides][survey-slides] | -[2019-kubecon-na]: https://kccncna19.sched.com/event/UaYG/evolving-the-kubernetes-ingress-apis-to-ga-and-beyond-christopher-m-luciano-ibm-bowei-du-google -[2019-kubecon-na-slides]: https://static.sched.com/hosted_files/kccncna19/a5/Kubecon%20San%20Diego%202019%20-%20Evolving%20the%20Kubernetes%20Ingress%20APIs%20to%20GA%20and%20Beyond%20%5BPUBLIC%5D.pdf +[2024-kubecon-video-1]: https://www.youtube.com/watch?v=UMGRp0fGk3o +[2024-kubecon-video-2]: https://www.youtube.com/watch?v=LITg6TvctjM +[2024-kubecon-video-3]: https://www.youtube.com/watch?v=UMGRp0fGk3o +[2023-kubecon-video-3]: https://www.youtube.com/watch?v=V3Vu_FWb4l4 +[2023-kubecon-video-1]: https://www.youtube.com/watch?v=piDYmZObh_M +[2023-kubecon-video-2]: https://www.youtube.com/watch?v=7P55G8GsYRs: +[2022-kubecon-video-4]: https://www.youtube.com/watch?v=vYGP5XdP2TA +[2022-kubecon-video-3]: https://www.youtube.com/watch?v=sTQv4QOC-TI +[2022-kubecon-video-2]: https://www.youtube.com/watch?v=9Ag45POgnKw +[2022-kubecon-video-1]: https://www.youtube.com/watch?v=YPiuicxC8UU +[2021-kubecon-video-2]: https://www.youtube.com/watch?v=vs8YrjdRJJU +[2021-kubecon-video-1]: https://www.youtube.com/watch?v=lCRuzWFJBO0 [2019-kubecon-na-video]: https://www.youtube.com/watch?v=cduG0FrjdJA [2019-kubecon-eu]: https://kccnceu19.sched.com/event/MPb6/ingress-v2-and-multicluster-services-rohit-ramkumar-bowei-du-google [2019-kubecon-eu-slides]: https://static.sched.com/hosted_files/kccnceu19/97/%5Bwith%20speaker%20notes%5D%20Kubecon%20EU%202019_%20Ingress%20V2%20%26%20Multi-Cluster%20Services.pdf diff --git a/site-src/contributing/release-cycle.md b/site-src/contributing/release-cycle.md index 43a811dfff..f25686d1d7 100644 --- a/site-src/contributing/release-cycle.md +++ b/site-src/contributing/release-cycle.md @@ -79,6 +79,21 @@ candidates. These release candidates will enable implementations to test against our release, work out any bugs, and gather early feedback on the viability of the release. +## What happens when GEPs are unable to meet a timeline? + +There will be situations where the above phases and timelines can't be met by +a GEP for one reason or another. In special circumstances (particularly, when it +is is anticipated that only a little bit more time is needed to meet the goal) a +time extension _might_ be granted if requested by the GEP authors, at the +discretion of the maintainers. + +In the normal case however, when a GEP misses the timeline for a phase it will +be pulled out of the release to maximize bandwidth and reduce disruptions to the +overall release timeline. In such a case the Gateway API maintainers will stop +progression and set the status of the GEP to a halted status (such as `Deferred` +or `Declined`) with a note on the GEP explaining why it reached this status and +what it would take to get it re-approved for work in a later iteration. + ## Contributions Welcome in Each Phase The following table illustrates when different kinds of contributions will be diff --git a/site-src/faq.md b/site-src/faq.md index 0e58068968..e02f9032c2 100644 --- a/site-src/faq.md +++ b/site-src/faq.md @@ -1,7 +1,8 @@ # Frequently Asked Questions (FAQ) #### How can I get involved with Gateway API? -The [community](/contributing/community) page keeps track of how to get involved + +The [community](contributing/index.md) page keeps track of how to get involved with the project. #### Will Gateway API replace the Ingress API? diff --git a/site-src/guides/crd-management.md b/site-src/guides/crd-management.md index d2cfd5884c..7a9c05cc0f 100644 --- a/site-src/guides/crd-management.md +++ b/site-src/guides/crd-management.md @@ -33,7 +33,7 @@ explores one possible approach implementations could use to accomplish this. ## Upgrading to a new version Gateway API releases CRDs in two [release -channels](../concepts/versioning.md#release-channels-eg-experimental-standard). +channels](../concepts/versioning.md#release-channels). Sticking with standard channel CRDs will ensure CRD upgrades are both simpler and safer. diff --git a/site-src/guides/http-header-modifier.md b/site-src/guides/http-header-modifier.md index a55e2b86d4..1118124e00 100644 --- a/site-src/guides/http-header-modifier.md +++ b/site-src/guides/http-header-modifier.md @@ -1,7 +1,5 @@ # HTTP Header Modifiers -[HTTPRoute resources](../api-types/httproute.md) can modify the headers of HTTP requests and the HTTP responses from clients. -There are two types of [filters](../api-types/httproute.md#filters-optional) available to meet these requirements: `RequestHeaderModifier` and `ResponseHeaderModifier`. [HTTPRoute resources](../api-types/httproute.md) can modify the headers of HTTP requests and the HTTP responses from clients. There are two types of [filters](../api-types/httproute.md#filters-optional) available to meet these requirements: `RequestHeaderModifier` and `ResponseHeaderModifier`. diff --git a/site-src/guides/migrating-from-ingress.md b/site-src/guides/migrating-from-ingress.md index bef5a6c4a7..77fef68de0 100644 --- a/site-src/guides/migrating-from-ingress.md +++ b/site-src/guides/migrating-from-ingress.md @@ -251,7 +251,7 @@ In contrast, Gateway API specifies how to merge rules and resolve conflicts: * A Gateway implementation must merge the routing rules from all HTTPRoutes attached to a listener. * Conflicts must be handled as - prescribed in [API Design Guide: Conflicts](/guides/api-design/#conflicts). For example, more specific + prescribed in [API Design Guide: Conflicts](../guides/api-design.md#conflicts). For example, more specific matches in a routing rule win over the less specific ones. #### Default Backend diff --git a/site-src/guides/multiple-ns.md b/site-src/guides/multiple-ns.md index dce09dc695..6805f2c5d1 100644 --- a/site-src/guides/multiple-ns.md +++ b/site-src/guides/multiple-ns.md @@ -158,7 +158,7 @@ After these three Routes are deployed, they will all be attached to the list of routing rules. [Routing precedence](../reference/spec.md#gateway.networking.k8s.io/v1.HTTPRouteRule) between these routing rules is determined by most specific match and conflicts are handled according to [conflict -resolution](/concepts/guidelines#conflicts). This provides predictable and +resolution](api-design.md#conflicts). This provides predictable and deterministic merging of routing rules between independent users. Thanks to cross-Namespace routing, the Foobar Corporation can distribute diff --git a/site-src/implementations.md b/site-src/implementations.md index 77fa74a7d2..dc12477c22 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -5,16 +5,86 @@ and provides status and resource references for them. Implementors and integrators of Gateway API are encouraged to update this document with status information about their implementations, the versions they -cover, and documentation to help users get started. +cover, and documentation to help users get started. This status information should +be no longer than a few paragraphs. +## Conformance levels + +There are three levels of Gateway API conformance: + +### Conformant implementations + +These implementations have submitted at least one conformance report that has passes for: + + * All core conformance tests for at least one combination of Route type and + Profile + * All claimed Extended features + +for one of the two (2) most recent Gateway API releases. + +So, it's conformant to support Mesh + HTTPRoute, or Gateway + HTTPRoute, or +Gateway + TLSRoute, or Gateway + Mesh + HTTPRoute, plus any extended features +the implementation claims. But implementaions _must_ support at least one +Profile and one Route type in that profile, and must pass all Core conformance +tests for that Profile and Route type in addition to all claimed Extended +features. + +### Partially Conformant implementations + +These implementations are aiming for full conformance but are not currently +achieving it. They have submitted at least one conformance report passing some +of the tests to be Conformant (as above) for one of the three (3) most recent +Gateway API releases. Note that the requirements to be considered "partially +conformant" may be tightened in a future release of Gateway API. + +### Stale implementations + +These implementations may not be being actively developed and will be removed +from this page on the next page review unless they submit a conformance report +moving them to one of the other categories. + +Page reviews are performed at least one month after every Gateway API release, +with the first being performed after the release of Gateway API v1.3, in late +June 2025. Following the Gateway API v1.5 review process, due in mid-2026, +stale implementations will no longer be listed. + +## Implementation profiles + +Implementations also generally fall into two categories, which are called +_profiles_: + +* **Gateway** controllers reconcile the Gateway resource and are intended to +handle north-south traffic, mainly concerned with coming from outside the +cluster to inside. +* **Mesh** controllers reconcile Service resources with HTTPRoutes attached +and are intended to handle east-west traffic, within the same cluster or +set of clusters. + +Each profile has a set of conformance tests associated with it, that lay out +the expected behavior for implementations to be conformant (as above). + +Implementations may also fit both profiles. + +## Integrations + +Also listed on this page are **integrations**, which are other software +projects that are able to make use of Gateway API resources to perform +other functions (like managing DNS or creating certificates). + +!!! note + This page contains links to third party projects that provide functionality + required for Gateway API to work. The Gateway API project authors aren't + responsible for these projects, which are listed alphabetically within their + class. !!! info "Compare extended supported features across implementations" - [View a table to quickly compare supported features of projects](implementations/v1.1.md). These outline Gateway controller implementations that have passed core conformance tests, and focus on extended conformance features that they have implemented. + [View a table to quickly compare supported features of projects](implementations/v1.2.md). These outline Gateway controller implementations that have passed core conformance tests, and focus on extended conformance features that they have implemented. ## Gateway Controller Implementation Status - [Acnodal EPIC][1] +- [Agent Gateway][40] - [Airlock Microgateway][34] - [Amazon Elastic Kubernetes Service][23] (GA) - [Apache APISIX][2] (beta) @@ -35,6 +105,7 @@ cover, and documentation to help users get started. - [kgateway][37] (GA) - [Kong Ingress Controller][10] (GA) - [Kong Gateway Operator][35] (GA) +* [Kubvernor][39](work in progress) - [Kuma][11] (GA) - [LiteSpeed Ingress Controller][19] - [LoxiLB][36] (beta) @@ -47,9 +118,10 @@ cover, and documentation to help users get started. ## Service Mesh Implementation Status +- [Google Cloud Service Mesh][38] (GA) - [Istio][9] (GA) - [Kuma][11] (GA) -- [Linkerd][28] (experimental) +- [Linkerd][28] (GA) ## Integrations @@ -58,6 +130,7 @@ cover, and documentation to help users get started. - [argo-rollouts][22] (alpha) - [Knative][24] (alpha) - [Kuadrant][26] (GA) +- [kruise-rollouts][41] (alpha) [1]:#acnodal-epic [2]:#apisix @@ -95,9 +168,13 @@ cover, and documentation to help users get started. [35]:#kong-gateway-operator [36]:#loxilb [37]:#kgateway +[38]:#google-cloud-service-mesh +[39]:#kubvernor +[40]:#agentgateway-with-kgateway +[41]:#kruise-rollouts -[gamma]:/concepts/gamma/ +[gamma]:mesh/index.md @@ -114,22 +191,23 @@ In this section you will find specific links to blog posts, documentation and ot [epicdocs]:https://www.epic-gateway.org/ [epicsource]:https://github.com/epic-gateway +### Agent Gateway (with Kgateway) +[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.3.0-Agentgateway-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.3.0/airlock-microgateway) + +[Agent Gateway](https://agentgateway.dev/) is an open source Gateway API implementation focusing on AI use cases, including LLM consumption, LLM serving, agent-to-agent ([A2A](https://a2aproject.github.io/A2A/latest/)), and agent-to-tool ([MCP](https://modelcontextprotocol.io/introduction)). It is the first and only proxy designed specifically for the Kubernetes Gateway API, powered by a high performance and scalable Rust dataplane implementation. + ### Airlock Microgateway -[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.2.1-Airlock%20Microgateway-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.2.1/airlock-microgateway) +[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.3.0-Airlock%20Microgateway-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.3.0/airlock-microgateway) -[Airlock Microgateway][airlock-microgateway] is a Kubernetes native WAAP (Web Application and API Protection) solution to protect microservices. +[Airlock Microgateway][airlock-microgateway] is a Kubernetes native WAAP (Web Application and API Protection, formerly known as WAF) solution optimized for Kubernetes environments and certified for RedHat OpenShift. Modern application security is embedded in the development workflow and follows DevSecOps paradigms. Airlock Microgateway protects your applications and microservices with the tried-and-tested Airlock security features against attacks, while also providing a high degree of scalability. -With [Airlock Microgateway 4.4][airlock-microgateway-gwapi-arch], Airlock Microgateway introduces a sidecarless data plane mode -based on Gateway API to avoid the operational complexity of sidecars. - #### Features -- Kubernetes native integration with sidecar injection and Gateway API support +- Comprehensive WAAP (formerly known as WAF) with security features like Deny Rules to protect against known attacks (OWASP Top 10), header filtering, JSON parsing, OpenAPI specification enforcement, and GraphQL schema validation +- Identity aware proxy which makes it possible to enforce authentication using JWT authentication or OIDC, with OAuth 2.0 Token Introspection and Token Exchange for continuous validation and secure delegation across services - Reverse proxy functionality with request routing rules, TLS termination and remote IP extraction -- Using native Envoy HTTP filters like Lua scripting, RBAC, ext_authz, JWT authentication -- Content security filters for protecting against known attacks (OWASP Top 10) -- API security features like JSON parsing, OpenAPI specification enforcement or GraphQL schema validation +- Easy-to-use Grafana dashboards which provide valuable insights in allowed and blocked traffic and other metrics #### Documentation and links - [Product documentation][airlock-microgateway-documentation] @@ -137,7 +215,6 @@ based on Gateway API to avoid the operational complexity of sidecars. - Check our [Airlock community forum][airlock-microgateway-community-support] and [support process][airlock-microgateway-premium-support] for support. [airlock-microgateway]:https://www.airlock.com/en/secure-access-hub/components/microgateway -[airlock-microgateway-gwapi-arch]:https://docs.airlock.com/microgateway/latest/?topic=MGW-00000141 [airlock-microgateway-documentation]:https://docs.airlock.com/microgateway/latest [airlock-microgateway-guide]:https://docs.airlock.com/microgateway/latest/?topic=MGW-00000142 [airlock-microgateway-community-support]:https://forum.airlock.com/ @@ -184,17 +261,17 @@ Documentation to deploy and use AKO Gateway API can be found at [Avi Kubernetes ### Cilium -[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.0.0-Cilium-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.0.0/cilium) +[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.3.0-Cilium-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.3.0/cilium-cilium) [Cilium][cilium] is an eBPF-based networking, observability and security solution for Kubernetes and other networking environments. It includes [Cilium Service Mesh][cilium-service-mesh], a highly efficient mesh data plane that can be run in [sidecarless mode][cilium-sidecarless] to dramatically improve performance, and avoid the operational complexity of sidecars. Cilium also -supports the sidecar proxy model, offering choice to users. As of [Cilium 1.14][cilium114blog], -Cilium supports Gateway API, passing conformance for v0.7.1. +supports the sidecar proxy model, offering choice to users. +Cilium supports Gateway API, passing conformance for v1.3.0 as of [Cilium 1.18][cilium118blog]. -Cilium is open source and is a CNCF Graduates project. +Cilium is open source and is a CNCF Graduated project. If you have questions about Cilium Service Mesh the #service-mesh channel on [Cilium Slack][cilium-slack] is a good place to start. For contributing to the development @@ -203,19 +280,19 @@ effort, check out the #development channel or join our [weekly developer meeting [cilium]:https://cilium.io [cilium-service-mesh]:https://docs.cilium.io/en/stable/gettingstarted/#service-mesh [cilium-sidecarless]:https://isovalent.com/blog/post/cilium-service-mesh/ -[cilium114blog]:https://isovalent.com/blog/post/cilium-release-114/ +[cilium118blog]:https://isovalent.com/blog/post/cilium-1-18/#service-mesh-gateway-api [cilium-slack]:https://cilium.io/slack [cilium-meeting]:https://github.com/cilium/cilium#weekly-developer-meeting ### Contour -[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.1.0-Contour-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.1.0/projectcontour-contour) +[![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.2.1-Contour-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.2.1/projectcontour-contour) [Contour][contour] is a CNCF open source Envoy-based ingress controller for Kubernetes. -Contour [v1.30.0][contour-release] implements Gateway API v1.1.0. +Contour [v1.31.0][contour-release] implements Gateway API v1.2.1. All [Standard channel][contour-standard] v1 API group resources (GatewayClass, Gateway, HTTPRoute, ReferenceGrant), plus most v1alpha2 API group resources (TLSRoute, TCPRoute, GRPCRoute, ReferenceGrant, and BackendTLSPolicy) are supported. -Contour's implementation passes all core and most extended Gateway API conformance tests included in the v1.1.0 release. +Contour's implementation passes most core extended Gateway API conformance tests included in the v1.2.1 release. See the [Contour Gateway API Guide][contour-guide] for information on how to deploy and use Contour's Gateway API implementation. @@ -223,7 +300,7 @@ For help and support with Contour's implementation, [create an issue][contour-is [contour]:https://projectcontour.io [contour-release]:https://github.com/projectcontour/contour/releases/tag/v1.30.0 -[contour-standard]:concepts/versioning.md#release-channels-eg-experimental-standard +[contour-standard]:concepts/versioning.md#release-channels [contour-guide]:https://projectcontour.io/docs/1.30/guides/gateway-api/ [contour-issue-new]:https://github.com/projectcontour/contour/issues/new/choose [contour-slack]:https://kubernetes.slack.com/archives/C8XRH2R4J @@ -290,6 +367,23 @@ profile except `HTTPRouteServiceTypes`. [gloogateway]:https://docs.solo.io/gateway/latest/ [solo]:https://www.solo.io +### Google Cloud Service Mesh + + +[Google Kubernetes Engine (GKE)][gke] is a managed Kubernetes platform offered +by Google Cloud. + +GKE's implementation of Gateway For Mesh (GAMMA) is through the [Cloud Service Mesh][cloud-service-mesh]. + + +Google Cloud Service Mesh supports [Envoy-based sidecar mesh][envoy-sidecar-mesh] and [Proxyless-GRPC][proxyless-grpc-mesh] (using GRPCRoute). + + +[gke]:https://cloud.google.com/kubernetes-engine +[cloud-service-mesh]:https://cloud.google.com/products/service-mesh +[envoy-sidecar-mesh]:https://cloud.google.com/service-mesh/docs/gateway/set-up-envoy-mesh +[proxyless-grpc-mesh]:https://cloud.google.com/service-mesh/docs/gateway/proxyless-grpc-mesh + ### Google Kubernetes Engine [![Conformance](https://img.shields.io/badge/Gateway_API_Partial_Conformance_v1.1.0-Google_Kubernetes_Engine-orange)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.1.0/gke-gateway) @@ -404,6 +498,12 @@ For help and support with Kong Gateway operator please feel free to [create an i [kgo-issue-new]:https://github.com/Kong/gateway-operator/issues/new [kgo-disc-new]:https://github.com/Kong/gateway-operator/discussions/new + +### Kubvernor +[Kubvernor][kubvernor] is an open-source, highly experimental implementation of API controller in Rust programming language. Currently, Kubernor supports Envoy Proxy. The project aims to be as generic as possible so Kubvernor can be used to manage/deploy different gateways (Envoy, Nginx, HAProxy, etc.). + +[kubvernor]:https://github.com/kubvernor/kubvernor + ### Kuma [![Conformance](https://img.shields.io/badge/Gateway%20API%20Conformance%20v1.0.0-Kuma-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.0.0/kumahq-kuma) @@ -473,7 +573,13 @@ If you have any suggestions or experience issues with NGINX Gateway Fabric, plea ### ngrok Kubernetes Operator -[ngrok Kubernetes Operator][ngrok-k8s-operator] provides an implementation of the Gateway API that uses [ngrok's ingress-as-a-service][ngrok]. This project uses the Gateway API to support routing traffic from ngrok's global network to applications running on Kubernetes clusters. This easily adds the benefits of ngrok, like security, network policy, and a global presence with the simplicity of cloud service. The operator contains both a Gateway API implementation as well as a controller using Kubernetes Ingress. The Gateway API implementation is currently under development and supports only the Gateway, GatewayClass and HTTPRoute. As the TLSRoute and TCPRoute move from experimental to stable, they will also be implemented. +[ngrok Kubernetes Operator][ngrok-k8s-operator] After adding preliminary support last year, the [ngrok Kubernetes Operator][ngrok-k8s-operator] supports the entire core Gateway API. This includes: + +- Routes (HTTPRoute, TCPRoute, TLSRoute) + RouteMatches (Header, Path, +more) +- Filters: Header, Redirect, Rewrite + more +- Backends: Backend Filters + Weighted balancing +- ReferenceGrant: RBAC for multi-tenant clusters handling +- Traffic Policy as an extensionRef or annotation when the Gateway API isn’t flexible enough You can read our [docs][ngrok-k8s-gwapi-docs] for more information. If you have any feature requests or bug reports, please [create an issue][ngrok-issue-new]. You can also reach out for help on [Slack][ngrok-slack] @@ -580,3 +686,63 @@ For help and support with Kuadrant's implementation please feel free to [create [kuadrant]:https://kuadrant.io/ [kuadrant-issue-new]:https://github.com/Kuadrant/kuadrant-operator/issues/new [kuadrant-slack]:https://kubernetes.slack.com/archives/C05J0D0V525 + +### OpenKruise Rollouts +[OpenKruise Rollouts][kruise-rollouts] is a plugin-n-play progressive delivery controller for Kubernetes. It supports several advanced deployment methods such as blue/green and canaries. OpenKruise Rollouts has built-in support for the Gateway API. + +[kruise-rollouts]:https://openkruise.io/rollouts/introduction + +## Adding new entries + +Implementations are free to make a PR to add their entry to this page; however, +in order to meet the requirements for being Partially Conformant or Conformant, +the implementation must have had a conformance report submission PR merged. + +Part of the review process for new additions to this page is that a maintainer +will check the conformance level and verify the state. + +## Page Review Policy + +This page is intended to showcase actively developed and conformant implementations +of Gateway API, and so is subject to regular reviews. + +These reviews are performed at least one month after every Gateway API release +(starting with the Gateway API v1.3 release). + +As part of the review, a maintainer will check: + +* which implementations are **Conformant** - as defined above in this document. +* which implementations are **Partially Conformant**, as defined above in this + document. + +If the maintainer performing the review finds that there are implementations +that no longer satisfy the criteria for Partially Conformant or Conformant, or +finds implementations that are in the "Stale" state, then that maintainer will: + +* Inform the other maintainers and get their agreement on the list of stale and +to-be-removed implementations +* Post on the #sig-network-gateway-api channel informing the maintainers of +implementations that are no longer at least partially conformant should contact +the Gateway API maintainers to discuss the implementation's status. This period +is called the "**right-of-reply**" period, is at least two weeks long, and functions +as a lazy consensus period. +* Any implementations that do not respond within the right-of-reply period will be +downgraded in status, either by being moved to "Stale", or being removed +from this page if they are already "Stale". + +Page review timeline, starting with the v1.3 Page Review: + +* Gateway API v1.3 release Page Review: a maintainer will move anyone who hasn't + submitted a conformance report using the rules above to "Stale". They will also + contact anyone who moves to Stale to inform them about this rule change. +* Gateway API v1.4 release Page Review (at least one month after the actual + release): A maintainer will perform the Page Review process again, removing + any implementations that are are still Stale (after a right-of-reply period). +* Gateway API v1.5 release Page Review (at least one month after the actual + release): We will remove the Stale category, and implementation maintainers + will need to be at least partially conformant on each review, or during the + right-of-reply period, or be removed from the implementations page. + +This means that, after the Gateway API v1.5 release, implementations cannot be +added to this page unless they have submitted at least a Partially Conformant +conformance report. diff --git a/site-src/implementations/v1.0.md b/site-src/implementations/v1.0.md index 901a48a138..e268964115 100644 --- a/site-src/implementations/v1.0.md +++ b/site-src/implementations/v1.0.md @@ -1,6 +1,6 @@ The following tables are populated from the conformance reports [uploaded by project implementations](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports). They are separated into the extended features that each project supports listed in their reports. -Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. +Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. Implementations that submit conformance reports with skipped tests won't appear in the tables. @@ -16,33 +16,33 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | HTTPRouteMethodMatching | HTTPRouteQueryParamMatching | HTTPRouteResponseHeaderModification | HTTPRouteBackendTimeout | HTTPRoutePortRedirect | HTTPRoutePathRedirect | HTTPRouteHostRewrite | HTTPRouteSchemeRedirect | HTTPRoutePathRewrite | HTTPRouteParentRefPort | HTTPRouteRequestMirror | HTTPRouteRequestMultipleMirrors | HTTPRouteRequestTimeout | -|:----------------|:-----------------------------------|:--------------|:--------------------------|:------------------------------|:--------------------------------------|:--------------------------|:------------------------|:------------------------|:-----------------------|:--------------------------|:-----------------------|:-------------------------|:-------------------------|:----------------------------------|:--------------------------| -| Kong | kubernetes-ingress-controller | v3.0.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.1.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| Microsoft Azure | Application Gateway for Containers | v1.0.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | -| cilium | cilium | v1.15.0-pre.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v0.6.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| kumahq | kuma | 2.6.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | -| nginx | nginx-gateway-fabric | v1.1.0 | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | -| nginx | nginx-gateway-fabric | v1.2.0 | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | -| projectcontour | contour | v1.28.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.28.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.28.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.28.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.28.5 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.28.6 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.29.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.29.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| projectcontour | contour | v1.29.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| solo.io | gloo-gateway | v1.17.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | +| Organization | Project | Version | HTTPRoute Method Matching | HTTPRoute Query Param Matching | HTTPRoute Response Header Modification | HTTPRoute Backend Timeout | HTTPRoute Port Redirect | HTTPRoute Path Redirect | HTTPRoute Host Rewrite | HTTPRoute Scheme Redirect | HTTPRoute Path Rewrite | HTTPRoute Parent Ref Port | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Timeout | +|:----------------|:-----------------------------------|:--------------|:----------------------------|:---------------------------------|:-----------------------------------------|:----------------------------|:--------------------------|:--------------------------|:-------------------------|:----------------------------|:-------------------------|:----------------------------|:---------------------------|:-------------------------------------|:----------------------------| +| Kong | kubernetes-ingress-controller | v3.0.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.1.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Microsoft Azure | Application Gateway for Containers | v1.0.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | +| cilium | cilium | v1.15.0-pre.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v0.6.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| kumahq | kuma | 2.6.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.1.0 | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.2.0 | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | +| projectcontour | contour | v1.28.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.28.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.28.3 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.28.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.28.5 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.28.6 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.29.0 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.29.1 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.29.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| solo.io | gloo-gateway | v1.17.4 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | ## Mesh Profile ### HTTPRoute -| Organization | Project | Version | HTTPRouteRequestTimeout | HTTPRoutePathRedirect | HTTPRouteRequestMirror | HTTPRoutePathRewrite | HTTPRouteMethodMatching | HTTPRouteRequestMultipleMirrors | HTTPRouteBackendTimeout | HTTPRouteResponseHeaderModification | HTTPRoutePortRedirect | HTTPRouteSchemeRedirect | HTTPRouteHostRewrite | HTTPRouteQueryParamMatching | -|:---------------|:----------|:----------|:--------------------------|:------------------------|:-------------------------|:-----------------------|:--------------------------|:----------------------------------|:--------------------------|:--------------------------------------|:------------------------|:--------------------------|:-----------------------|:------------------------------| -| istio | istio | 1.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| kumahq | kuma | 2.6.0 | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | \ No newline at end of file +| Organization | Project | Version | HTTPRoute Request Timeout | HTTPRoute Path Redirect | HTTPRoute Request Mirror | HTTPRoute Path Rewrite | HTTPRoute Method Matching | HTTPRoute Request Multiple Mirrors | HTTPRoute Backend Timeout | HTTPRoute Response Header Modification | HTTPRoute Port Redirect | HTTPRoute Scheme Redirect | HTTPRoute Host Rewrite | HTTPRoute Query Param Matching | +|:---------------|:----------|:----------|:----------------------------|:--------------------------|:---------------------------|:-------------------------|:----------------------------|:-------------------------------------|:----------------------------|:-----------------------------------------|:--------------------------|:----------------------------|:-------------------------|:---------------------------------| +| istio | istio | 1.2 | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| kumahq | kuma | 2.6.0 | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | \ No newline at end of file diff --git a/site-src/implementations/v1.1.md b/site-src/implementations/v1.1.md index 577c5642a6..69a3326bfb 100644 --- a/site-src/implementations/v1.1.md +++ b/site-src/implementations/v1.1.md @@ -1,6 +1,6 @@ The following tables are populated from the conformance reports [uploaded by project implementations](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports). They are separated into the extended features that each project supports listed in their reports. -Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. +Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. Implementations that submit conformance reports with skipped tests won't appear in the tables. @@ -16,50 +16,56 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | Mode | GatewayPort8080 | HTTPRouteHostRewrite | HTTPRoutePathRedirect | HTTPRouteRequestMirror | HTTPRouteResponseHeaderModification | HTTPRouteSchemeRedirect | HTTPRouteMethodMatching | HTTPRoutePathRewrite | HTTPRouteQueryParamMatching | HTTPRouteParentRefPort | GatewayHTTPListenerIsolation | GatewayStaticAddresses | HTTPRouteBackendProtocolH2C | HTTPRouteBackendProtocolWebSocket | HTTPRouteBackendRequestHeaderModification | HTTPRouteBackendTimeout | HTTPRoutePortRedirect | HTTPRouteRequestMultipleMirrors | HTTPRouteRequestTimeout | -|:---------------|:------------------------------|:-------------------|:---------------------------------|:-------------------|:-----------------------|:------------------------|:-------------------------|:--------------------------------------|:--------------------------|:--------------------------|:-----------------------|:------------------------------|:-------------------------|:-------------------------------|:-------------------------|:------------------------------|:------------------------------------|:--------------------------------------------|:--------------------------|:------------------------|:----------------------------------|:--------------------------| -| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-global-external-managed | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-rilb | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-regional-external-managed | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.2.0 | expressions | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.3.1 | expressions | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| airlock | microgateway | v4.4.0 | default | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.3.0 | default | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | -| nginx | nginx-gateway-fabric | v1.4.0 | default | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | -| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| traefik | traefik | v3.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | +| Organization | Project | Version | Mode | Gateway Port 8080 | HTTPRoute Host Rewrite | HTTPRoute Path Redirect | HTTPRoute Request Mirror | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | HTTPRoute Method Matching | HTTPRoute Path Rewrite | HTTPRoute Query Param Matching | HTTPRoute Port Redirect | HTTPRoute Parent Ref Port | Gateway HTTP Listener Isolation | Gateway Static Addresses | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Timeout | +|:----------------|:-----------------------------------|:-------------------|:---------------------------------|:--------------------|:-------------------------|:--------------------------|:---------------------------|:-----------------------------------------|:----------------------------|:----------------------------|:-------------------------|:---------------------------------|:--------------------------|:----------------------------|:----------------------------------|:---------------------------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:-------------------------------------|:----------------------------| +| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-global-external-managed | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-rilb | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| GKE | gke-gateway | 1.30.3-gke.1211000 | gke-l7-regional-external-managed | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.2.0 | expressions | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.3.1 | expressions | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Microsoft Azure | Application Gateway for Containers | 1.3.7 | default | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.6.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.7.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | v4.4.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v1.3.0 | default | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.4.0 | default | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| solo.io | gloo-gateway | v1.18.0-beta30 | default | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| traefik | traefik | v3.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | ### GRPCRoute -| Organization | Project | Version | Mode | GatewayHTTPListenerIsolation | GatewayPort8080 | GatewayStaticAddresses | -|:---------------|:------------------------------|:----------|:------------|:-------------------------------|:-------------------|:-------------------------| -| Kong | kubernetes-ingress-controller | v3.2.0 | expressions | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.3.1 | expressions | :x: | :x: | :x: | -| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.3.0 | default | :x: | :x: | :x: | -| nginx | nginx-gateway-fabric | v1.4.0 | default | :x: | :x: | :x: | -| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Organization | Project | Version | Mode | Gateway HTTP Listener Isolation | Gateway Port 8080 | Gateway Static Addresses | +|:----------------|:-----------------------------------|:----------|:------------|:----------------------------------|:--------------------|:---------------------------| +| Kong | kubernetes-ingress-controller | v3.2.0 | expressions | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.3.1 | expressions | :x: | :x: | :x: | +| Microsoft Azure | Application Gateway for Containers | 1.3.7 | default | :x: | :x: | :x: | +| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v1.3.0 | default | :x: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.4.0 | default | :x: | :x: | :x: | +| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | ### TLSRoute -| Organization | Project | Version | Mode | GatewayHTTPListenerIsolation | GatewayPort8080 | GatewayStaticAddresses | -|:---------------|:---------------------|:----------|:--------|:-------------------------------|:-------------------|:-------------------------| -| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.4.0 | default | :x: | :x: | :x: | -| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Organization | Project | Version | Mode | Gateway HTTP Listener Isolation | Gateway Port 8080 | Gateway Static Addresses | +|:---------------|:---------------------|:----------|:--------|:----------------------------------|:--------------------|:---------------------------| +| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.22 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v1.4.0 | default | :x: | :x: | :x: | +| projectcontour | contour | v1.30.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | ## Mesh Profile ### HTTPRoute -| Organization | Project | Version | Mode | HTTPRouteBackendProtocolH2C | HTTPRouteBackendProtocolWebSocket | HTTPRouteBackendRequestHeaderModification | HTTPRouteBackendTimeout | HTTPRouteHostRewrite | HTTPRouteMethodMatching | HTTPRoutePathRedirect | HTTPRoutePathRewrite | HTTPRoutePortRedirect | HTTPRouteQueryParamMatching | HTTPRouteRequestMirror | HTTPRouteRequestMultipleMirrors | HTTPRouteRequestTimeout | HTTPRouteResponseHeaderModification | HTTPRouteSchemeRedirect | MeshClusterIPMatching | MeshConsumerRoute | HTTPRouteParentRefPort | -|:---------------|:----------|:----------|:--------|:------------------------------|:------------------------------------|:--------------------------------------------|:--------------------------|:-----------------------|:--------------------------|:------------------------|:-----------------------|:------------------------|:------------------------------|:-------------------------|:----------------------------------|:--------------------------|:--------------------------------------|:--------------------------|:------------------------|:--------------------|:-------------------------| -| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | -| istio | istio | 1.22 | default | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | \ No newline at end of file +| Organization | Project | Version | Mode | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Path Redirect | HTTPRoute Path Rewrite | HTTPRoute Port Redirect | HTTPRoute Query Param Matching | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Mesh Cluster IP Matching | Mesh Consumer Route | HTTPRoute Parent Ref Port | +|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------|:----------------------|:----------------------------| +| cilium | cilium | v1.16.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| istio | istio | 1.22 | default | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | \ No newline at end of file diff --git a/site-src/implementations/v1.2.md b/site-src/implementations/v1.2.md index 5f7b35a34b..a3728f6aca 100644 --- a/site-src/implementations/v1.2.md +++ b/site-src/implementations/v1.2.md @@ -1,6 +1,6 @@ The following tables are populated from the conformance reports [uploaded by project implementations](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports). They are separated into the extended features that each project supports listed in their reports. -Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. +Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. Implementations that submit conformance reports with skipped tests won't appear in the tables. @@ -16,43 +16,57 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | Mode | GatewayPort8080 | HTTPRouteHostRewrite | HTTPRouteMethodMatching | HTTPRoutePathRewrite | HTTPRouteQueryParamMatching | HTTPRouteResponseHeaderModification | GatewayHTTPListenerIsolation | GatewayInfrastructurePropagation | GatewayStaticAddresses | HTTPRouteBackendProtocolH2C | HTTPRouteBackendProtocolWebSocket | HTTPRouteBackendRequestHeaderModification | HTTPRouteBackendTimeout | HTTPRouteDestinationPortMatching | HTTPRoutePathRedirect | HTTPRoutePortRedirect | HTTPRouteRequestMirror | HTTPRouteRequestMultipleMirrors | HTTPRouteRequestTimeout | HTTPRouteSchemeRedirect | HTTPRouteParentRefPort | -|:---------------|:------------------------------|:----------------------|:------------|:-------------------|:-----------------------|:--------------------------|:-----------------------|:------------------------------|:--------------------------------------|:-------------------------------|:-----------------------------------|:-------------------------|:------------------------------|:------------------------------------|:--------------------------------------------|:--------------------------|:-----------------------------------|:------------------------|:------------------------|:-------------------------|:----------------------------------|:--------------------------|:--------------------------|:-------------------------| -| Kong | gateway-operator | v1.4.0 | expressions | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.2.0-244-gea4944bb0 | expressions | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | -| cilium | cilium | v1.17.0-pre.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | -| envoyproxy | envoy-gateway | v1.2.0-rc.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :x: | -| solo.io | gloo-gateway | v1.18.0 | default | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | -| traefik | traefik | v3.2 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :x: | +| Organization | Project | Version | Mode | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Path Rewrite | HTTPRoute Query Param Matching | HTTPRoute Response Header Modification | HTTPRoute Destination Port Matching | HTTPRoute Path Redirect | HTTPRoute Port Redirect | HTTPRoute Scheme Redirect | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Timeout | HTTPRoute Parent Ref Port | HTTPRoute Request Timeout | Gateway HTTP Listener Isolation | Gateway Static Addresses | HTTPRoute Backend Request Header Modification | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | +|:----------------|:-----------------------------------|:----------|:-----------------------|:-------------------------|:----------------------------|:-------------------------|:---------------------------------|:-----------------------------------------|:--------------------------------------|:--------------------------|:--------------------------|:----------------------------|:-------------------------------------|:--------------------|:---------------------------------|:----------------------------------------|:----------------------------|:----------------------------|:----------------------------|:----------------------------------|:---------------------------|:------------------------------------------------|:---------------------------|:-------------------------------------| +| Kong | kubernetes-ingress-controller | v3.4.0 | expressions | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.4.0 | traditional_compatible | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| Microsoft Azure | Application Gateway for Containers | 1.7.9 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.6.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| airlock | microgateway | 4.7.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| cilium | cilium | v1.17 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | latest | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| kgateway-dev | kgateway | v2.0.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | +| kubvernor | kubvernor | 0.1.0 | default | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.6.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v2.0.2 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | +| projectcontour | contour | v1.31.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| traefik | traefik | v3.2.2 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | :x: | ### GRPCRoute -| Organization | Project | Version | Mode | GatewayHTTPListenerIsolation | GatewayInfrastructurePropagation | GatewayPort8080 | GatewayStaticAddresses | -|:---------------|:------------------------------|:----------------------|:------------|:-------------------------------|:-----------------------------------|:-------------------|:-------------------------| -| Kong | kubernetes-ingress-controller | v3.2.0-244-gea4944bb0 | expressions | :x: | :x: | :x: | :x: | -| cilium | cilium | v1.17.0-pre.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v1.2.0-rc.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.5.0 | default | :x: | :x: | :x: | :x: | -| traefik | traefik | v3.2 | default | :x: | :x: | :x: | :x: | +| Organization | Project | Version | Mode | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | +|:----------------|:-----------------------------------|:----------|:-----------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| +| Kong | kubernetes-ingress-controller | v3.4.0 | expressions | :x: | :x: | :x: | :x: | +| Kong | kubernetes-ingress-controller | v3.4.0 | traditional_compatible | :x: | :x: | :x: | :x: | +| Microsoft Azure | Application Gateway for Containers | 1.7.9 | default | :x: | :x: | :x: | :x: | +| cilium | cilium | v1.17 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | latest | default | :x: | :x: | :x: | :x: | +| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| kubvernor | kubvernor | 0.1.0 | default | :x: | :x: | :x: | :x: | +| nginx | nginx-gateway-fabric | v1.6.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| nginx | nginx-gateway-fabric | v2.0.2 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| projectcontour | contour | v1.31.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| traefik | traefik | v3.2.2 | default | :x: | :x: | :x: | :x: | ### TLSRoute -| Organization | Project | Version | Mode | GatewayHTTPListenerIsolation | GatewayInfrastructurePropagation | GatewayPort8080 | GatewayStaticAddresses | -|:---------------|:---------------------|:--------------|:--------|:-------------------------------|:-----------------------------------|:-------------------|:-------------------------| -| cilium | cilium | v1.17.0-pre.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| envoyproxy | envoy-gateway | v1.2.0-rc.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -| nginx | nginx-gateway-fabric | v1.5.0 | default | :x: | :x: | :x: | :x: | -| traefik | traefik | v3.2 | default | :x: | :x: | :x: | :x: | +| Organization | Project | Version | Mode | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | +|:---------------|:---------------------|:----------|:--------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| +| cilium | cilium | v1.17 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | latest | default | :x: | :x: | :x: | :x: | +| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v1.6.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| nginx | nginx-gateway-fabric | v2.0.2 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| projectcontour | contour | v1.31.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| traefik | traefik | v3.2.2 | default | :x: | :x: | :x: | :x: | ## Mesh Profile ### HTTPRoute -| Organization | Project | Version | Mode | HTTPRouteBackendProtocolH2C | HTTPRouteBackendProtocolWebSocket | HTTPRouteBackendRequestHeaderModification | HTTPRouteBackendTimeout | HTTPRouteDestinationPortMatching | HTTPRouteHostRewrite | HTTPRouteMethodMatching | HTTPRoutePathRedirect | HTTPRoutePathRewrite | HTTPRoutePortRedirect | HTTPRouteQueryParamMatching | HTTPRouteRequestMirror | HTTPRouteRequestMultipleMirrors | HTTPRouteRequestTimeout | HTTPRouteResponseHeaderModification | HTTPRouteSchemeRedirect | MeshClusterIPMatching | HTTPRouteParentRefPort | MeshConsumerRoute | -|:---------------|:----------|:--------------|:--------|:------------------------------|:------------------------------------|:--------------------------------------------|:--------------------------|:-----------------------------------|:-----------------------|:--------------------------|:------------------------|:-----------------------|:------------------------|:------------------------------|:-------------------------|:----------------------------------|:--------------------------|:--------------------------------------|:--------------------------|:------------------------|:-------------------------|:--------------------| -| cilium | cilium | v1.17.0-pre.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | -| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | \ No newline at end of file +| Organization | Project | Version | Mode | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Path Redirect | HTTPRoute Path Rewrite | HTTPRoute Port Redirect | HTTPRoute Query Param Matching | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Mesh Cluster IP Matching | HTTPRoute Parent Ref Port | Mesh Consumer Route | +|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------|:----------------------------|:----------------------| +| cilium | cilium | v1.17 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | +| istio | istio | 1.24 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | \ No newline at end of file diff --git a/site-src/implementations/v1.3.md b/site-src/implementations/v1.3.md new file mode 100644 index 0000000000..653a8b8077 --- /dev/null +++ b/site-src/implementations/v1.3.md @@ -0,0 +1,63 @@ + +The following tables are populated from the conformance reports [uploaded by project implementations](https://github.com/kubernetes-sigs/gateway-api/tree/main/conformance/reports). They are separated into the extended features that each project supports listed in their reports. +Implementations only appear in this page if they pass Core conformance for the resource type, and the features listed should be Extended features. Implementations that submit conformance reports with skipped tests won't appear in the tables. + + + +???+ warning + + + This page is under active development and is not in its final form, + especially for the project name and the names of the features. + However, as it is based on submitted conformance reports, the information is correct. + + +## Gateway Profile + +### HTTPRoute + +| Organization | Project | Version | Mode | Gateway Address Empty | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Parent Ref Port | HTTPRoute Path Redirect | HTTPRoute Path Rewrite | HTTPRoute Port Redirect | HTTPRoute Query Param Matching | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Percentage Mirror | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | +|:---------------|:---------------------|:------------|:-----------------|:------------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------| +| agentgateway | agentgateway | v0.6.0-dev | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| airlock | microgateway | 4.6.0 | default | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| airlock | microgateway | 4.7.0 | default | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.5.0 | GatewayNamespace | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| istio | istio | 1.26.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| kgateway-dev | kgateway | v2.1.0-main | default | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v2.0.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v2.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | + +### GRPCRoute + +| Organization | Project | Version | Mode | Gateway Address Empty | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | +|:---------------|:---------------------|:----------|:-----------------|:------------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| +| cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.5.0 | GatewayNamespace | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| envoyproxy | envoy-gateway | v1.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| istio | istio | 1.26.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v2.0.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| nginx | nginx-gateway-fabric | v2.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | + +### TLSRoute + +| Organization | Project | Version | Mode | Gateway Address Empty | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | +|:---------------|:---------------------|:----------|:-----------------|:------------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| +| cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| envoyproxy | envoy-gateway | v1.5.0 | GatewayNamespace | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| envoyproxy | envoy-gateway | v1.5.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| istio | istio | 1.26.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| nginx | nginx-gateway-fabric | v2.0.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | +| nginx | nginx-gateway-fabric | v2.1.0 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | + +## Mesh Profile + +### HTTPRoute + +| Organization | Project | Version | Mode | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Request Header Modification | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Parent Ref Port | HTTPRoute Path Redirect | HTTPRoute Path Rewrite | HTTPRoute Port Redirect | HTTPRoute Query Param Matching | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Percentage Mirror | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Mesh Cluster IP Matching | Mesh Consumer Route | Mesh HTTPRoute Backend Request Header Modification | Mesh HTTPRoute Query Param Matching | Mesh HTTPRoute Redirect Port | Mesh HTTPRoute Scheme Redirect | +|:---------------|:-------------------------------|:----------------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------|:----------------------|:-----------------------------------------------------|:--------------------------------------|:-------------------------------|:---------------------------------| +| Buoyant | Buoyant Enterprise for Linkerd | enterprise-2.18 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| Linkerd | Linkerd | version-2.18 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| istio | istio | 1.26.1 | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | \ No newline at end of file diff --git a/site-src/index.md b/site-src/index.md index 417c3f23ab..088315b24d 100644 --- a/site-src/index.md +++ b/site-src/index.md @@ -69,15 +69,15 @@ individual route resources (such as [HTTPRoute](api-types/httproute.md)) are mesh to manage traffic from any traffic directed to that Service while preserving the role-oriented nature of Gateway API. -To date, [GAMMA](mesh/gamma.md) has been able to support mesh functionality with +To date, [GAMMA](mesh/index.md) has been able to support mesh functionality with fairly minimal changes to Gateway API. One particular area that has rapidly become critical for GAMMA, though, is the definition of the different [facets of the Service resource][service-facets]. -[gamma]:/concepts/gamma/ +[gamma]:mesh/index.md [service-mesh]:concepts/glossary.md#service-mesh -[service-facets]:/concepts/service-facets -[mesh-attachment]:/concepts/gamma#gateway-api-for-mesh +[service-facets]:mesh/service-facets.md +[mesh-attachment]:mesh/index.md ## Getting started @@ -89,7 +89,7 @@ you the necessary background: - [User guides](guides/index.md) - [Implementations](implementations.md) - [API reference spec](reference/spec.md) -- [Community links](/contributing/community) and [developer guide](contributing/devguide.md) +- [Community links](contributing/index.md) and [developer guide](contributing/devguide.md) ## Gateway API concepts The following design goals drive the concepts of Gateway API. These @@ -189,7 +189,7 @@ It allows organizations to move key functions, such as authentication and authorization or limiting the number of requests between applications, to a centrally managed location. An API gateway functions as a common interface to (often external) API consumers. -Gateway API is an interface, defined as a set of Kubernetes resources, that +Gateway API is an interface, defined as a set of Kubernetes resources, that models service networking in Kubernetes. One of the main resources is a `Gateway`, which declares the Gateway type (or class) to instantiate and its configuration. As a Gateway provider, you can implement Gateway API to model Kubernetes service @@ -205,7 +205,7 @@ project being built to improve and standardize service networking in Kubernetes. Check out the [implementations reference](implementations.md) to see the latest projects & products that support Gateway. If you are interested in contributing to or building an implementation using Gateway API then don’t hesitate to [get -involved!](/contributing/community) +involved!](contributing/index.md) [sig-network]: https://github.com/kubernetes/community/tree/master/sig-network diff --git a/site-src/mesh/gamma.md b/site-src/mesh/gamma.md index 6071711ce2..fd4b62a89e 100644 --- a/site-src/mesh/gamma.md +++ b/site-src/mesh/gamma.md @@ -44,5 +44,5 @@ The simplest way to get started is to attend one of the regular Gateway API [role-oriented]:../concepts/roles-and-personas.md [geps]:../geps/overview.md [contributor-ladder]:../contributing/contributor-ladder.md -[meetings]:/contributing/community/#meetings +[meetings]:../contributing/index.md/#meetings [GAMMA leads]:https://github.com/kubernetes-sigs/gateway-api/blob/main/OWNERS_ALIASES#L23 diff --git a/site-src/mesh/index.md b/site-src/mesh/index.md index 988919091f..0d56793f7f 100644 --- a/site-src/mesh/index.md +++ b/site-src/mesh/index.md @@ -36,7 +36,7 @@ Service. [TCPRoute]: ../concepts/api-overview.md#tcproute-and-udproute [Service]: https://kubernetes.io/docs/concepts/services-networking/service/ [service-mesh]:../concepts/glossary.md#service-mesh -[service-facets]:/concepts/service-facets +[service-facets]:service-facets.md ## Connecting routes and services diff --git a/site-src/mesh/service-facets.md b/site-src/mesh/service-facets.md index 9b5f880bc5..96633fca81 100644 --- a/site-src/mesh/service-facets.md +++ b/site-src/mesh/service-facets.md @@ -46,5 +46,5 @@ formalize guidance for this use case. [Service]: https://kubernetes.io/docs/concepts/services-networking/service/ [north/south]:../concepts/glossary.md#northsouth-traffic [east/west traffic]:../concepts/glossary.md#eastwest-traffic -[gamma]:/concepts/gamma/ +[gamma]:gamma.md [Ana]:../concepts/roles-and-personas.md#ana