From 1e14dd602df6c0bad62c0e7f83dd2c7d1d2d6886 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Thu, 24 Apr 2025 14:42:35 -0700 Subject: [PATCH 001/148] add mesh conformance tests structure and a first test (#3729) * add mesh confomance tests structure and first test * move mesh tests to mesh folder --- conformance/tests/main.go | 8 +- .../tests/mesh/httproute-rewrite-path.go | 155 ++++++++++++++++++ .../tests/mesh/httproute-rewrite-path.yaml | 101 ++++++++++++ conformance/tests/mesh/main.go | 21 +++ conformance/tests/{ => mesh}/mesh-basic.go | 4 +- .../tests/{ => mesh}/mesh-consumer-route.go | 6 +- .../tests/{ => mesh}/mesh-consumer-route.yaml | 0 .../{ => mesh}/mesh-frontend-hostname.go | 6 +- conformance/tests/{ => mesh}/mesh-frontend.go | 6 +- .../tests/{ => mesh}/mesh-frontend.yaml | 0 conformance/tests/{ => mesh}/mesh-ports.go | 6 +- conformance/tests/{ => mesh}/mesh-ports.yaml | 0 conformance/tests/{ => mesh}/mesh-split.go | 6 +- conformance/tests/{ => mesh}/mesh-split.yaml | 0 conformance/utils/echo/pod.go | 8 + pkg/features/mesh.go | 9 + 16 files changed, 317 insertions(+), 19 deletions(-) create mode 100644 conformance/tests/mesh/httproute-rewrite-path.go create mode 100644 conformance/tests/mesh/httproute-rewrite-path.yaml create mode 100644 conformance/tests/mesh/main.go rename conformance/tests/{ => mesh}/mesh-basic.go (95%) rename conformance/tests/{ => mesh}/mesh-consumer-route.go (94%) rename conformance/tests/{ => mesh}/mesh-consumer-route.yaml (100%) rename conformance/tests/{ => mesh}/mesh-frontend-hostname.go (94%) rename conformance/tests/{ => mesh}/mesh-frontend.go (94%) rename conformance/tests/{ => mesh}/mesh-frontend.yaml (100%) rename conformance/tests/{ => mesh}/mesh-ports.go (95%) rename conformance/tests/{ => mesh}/mesh-ports.yaml (100%) rename conformance/tests/{ => mesh}/mesh-split.go (93%) rename conformance/tests/{ => mesh}/mesh-split.yaml (100%) 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-rewrite-path.go b/conformance/tests/mesh/httproute-rewrite-path.go new file mode 100644 index 0000000000..79416a96c8 --- /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.SupportMeshHTTPRouteRewritePath, + features.SupportHTTPRoute, + }, + 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/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/utils/echo/pod.go b/conformance/utils/echo/pod.go index f61d843744..24d0442945 100644 --- a/conformance/utils/echo/pod.go +++ b/conformance/utils/echo/pod.go @@ -57,6 +57,14 @@ const ( func (m *MeshPod) MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, exp http.ExpectedResponse, timeoutConfig config.TimeoutConfig) { t.Helper() + if exp.Request.Method == "" { + exp.Request.Method = "GET" + } + + if exp.Response.StatusCode == 0 { + exp.Response.StatusCode = 200 + } + http.AwaitConvergence(t, timeoutConfig.RequiredConsecutiveSuccesses, timeoutConfig.MaxTimeToConsistency, func(elapsed time.Duration) bool { req := makeRequest(t, exp.Request) diff --git a/pkg/features/mesh.go b/pkg/features/mesh.go index b52a7dff93..711681c58c 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -48,6 +48,8 @@ const ( SupportMeshClusterIPMatching FeatureName = "MeshClusterIPMatching" // This option indicates support for "consumer" routes, where a namespace creates a route for a service in another namespace. SupportMeshConsumerRoute FeatureName = "MeshConsumerRoute" + // This option indicates mesh support for HTTPRoute path rewrite (extended conformance) + SupportMeshHTTPRouteRewritePath FeatureName = "MeshHTTPRouteRewritePath" ) var ( @@ -61,6 +63,12 @@ var ( Name: SupportMeshConsumerRoute, Channel: FeatureChannelStandard, } + + // MeshHTTPRouteRewritePath contains metadata for the MeshHTTPRouteRewritePath feature. + MeshHTTPRouteRewritePath = Feature{ + Name: SupportMeshHTTPRouteRewritePath, + Channel: FeatureChannelStandard, + } ) // MeshExtendedFeatures includes all the supported features for the service mesh at @@ -68,4 +76,5 @@ var ( var MeshExtendedFeatures = sets.New( MeshClusterIPMatchingFeature, MeshConsumerRouteFeature, + MeshHTTPRouteRewritePath, ) From 983ce8afa758bf3007490e2dc55a61de2f0fc8dc Mon Sep 17 00:00:00 2001 From: Sergei Zviagintsev <10072335+szviagintsev@users.noreply.github.com> Date: Fri, 9 May 2025 03:15:14 +0200 Subject: [PATCH 002/148] Fix v1.3.0 release URL in README.md (#3782) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 2cb99f3a25421756f852aae6464e84a2e93e6274 Mon Sep 17 00:00:00 2001 From: Jonathan Stacks Date: Thu, 8 May 2025 20:39:14 -0500 Subject: [PATCH 003/148] docs: Update HTTPRoute status example (#3784) --- site-src/api-types/httproute.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site-src/api-types/httproute.md b/site-src/api-types/httproute.md index a1e051ab8a..c9d96deef1 100644 --- a/site-src/api-types/httproute.md +++ b/site-src/api-types/httproute.md @@ -322,7 +322,7 @@ metadata: ... status: parents: - - parentRefs: + - parentRef: name: gw-example namespace: gw-example-ns conditions: From 344f8de09c63f03077743df802888d22e78712fe Mon Sep 17 00:00:00 2001 From: "naruse (poko)" <62323683+naruse666@users.noreply.github.com> Date: Mon, 12 May 2025 13:09:15 +0900 Subject: [PATCH 004/148] rm duplicate explanation (#3780) --- site-src/guides/http-header-modifier.md | 2 -- 1 file changed, 2 deletions(-) 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`. From c698f24b49f80a50d371e61b47971ed3ecf01619 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 13 May 2025 18:43:16 -0700 Subject: [PATCH 005/148] Add mesh conformance tests for httproute path host and status redirect (#3777) * add redirect-port and redirect scheme mesh tests * mesh tests for path host and status redirect --- .../httproute-redirect-host-and-status.go | 84 +++++++++++ .../httproute-redirect-host-and-status.yaml | 30 ++++ .../tests/mesh/httproute-redirect-path.go | 139 ++++++++++++++++++ .../tests/mesh/httproute-redirect-path.yaml | 76 ++++++++++ .../tests/mesh/httproute-redirect-port.go | 113 ++++++++++++++ .../tests/mesh/httproute-redirect-port.yaml | 48 ++++++ .../tests/mesh/httproute-redirect-scheme.go | 116 +++++++++++++++ .../tests/mesh/httproute-redirect-scheme.yaml | 49 ++++++ .../tests/mesh/httproute-rewrite-path.go | 2 +- pkg/features/mesh.go | 26 ++++ 10 files changed, 682 insertions(+), 1 deletion(-) create mode 100644 conformance/tests/mesh/httproute-redirect-host-and-status.go create mode 100644 conformance/tests/mesh/httproute-redirect-host-and-status.yaml create mode 100644 conformance/tests/mesh/httproute-redirect-path.go create mode 100644 conformance/tests/mesh/httproute-redirect-path.yaml create mode 100644 conformance/tests/mesh/httproute-redirect-port.go create mode 100644 conformance/tests/mesh/httproute-redirect-port.yaml create mode 100644 conformance/tests/mesh/httproute-redirect-scheme.go create mode 100644 conformance/tests/mesh/httproute-redirect-scheme.yaml 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-rewrite-path.go b/conformance/tests/mesh/httproute-rewrite-path.go index 79416a96c8..22f8ae66a3 100644 --- a/conformance/tests/mesh/httproute-rewrite-path.go +++ b/conformance/tests/mesh/httproute-rewrite-path.go @@ -34,8 +34,8 @@ var MeshHTTPRouteRewritePath = suite.ConformanceTest{ Description: "An HTTPRoute with path rewrite filter", Features: []features.FeatureName{ features.SupportMesh, - features.SupportMeshHTTPRouteRewritePath, features.SupportHTTPRoute, + features.SupportMeshHTTPRouteRewritePath, }, Manifests: []string{"tests/mesh/httproute-rewrite-path.yaml"}, Test: func(t *testing.T, s *suite.ConformanceTestSuite) { diff --git a/pkg/features/mesh.go b/pkg/features/mesh.go index 711681c58c..e2af0a6089 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -50,6 +50,12 @@ const ( SupportMeshConsumerRoute FeatureName = "MeshConsumerRoute" // This option indicates mesh support for HTTPRoute path rewrite (extended conformance) SupportMeshHTTPRouteRewritePath FeatureName = "MeshHTTPRouteRewritePath" + // This option indicates mesh support for HTTPRoute scheme redirect (extended conformance) + SupportMeshHTTPRouteSchemeRedirect FeatureName = "MeshHTTPRouteSchemeRedirect" + // This option indicates mesh support for HTTPRoute port redirect (extended conformance) + SupportMeshHTTPRouteRedirectPort FeatureName = "MeshHTTPRouteRedirectPort" + // This option indicates mesh support for HTTPRoute path redirect (extended conformance) + SupportMeshHTTPRouteRedirectPath FeatureName = "MeshHTTPRouteRedirectPath" ) var ( @@ -69,6 +75,24 @@ var ( Name: SupportMeshHTTPRouteRewritePath, Channel: FeatureChannelStandard, } + + // MeshHTTPRouteSchemeRedirect contains metadata for the MeshHTTPRouteSchemeRedirect feature. + MeshHTTPRouteSchemeRedirect = Feature{ + Name: SupportMeshHTTPRouteRewritePath, + Channel: FeatureChannelStandard, + } + + // MeshHTTPRouteRedirectPort contains metadata for the MeshHTTPRouteRedirectPort feature. + MeshHTTPRouteRedirectPort = Feature{ + Name: SupportMeshHTTPRouteRedirectPort, + Channel: FeatureChannelStandard, + } + + // MeshHTTPRouteRedirectPath contains metadata for the MeshHTTPRouteRedirectPath feature. + MeshHTTPRouteRedirectPath = Feature{ + Name: SupportMeshHTTPRouteRedirectPath, + Channel: FeatureChannelStandard, + } ) // MeshExtendedFeatures includes all the supported features for the service mesh at @@ -77,4 +101,6 @@ var MeshExtendedFeatures = sets.New( MeshClusterIPMatchingFeature, MeshConsumerRouteFeature, MeshHTTPRouteRewritePath, + MeshHTTPRouteSchemeRedirect, + MeshHTTPRouteRedirectPath, ) From 0912739c889731f9e2e1ffe94f0f4c21987da17c Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Wed, 14 May 2025 07:05:16 +0200 Subject: [PATCH 006/148] fix: remove misleading description (#3778) Signed-off-by: Norwin Schnyder --- apis/v1/httproute_types.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 6131d70b7b..6fec27d6e0 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -988,11 +988,11 @@ type HTTPHeader struct { } // 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. From 793e5626914ac3cd9015b4dc0c94f23f2c41bfbf Mon Sep 17 00:00:00 2001 From: Sunjay Bhatia <5337253+sunjayBhatia@users.noreply.github.com> Date: Wed, 14 May 2025 01:05:23 -0400 Subject: [PATCH 007/148] Add conformance report for Contour 1.31.0 (#3783) * Add conformance report for Contour 1.31.0 Supports gateway API 1.2.1 Signed-off-by: Sunjay Bhatia * update implementations.md Signed-off-by: Sunjay Bhatia --------- Signed-off-by: Sunjay Bhatia --- .../v1.2.1/projectcontour-contour/README.md | 48 +++++++++ .../experimental-v1.31.0-default-report.yaml | 101 ++++++++++++++++++ site-src/implementations.md | 6 +- 3 files changed, 152 insertions(+), 3 deletions(-) create mode 100644 conformance/reports/v1.2.1/projectcontour-contour/README.md create mode 100644 conformance/reports/v1.2.1/projectcontour-contour/experimental-v1.31.0-default-report.yaml 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/site-src/implementations.md b/site-src/implementations.md index 77fa74a7d2..f571d5c865 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -209,13 +209,13 @@ effort, check out the #development channel or join our [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. From dce6bc41d2ddc352f512424f1c2f3b9a21a79a22 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 14 May 2025 19:27:24 -0700 Subject: [PATCH 008/148] Add Google Cloud Service Mesh to implementations.md (#3781) * add csm mesh to implementations.md * fix * fix1 * Update implementations.md Co-authored-by: Rob Scott --------- Co-authored-by: Rob Scott --- site-src/implementations.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/site-src/implementations.md b/site-src/implementations.md index f571d5c865..4bc723430f 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -47,6 +47,7 @@ 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) @@ -95,6 +96,7 @@ cover, and documentation to help users get started. [35]:#kong-gateway-operator [36]:#loxilb [37]:#kgateway +[38]:#google-cloud-service-mesh [gamma]:/concepts/gamma/ @@ -290,6 +292,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) From 6fbbd90954c2a30a6502cbb22ec6e7f3359ed3a0 Mon Sep 17 00:00:00 2001 From: Enrico Date: Thu, 15 May 2025 05:57:19 +0200 Subject: [PATCH 009/148] Improve feature name readability in conformance reports (#3564) Add feature name processing to remove redundant prefixes and improve readability in conformance comparison tables. Changes include: - Remove "HTTPRoute" and "Gateway" prefixes from feature names - Split camelCase words into space-separated words - Add process_feature_name() function for consistent text processing - Update generate_profiles_report() to use processed feature names This makes the conformance reports easier to read --- hack/mkdocs-generate-conformance.py | 15 ++++++++++++++- site-src/implementations/v1.0.md | 8 ++++---- site-src/implementations/v1.1.md | 8 ++++---- site-src/implementations/v1.2.md | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/hack/mkdocs-generate-conformance.py b/hack/mkdocs-generate-conformance.py index f24832af57..0486c530da 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") @@ -151,7 +162,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/site-src/implementations/v1.0.md b/site-src/implementations/v1.0.md index 901a48a138..ec3e6db233 100644 --- a/site-src/implementations/v1.0.md +++ b/site-src/implementations/v1.0.md @@ -42,7 +42,7 @@ Implementations only appear in this page if they pass Core conformance for the r ### 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..443ea07fbc 100644 --- a/site-src/implementations/v1.1.md +++ b/site-src/implementations/v1.1.md @@ -59,7 +59,7 @@ Implementations only appear in this page if they pass Core conformance for the r ### 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..21bb980689 100644 --- a/site-src/implementations/v1.2.md +++ b/site-src/implementations/v1.2.md @@ -55,4 +55,4 @@ Implementations only appear in this page if they pass Core conformance for the r | 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 +| 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: | From b7d2c5788bf38fc2c18085de524e204034c69a14 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Sat, 17 May 2025 06:18:30 -0400 Subject: [PATCH 010/148] Update RELEASE_MANAGEMENT.md --- RELEASE_MANAGEMENT.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/RELEASE_MANAGEMENT.md b/RELEASE_MANAGEMENT.md index cd8f0f1851..94e2c724de 100644 --- a/RELEASE_MANAGEMENT.md +++ b/RELEASE_MANAGEMENT.md @@ -107,5 +107,9 @@ 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 From b9062b78fa40afb27d0701ef61b4db7756241c81 Mon Sep 17 00:00:00 2001 From: Beka Modebadze <58038950+bexxmodd@users.noreply.github.com> Date: Tue, 20 May 2025 10:45:15 -0700 Subject: [PATCH 011/148] Fix typo for the file name case type. (#3807) --- geps/gep-2162/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geps/gep-2162/index.md b/geps/gep-2162/index.md index 38b2dbf60e..a8959acc8e 100644 --- a/geps/gep-2162/index.md +++ b/geps/gep-2162/index.md @@ -123,7 +123,7 @@ Every feature should: #### 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. From 7bfd028678c4bf831528184199e71c923b8f3ac5 Mon Sep 17 00:00:00 2001 From: Xunzhuo Date: Thu, 22 May 2025 00:58:35 +0800 Subject: [PATCH 012/148] feat: add eg v1.3 gwapi conformance report (#3795) Signed-off-by: bitliu --- .../reports/v1.3.0/envoy-gateway/README.md | 34 +++++++++ .../experimental-v1.4.0-default-report.yaml | 71 +++++++++++++++++++ 2 files changed, 105 insertions(+) create mode 100644 conformance/reports/v1.3.0/envoy-gateway/README.md create mode 100644 conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml 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..d48c5c9ac0 --- /dev/null +++ b/conformance/reports/v1.3.0/envoy-gateway/README.md @@ -0,0 +1,34 @@ +# Envoy Gateway + +## Table of Contents + +|API channel|Implementation version|Mode|Report| +|-----------|----------------------|----|------| +| experimental |[v1.4.0](https://github.com/envoyproxy/gateway/releases/tag/v1.4.0)| default |[link](./experimental-v1.4.0-default-report.yaml)| + +## 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 + 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.4.0-default-report.yaml b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml new file mode 100644 index 0000000000..4504a506da --- /dev/null +++ b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml @@ -0,0 +1,71 @@ +apiVersion: gateway.networking.k8s.io/v1 +date: "2025-05-14T03:12:24Z" +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: latest +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: 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. +succeededProvisionalTests: +- HTTPRouteRequestPercentageMirror From 5e934892dc226d88f7813cc1141f95ecbfc66336 Mon Sep 17 00:00:00 2001 From: Tam Mach Date: Thu, 22 May 2025 02:58:42 +1000 Subject: [PATCH 013/148] conformance: Add Cilium report for v1.3.0 (#3799) The report is generated by Cilium GHA CI https://github.com/cilium/cilium/actions/runs/15111523465 Signed-off-by: Tam Mach --- .../reports/v1.3.0/cilium-cilium/README.md | 12 ++ .../experimental-main-default-report.yaml | 140 ++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 conformance/reports/v1.3.0/cilium-cilium/README.md create mode 100644 conformance/reports/v1.3.0/cilium-cilium/experimental-main-default-report.yaml 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 From 270a3892488c3b4ce8e8f66cec11ef61116aee1e Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Thu, 22 May 2025 23:06:35 +0200 Subject: [PATCH 014/148] conformance: Add Airlock Microgateway report for v1.3.0 (#3809) * conformance: Add Airlock Microgateway report for v1.3.0 Signed-off-by: Norwin Schnyder * add trailing new lines Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- .../v1.1.0/airlock-microgateway/README.md | 2 +- .../standard-4.6.0-default-report.yaml | 47 ++++++++++++++++ .../v1.1.1/airlock-microgateway/README.md | 1 + .../standard-4.6.0-default-report.yaml | 47 ++++++++++++++++ .../v1.2.0/airlock-microgateway/README.md | 1 + .../standard-4.6.0-default-report.yaml | 53 ++++++++++++++++++ .../v1.2.1/airlock-microgateway/README.md | 1 + .../standard-4.6.0-default-report.yaml | 53 ++++++++++++++++++ .../v1.3.0/airlock-microgateway/README.md | 20 +++++++ .../experimental-4.6.0-default-report.yaml | 55 +++++++++++++++++++ site-src/implementations.md | 15 ++--- 11 files changed, 284 insertions(+), 11 deletions(-) create mode 100644 conformance/reports/v1.1.0/airlock-microgateway/standard-4.6.0-default-report.yaml create mode 100644 conformance/reports/v1.1.1/airlock-microgateway/standard-4.6.0-default-report.yaml create mode 100644 conformance/reports/v1.2.0/airlock-microgateway/standard-4.6.0-default-report.yaml create mode 100644 conformance/reports/v1.2.1/airlock-microgateway/standard-4.6.0-default-report.yaml create mode 100644 conformance/reports/v1.3.0/airlock-microgateway/README.md create mode 100644 conformance/reports/v1.3.0/airlock-microgateway/experimental-4.6.0-default-report.yaml diff --git a/conformance/reports/v1.1.0/airlock-microgateway/README.md b/conformance/reports/v1.1.0/airlock-microgateway/README.md index c746409217..a23522a4ad 100644 --- a/conformance/reports/v1.1.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.1.0/airlock-microgateway/README.md @@ -6,7 +6,7 @@ |--------------|----------------------------------------------------------------------|---------|--------------------------------------------------| | 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) | - +| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [v4.6.0 report](./standard-4.6.0-default-report.yaml) | ## Reproduce 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.1/airlock-microgateway/README.md b/conformance/reports/v1.1.1/airlock-microgateway/README.md index 27868c3f1f..a61abd8398 100644 --- a/conformance/reports/v1.1.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.1.1/airlock-microgateway/README.md @@ -5,6 +5,7 @@ | 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) | ## Reproduce 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.2.0/airlock-microgateway/README.md b/conformance/reports/v1.2.0/airlock-microgateway/README.md index 27868c3f1f..a61abd8398 100644 --- a/conformance/reports/v1.2.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.0/airlock-microgateway/README.md @@ -5,6 +5,7 @@ | 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) | ## Reproduce 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.1/airlock-microgateway/README.md b/conformance/reports/v1.2.1/airlock-microgateway/README.md index 6e691ffb1e..97c52418f9 100644 --- a/conformance/reports/v1.2.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.1/airlock-microgateway/README.md @@ -5,6 +5,7 @@ | 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) | ## Reproduce 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..38f5f352f3 --- /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:33:38Z" +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-ci-4 +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.3.0/airlock-microgateway/README.md b/conformance/reports/v1.3.0/airlock-microgateway/README.md new file mode 100644 index 0000000000..bae978e399 --- /dev/null +++ b/conformance/reports/v1.3.0/airlock-microgateway/README.md @@ -0,0 +1,20 @@ +# 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) | + +## 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. + +> [!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. +> 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 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/site-src/implementations.md b/site-src/implementations.md index 4bc723430f..3067f7d739 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -117,21 +117,17 @@ In this section you will find specific links to blog posts, documentation and ot [epicsource]:https://github.com/epic-gateway ### 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 - 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] @@ -139,7 +135,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/ From fe41f50e3406682f68e462e185041585481b880e Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Sun, 25 May 2025 01:28:35 +0200 Subject: [PATCH 015/148] conformance: fix typo in Airlock Microgateway report (#3811) Signed-off-by: Norwin Schnyder --- .../airlock-microgateway/standard-4.6.0-default-report.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 38f5f352f3..0589d7e379 100644 --- 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 @@ -1,5 +1,5 @@ apiVersion: gateway.networking.k8s.io/v1 -date: "2025-05-19T14:33:38Z" +date: "2025-05-19T14:36:18Z" gatewayAPIChannel: standard gatewayAPIVersion: v1.2.1 implementation: @@ -8,7 +8,7 @@ implementation: organization: airlock project: microgateway url: https://github.com/airlock/microgateway - version: 4.6.0-ci-4 + version: 4.6.0 kind: ConformanceReport mode: default profiles: From ce0cfebeb52c10af6833beadbc2a1a70aea4c0df Mon Sep 17 00:00:00 2001 From: zirain Date: Tue, 27 May 2025 18:14:16 +0800 Subject: [PATCH 016/148] conformance: add Hook in ConformanceTestSuite (#3786) * conformance: add Hook in ConformanceTestSuite * update comment Signed-off-by: zirain * add Hook in ConformanceOptions Signed-off-by: zirain --------- Signed-off-by: zirain --- conformance/utils/suite/suite.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 53700d6c53..e6a5cb1264 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -74,6 +74,7 @@ type ConformanceTestSuite struct { 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 @@ -121,7 +122,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 @@ -152,7 +153,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 @@ -268,6 +270,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, mode: mode, apiVersion: apiVersion, apiChannel: apiChannel, + Hook: options.Hook, } for _, conformanceProfileName := range options.ConformanceProfiles.UnsortedList() { @@ -470,6 +473,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 From f311bd751e6ec6280af513210a1644ff66b250de Mon Sep 17 00:00:00 2001 From: Davin Kevin Date: Tue, 27 May 2025 21:40:16 +0200 Subject: [PATCH 017/148] fix(gep-1911): remove duplicated header in table (#3818) --- geps/gep-1911/index.md | 1 - 1 file changed, 1 deletion(-) 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) From 54df0a899c1c5c845dd3a80f05dcfdf65576f03c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felipe=20Y=C3=A9pez?= <58478476+FelipeYepez@users.noreply.github.com> Date: Wed, 28 May 2025 00:36:22 +0200 Subject: [PATCH 018/148] Remove unused dependabot config for Github actions (#3816) This PR removes the Dependabot configuration for the `github-actions` package ecosystem since Github Actions are not used in this repository. There is no PR ever created with a `dependencies` tag which is not for `go`, `docker`, or `python`. --- .github/dependabot.yml | 11 ----------- 1 file changed, 11 deletions(-) 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: "/" From e7c711b0a91273727288942faa10573164e6981b Mon Sep 17 00:00:00 2001 From: samcrichard <119348077+samcrichard@users.noreply.github.com> Date: Wed, 28 May 2025 20:36:16 -0400 Subject: [PATCH 019/148] Updating ngrok Gateway API Implementation on Implementations page (#3775) --- site-src/implementations.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/site-src/implementations.md b/site-src/implementations.md index 3067f7d739..6f42e00e65 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -487,7 +487,12 @@ 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] @@ -495,7 +500,7 @@ You can read our [docs][ngrok-k8s-gwapi-docs] for more information. If you have [ngrok]:https://ngrok.com [ngrok-k8s-gwapi-docs]:https://ngrok.com/docs/k8s/ [ngrok-issue-new]: https://github.com/ngrok/ngrok-operator/issues/new/choose -[ngrok-slack]:https://ngrokcommunity.slack.com/channels/general + ### STUNner From dbd2ff92a93e7c8a29bce07cc331e40e6d470efe Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Fri, 30 May 2025 17:00:18 -0700 Subject: [PATCH 020/148] add mesh conformance for request header modifier (#3812) * add mesh conformance for request header modifier * address feedback --- ...route-request-header-modifier-backend.yaml | 93 ++++++++ .../mesh/httproute-request-header-modifier.go | 213 ++++++++++++++++++ .../httproute-request-header-modifier.yaml | 93 ++++++++ conformance/utils/echo/parse.go | 3 +- conformance/utils/echo/pod.go | 67 ++++-- pkg/features/mesh.go | 9 + 6 files changed, 460 insertions(+), 18 deletions(-) create mode 100644 conformance/tests/mesh/httproute-request-header-modifier-backend.yaml create mode 100644 conformance/tests/mesh/httproute-request-header-modifier.go create mode 100644 conformance/tests/mesh/httproute-request-header-modifier.yaml 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/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 24d0442945..3861f53c73 100644 --- a/conformance/utils/echo/pod.go +++ b/conformance/utils/echo/pod.go @@ -57,16 +57,8 @@ const ( func (m *MeshPod) MakeRequestAndExpectEventuallyConsistentResponse(t *testing.T, exp http.ExpectedResponse, timeoutConfig config.TimeoutConfig) { t.Helper() - if exp.Request.Method == "" { - exp.Request.Method = "GET" - } - - if exp.Response.StatusCode == 0 { - exp.Response.StatusCode = 200 - } - 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 { @@ -84,7 +76,19 @@ 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 exp.Response.StatusCode == 0 { + exp.Response.StatusCode = 200 + } + + r := exp.Request protocol := strings.ToLower(r.Protocol) if protocol == "" { protocol = "http" @@ -95,22 +99,53 @@ 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) + wantReq := exp.ExpectedRequest + wantResp := exp.Response + if fmt.Sprint(wantResp.StatusCode) != resp.Code { + return fmt.Errorf("wanted status code %v, got %v", wantResp.StatusCode, resp.Code) } - for _, name := range want.AbsentHeaders { + 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) } diff --git a/pkg/features/mesh.go b/pkg/features/mesh.go index e2af0a6089..f088cdad83 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -56,6 +56,8 @@ const ( SupportMeshHTTPRouteRedirectPort FeatureName = "MeshHTTPRouteRedirectPort" // This option indicates mesh support for HTTPRoute path redirect (extended conformance) SupportMeshHTTPRouteRedirectPath FeatureName = "MeshHTTPRouteRedirectPath" + // This option indicates support for HTTPRoute backend request header modification + SupportMeshHTTPRouteBackendRequestHeaderModification FeatureName = "MeshHTTPRouteBackendRequestHeaderModification" ) var ( @@ -93,6 +95,12 @@ var ( Name: SupportMeshHTTPRouteRedirectPath, Channel: FeatureChannelStandard, } + + // MeshHTTPRouteRedirectPath contains metadata for the MeshHTTPRouteRedirectPath feature. + MeshHTTPRouteBackendRequestHeaderModification = Feature{ + Name: SupportMeshHTTPRouteBackendRequestHeaderModification, + Channel: FeatureChannelStandard, + } ) // MeshExtendedFeatures includes all the supported features for the service mesh at @@ -103,4 +111,5 @@ var MeshExtendedFeatures = sets.New( MeshHTTPRouteRewritePath, MeshHTTPRouteSchemeRedirect, MeshHTTPRouteRedirectPath, + MeshHTTPRouteBackendRequestHeaderModification, ) From 268d2f435968be788cb1b640a92447c55f061c9d Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Mon, 2 Jun 2025 06:28:36 +0200 Subject: [PATCH 021/148] docs: Add v1.3 conformance report table (#3810) * docs: Add v1.3 conformance report table Signed-off-by: Norwin Schnyder * Automatically update conformance table files Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- hack/mkdocs-generate-conformance.py | 4 ++ mkdocs.yml | 1 + site-src/implementations.md | 2 +- site-src/implementations/v1.0.md | 44 +++++++++--------- site-src/implementations/v1.1.md | 71 +++++++++++++++-------------- site-src/implementations/v1.2.md | 66 +++++++++++++++------------ site-src/implementations/v1.3.md | 45 ++++++++++++++++++ 7 files changed, 147 insertions(+), 86 deletions(-) create mode 100644 site-src/implementations/v1.3.md diff --git a/hack/mkdocs-generate-conformance.py b/hack/mkdocs-generate-conformance.py index 0486c530da..bec9ecdef1 100644 --- a/hack/mkdocs-generate-conformance.py +++ b/hack/mkdocs-generate-conformance.py @@ -58,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 diff --git a/mkdocs.yml b/mkdocs.yml index 228a0cccc4..4a4a7de35d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -85,6 +85,7 @@ nav: - Implementations: - List: implementations.md - Comparisons: + - v1.3: implementations/v1.3.md - v1.2: implementations/v1.2.md - v1.1: implementations/v1.1.md - v1.0: implementations/v1.0.md diff --git a/site-src/implementations.md b/site-src/implementations.md index 6f42e00e65..efdffc5c63 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -10,7 +10,7 @@ cover, and documentation to help users get started. !!! 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 diff --git a/site-src/implementations/v1.0.md b/site-src/implementations/v1.0.md index ec3e6db233..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,27 +16,27 @@ 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 diff --git a/site-src/implementations/v1.1.md b/site-src/implementations/v1.1.md index 443ea07fbc..bc97fc01fb 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,44 +16,49 @@ 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-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-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-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 | 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 diff --git a/site-src/implementations/v1.2.md b/site-src/implementations/v1.2.md index 21bb980689..1c38f3351d 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,49 @@ 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 | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Parent Ref Port | HTTPRoute Port Redirect | HTTPRoute Request Timeout | HTTPRoute Scheme Redirect | HTTPRoute Path Redirect | 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: | +| 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: | +| 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: | :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: | +| envoyproxy | envoy-gateway | latest | 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: | :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: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :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: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| 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: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :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: | +| 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 | :x: | :x: | :x: | :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 | :x: | :x: | :x: | :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: | +| 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..0ce9516a8e --- /dev/null +++ b/site-src/implementations/v1.3.md @@ -0,0 +1,45 @@ + +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 Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | 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 Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Gateway Address Empty | Gateway HTTP Listener Isolation | Gateway Static Addresses | HTTPRoute Backend Request Header Modification | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Percentage Mirror | +|:---------------|:--------------|:----------|:--------|:-------------------------------------|:--------------------|:---------------------------------|:----------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:------------------------|:----------------------------------|:---------------------------|:------------------------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------| +| 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: | :x: | :x: | +| 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: | :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: | +| envoyproxy | envoy-gateway | latest | 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: | :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: | + +### 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 | latest | default | :x: | :x: | :x: | :x: | :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 | latest | default | :x: | :x: | :x: | :x: | :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 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 | +|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------| +| 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: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | \ No newline at end of file From cdcca5f1eb2b541016a7c88fd7498f2fb21473c5 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Tue, 3 Jun 2025 13:18:43 -0400 Subject: [PATCH 022/148] chore: remove inactive reviewers (#3829) Signed-off-by: Shane Utt --- OWNERS_ALIASES | 2 -- 1 file changed, 2 deletions(-) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 8bdeafe24c..6e461c1596 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -32,9 +32,7 @@ aliases: gateway-api-conformance-reviewers: - candita - - michaelbeaumont - sunjayBhatia - - xunzhuo gateway-api-conformance-approvers: - arkodg From 69a4a5fe594924837bf5397f8a59b0e3bad277f5 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 3 Jun 2025 16:34:37 -0700 Subject: [PATCH 023/148] add httproute weight based routing mesh conformance tests (#3827) * add httproute weights mesh conformance tests * gofmt --- conformance/tests/mesh/httproute-weight.go | 143 +++++++++++++++++++ conformance/tests/mesh/httproute-weight.yaml | 19 +++ conformance/utils/echo/pod.go | 19 +++ 3 files changed, 181 insertions(+) create mode 100644 conformance/tests/mesh/httproute-weight.go create mode 100644 conformance/tests/mesh/httproute-weight.yaml diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go new file mode 100644 index 0000000000..09ef3465b5 --- /dev/null +++ b/conformance/tests/mesh/httproute-weight.go @@ -0,0 +1,143 @@ +/* +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 { + _, cRes, err := client.CaptureRequestResponseAndCompare(t, expected) + 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/utils/echo/pod.go b/conformance/utils/echo/pod.go index 3861f53c73..0222ff12dd 100644 --- a/conformance/utils/echo/pod.go +++ b/conformance/utils/echo/pod.go @@ -105,6 +105,9 @@ func makeRequest(t *testing.T, exp *http.ExpectedResponse) []string { } func compareRequest(exp http.ExpectedResponse, resp Response) error { + if exp.ExpectedRequest == nil { + exp.ExpectedRequest = &http.ExpectedRequest{} + } wantReq := exp.ExpectedRequest wantResp := exp.Response if fmt.Sprint(wantResp.StatusCode) != resp.Code { @@ -220,3 +223,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 +} From a879542fff1b622e63355cafde4da1a86545bdcc Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 4 Jun 2025 15:58:37 -0700 Subject: [PATCH 024/148] same-namespace-attachment-mesh-conformance (#3833) --- .../mesh/httproute-simple-same-namespace.go | 52 +++++++++++++++++++ .../mesh/httproute-simple-same-namespace.yaml | 15 ++++++ 2 files changed, 67 insertions(+) create mode 100644 conformance/tests/mesh/httproute-simple-same-namespace.go create mode 100644 conformance/tests/mesh/httproute-simple-same-namespace.yaml 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 From 77baa438dc3cb7be41c89fcaf6f9dc9407489234 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 4 Jun 2025 19:16:37 -0700 Subject: [PATCH 025/148] add httproute matching conformance (#3831) --- conformance/tests/mesh/httproute-matching.go | 93 +++++++++++++++++++ .../tests/mesh/httproute-matching.yaml | 32 +++++++ 2 files changed, 125 insertions(+) create mode 100644 conformance/tests/mesh/httproute-matching.go create mode 100644 conformance/tests/mesh/httproute-matching.yaml 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 From d7b4030b2e536d900460c7d73ed291288429e3fb Mon Sep 17 00:00:00 2001 From: Craig Brookes Date: Thu, 5 Jun 2025 15:38:40 +0100 Subject: [PATCH 026/148] GEP-2627 DNS Configuration - Initial Provisional PR (#2712) * draft dns configuration for gateway API GEP-2627 minor tweaks Update geps/gep-2627/index.md Co-authored-by: Candace Holman Update geps/gep-2627/index.md Co-authored-by: Candace Holman Update geps/gep-2627/index.md Co-authored-by: Candace Holman * changes post review * rewording * Update geps/gep-2627/index.md Co-authored-by: Nick Young * Update geps/gep-2627/index.md Co-authored-by: Nick Young * Update geps/gep-2627/index.md Co-authored-by: Nick Young * Update geps/gep-2627/index.md Co-authored-by: Nick Young * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * Update geps/gep-2627/index.md Co-authored-by: Shane Utt * minor tweaks to the text and link to kuadrant as an example of a DNSPolicy type API * fix new line * move kuadrant to a reference --------- Co-authored-by: Candace Holman Co-authored-by: Nick Young Co-authored-by: Shane Utt --- geps/gep-2627/index.md | 51 +++++++++++++++++++++++++++++++++++++ geps/gep-2627/metadata.yaml | 7 +++++ 2 files changed, 58 insertions(+) create mode 100644 geps/gep-2627/index.md create mode 100644 geps/gep-2627/metadata.yaml 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 From b3e0aa92d9ea636f41e6b82adf6dd2d68b51f3ff Mon Sep 17 00:00:00 2001 From: Keith Mattix II Date: Fri, 6 Jun 2025 17:24:45 -0500 Subject: [PATCH 027/148] Add Istio report for 1.3.0 (#3808) Signed-off-by: Keith Mattix II --- .../reports/v1.3.0/istio-istio/README.md | 11 ++ .../experimental-1.26.1-default-report.yaml | 131 ++++++++++++++++++ site-src/implementations/v1.1.md | 2 +- site-src/implementations/v1.2.md | 28 ++-- site-src/implementations/v1.3.md | 10 +- 5 files changed, 164 insertions(+), 18 deletions(-) create mode 100644 conformance/reports/v1.3.0/istio-istio/README.md create mode 100644 conformance/reports/v1.3.0/istio-istio/experimental-1.26.1-default-report.yaml 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/site-src/implementations/v1.1.md b/site-src/implementations/v1.1.md index bc97fc01fb..21063b28e6 100644 --- a/site-src/implementations/v1.1.md +++ b/site-src/implementations/v1.1.md @@ -18,9 +18,9 @@ Implementations only appear in this page if they pass Core conformance for the r | 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-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-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-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: | +| 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: | | 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: | diff --git a/site-src/implementations/v1.2.md b/site-src/implementations/v1.2.md index 1c38f3351d..c26434b418 100644 --- a/site-src/implementations/v1.2.md +++ b/site-src/implementations/v1.2.md @@ -16,26 +16,26 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | Mode | HTTPRoute Host Rewrite | HTTPRoute Method Matching | HTTPRoute Path Rewrite | HTTPRoute Query Param Matching | HTTPRoute Response Header Modification | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Parent Ref Port | HTTPRoute Port Redirect | HTTPRoute Request Timeout | HTTPRoute Scheme Redirect | HTTPRoute Path Redirect | 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: | -| 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: | -| 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: | :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: | -| envoyproxy | envoy-gateway | latest | 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: | :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: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :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: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | -| 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: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| Organization | Project | Version | Mode | HTTPRoute Host Rewrite | HTTPRoute Path Rewrite | HTTPRoute Response Header Modification | HTTPRoute Method Matching | HTTPRoute Query Param Matching | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Parent Ref Port | HTTPRoute Port Redirect | HTTPRoute Request Timeout | HTTPRoute Scheme Redirect | HTTPRoute Path Redirect | 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 | 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: | +| 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: | +| 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: | +| 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: | :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: | +| envoyproxy | envoy-gateway | latest | 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: | :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: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :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: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | +| 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: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | ### GRPCRoute | 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: | +| Kong | kubernetes-ingress-controller | v3.4.0 | expressions | :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: | diff --git a/site-src/implementations/v1.3.md b/site-src/implementations/v1.3.md index 0ce9516a8e..552e98cd54 100644 --- a/site-src/implementations/v1.3.md +++ b/site-src/implementations/v1.3.md @@ -21,6 +21,7 @@ Implementations only appear in this page if they pass Core conformance for the r | 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: | :x: | :x: | | 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: | :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: | | envoyproxy | envoy-gateway | latest | 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: | :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: | +| 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: | ### GRPCRoute @@ -28,6 +29,7 @@ Implementations only appear in this page if they pass Core conformance for the r |:---------------|:--------------|:----------|:--------|:------------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| | cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | envoyproxy | envoy-gateway | latest | default | :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: | ### TLSRoute @@ -35,11 +37,13 @@ Implementations only appear in this page if they pass Core conformance for the r |:---------------|:--------------|:----------|:--------|:------------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| | cilium | cilium | main | default | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | envoyproxy | envoy-gateway | latest | default | :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: | ## 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 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 | -|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------| -| 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: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :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 Percentage Mirror | HTTPRoute Request Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Mesh Cluster IP Matching | HTTPRoute Parent Ref Port | Mesh Consumer Route | +|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------|:----------------------------|:----------------------| +| 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: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :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: | :x: | :white_check_mark: | :white_check_mark: | \ No newline at end of file From 1b895febbb4acb2864f8ee1bab2750df7f31217f Mon Sep 17 00:00:00 2001 From: Dawid Nowak Date: Fri, 6 Jun 2025 23:46:38 +0100 Subject: [PATCH 028/148] Add Kubvernor conformance report (#3813) * Kubevernor conformance report * Adding Kubvernor section to implementations section --- .../reports/v1.2.1/kubvernor/README.md | 51 +++++++++++++++++++ .../kubvernor-conformance-output-1.2.1.yaml | 30 +++++++++++ site-src/implementations.md | 9 ++++ 3 files changed, 90 insertions(+) create mode 100644 conformance/reports/v1.2.1/kubvernor/README.md create mode 100644 conformance/reports/v1.2.1/kubvernor/kubvernor-conformance-output-1.2.1.yaml 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/site-src/implementations.md b/site-src/implementations.md index efdffc5c63..e65f26aa4f 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -35,6 +35,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) @@ -97,6 +98,7 @@ cover, and documentation to help users get started. [36]:#loxilb [37]:#kgateway [38]:#google-cloud-service-mesh +[39]:#kubvernor [gamma]:/concepts/gamma/ @@ -418,6 +420,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) @@ -599,3 +607,4 @@ 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 + From c3dd6c38f7c798aeb6ac0525a2189c10ac2e75a8 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Fri, 6 Jun 2025 16:46:45 -0600 Subject: [PATCH 029/148] Add NGINX Gateway Fabric v2.0 conformance report (#3836) Adding conformance report for the v2.0 NGINX Gateway Fabric release. Now supporting Gateway API v1.3. --- .../nginx-nginx-gateway-fabric/README.md | 23 +++++ .../experimental-2.0.0-default-report.yaml | 97 +++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md create mode 100644 conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.0.0-default-report.yaml 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..ae54954fae --- /dev/null +++ b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md @@ -0,0 +1,23 @@ +# 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) | + +## 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..d6d0353a10 --- /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: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayAddressEmpty + - 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: 14 + Skipped: 0 + supportedFeatures: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + - HTTPRouteHostRewrite + - HTTPRouteMethodMatching + - HTTPRoutePathRedirect + - HTTPRoutePathRewrite + - HTTPRoutePortRedirect + - HTTPRouteQueryParamMatching + - HTTPRouteRequestMirror + - HTTPRouteRequestMultipleMirrors + - HTTPRouteResponseHeaderModification + - HTTPRouteSchemeRedirect + unsupportedFeatures: + - GatewayAddressEmpty + - 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: + - GatewayHTTPListenerIsolation + - GatewayInfrastructurePropagation + - GatewayPort8080 + unsupportedFeatures: + - GatewayAddressEmpty + - GatewayStaticAddresses + name: GATEWAY-TLS + summary: Core tests succeeded. Extended tests succeeded. +succeededProvisionalTests: +- GatewayInfrastructure From 3fa0912a5d1ef46a55084ad3f8b8feb5478aedf0 Mon Sep 17 00:00:00 2001 From: Siyi Wang <32469039+syw14@users.noreply.github.com> Date: Mon, 9 Jun 2025 14:50:24 -0700 Subject: [PATCH 030/148] Fix godoc comment for GatewaySpecAddress (#3845) * Update naming * fix failures --- apis/v1beta1/gateway_types.go | 2 +- pkg/generated/openapi/zz_generated.openapi.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apis/v1beta1/gateway_types.go b/apis/v1beta1/gateway_types.go index 80c746fcdd..1998c2ac27 100644 --- a/apis/v1beta1/gateway_types.go +++ b/apis/v1beta1/gateway_types.go @@ -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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 60e2caa920..f4a7d0d4f2 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -4007,7 +4007,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": { From 962d22f43dd30e80752cc586a971a71d308526b9 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Mon, 9 Jun 2025 15:06:23 -0700 Subject: [PATCH 031/148] add mesh conformance for httproute-queryparmas-match (#3834) --- .../mesh/httproute-query-param-matching.go | 135 ++++++++++++++++++ .../mesh/httproute-query-param-matching.yaml | 85 +++++++++++ pkg/features/mesh.go | 8 ++ 3 files changed, 228 insertions(+) create mode 100644 conformance/tests/mesh/httproute-query-param-matching.go create mode 100644 conformance/tests/mesh/httproute-query-param-matching.yaml 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/pkg/features/mesh.go b/pkg/features/mesh.go index f088cdad83..d191dc3846 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -58,6 +58,8 @@ const ( SupportMeshHTTPRouteRedirectPath FeatureName = "MeshHTTPRouteRedirectPath" // This option indicates support for HTTPRoute backend request header modification SupportMeshHTTPRouteBackendRequestHeaderModification FeatureName = "MeshHTTPRouteBackendRequestHeaderModification" + // This option indicates mesh support for HTTPRoute query param matching (extended conformance). + SupportMeshHTTPRouteQueryParamMatching FeatureName = "MeshHTTPRouteQueryParamMatching" ) var ( @@ -101,6 +103,11 @@ var ( Name: SupportMeshHTTPRouteBackendRequestHeaderModification, Channel: FeatureChannelStandard, } + // MeshHTTPRouteRedirectPath contains metadata for the MeshHTTPRouteRedirectPath feature. + MeshHTTPRouteQueryParamMatching = Feature{ + Name: SupportMeshHTTPRouteQueryParamMatching, + Channel: FeatureChannelStandard, + } ) // MeshExtendedFeatures includes all the supported features for the service mesh at @@ -112,4 +119,5 @@ var MeshExtendedFeatures = sets.New( MeshHTTPRouteSchemeRedirect, MeshHTTPRouteRedirectPath, MeshHTTPRouteBackendRequestHeaderModification, + MeshHTTPRouteQueryParamMatching, ) From 270d637886ff72a5c24431dba45e0f4b88fdeb17 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Jun 2025 15:56:23 -0700 Subject: [PATCH 032/148] build(deps): bump google.golang.org/grpc from 1.71.1 to 1.73.0 (#3842) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.71.1 to 1.73.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.71.1...v1.73.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-version: 1.73.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 46c6618d28..4bf07ec2f5 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( 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 + google.golang.org/grpc v1.73.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 @@ -70,14 +70,14 @@ require ( 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/oauth2 v0.28.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 + google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // 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 diff --git a/go.sum b/go.sum index 6c92e7ba96..b380233c61 100644 --- a/go.sum +++ b/go.sum @@ -142,16 +142,16 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= +go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= +go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= +go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= 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= @@ -173,8 +173,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL 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/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= 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= @@ -207,10 +207,10 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T 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= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= +google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= 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= From 17a60f668a0d0ff6dd5bdbbfb91fd74702a84532 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Wed, 11 Jun 2025 04:26:59 -0700 Subject: [PATCH 033/148] fix meshredirectport and schemeredirect mesh conformance features (#3847) * include meshredirectport in extended * Update mesh.go --- pkg/features/mesh.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/features/mesh.go b/pkg/features/mesh.go index d191dc3846..4d7ca20b29 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -82,7 +82,7 @@ var ( // MeshHTTPRouteSchemeRedirect contains metadata for the MeshHTTPRouteSchemeRedirect feature. MeshHTTPRouteSchemeRedirect = Feature{ - Name: SupportMeshHTTPRouteRewritePath, + Name: SupportMeshHTTPRouteSchemeRedirect, Channel: FeatureChannelStandard, } @@ -117,6 +117,7 @@ var MeshExtendedFeatures = sets.New( MeshConsumerRouteFeature, MeshHTTPRouteRewritePath, MeshHTTPRouteSchemeRedirect, + MeshHTTPRouteRedirectPort, MeshHTTPRouteRedirectPath, MeshHTTPRouteBackendRequestHeaderModification, MeshHTTPRouteQueryParamMatching, From 6cd1558a9ed65ab0afb036a869f8a8530b8d68d8 Mon Sep 17 00:00:00 2001 From: Bob Tian Date: Wed, 11 Jun 2025 10:02:56 -0700 Subject: [PATCH 034/148] Add body to http.Request and roundTripper.request to extend conformance util. (#3853) --- conformance/utils/http/http.go | 2 ++ conformance/utils/roundtripper/roundtripper.go | 9 ++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go index 7866790321..18b5e1feb0 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -70,6 +70,7 @@ type Request struct { Headers map[string]string UnfollowRedirect bool Protocol string + Body string } // ExpectedRequest defines expected properties of a request that reaches a backend. @@ -139,6 +140,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 { diff --git a/conformance/utils/roundtripper/roundtripper.go b/conformance/utils/roundtripper/roundtripper.go index c37f4500aa..f79508784f 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 @@ -194,7 +196,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 } From 7d8e56bfda71e77acb23b664643cc22619af4d1e Mon Sep 17 00:00:00 2001 From: Flynn Date: Wed, 11 Jun 2025 14:52:55 -0400 Subject: [PATCH 035/148] Initial Linkerd 1.3.0 conformance reports (#3839) * Conformance reports for Linkerd and Buoyant Enterprise for Linkerd Signed-off-by: Flynn * Tell people where to stand to run the tests. Signed-off-by: Flynn * Wordsmithing. Signed-off-by: Flynn * Update conformance report (with standard report names and reproduction scripts) Signed-off-by: Flynn * Clean up lint failures. Signed-off-by: Flynn * Correctly mark unsupported features, and clean up run-conformance scripts a touch Signed-off-by: Flynn * Fix typos :man_facepalming: Signed-off-by: Flynn * Linkerd's Gateway API support is not experimental. Signed-off-by: Flynn * Update conformance results now that all the mesh tests are correctly being run Signed-off-by: Flynn * Update READMEs to note that these tests used the v1.3.0 CRDs, but the main branch. (There are better MESH-profile tests on main that I wanted to take advantage of.) Signed-off-by: Flynn --------- Signed-off-by: Flynn --- .../buoyant-enterprise-for-linkerd/README.md | 32 +++++++++ .../run-conformance.sh | 65 ++++++++++++++++++ .../standard-2.18-default-report.yaml | 64 ++++++++++++++++++ .../reports/v1.3.0/linkerd-linkerd/README.md | 65 ++++++++++++++++++ .../v1.3.0/linkerd-linkerd/run-conformance.sh | 66 +++++++++++++++++++ .../standard-2.18-default-report.yaml | 64 ++++++++++++++++++ site-src/implementations.md | 2 +- 7 files changed, 357 insertions(+), 1 deletion(-) create mode 100644 conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/README.md create mode 100644 conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/run-conformance.sh create mode 100644 conformance/reports/v1.3.0/buoyant-enterprise-for-linkerd/standard-2.18-default-report.yaml create mode 100644 conformance/reports/v1.3.0/linkerd-linkerd/README.md create mode 100644 conformance/reports/v1.3.0/linkerd-linkerd/run-conformance.sh create mode 100644 conformance/reports/v1.3.0/linkerd-linkerd/standard-2.18-default-report.yaml 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/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/site-src/implementations.md b/site-src/implementations.md index e65f26aa4f..06b0e7926e 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -51,7 +51,7 @@ cover, and documentation to help users get started. - [Google Cloud Service Mesh][38] (GA) - [Istio][9] (GA) - [Kuma][11] (GA) -- [Linkerd][28] (experimental) +- [Linkerd][28] (GA) ## Integrations From 8185c7df9362607773ed74ff629e3a00593d2007 Mon Sep 17 00:00:00 2001 From: Dave Protasowski Date: Wed, 11 Jun 2025 18:18:55 -0400 Subject: [PATCH 036/148] GEP-1713 Revisions (#3744) * formatting * clarify optional port semantics * clarify listener name semantics * clarify attachment/grants semantics - Route attachment without sectionName - re-order policy attachment section - include a section about ReferenceGrants * set proper min/max value for listenerentry.port We had to drop the use of the PortNumber type because of limitations with overriding min max using kubebuilder annotations * Update geps/gep-1713/index.md Co-authored-by: Nick Young * Drop validation markers this is handled in another PR See: https://github.com/kubernetes-sigs/gateway-api/pull/3750 * address Nick's feedback * remove stray backtick * address Rob's feedback * incorporate gep changes into godoc --------- Co-authored-by: Nick Young --- apis/v1/gateway_types.go | 31 ++++++++++ apisx/v1alpha1/xlistenerset_types.go | 33 ++++++++-- ...way.networking.x-k8s.io_xlistenersets.yaml | 33 ++++++++-- geps/gep-1713/index.md | 60 +++++++++++-------- pkg/generated/openapi/zz_generated.openapi.go | 4 +- 5 files changed, 126 insertions(+), 35 deletions(-) diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index 3e1ec4c7ea..f54e5d10ce 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -1062,6 +1062,37 @@ 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. diff --git a/apisx/v1alpha1/xlistenerset_types.go b/apisx/v1alpha1/xlistenerset_types.go index 529b7f3508..92cca1b735 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -29,8 +29,33 @@ 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.ObjectMeta `json:"metadata,omitempty"` @@ -63,10 +88,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. 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..2454521c2e 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. diff --git a/geps/gep-1713/index.md b/geps/gep-1713/index.md index f51f044dda..4cad39fde1 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 @@ -164,15 +164,8 @@ 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 - // 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"` + Port PortNumber `json:"port,omitempty"` // Protocol specifies the network protocol this listener expects to receive. // @@ -385,8 +378,7 @@ 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 ## Semantics @@ -399,7 +391,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 +405,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 +453,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 +532,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 +573,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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index f4a7d0d4f2..96ac164691 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7882,7 +7882,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 +8161,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": { From ed2bd6b55c38cca9c265131c5fd71376b60d2778 Mon Sep 17 00:00:00 2001 From: Beka Modebadze <58038950+bexxmodd@users.noreply.github.com> Date: Thu, 12 Jun 2025 14:56:58 -0700 Subject: [PATCH 037/148] Infer SupportedFeatures in Conformance Tests (GEP-2162) [#3759] (#3848) * SupportedFeatures * Added inferredSupportedFeatures to determine and report if feature for tests were manually supplied or inferred from GatewayClass * Corrected suite unit tests after addition of a new field. * Added logic of determining if supportedFeatures are inferred or supplied and refactored some code around it. * moved SupportedFeatures init after scheme addition * Cleaned up and organized code to properly determine features we are testing and if they were inferred or not. * Cleanup v2 * Make inferring supportedFeatures to take precedence over all other feature flags. * Fix when no profile was setting inferred to false. * remove debug log * Switched args arrangement so ctx is the first argument passed to fetchSupportedFeatures function. * Updated context as it's unclear where it should be supplied from * removed SupportedFeatures struct and method for determining supported features. * Refactored logic of determining supported features and add flag for the report in cSuite. * Reversed flag parsing for some values. * Tweaked logging options. * Cleaned up last places for SupportedFeatures struct. * Wrote unit tests for supported features determination logic in conformance suite. * Formatting fixes. * Resolved comments. * Fixed formatting. * Updated conformance docs. * Removed doc update so it can be submitted as a seperate PR. --- conformance/apis/v1/conformancereport.go | 4 + conformance/conformance.go | 5 + conformance/utils/suite/conformance.go | 6 +- conformance/utils/suite/reports.go | 6 +- conformance/utils/suite/suite.go | 100 ++++++++++++----- conformance/utils/suite/suite_test.go | 133 ++++++++++++++++++++++- 6 files changed, 217 insertions(+), 37 deletions(-) diff --git a/conformance/apis/v1/conformancereport.go b/conformance/apis/v1/conformancereport.go index 7f4f4d5325..dcea92dffc 100644 --- a/conformance/apis/v1/conformancereport.go +++ b/conformance/apis/v1/conformancereport.go @@ -50,6 +50,10 @@ type ConformanceReport struct { // SucceededProvisionalTests is a list of the names of the provisional tests that // have been successfully run. SucceededProvisionalTests []string `json:"succeededProvisionalTests,omitempty"` + + // InferredSupportedFeatures indicates whether the supported features were + // automatically detected by the conformance suite. + InferredSupportedFeatures bool `json:"inferredSupportedFeatures"` } // Implementation provides metadata information on the downstream diff --git a/conformance/conformance.go b/conformance/conformance.go index ce264a9441..12e5884968 100644 --- a/conformance/conformance.go +++ b/conformance/conformance.go @@ -29,11 +29,14 @@ import ( "sigs.k8s.io/gateway-api/conformance/tests" conformanceconfig "sigs.k8s.io/gateway-api/conformance/utils/config" "sigs.k8s.io/gateway-api/conformance/utils/flags" + "sigs.k8s.io/gateway-api/conformance/utils/suite" "github.com/stretchr/testify/require" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" + clientset "k8s.io/client-go/kubernetes" + "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/yaml" @@ -63,6 +66,7 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { supportedFeatures := suite.ParseSupportedFeatures(*flags.SupportedFeatures) exemptFeatures := suite.ParseSupportedFeatures(*flags.ExemptFeatures) + skipTests := suite.ParseSkipTests(*flags.SkipTests) namespaceLabels := suite.ParseKeyValuePairs(*flags.NamespaceLabels) namespaceAnnotations := suite.ParseKeyValuePairs(*flags.NamespaceAnnotations) @@ -144,6 +148,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/utils/suite/conformance.go b/conformance/utils/suite/conformance.go index 3bbbbc1c23..12db14d6df 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" ) @@ -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/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 e6a5cb1264..f1164fa2fe 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,7 +71,7 @@ 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 @@ -79,6 +81,11 @@ type ConformanceTestSuite struct { 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. + isInferredSupportedFeatures bool + // mode is the operating mode of the implementation. // The default value for it is "default". mode string @@ -142,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 @@ -172,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 @@ -181,16 +190,23 @@ const ( // 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) + isInferred := false + switch { + case options.EnableAllSupportedFeatures: + supportedFeatures = features.SetsToNamesSet(features.AllFeatures) + case 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) + } + isInferred = true + } + + // If features were not inferred from Status, it's a GWC issue. + if isInferred && supportedFeatures.Len() == 0 { + return nil, fmt.Errorf("no supported features were determined for test suite") } config.SetupTimeoutConfig(&options.TimeoutConfig) @@ -224,19 +240,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, @@ -254,7 +257,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, @@ -270,6 +273,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, mode: mode, apiVersion: apiVersion, apiChannel: apiChannel, + isInferredSupportedFeatures: isInferred, Hook: options.Hook, } @@ -288,12 +292,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) } @@ -390,6 +394,10 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest) } } +func (suite *ConformanceTestSuite) IsInferredSupportedFeatures() bool { + return suite.isInferredSupportedFeatures +} + func (suite *ConformanceTestSuite) setClientsetForTest(test ConformanceTest) error { featureNames := []string{} for _, v := range test.Features { @@ -544,6 +552,7 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) { GatewayAPIChannel: suite.apiChannel, ProfileReports: profileReports.list(), SucceededProvisionalTests: succeededProvisionalTests, + InferredSupportedFeatures: suite.IsInferredSupportedFeatures(), }, nil } @@ -573,6 +582,39 @@ 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.ConformanceProfiles.Len() == 0 && + len(opts.SkipTests) == 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..ccb259adb0 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -22,9 +22,13 @@ 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 +221,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 @@ -276,6 +280,7 @@ func TestSuiteReport(t *testing.T) { coreProvisionalTest.ShortName, extendedProvisionalTest.ShortName, }, + InferredSupportedFeatures: true, }, }, { @@ -385,6 +390,7 @@ func TestSuiteReport(t *testing.T) { }, }, }, + InferredSupportedFeatures: true, }, }, } @@ -407,3 +413,128 @@ 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 + expectedIsInferred bool + }{ + { + name: "properly infer supported features", + expectedFeatures: namesToFeatureSet(statusFeatureNames), + expectedIsInferred: true, + }, + { + name: "no features", + supportedFeatures: sets.New[features.FeatureName]("Gateway"), + expectedFeatures: sets.New[features.FeatureName]("Gateway"), + }, + { + name: "remove exempt features", + supportedFeatures: sets.New[features.FeatureName]("Gateway", "HTTPRoute"), + exemptFeatures: sets.New[features.FeatureName]("HTTPRoute"), + expectedFeatures: sets.New[features.FeatureName]("Gateway"), + }, + { + name: "allow all features", + allowAllFeatures: true, + expectedFeatures: features.SetsToNamesSet(features.AllFeatures), + }, + { + name: "supports conformance profile - core", + ConformanceProfile: sets.New(GatewayHTTPConformanceProfileName), + expectedFeatures: namesToFeatureSet([]string{"Gateway", "HTTPRoute", "ReferenceGrant"}), + }, + } + + 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.IsInferredSupportedFeatures() != tc.expectedIsInferred { + t.Errorf("InferredSupportedFeatures mismatch: got %v, want %v", cSuite.IsInferredSupportedFeatures(), tc.expectedIsInferred) + } + + if equal := cSuite.SupportedFeatures.Equal(tc.expectedFeatures); !equal { + t.Errorf("SupportedFeatures mismatch: got %v, want %v", cSuite.SupportedFeatures.UnsortedList(), tc.expectedFeatures.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 +} From 66539b9ad348fdabd3dfd7cd5956c828675b187d Mon Sep 17 00:00:00 2001 From: Nick Young Date: Mon, 16 Jun 2025 16:56:58 +1000 Subject: [PATCH 038/148] Make feature name required for Experimental (#3859) We have discussed this in community meetings and Slack, and have informally agreed that a conformance Feature Name must be set for a GEP to graduate to Experimental. This commit adds changes to the GEP process page and the GEP template to make this official. Signed-off-by: Nick Young --- geps/gep-696/index.md | 2 ++ geps/overview.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/geps/gep-696/index.md b/geps/gep-696/index.md index bedcc6e658..4a4a97dd19 100644 --- a/geps/gep-696/index.md +++ b/geps/gep-696/index.md @@ -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/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. From 1a9fdd310de40f83c5ad58c1215d1c6c2c6832cb Mon Sep 17 00:00:00 2001 From: Arko Dasgupta Date: Mon, 16 Jun 2025 13:57:02 -0700 Subject: [PATCH 039/148] GEP 91: Update Goals and Prior Art (#3838) * GEP 91: Update Goals and Prior Art Relates to https://github.com/kubernetes-sigs/gateway-api/discussions/3760#discussioncomment-12997389 Signed-off-by: Arko Dasgupta * fix table Signed-off-by: Arko Dasgupta * moves prior art to the end of the file Signed-off-by: Arko Dasgupta * rewrite prior art section description Signed-off-by: Arko Dasgupta --------- Signed-off-by: Arko Dasgupta --- geps/gep-91/index.md | 67 +++++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/geps/gep-91/index.md b/geps/gep-91/index.md index 6fddddb59f..4216a2674e 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,31 +8,18 @@ ## 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][]. ## 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. +* 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). +* Supporting a mode where validating client certificates is optional, useful for debugging and migrating to strict TLS. ## Non-Goals * Define other fields that can be used to verify the client certificate such as the Certificate Hash. -## Existing support in Implementations - -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. - -| 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) | - ### API * 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. @@ -151,10 +138,50 @@ 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 From b4794ff3cfee5e49910aa1ba55eb1b8336695ce9 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 17 Jun 2025 17:24:52 -0700 Subject: [PATCH 040/148] GEP 3779 - East/West Identity-Based Authorization (#3822) * add draft authz gep e/w * add a table * fix * add cilium content * add all mesh authz model * small nits * fix * newline * Apply suggestions from code review Co-authored-by: Nick Young * move cluster-admin non-overridable case to stretch goals * change stretch to tbd --------- Co-authored-by: Aryan Gupta Co-authored-by: Nick Young --- geps/gep-3779/index.md | 266 ++++++++++++++++++++++++++++++++++++ geps/gep-3779/metadata.yaml | 19 +++ 2 files changed, 285 insertions(+) create mode 100644 geps/gep-3779/index.md create mode 100644 geps/gep-3779/metadata.yaml 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: {} From 9d59dd814c5df82a0cc57730167cf4679854be4f Mon Sep 17 00:00:00 2001 From: Tim Flannagan Date: Wed, 18 Jun 2025 16:40:51 -0400 Subject: [PATCH 041/148] Add kgateway 1.3 conformance report (#3865) * Add kgateway 1.3 conformance report Signed-off-by: timflannagan * Override VERSION variable, update conformance report, etc Signed-off-by: timflannagan --------- Signed-off-by: timflannagan --- conformance/reports/v1.3.0/kgateway/README.md | 40 ++++++++++++++ .../v1.3.0/kgateway/v2.1.0-main-report.yaml | 53 +++++++++++++++++++ 2 files changed, 93 insertions(+) create mode 100644 conformance/reports/v1.3.0/kgateway/README.md create mode 100644 conformance/reports/v1.3.0/kgateway/v2.1.0-main-report.yaml 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. From 80200b8745a92a944a57b1a55297ce9ef7e7b86d Mon Sep 17 00:00:00 2001 From: Arihant Bachhawat Date: Mon, 2 Jun 2025 12:17:14 +0000 Subject: [PATCH 042/148] Adding GEP-3798 client ip based session persistence --- geps/gep-3798/index.md | 133 ++++++++++++++++++++++++++++++++++++ geps/gep-3798/metadata.yaml | 37 ++++++++++ 2 files changed, 170 insertions(+) create mode 100644 geps/gep-3798/index.md create mode 100644 geps/gep-3798/metadata.yaml diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md new file mode 100644 index 0000000000..80df3a4e05 --- /dev/null +++ b/geps/gep-3798/index.md @@ -0,0 +1,133 @@ +# GEP-3798: Client IP-Based Session Persistence + +* Issue: [#3798](https://github.com/kubernetes-sigs/gateway-api/issues/3798) +* Status: Provisional + +(See [status definitions](../overview.md#gep-states).) + +## 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 per the nomenclature established in [#1619](https://gateway-api.sigs.k8s.io/geps/gep-1619), this feature is being referred as Session Affinity . + + +## 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. + +* Ensure the solution is generic enough to be implemented by various Gateway API controllers. + +* 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: + +* Lack of Portability: 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. + +* Inconsistent User Experience: Users have to learn different methods for configuring the same logical feature depending on their chosen Gateway API implementation. + +* Limited API Expressiveness: Important traffic management capabilities are not directly exposed or controlled through the Gateway API, making it less comprehensive for certain application requirements. + +* 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 Applications: Applications that rely on client IP affinity (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 + +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. + +Requirement is to introduce a new `SessionPersistenceType` called `ClientIP` + +Example (illustrative, exact field names and structure are subject to review): + +``` +# Existing SessionPersistence (simplified for example) +# apiVersion: gateway.networking.k8s.io/v1beta1 +# kind: HTTPRoute + +spec: + rules: + - backendRefs: + - name: my-service + port: 80 + sessionPersistence: + # New field for client IP based persistence + type: "ClientIP" + absoluteTimeout: "5m" + ipMask: 24 # Optional: IP mask for subnet persistence (e.g., "24" for /24 subnet) +``` +``` +type SessionPersistence struct { + ... + + // IPMask defines the IP mask to be applied on client this may be + // used to persist clients from a same subnet to stick to same session + // + // Support: Implementation-specific + // + // +optional + // +kubebuilder:validation:Minimum=0 + // +kubebuilder:validation:Maximum=128 + IPMask *uint32 `json:"ipMask,omitempty"` + +} + +type SessionPersistenceType string + +const ( + // CookieBasedSessionPersistence specifies cookie-based session + // persistence. + // + // Support: Core + CookieBasedSessionPersistence SessionPersistenceType = "Cookie" + + // HeaderBasedSessionPersistence specifies header-based session + // persistence. + // + // Support: Extended + HeaderBasedSessionPersistence SessionPersistenceType = "Header" + + // ClientIPBasedSessionPersistence specifies Client IP based session + // persistence. + // + // Support: Implementation-specific + ClientIPBasedSessionPersistence SessionPersistenceType = "ClientIP" +) +``` + +### 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) +* [Envoy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-routeaction-hashpolicy-connectionproperties) (the connection property hash policy can be used with Ring Hash load balancing to ensure session persistence for a particular source IP) +* [Nginx](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash) +* [Native k8s](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) + diff --git a/geps/gep-3798/metadata.yaml b/geps/gep-3798/metadata.yaml new file mode 100644 index 0000000000..375caf7558 --- /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: Provisional +# 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: {} From ff7e2e8aed2e48156aa85c9e5418c2275ab1bb4a Mon Sep 17 00:00:00 2001 From: Arihant Bachhawat Date: Tue, 10 Jun 2025 09:42:39 +0000 Subject: [PATCH 043/148] address some review comments --- geps/gep-3798/index.md | 7 ++----- geps/gep-3798/metadata.yaml | 6 +++--- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index 80df3a4e05..ae89cc1f01 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -8,8 +8,7 @@ ## 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 per the nomenclature established in [#1619](https://gateway-api.sigs.k8s.io/geps/gep-1619), this feature is being referred as Session Affinity . - + 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. ## Goals @@ -49,7 +48,7 @@ This GEP addresses these issues by providing a first-class API mechanism for cli * Gateway API Implementers: Receive a clear specification for implementing client IP-based session persistence, fostering interoperability and reducing divergent approaches. -* Users with Stateful Applications: Applications that rely on client IP affinity (e.g., certain legacy applications, gaming servers, or applications with in-memory session stores) will directly benefit from a reliable and configurable persistence mechanism. +* Users with Stateful 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 @@ -127,7 +126,5 @@ Yet to do 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) -* [Envoy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/config/route/v3/route_components.proto#envoy-v3-api-msg-config-route-v3-routeaction-hashpolicy-connectionproperties) (the connection property hash policy can be used with Ring Hash load balancing to ensure session persistence for a particular source IP) -* [Nginx](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#ip_hash) * [Native k8s](https://kubernetes.io/docs/reference/networking/virtual-ips/#session-affinity) diff --git a/geps/gep-3798/metadata.yaml b/geps/gep-3798/metadata.yaml index 375caf7558..e7d33a7c8b 100644 --- a/geps/gep-3798/metadata.yaml +++ b/geps/gep-3798/metadata.yaml @@ -21,9 +21,9 @@ relationships: # 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 + - 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. From dfcdf5bd54142eb840ab71e88279812ee8c7f30f Mon Sep 17 00:00:00 2001 From: Arihant Bachhawat Date: Mon, 16 Jun 2025 09:02:19 +0000 Subject: [PATCH 044/148] Removed API section and add examples of load balancers using subnet mask to implement session persistence --- geps/gep-3798/index.md | 70 ++++++------------------------------------ 1 file changed, 10 insertions(+), 60 deletions(-) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index ae89cc1f01..682a091db2 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -10,6 +10,8 @@ ### 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. + ## Goals * Define an API extension within Gateway API to enable client IP-based session persistence. @@ -52,66 +54,7 @@ This GEP addresses these issues by providing a first-class API mechanism for cli ## API -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. - -Requirement is to introduce a new `SessionPersistenceType` called `ClientIP` - -Example (illustrative, exact field names and structure are subject to review): - -``` -# Existing SessionPersistence (simplified for example) -# apiVersion: gateway.networking.k8s.io/v1beta1 -# kind: HTTPRoute - -spec: - rules: - - backendRefs: - - name: my-service - port: 80 - sessionPersistence: - # New field for client IP based persistence - type: "ClientIP" - absoluteTimeout: "5m" - ipMask: 24 # Optional: IP mask for subnet persistence (e.g., "24" for /24 subnet) -``` -``` -type SessionPersistence struct { - ... - - // IPMask defines the IP mask to be applied on client this may be - // used to persist clients from a same subnet to stick to same session - // - // Support: Implementation-specific - // - // +optional - // +kubebuilder:validation:Minimum=0 - // +kubebuilder:validation:Maximum=128 - IPMask *uint32 `json:"ipMask,omitempty"` - -} - -type SessionPersistenceType string - -const ( - // CookieBasedSessionPersistence specifies cookie-based session - // persistence. - // - // Support: Core - CookieBasedSessionPersistence SessionPersistenceType = "Cookie" - - // HeaderBasedSessionPersistence specifies header-based session - // persistence. - // - // Support: Extended - HeaderBasedSessionPersistence SessionPersistenceType = "Header" - - // ClientIPBasedSessionPersistence specifies Client IP based session - // persistence. - // - // Support: Implementation-specific - ClientIPBasedSessionPersistence SessionPersistenceType = "ClientIP" -) -``` +TBD ### Conformance tests @@ -128,3 +71,10 @@ Below are references showing how ClientIP persistence is currently supported acr * [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) From 71aee26d97ce2880c9b217982ec65c9090290e5d Mon Sep 17 00:00:00 2001 From: Arihant Bachhawat Date: Tue, 17 Jun 2025 05:52:27 +0000 Subject: [PATCH 045/148] Merge similar points as per review --- geps/gep-3798/index.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index 682a091db2..0daef3e58a 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -10,7 +10,9 @@ ### 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. + 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 @@ -33,11 +35,7 @@ This GEP does not dictate the specific algorithm or implementation details for h ### 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: -* Lack of Portability: 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. - -* Inconsistent User Experience: Users have to learn different methods for configuring the same logical feature depending on their chosen Gateway API implementation. - -* Limited API Expressiveness: Important traffic management capabilities are not directly exposed or controlled through the Gateway API, making it less comprehensive for certain application requirements. +* 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. @@ -50,7 +48,7 @@ This GEP addresses these issues by providing a first-class API mechanism for cli * Gateway API Implementers: Receive a clear specification for implementing client IP-based session persistence, fostering interoperability and reducing divergent approaches. -* Users with Stateful 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. +* 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 From 961b4f3739f58c7487b616afaba6954e53763f28 Mon Sep 17 00:00:00 2001 From: Arihant Bachhawat Date: Tue, 17 Jun 2025 20:14:43 +0530 Subject: [PATCH 046/148] Apply suggestions from code review Co-authored-by: Shane Utt --- geps/gep-3798/index.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index 0daef3e58a..9afe230b9f 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -22,8 +22,6 @@ * 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. -* Ensure the solution is generic enough to be implemented by various Gateway API controllers. - * Improve portability of applications requiring client IP persistence across different Gateway API implementations. ## Non-Goals @@ -52,7 +50,7 @@ This GEP addresses these issues by providing a first-class API mechanism for cli ## API -TBD +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 From 46d3d0b4f8019f7905fd5b75d6c142ec49fde8d2 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Wed, 18 Jun 2025 18:42:16 -0400 Subject: [PATCH 047/148] Update geps/gep-3798/index.md --- geps/gep-3798/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index 9afe230b9f..84b4a603c8 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -5,6 +5,10 @@ (See [status definitions](../overview.md#gep-states).) +## Notes and Disclaimers + +* This is currently targeting release as `Experimental` in [v1.4.0](https://github.com/kubernetes-sigs/gateway-api/milestone/22). However there was notable concern in [PR#3844](https://github.com/kubernetes-sigs/gateway-api/pull/3844) that it may be difficult to get multiple implementations who will be ready to implement this and move it forward. As such, the primary focus at this point should be finding representatives of implementations who may be interested in implementing this. Otherwise, this GEP may need to be `Deferred` and revisited as part of a later release. + ## TLDR ### What From c9720d935605ca3f56cb204974bbd2620f0da185 Mon Sep 17 00:00:00 2001 From: Flynn Date: Wed, 18 Jun 2025 19:52:52 -0400 Subject: [PATCH 048/148] GEP-3792: Off-Cluster Gateways (#3851) * GEP-3792 Signed-off-by: Flynn * Wordsmith feature name. Signed-off-by: Flynn * Address review feedback. Signed-off-by: Flynn --------- Signed-off-by: Flynn --- geps/gep-3792/index.md | 264 ++++++++++++++++++++++++++++++++++++ geps/gep-3792/metadata.yaml | 33 +++++ 2 files changed, 297 insertions(+) create mode 100644 geps/gep-3792/index.md create mode 100644 geps/gep-3792/metadata.yaml diff --git a/geps/gep-3792/index.md b/geps/gep-3792/index.md new file mode 100644 index 0000000000..3306958554 --- /dev/null +++ b/geps/gep-3792/index.md @@ -0,0 +1,264 @@ +# GEP-3792: External 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://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro +[Ian]: https://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.) + +#### 4. 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..2551cb0aca --- /dev/null +++ b/geps/gep-3792/metadata.yaml @@ -0,0 +1,33 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3792 +name: GEP template +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: {} From b4055ba1611daac73fddfd2b005ae85b68733c8a Mon Sep 17 00:00:00 2001 From: Flynn Date: Thu, 19 Jun 2025 06:46:51 -0400 Subject: [PATCH 049/148] GEP-3793: Default Gateways (#3852) * GEP-3793 Signed-off-by: Flynn * Review feedback. Signed-off-by: Flynn * Review feedback. Signed-off-by: Flynn --------- Signed-off-by: Flynn --- geps/gep-3793/index.md | 217 ++++++++++++++++++++++++++++++++++++ geps/gep-3793/metadata.yaml | 33 ++++++ 2 files changed, 250 insertions(+) create mode 100644 geps/gep-3793/index.md create mode 100644 geps/gep-3793/metadata.yaml diff --git a/geps/gep-3793/index.md b/geps/gep-3793/index.md new file mode 100644 index 0000000000..0c8ba3e6ae --- /dev/null +++ b/geps/gep-3793/index.md @@ -0,0 +1,217 @@ +# GEP-3793: Default Gateways + +* Issue: [#3793](https://github.com/kubernetes-sigs/gateway-api/issues/3793) +* Status: Provisional + +(See [status definitions](../overview.md#gep-states).) + +## 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]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana + +## Goals + +- Give Ana a way to use Gateway API without having to explicitly specify a + Gateway for every Route, ideally without mutating Routes. + +- Give Ana an easy way to determine which Gateway is the default, and which of + her Routes are bound to it. + +- Continue supporting multiple Gateways in a cluster, while allowing exactly + one of them to be the default Gateway. + +- Allow [Chihiro] to retain control over which Gateway is the default, so that + they can ensure that it meets their requirements for security, performance, + and other operational concerns. + +- Allow Chihiro to choose not to provide a default Gateway. + +- Allow Chihiro to rename, reconfigure, or replace the default Gateway at + runtime. + + - If Chihiro renames the default Gateway, Routes using the default Gateway + MUST remain bound to the new default Gateway. Ana shouldn't need to go + recreate all her Routes just because Chihiro is being indecisive. + + - Determine how (or if) to signal changes in functionality if the default + Gateway implementation is changed. For example, suppose that Chihiro + switches the 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 the default Gateway, and + to enumerate which Routes are currently bound to the 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 + +- Support multiple "default" Gateways in a single cluster. If Ana has to make + a choice about which Gateway she wants to use, she'll need to be explicit + about that. + + Loosening this restriction later is a possibility. For example, we may later + want to consider allowing a default Gateway per namespace, or a default + Gateway per implementation running in a cluster. However, these examples are + not in scope for this GEP, in order to have a fighting chance of getting + functionality into Gateway API 1.4. + +- Allow Ana to override Chihiro's choice for the default Gateway for a given + Route without explicitly specifying the Gateway. + +- Require that every possible routing use case be met by a Route using the + 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. + +### Prior Art + +This is very much not a new problem: there are many other systems out there +where being unambiguous is crucial, but where being completely explicit is a +burden. One of the simplest examples 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. + +The Ingress resource, of course, is another 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.) + +It's rare to find systems that are completely explicit or completely implicit: +in practice, the trick is to find a usable balance between explicitness and +simplicity, while managing ambiguity. + +### 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. + +[Chihiro]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro +[Ian]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian + +## API + +Most of the API work for this GEP is TBD at this point. The challenge 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 the Gateway and its configuration. + +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. This is obviously a key point that +will need resolution before this GEP can graduate. + +[discussion]: https://github.com/kubernetes-sigs/gateway-api/pull/3852#discussion_r2140117567 + +### Gateway for Ingress (North/South) + +### Gateway For Mesh (East/West) + +## 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 + +## 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 + +## References diff --git a/geps/gep-3793/metadata.yaml b/geps/gep-3793/metadata.yaml new file mode 100644 index 0000000000..d7db3ffebf --- /dev/null +++ b/geps/gep-3793/metadata.yaml @@ -0,0 +1,33 @@ +apiVersion: internal.gateway.networking.k8s.io/v1alpha1 +kind: GEPDetails +number: 3793 +name: GEP template +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: {} From 9e413ccb0ae77eccf61b48a509884addfbfd1945 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 19 Jun 2025 18:26:55 -0400 Subject: [PATCH 050/148] docs: note about expectations when a gep misses a release timeline (#3866) Signed-off-by: Shane Utt --- site-src/contributing/release-cycle.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 From 8ed3a0652b3cb0b295b890ede81d24b72d0e34a0 Mon Sep 17 00:00:00 2001 From: Flynn Date: Thu, 19 Jun 2025 18:42:52 -0400 Subject: [PATCH 051/148] GEP-3792 and GEP-3793 title fixes :man_facepalming: (#3870) * GEP-3792 and GEP-3793 title fixes :man_facepalming: Signed-off-by: Flynn * It's really annoying to have to constantly update this file. Signed-off-by: Flynn * May as well include Lior's GEP too. Signed-off-by: Flynn --------- Signed-off-by: Flynn --- geps/gep-3792/index.md | 2 +- geps/gep-3792/metadata.yaml | 2 +- geps/gep-3793/metadata.yaml | 2 +- mkdocs.yml | 3 +++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/geps/gep-3792/index.md b/geps/gep-3792/index.md index 3306958554..b0c5d80b6b 100644 --- a/geps/gep-3792/index.md +++ b/geps/gep-3792/index.md @@ -1,4 +1,4 @@ -# GEP-3792: External Gateways +# GEP-3792: Out-of-Cluster Gateways * Issue: [#3792](https://github.com/kubernetes-sigs/gateway-api/issues/3792) * Status: Provisional diff --git a/geps/gep-3792/metadata.yaml b/geps/gep-3792/metadata.yaml index 2551cb0aca..4478b32b1e 100644 --- a/geps/gep-3792/metadata.yaml +++ b/geps/gep-3792/metadata.yaml @@ -1,7 +1,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 3792 -name: GEP template +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. diff --git a/geps/gep-3793/metadata.yaml b/geps/gep-3793/metadata.yaml index d7db3ffebf..060426f033 100644 --- a/geps/gep-3793/metadata.yaml +++ b/geps/gep-3793/metadata.yaml @@ -1,7 +1,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 3793 -name: GEP template +name: Default Gateways status: Provisional # Any authors who contribute to the GEP in any way should be listed here using # their GitHub handle. diff --git a/mkdocs.yml b/mkdocs.yml index 4a4a7de35d..4688e7f585 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -130,6 +130,9 @@ nav: - geps/gep-1494/index.md - geps/gep-1651/index.md - geps/gep-2648/index.md + - geps/gep-3379/index.md + - geps/gep-3792/index.md + - geps/gep-3793/index.md - Implementable: - geps/gep-91/index.md - geps/gep-3567/index.md From 6f56152752710213525101ea8ce4be964512df73 Mon Sep 17 00:00:00 2001 From: Yoon Seoyul Date: Sat, 21 Jun 2025 03:36:52 +0900 Subject: [PATCH 052/148] docs: fix typo and add contents about "ngrok Kubernetes Operator" (#3874) --- site-src/implementations.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/site-src/implementations.md b/site-src/implementations.md index 06b0e7926e..6531b831f0 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -496,11 +496,12 @@ If you have any suggestions or experience issues with NGINX Gateway Fabric, plea ### ngrok Kubernetes Operator [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 + +- 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] @@ -508,7 +509,7 @@ You can read our [docs][ngrok-k8s-gwapi-docs] for more information. If you have [ngrok]:https://ngrok.com [ngrok-k8s-gwapi-docs]:https://ngrok.com/docs/k8s/ [ngrok-issue-new]: https://github.com/ngrok/ngrok-operator/issues/new/choose - +[ngrok-slack]:https://ngrokcommunity.slack.com/channels/general ### STUNner From 7f29273e9307f81d5560d2d41c6d54d228b44973 Mon Sep 17 00:00:00 2001 From: Blake Covarrubias Date: Fri, 20 Jun 2025 11:52:51 -0700 Subject: [PATCH 053/148] docs: Fix links to nonexistent anchors (#3862) --- geps/gep-1324/index.md | 2 +- geps/gep-1619/index.md | 4 ++-- geps/gep-1686/index.md | 2 +- geps/gep-1709/index.md | 6 +++--- geps/gep-1867/index.md | 2 +- geps/gep-1897/index.md | 2 -- geps/gep-2722/index.md | 2 +- geps/gep-91/index.md | 4 ++-- geps/gep-995/index.md | 2 +- site-src/api-types/backendtlspolicy.md | 12 ++++++------ site-src/api-types/backendtrafficpolicy.md | 4 ++-- site-src/api-types/grpcroute.md | 2 +- site-src/api-types/httproute.md | 2 +- site-src/blog/2021/introducing-v1alpha2.md | 2 +- site-src/blog/2022/graduating-to-beta.md | 18 +++++++++--------- site-src/blog/2023/0829-mesh-support.md | 16 ++++++++-------- site-src/blog/index.md | 2 +- site-src/concepts/api-overview.md | 6 +++--- site-src/concepts/use-cases.md | 8 ++++---- site-src/faq.md | 3 ++- site-src/guides/crd-management.md | 2 +- site-src/guides/migrating-from-ingress.md | 2 +- site-src/guides/multiple-ns.md | 2 +- site-src/implementations.md | 4 ++-- site-src/index.md | 14 +++++++------- site-src/mesh/gamma.md | 2 +- site-src/mesh/index.md | 2 +- site-src/mesh/service-facets.md | 2 +- 28 files changed, 65 insertions(+), 66 deletions(-) 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-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-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/index.md b/geps/gep-1897/index.md index 9f2a9918f9..3203d34d95 100644 --- a/geps/gep-1897/index.md +++ b/geps/gep-1897/index.md @@ -405,8 +405,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-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-91/index.md b/geps/gep-91/index.md index 4216a2674e..5d28c9a117 100644 --- a/geps/gep-91/index.md +++ b/geps/gep-91/index.md @@ -69,7 +69,7 @@ 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 + // 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"` @@ -187,7 +187,7 @@ This GEP aims to standardize this behavior as an official part of the upstream s [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 +[GatewayTLSConfig]: ../../reference/spec.md#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 diff --git a/geps/gep-995/index.md b/geps/gep-995/index.md index 6236d1a279..972fde1080 100644 --- a/geps/gep-995/index.md +++ b/geps/gep-995/index.md @@ -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/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 c9d96deef1..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. 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/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/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 6531b831f0..7460c920ad 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -101,7 +101,7 @@ cover, and documentation to help users get started. [39]:#kubvernor -[gamma]:/concepts/gamma/ +[gamma]:mesh/index.md @@ -222,7 +222,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 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 From 392be7c235c4cd516a9765abe7dd30e9dca6c4ee Mon Sep 17 00:00:00 2001 From: carson <127476216+carsontham@users.noreply.github.com> Date: Sun, 22 Jun 2025 09:50:52 +0800 Subject: [PATCH 054/148] Improve distribution tests in conformance for MeshHTTPRouteWeight (#3855) * added entropy to mesh weight test Signed-off-by: carsontham * added nolint:gosec to skip linter issues for conformance test * move creation of header map to entropy func to avoid concurrent map writes * use crypto/rand instead of math/rand * handle error checking and add default in switch * return error in default for switch case --------- Signed-off-by: carsontham --- conformance/tests/mesh/httproute-weight.go | 60 +++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index 09ef3465b5..cc296d92d5 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -18,13 +18,16 @@ package meshtests import ( "cmp" + "crypto/rand" "errors" "fmt" "math" + "math/big" "slices" "strings" "sync" "testing" + "time" "golang.org/x/sync/errgroup" @@ -89,7 +92,11 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR g.SetLimit(concurrentRequests) for i := 0.0; i < totalRequests; i++ { g.Go(func() error { - _, cRes, err := client.CaptureRequestResponseAndCompare(t, expected) + uniqueExpected := expected + if err := 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) } @@ -141,3 +148,54 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR }) return errors.Join(errs...) } + +// 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 *http.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) + } +} From 4e9978a686090d6fdf45adce9ec2912694c39930 Mon Sep 17 00:00:00 2001 From: Rob Scott Date: Tue, 24 Jun 2025 03:36:29 -0700 Subject: [PATCH 055/148] Adding Lior to Mesh Leads (#3877) --- OWNERS_ALIASES | 1 + 1 file changed, 1 insertion(+) diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES index 6e461c1596..207dd1d776 100644 --- a/OWNERS_ALIASES +++ b/OWNERS_ALIASES @@ -26,6 +26,7 @@ aliases: - howardjohn - mikemorris - kflynn + - LiorLieberman emeritus-gateway-api-mesh-leads: - keithmattix From b58707ce59f2cbbd2e1f1c292d7180212a57748e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 06:06:30 -0700 Subject: [PATCH 056/148] build(deps): bump the k8s-io group with 6 updates (#3819) * build(deps): bump the k8s-io group with 6 updates Bumps the k8s-io group with 6 updates: | Package | From | To | | --- | --- | --- | | [k8s.io/api](https://github.com/kubernetes/api) | `0.32.3` | `0.33.1` | | [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.32.3` | `0.33.1` | | [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.32.3` | `0.33.1` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.32.3` | `0.33.1` | | [k8s.io/code-generator](https://github.com/kubernetes/code-generator) | `0.32.3` | `0.33.1` | | [k8s.io/kube-openapi](https://github.com/kubernetes/kube-openapi) | `0.0.0-20241105132330-32ad38e42d3f` | `0.0.0-20250318190949-c8a335a9a2ff` | Updates `k8s.io/api` from 0.32.3 to 0.33.1 - [Commits](https://github.com/kubernetes/api/compare/v0.32.3...v0.33.1) Updates `k8s.io/apiextensions-apiserver` from 0.32.3 to 0.33.1 - [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases) - [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.32.3...v0.33.1) Updates `k8s.io/apimachinery` from 0.32.3 to 0.33.1 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.32.3...v0.33.1) Updates `k8s.io/client-go` from 0.32.3 to 0.33.1 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.32.3...v0.33.1) Updates `k8s.io/code-generator` from 0.32.3 to 0.33.1 - [Commits](https://github.com/kubernetes/code-generator/compare/v0.32.3...v0.33.1) Updates `k8s.io/kube-openapi` from 0.0.0-20241105132330-32ad38e42d3f to 0.0.0-20250318190949-c8a335a9a2ff - [Commits](https://github.com/kubernetes/kube-openapi/commits) --- updated-dependencies: - dependency-name: k8s.io/api dependency-version: 0.33.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/apiextensions-apiserver dependency-version: 0.33.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-version: 0.33.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-version: 0.33.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/code-generator dependency-version: 0.33.1 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: k8s-io - dependency-name: k8s.io/kube-openapi dependency-version: 0.0.0-20250318190949-c8a335a9a2ff dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io ... Signed-off-by: dependabot[bot] * chore(clients): make generate Signed-off-by: Mattia Lavacca --------- Signed-off-by: dependabot[bot] Signed-off-by: Mattia Lavacca Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Mattia Lavacca --- go.mod | 23 ++++----- go.sum | 51 ++++++++++--------- .../versioned/fake/clientset_generated.go | 13 ++++- .../versioned/typed/apis/v1/apis_client.go | 12 ++--- .../typed/apis/v1alpha2/apis_client.go | 12 ++--- .../typed/apis/v1alpha3/apis_client.go | 12 ++--- .../typed/apis/v1beta1/apis_client.go | 12 ++--- .../typed/apisx/v1alpha1/apisx_client.go | 12 ++--- .../externalversions/apis/v1/gateway.go | 16 +++++- .../externalversions/apis/v1/gatewayclass.go | 16 +++++- .../externalversions/apis/v1/grpcroute.go | 16 +++++- .../externalversions/apis/v1/httproute.go | 16 +++++- .../apis/v1alpha2/grpcroute.go | 16 +++++- .../apis/v1alpha2/referencegrant.go | 16 +++++- .../apis/v1alpha2/tcproute.go | 16 +++++- .../apis/v1alpha2/tlsroute.go | 16 +++++- .../apis/v1alpha2/udproute.go | 16 +++++- .../apis/v1alpha3/backendtlspolicy.go | 16 +++++- .../externalversions/apis/v1beta1/gateway.go | 16 +++++- .../apis/v1beta1/gatewayclass.go | 16 +++++- .../apis/v1beta1/httproute.go | 16 +++++- .../apis/v1beta1/referencegrant.go | 16 +++++- .../apisx/v1alpha1/xbackendtrafficpolicy.go | 16 +++++- .../apisx/v1alpha1/xlistenerset.go | 16 +++++- pkg/generated/openapi/zz_generated.openapi.go | 42 ++++++++++++--- 25 files changed, 323 insertions(+), 122 deletions(-) diff --git a/go.mod b/go.mod index 4bf07ec2f5..a9db23934e 100644 --- a/go.mod +++ b/go.mod @@ -11,12 +11,12 @@ require ( google.golang.org/grpc v1.73.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 + k8s.io/api v0.33.2 + k8s.io/apiextensions-apiserver v0.33.2 + k8s.io/apimachinery v0.33.2 + k8s.io/client-go v0.33.2 + k8s.io/code-generator v0.33.2 + 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 @@ -40,12 +40,10 @@ require ( github.com/gobuffalo/flect v1.0.3 // indirect github.com/goccy/go-yaml v1.11.3 // 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 @@ -74,7 +72,7 @@ require ( 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/time v0.9.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-20250324211829-b45e905df463 // indirect @@ -82,7 +80,8 @@ require ( 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 b380233c61..2b6eb53c72 100644 --- a/go.sum +++ b/go.sum @@ -51,20 +51,18 @@ 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= @@ -120,8 +118,8 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/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,6 +128,8 @@ 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= @@ -193,8 +193,8 @@ 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/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= @@ -230,22 +230,22 @@ 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.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= +k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= +k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= +k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= +k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= +k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= +k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= +k8s.io/code-generator v0.33.2 h1:PCJ0Y6viTCxxJHMOyGqYwWEteM4q6y1Hqo2rNpl6jF4= +k8s.io/code-generator v0.33.2/go.mod h1:hBjCA9kPMpjLWwxcr75ReaQfFXY8u+9bEJJ7kRw3J8c= +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= @@ -254,8 +254,9 @@ sigs.k8s.io/controller-tools v0.17.3 h1:lwFPLicpBKLgIepah+c8ikRBubFW5kOQyT88r3Ew sigs.k8s.io/controller-tools v0.17.3/go.mod h1:1ii+oXcYZkxcBXzwv3YZBlzjt1fvkrCGjVF73blosJI= 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= diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index ecf37e8b51..b1600ecbd3 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -19,6 +19,7 @@ limitations under the License. package fake import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/watch" "k8s.io/client-go/discovery" @@ -58,9 +59,13 @@ func NewSimpleClientset(objects ...runtime.Object) *Clientset { cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} cs.AddReactor("*", "*", testing.ObjectReaction(o)) cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + var opts metav1.ListOptions + if watchActcion, ok := action.(testing.WatchActionImpl); ok { + opts = watchActcion.ListOptions + } gvr := action.GetResource() ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) + watch, err := o.Watch(gvr, ns, opts) if err != nil { return false, nil, err } @@ -107,9 +112,13 @@ func NewClientset(objects ...runtime.Object) *Clientset { cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} cs.AddReactor("*", "*", testing.ObjectReaction(o)) cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + var opts metav1.ListOptions + if watchActcion, ok := action.(testing.WatchActionImpl); ok { + opts = watchActcion.ListOptions + } gvr := action.GetResource() ns := action.GetNamespace() - watch, err := o.Watch(gvr, ns) + watch, err := o.Watch(gvr, ns, opts) if err != nil { return false, nil, err } diff --git a/pkg/client/clientset/versioned/typed/apis/v1/apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1/apis_client.go index 1742ff45eb..7ed0bc4d55 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1/apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1/apis_client.go @@ -60,9 +60,7 @@ func (c *GatewayV1Client) HTTPRoutes(namespace string) HTTPRouteInterface { // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*GatewayV1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err @@ -74,9 +72,7 @@ func NewForConfig(c *rest.Config) (*GatewayV1Client, error) { // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GatewayV1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err @@ -99,7 +95,7 @@ func New(c rest.Interface) *GatewayV1Client { return &GatewayV1Client{c} } -func setConfigDefaults(config *rest.Config) error { +func setConfigDefaults(config *rest.Config) { gv := apisv1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" @@ -108,8 +104,6 @@ func setConfigDefaults(config *rest.Config) error { if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } - - return nil } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha2/apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1alpha2/apis_client.go index 97b6ad062f..c25ef87c96 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1alpha2/apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha2/apis_client.go @@ -65,9 +65,7 @@ func (c *GatewayV1alpha2Client) UDPRoutes(namespace string) UDPRouteInterface { // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*GatewayV1alpha2Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err @@ -79,9 +77,7 @@ func NewForConfig(c *rest.Config) (*GatewayV1alpha2Client, error) { // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GatewayV1alpha2Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err @@ -104,7 +100,7 @@ func New(c rest.Interface) *GatewayV1alpha2Client { return &GatewayV1alpha2Client{c} } -func setConfigDefaults(config *rest.Config) error { +func setConfigDefaults(config *rest.Config) { gv := apisv1alpha2.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" @@ -113,8 +109,6 @@ func setConfigDefaults(config *rest.Config) error { if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } - - return nil } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go index 0a546b5538..681d5090ed 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go @@ -45,9 +45,7 @@ func (c *GatewayV1alpha3Client) BackendTLSPolicies(namespace string) BackendTLSP // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*GatewayV1alpha3Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err @@ -59,9 +57,7 @@ func NewForConfig(c *rest.Config) (*GatewayV1alpha3Client, error) { // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GatewayV1alpha3Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err @@ -84,7 +80,7 @@ func New(c rest.Interface) *GatewayV1alpha3Client { return &GatewayV1alpha3Client{c} } -func setConfigDefaults(config *rest.Config) error { +func setConfigDefaults(config *rest.Config) { gv := apisv1alpha3.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" @@ -93,8 +89,6 @@ func setConfigDefaults(config *rest.Config) error { if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } - - return nil } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/client/clientset/versioned/typed/apis/v1beta1/apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1beta1/apis_client.go index d9b158d567..498e0373a4 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1beta1/apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1beta1/apis_client.go @@ -60,9 +60,7 @@ func (c *GatewayV1beta1Client) ReferenceGrants(namespace string) ReferenceGrantI // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*GatewayV1beta1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err @@ -74,9 +72,7 @@ func NewForConfig(c *rest.Config) (*GatewayV1beta1Client, error) { // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*GatewayV1beta1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err @@ -99,7 +95,7 @@ func New(c rest.Interface) *GatewayV1beta1Client { return &GatewayV1beta1Client{c} } -func setConfigDefaults(config *rest.Config) error { +func setConfigDefaults(config *rest.Config) { gv := apisv1beta1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" @@ -108,8 +104,6 @@ func setConfigDefaults(config *rest.Config) error { if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } - - return nil } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/client/clientset/versioned/typed/apisx/v1alpha1/apisx_client.go b/pkg/client/clientset/versioned/typed/apisx/v1alpha1/apisx_client.go index 582ef47b3d..234356e48e 100644 --- a/pkg/client/clientset/versioned/typed/apisx/v1alpha1/apisx_client.go +++ b/pkg/client/clientset/versioned/typed/apisx/v1alpha1/apisx_client.go @@ -50,9 +50,7 @@ func (c *ExperimentalV1alpha1Client) XListenerSets(namespace string) XListenerSe // where httpClient was generated with rest.HTTPClientFor(c). func NewForConfig(c *rest.Config) (*ExperimentalV1alpha1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) httpClient, err := rest.HTTPClientFor(&config) if err != nil { return nil, err @@ -64,9 +62,7 @@ func NewForConfig(c *rest.Config) (*ExperimentalV1alpha1Client, error) { // Note the http client provided takes precedence over the configured transport values. func NewForConfigAndClient(c *rest.Config, h *http.Client) (*ExperimentalV1alpha1Client, error) { config := *c - if err := setConfigDefaults(&config); err != nil { - return nil, err - } + setConfigDefaults(&config) client, err := rest.RESTClientForConfigAndClient(&config, h) if err != nil { return nil, err @@ -89,7 +85,7 @@ func New(c rest.Interface) *ExperimentalV1alpha1Client { return &ExperimentalV1alpha1Client{c} } -func setConfigDefaults(config *rest.Config) error { +func setConfigDefaults(config *rest.Config) { gv := apisxv1alpha1.SchemeGroupVersion config.GroupVersion = &gv config.APIPath = "/apis" @@ -98,8 +94,6 @@ func setConfigDefaults(config *rest.Config) error { if config.UserAgent == "" { config.UserAgent = rest.DefaultKubernetesUserAgent() } - - return nil } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/client/informers/externalversions/apis/v1/gateway.go b/pkg/client/informers/externalversions/apis/v1/gateway.go index 9df059e555..6884889ecd 100644 --- a/pkg/client/informers/externalversions/apis/v1/gateway.go +++ b/pkg/client/informers/externalversions/apis/v1/gateway.go @@ -62,13 +62,25 @@ func NewFilteredGatewayInformer(client versioned.Interface, namespace string, re if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().Gateways(namespace).List(context.TODO(), options) + return client.GatewayV1().Gateways(namespace).List(context.Background(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().Gateways(namespace).Watch(context.TODO(), options) + return client.GatewayV1().Gateways(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().Gateways(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().Gateways(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1.Gateway{}, diff --git a/pkg/client/informers/externalversions/apis/v1/gatewayclass.go b/pkg/client/informers/externalversions/apis/v1/gatewayclass.go index 7ad2c7f400..f601378bd9 100644 --- a/pkg/client/informers/externalversions/apis/v1/gatewayclass.go +++ b/pkg/client/informers/externalversions/apis/v1/gatewayclass.go @@ -61,13 +61,25 @@ func NewFilteredGatewayClassInformer(client versioned.Interface, resyncPeriod ti if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().GatewayClasses().List(context.TODO(), options) + return client.GatewayV1().GatewayClasses().List(context.Background(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().GatewayClasses().Watch(context.TODO(), options) + return client.GatewayV1().GatewayClasses().Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().GatewayClasses().List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().GatewayClasses().Watch(ctx, options) }, }, &gatewayapiapisv1.GatewayClass{}, diff --git a/pkg/client/informers/externalversions/apis/v1/grpcroute.go b/pkg/client/informers/externalversions/apis/v1/grpcroute.go index 5633d5b408..34fb735149 100644 --- a/pkg/client/informers/externalversions/apis/v1/grpcroute.go +++ b/pkg/client/informers/externalversions/apis/v1/grpcroute.go @@ -62,13 +62,25 @@ func NewFilteredGRPCRouteInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().GRPCRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1().GRPCRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().GRPCRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1().GRPCRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().GRPCRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().GRPCRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1.GRPCRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1/httproute.go b/pkg/client/informers/externalversions/apis/v1/httproute.go index 697d15013f..06da9daea4 100644 --- a/pkg/client/informers/externalversions/apis/v1/httproute.go +++ b/pkg/client/informers/externalversions/apis/v1/httproute.go @@ -62,13 +62,25 @@ func NewFilteredHTTPRouteInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().HTTPRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1().HTTPRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1().HTTPRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1().HTTPRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options metav1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().HTTPRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options metav1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1().HTTPRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1.HTTPRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha2/grpcroute.go b/pkg/client/informers/externalversions/apis/v1alpha2/grpcroute.go index 4317e8cd0d..cda505ce19 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha2/grpcroute.go +++ b/pkg/client/informers/externalversions/apis/v1alpha2/grpcroute.go @@ -62,13 +62,25 @@ func NewFilteredGRPCRouteInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().GRPCRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1alpha2().GRPCRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().GRPCRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha2().GRPCRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().GRPCRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().GRPCRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha2.GRPCRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha2/referencegrant.go b/pkg/client/informers/externalversions/apis/v1alpha2/referencegrant.go index a3ba093c67..8519c9eb23 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha2/referencegrant.go +++ b/pkg/client/informers/externalversions/apis/v1alpha2/referencegrant.go @@ -62,13 +62,25 @@ func NewFilteredReferenceGrantInformer(client versioned.Interface, namespace str if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().ReferenceGrants(namespace).List(context.TODO(), options) + return client.GatewayV1alpha2().ReferenceGrants(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().ReferenceGrants(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha2().ReferenceGrants(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().ReferenceGrants(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().ReferenceGrants(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha2.ReferenceGrant{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha2/tcproute.go b/pkg/client/informers/externalversions/apis/v1alpha2/tcproute.go index 850d5e2f59..da3c1292e4 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha2/tcproute.go +++ b/pkg/client/informers/externalversions/apis/v1alpha2/tcproute.go @@ -62,13 +62,25 @@ func NewFilteredTCPRouteInformer(client versioned.Interface, namespace string, r if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().TCPRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1alpha2().TCPRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().TCPRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha2().TCPRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().TCPRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().TCPRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha2.TCPRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha2/tlsroute.go b/pkg/client/informers/externalversions/apis/v1alpha2/tlsroute.go index 9a729348b0..fbc9d1fe83 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha2/tlsroute.go +++ b/pkg/client/informers/externalversions/apis/v1alpha2/tlsroute.go @@ -62,13 +62,25 @@ func NewFilteredTLSRouteInformer(client versioned.Interface, namespace string, r if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().TLSRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1alpha2().TLSRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().TLSRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha2().TLSRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().TLSRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().TLSRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha2.TLSRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha2/udproute.go b/pkg/client/informers/externalversions/apis/v1alpha2/udproute.go index 10a40c087f..1eb0f23e6f 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha2/udproute.go +++ b/pkg/client/informers/externalversions/apis/v1alpha2/udproute.go @@ -62,13 +62,25 @@ func NewFilteredUDPRouteInformer(client versioned.Interface, namespace string, r if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().UDPRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1alpha2().UDPRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha2().UDPRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha2().UDPRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().UDPRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha2().UDPRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha2.UDPRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1alpha3/backendtlspolicy.go b/pkg/client/informers/externalversions/apis/v1alpha3/backendtlspolicy.go index 28ec827d80..933c815e0a 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha3/backendtlspolicy.go +++ b/pkg/client/informers/externalversions/apis/v1alpha3/backendtlspolicy.go @@ -62,13 +62,25 @@ func NewFilteredBackendTLSPolicyInformer(client versioned.Interface, namespace s if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha3().BackendTLSPolicies(namespace).List(context.TODO(), options) + return client.GatewayV1alpha3().BackendTLSPolicies(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1alpha3().BackendTLSPolicies(namespace).Watch(context.TODO(), options) + return client.GatewayV1alpha3().BackendTLSPolicies(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().BackendTLSPolicies(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().BackendTLSPolicies(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1alpha3.BackendTLSPolicy{}, diff --git a/pkg/client/informers/externalversions/apis/v1beta1/gateway.go b/pkg/client/informers/externalversions/apis/v1beta1/gateway.go index 112506f9f3..6f60141696 100644 --- a/pkg/client/informers/externalversions/apis/v1beta1/gateway.go +++ b/pkg/client/informers/externalversions/apis/v1beta1/gateway.go @@ -62,13 +62,25 @@ func NewFilteredGatewayInformer(client versioned.Interface, namespace string, re if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().Gateways(namespace).List(context.TODO(), options) + return client.GatewayV1beta1().Gateways(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().Gateways(namespace).Watch(context.TODO(), options) + return client.GatewayV1beta1().Gateways(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().Gateways(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().Gateways(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1beta1.Gateway{}, diff --git a/pkg/client/informers/externalversions/apis/v1beta1/gatewayclass.go b/pkg/client/informers/externalversions/apis/v1beta1/gatewayclass.go index ed422ffa79..846bee3e28 100644 --- a/pkg/client/informers/externalversions/apis/v1beta1/gatewayclass.go +++ b/pkg/client/informers/externalversions/apis/v1beta1/gatewayclass.go @@ -61,13 +61,25 @@ func NewFilteredGatewayClassInformer(client versioned.Interface, resyncPeriod ti if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().GatewayClasses().List(context.TODO(), options) + return client.GatewayV1beta1().GatewayClasses().List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().GatewayClasses().Watch(context.TODO(), options) + return client.GatewayV1beta1().GatewayClasses().Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().GatewayClasses().List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().GatewayClasses().Watch(ctx, options) }, }, &gatewayapiapisv1beta1.GatewayClass{}, diff --git a/pkg/client/informers/externalversions/apis/v1beta1/httproute.go b/pkg/client/informers/externalversions/apis/v1beta1/httproute.go index 1aaf2e0ec3..c2217d1d2d 100644 --- a/pkg/client/informers/externalversions/apis/v1beta1/httproute.go +++ b/pkg/client/informers/externalversions/apis/v1beta1/httproute.go @@ -62,13 +62,25 @@ func NewFilteredHTTPRouteInformer(client versioned.Interface, namespace string, if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().HTTPRoutes(namespace).List(context.TODO(), options) + return client.GatewayV1beta1().HTTPRoutes(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().HTTPRoutes(namespace).Watch(context.TODO(), options) + return client.GatewayV1beta1().HTTPRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().HTTPRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().HTTPRoutes(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1beta1.HTTPRoute{}, diff --git a/pkg/client/informers/externalversions/apis/v1beta1/referencegrant.go b/pkg/client/informers/externalversions/apis/v1beta1/referencegrant.go index 5dea76f78d..f6209ffca2 100644 --- a/pkg/client/informers/externalversions/apis/v1beta1/referencegrant.go +++ b/pkg/client/informers/externalversions/apis/v1beta1/referencegrant.go @@ -62,13 +62,25 @@ func NewFilteredReferenceGrantInformer(client versioned.Interface, namespace str if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().ReferenceGrants(namespace).List(context.TODO(), options) + return client.GatewayV1beta1().ReferenceGrants(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.GatewayV1beta1().ReferenceGrants(namespace).Watch(context.TODO(), options) + return client.GatewayV1beta1().ReferenceGrants(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().ReferenceGrants(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1beta1().ReferenceGrants(namespace).Watch(ctx, options) }, }, &gatewayapiapisv1beta1.ReferenceGrant{}, diff --git a/pkg/client/informers/externalversions/apisx/v1alpha1/xbackendtrafficpolicy.go b/pkg/client/informers/externalversions/apisx/v1alpha1/xbackendtrafficpolicy.go index 44747690af..a1ef9b1c17 100644 --- a/pkg/client/informers/externalversions/apisx/v1alpha1/xbackendtrafficpolicy.go +++ b/pkg/client/informers/externalversions/apisx/v1alpha1/xbackendtrafficpolicy.go @@ -62,13 +62,25 @@ func NewFilteredXBackendTrafficPolicyInformer(client versioned.Interface, namesp if tweakListOptions != nil { tweakListOptions(&options) } - return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).List(context.TODO(), options) + return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).Watch(context.TODO(), options) + return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExperimentalV1alpha1().XBackendTrafficPolicies(namespace).Watch(ctx, options) }, }, &gatewayapiapisxv1alpha1.XBackendTrafficPolicy{}, diff --git a/pkg/client/informers/externalversions/apisx/v1alpha1/xlistenerset.go b/pkg/client/informers/externalversions/apisx/v1alpha1/xlistenerset.go index f959180852..189f25bf3a 100644 --- a/pkg/client/informers/externalversions/apisx/v1alpha1/xlistenerset.go +++ b/pkg/client/informers/externalversions/apisx/v1alpha1/xlistenerset.go @@ -62,13 +62,25 @@ func NewFilteredXListenerSetInformer(client versioned.Interface, namespace strin if tweakListOptions != nil { tweakListOptions(&options) } - return client.ExperimentalV1alpha1().XListenerSets(namespace).List(context.TODO(), options) + return client.ExperimentalV1alpha1().XListenerSets(namespace).List(context.Background(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.ExperimentalV1alpha1().XListenerSets(namespace).Watch(context.TODO(), options) + return client.ExperimentalV1alpha1().XListenerSets(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExperimentalV1alpha1().XListenerSets(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ExperimentalV1alpha1().XListenerSets(namespace).Watch(ctx, options) }, }, &gatewayapiapisxv1alpha1.XListenerSet{}, diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 96ac164691..c91725bc50 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -2733,16 +2733,46 @@ func schema_k8sio_apimachinery_pkg_version_Info(ref common.ReferenceCallback) co Properties: map[string]spec.Schema{ "major": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Major is the major version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", }, }, "minor": { SchemaProps: spec.SchemaProps{ - Default: "", - Type: []string{"string"}, - Format: "", + Description: "Minor is the minor version of the binary version", + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMajor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMajor is the major version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "emulationMinor": { + SchemaProps: spec.SchemaProps{ + Description: "EmulationMinor is the minor version of the emulation version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMajor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMajor is the major version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", + }, + }, + "minCompatibilityMinor": { + SchemaProps: spec.SchemaProps{ + Description: "MinCompatibilityMinor is the minor version of the minimum compatibility version", + Type: []string{"string"}, + Format: "", }, }, "gitVersion": { From e1310bbd66c54b757d28ee65cf363825f6189ca5 Mon Sep 17 00:00:00 2001 From: Nick Young Date: Fri, 27 Jun 2025 14:18:28 +1000 Subject: [PATCH 057/148] Update implementations.md with removal policy (#3863) This commit updates the "Implementations" page with details on what implementations need to do in order to stay a current and registered implementation of Gateway API. This includes a policy about when implementations will be removed from the page. Signed-off-by: Nick Young --- site-src/implementations.md | 126 +++++++++++++++++++++++++++++++++++- 1 file changed, 125 insertions(+), 1 deletion(-) diff --git a/site-src/implementations.md b/site-src/implementations.md index 7460c920ad..1b11204072 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -5,8 +5,77 @@ 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" @@ -609,3 +678,58 @@ For help and support with Kuadrant's implementation please feel free to [create [kuadrant-issue-new]:https://github.com/Kuadrant/kuadrant-operator/issues/new [kuadrant-slack]:https://kubernetes.slack.com/archives/C05J0D0V525 + +## 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. From de6d664c4eccead11e34387a99439522292450fe Mon Sep 17 00:00:00 2001 From: John Howard Date: Fri, 27 Jun 2025 11:28:30 -0700 Subject: [PATCH 058/148] Enhancements to the BackendTLSPolicy GEP (#3835) * Enhancements to the BackendTLSPolicy GEP Fixes https://github.com/kubernetes-sigs/gateway-api/issues/3516 * Update GEP with new semantics * Add 'from' * revert go type changes * Address some comments * Revert changes to Go types * Address Candace's comments * Revert everything again * Minimal changes * Address comments * Reference system certs * Address TLS passthrough * clarify persona --- geps/gep-1897/images/mesh.png | Bin 0 -> 69082 bytes geps/gep-1897/index.md | 116 ++++++++++++++++++---------------- 2 files changed, 62 insertions(+), 54 deletions(-) create mode 100644 geps/gep-1897/images/mesh.png diff --git a/geps/gep-1897/images/mesh.png b/geps/gep-1897/images/mesh.png new file mode 100644 index 0000000000000000000000000000000000000000..c82ced3089b6c2004ae00e7c0a7d8590832f7e32 GIT binary patch literal 69082 zcma%jbyU>b_cjaz3?MLofb`HPVbLHA9g>Qa64KqB1BjH864Irh(jgrR3aFHHw{#;N z?-{)Jet&=5weIVhr2@m}oU_l~&-3hk_L(p>6*)qDYJ3a~3_=BY=?54XumTJW%x^FV z_|6B#K_T!DrttH1@MrjT60ns!Hy*VAIEZ_Fl!%QBLt*^a3$+3}z3<8`8HB`u{^yGe9^gRs|M5(G zJS6nNjEqd&e?Ae3!35vHgk${ION|jT6nUdQ--7hN7K8yqLOxor5p=i7IU@-HW<%(~|neT_pG z3Li$Ap5dG%1~Snz)cwfk`Rnl>QQ+~LrE(qrI`bQ>$O`-$>+l+>4+EsO&lWw2LVTdQ z*VRR*n2-%SmHDa{huY-f&XtQK?H5G698JXDayR66EOY_F(tfcnsTm z&;Pcc%pI#&NUT?>V%vTb5!F}5bK?oKLl&c`tDCbEf~k8~cYU>Tj!W>ba6#GuyUnwO zpZ;t3yi!Ky^$AtQ5R+h$lDV|LVOxC|_ZypvZT9`%uNw_DSzSh*F|hs9!kc^<_bhq7 z@zYJ(-w-+dnI`)5PJe^TAW@ln45xp*Z|`XSM0s9;3Qr>xXNZjxjp51|(uu<*KW3AddC z;~yyB#EvrX^H~ptOG=ZN>SNPXG7Xq5(EjAn?01YSV*W03HB>5#v7WhVY_(b%|4vFL zKXT@kFbwt#S99i2j>7Y3YScuqqsC>>Y+9jf%-gqnCW8hh4`B}&EQ*=OW(|lv!0?V! z6ZfW6Z<>&u^<9)b# zmru3)8)2zYxtX2O$uD$ZcqCxNr-g?2-r%Dqu%&lGVZv6DAx3Ba-KmEuLF2qPa8&DP!KQ znqg1f+0^?y_iu=dt$vC?Wsggu$Wyf|!{n8{8YWHdyxTM-AZZW8`ZxO{O`!k>Wc$9Z zJXW8fjxRiV%MpwfUz&kRvx?TugWmJAW4yaxp=+BG#l6@TqWvaw7MEPzXwh;m&ZXb7 zZ?B(~G6l*rVL0hN23cf-EaQ~(u~)aZ>h#TG(gfwjQt8U`2;1M~SIo}cY>(>`Z zTlBm`9L6CEJ6@P8QX{kr3o%zQj1i~(^ zD)Ta?sVqj=8-^k&X#W+7-!mF|<5l;-8xbw@3gu$oAeeG^!_3&rF2Wh!W(?w0Py7vg z4S3twm!E&FxUC-5atT+8tkcecaA^bq(Vv)%Coy!tAUjze%!EW4%1P`q*KH%V%gs%< z32wCbT@?s;mcRBsOXz>&PYYv~kNnuxq-+Q{oy)%(a5%}@^Y-dIXC0JeJ@0ho{(6Y> z3fSt9uNK1{v?iroWuX*0juCpj_v>*e_3R=%pw_mfLSRl%XThasS5}^y8^W6&c1kkA zF#;$cvu)vGj;$?XNo#k%i*>EVbv5F)p9DOMK4cNl>9@$x&L?Av{!5jiDDg`0aX3qd}U`&HZ^J zGGB_Tl?>$MA;1&U5`sO_hpZ~Y^{x{!!H@sq*fNq^DV=O_VHS8Ax`qq5?-d*bPf-{( z;~LJ{pJO{r0IroyxV6Ln7ZO|)4f@?W;w9%P&O2BSu7{uqugkv{?wMOmSlQ&>Zx?q- zh{}HPxsg?{rubt)$K*$YpR-eD2=XiA>rWT(XWiYyVvnlur0)dU?#vgQY+zpe5SlO? ze7l_1_YBN#^|#_`vIO+OD7l0$ns%B6U?pCFOg}xLB?_5?hAQ&<6`0LD9;M4z=}zbM zpE9XAC|pQnxFnCiDHhN&>K@eQ2PQt@3_yj2q#boKxI-|~C~#n*|5dpRm?}kIRKg*P zoY$-J% z|JJ-ibr|w*`smGAt|@8$&lD-C+%M$C zt4Qhd-nTkw3Ai(D#D$9%cVPKp7_S*kny7PA)5Z{x$_>$3vP*k}2o+nj9Uke19j|ogQxY5c-d(KV$`isTl>Tyq5Lp$A>;)F*LRmyt#rrNUwi# z+L>(os$JZw3_FJ#IN-Sws)(|!(v`zR5d>t@8e7h#TlP=@0kPzwsYNqQDKcqd^Vq|g#`8Ch%tru$GaI}<^@GMRvcPZatF)t?g`BoU7a9JvWdJy3J{~>O3 z23}I9S=YA!A!NmUoG4wqT((6ArA*Q86eYH(1`Hb| z41A)w(uJsS+bIh)53(ZJa7HF!FXsdcHLdwm?(O@T5d^|of1;)+Fw19&AFfJS{;tHP zTtp(NpzUi6UE4ujJ0wcm+cgqbZ>({nSyJNpb-?LO2x+ZwW>-629R&9EIhjD+zcphB zOnWS!6hFGk%Y|cz6I!s0O!p*e@-!*s$K()Gkn7CZLcbH00q=RcTv!<1(I8x3c|Y1p z2BCo2{8cN{#D{cPSI6Qgx5{a0O|Zh2j#`9h@>9^b)#2(Yl(v4YFni4LFj(Vq zF~^gpNTUVJSRy;mt+lNYkJK-DHuV%s*Bx(=N;2m+&!wJ9B`kh^!ccr=zhBQHeo~1I zPiJg5!I;R2ffNxPsIet1N%oguY^H|{euM-CvY*SjRU21#nJM;fG>nAcNanv!hDHCLot+yUE(}+cc**v?!Jhkn0HC4J zoXm%j_K45*qK85bkA)3}>%Q^WCI9q&1>_m)^l4l3%LI@{3`-#<3?tLb2O_ijmPH3u zcUeh7EyQD+4nPipo){C}mZ<74Je{jVU8|x* z5@~LUJMsI!Gm9e9l8IcinM&*iRa}KR%(+ zZ8`&5Vd=GP9p~-pVYsZaL!ng*lYYifIQZU3)??--8j3hFFkY{{d$uewDBHy)WhHwM zhDm&5IRx5%$8k-Wb1UTe7Eu36cxBUn=Si+4(Wg&2K0+a`cC1AV7VCH1uf5wN_v3kp zSZpl)@s{o`jNa{&+D(bQ+^{l9Y(#|t% zTi`Q>qqW7Wq)hAla-S)a-FM9j|0EI&jE3u!*+_cng!?##4w|^n;sNmEdv@+EY zt2vc+bUE^7qf>O0I9aGFY0(%6NYPBJ>*~-lgL6Ehxv&nwn&DS=w>bCdNt05-*0pWk zC-B-nE)RQr_idbmf>eDaa%|t1JhgJrL8QetCqdMD{k;xBV*TDMa{Hb!x3tgqFsZ92 z^@lEBV2krc4}D@)%AA$-H|C2M-2=+Cxqz++I-Tp7q52jZgPI?u+;b#A6X7q}xc`-v zP{m}^xkNiD#8h<@=&(pcnY3vqbReTL9%mcz&C0>?qg82ct9gP&6O%>v2Y95rAJj^G zBMn%K@z39yo8f#mdr8mgXeG<9Y;Q~;7&#}(hCMO~h3!Ob678xvDTMHhW;-H?k0^+?TrkcwlILv!x7Ndh|e8&sForgkg*GAVhCBWB7M-t24E&*-*5RhasfBhqTTg&n*{CZ*M1ArRdLsN z-akjZ9GD6HIbuVH-ZNW z5`&rnz|6O85*!PH3$99LD%yYKXXUspflJr!HUu~SOS>aqLs`~wKqedPBCbXVSG$Ti z!j2WzRs#H8jF(jI5&CUNOXyERv+bK-CaQ#@4`dM5C&H5F>Z65W$6)^L^2n68lx$T2EuqB#TCTSnVA^-GL^zEzT#lk4fAXF2H zyg(A`8w8cXaV%$^Gi?a#w8q_9DX9Vyi-)*nX2z0#EQYr3PnaQfbR`k-X9)o5HEdWD z=TWW6GQ;@oQ#OgH!#`q*2+A1C}uTPi7czU3$c-J9I>>maF6Uvf@`BcaFk=tYs2Nhmxn`O;l z2-$a)&4rL3FTA z-@**lcl7{Xbov@K|JFf86_51$x*Dop1V?IFp9P>LK-AQw(5Sxi?Vj{=(pj|gUcNkD zqUMjkCgIF~Nhc5AXM})swCMNKJFnOLlfDEg+DuJ%vk_F#0Zvthw(cYI+#SpJpC9DI zSl(egg+!-p(3=ok8igefDwKs4CbFuA^0CN&{=PN{#Ybn+i7RZK#_}u(Y-G|s*CbKD zC33eVhr>IV#N*0E;!G;yor>N!J>QCn-aKW+_4>H6#Koxkh?JupuCh?-FH`NU%JpOw zi{R5yb_}K~4kp@g9bXFdhssoOc2Z$1ny6ct?d*0E8l+%)yU^GOcOA!rEyIZ!K#Q(T9P__)EE+pm>-gmR{C-ukbLEB* zubqfT72Pb&6-Km;r@0|S4J$THj$=NZW9JE_`|D=wDe9+hxXhB03+(gDLz~VB?kKf( z{Om-sAu@>|fgMQdmtT#hvIg+0u72i4bkpFfF##97fQP0HtrT)@njnb7kVe=rafYo7 zk!#%8m~e+cl*bK@Hb=J=WS}Kd4b^|!W4A^VUZ(`=9JeJBlQJXlhva$M+4xrx|EEIw zgdI-(8EogaS{&z{lZHelI>MxB_r`LpUm&lO*;TaLUTpHc= zb#5>R)le|dTK&&Z;LI2hF3jyghy5kwtR?c=#d6A={8{~U119``hgpW>BbIZIy?Z{q|io-a35!C z2Z9V44^8a}fEJIpLeq+gb=CYc5XcIKAHTPYo)WzI3rc}-QNXZ@R^7X$u22Jmc`ff3 zz}P1v?#DCR@m}KNRT-oxRl5!U<9Wex9!TM7{y;_F^eugL6Ll)|D%AurONm-{>pM(h zPx0YOSmF3X?R+*!F@)huWc(zTw)wcq9Kj`#{&9U2DAn@i17IB-kPw9BqmVvNKKQbY zJ~5Inrc}WSPs@9B*i1Emg_eGB8Zyry#$w|n?Xpsq+i$9ncQ+!m?%@N~C*`Fb>T-Rx z9a5ajw^h{@lO<_ulo}7+k6zR`01G;iY<&UnE6h1h$EiaY8VfZU{}WbXV15ikj3+M>?^;RFt@`U2K_YU3qo~mIeSCrs$GIc zT5=4p;-WX_Tmfl_W%KZ({rxjf-^rIuJq_#$)3?&e13>7Udv5nwq3!4pgPImW%?WN_ z_50LaSwbEi!OY51B>^ai;xsk-td`wRjOE3(ITdq?5#urm+CL74{yRFc`QhA<`|76u zql;Wcdlluus_QV2nk`9=En&{S+60bOHEL7e*I7nR6m+@36+y;>B}5JPAyvB_rlLXruyvC~(N#$44xY+ORHnIg4+_o>opDYC6{3 z@3lFCGWQm9F(EcGBdXb+k4gFvm$cMU!j>D zB)u}%EsL&ML{nTo(Nkhr5A|Oo`BR`2=)OM z`|}c2Kq*QLzJ)#&i|*5tW6@y4lrWzhWg`nD3@D*U-6@3TGXiKlhQSK_L9JA!v`v@y zNG9{9;^PsfQh4g|hGYe(5jEGL#T;Jk@;6$iOwGpo({;ykvG{5$Wh|m@wSmIHbJ97?eM$VIsuIS4Qx)Oy(-Ft}@nV zNr!XKsO$k?20K7zAf$Q{!J**;}2~pirsatr6J2wn(FEsWvxhx&*lNo9~%Sn+4of>m{-hLed>bkve zmvtVS09k+joRRJFnW!`-CBleAduoAL40{VW>?4$k7qdKQgis+?h*bCZiWHT0& znn<4<(R3~J?_PkU?^048E*}R*Pkv{(;hEJe|MntqPEso5C;ZGqEM~=ltOSa_Um8{U zBQ)Oo7y0CKt@PK(A%==kLJNx*vdRU$6qlI76#zipkHIho|AMN%rt;0yfVdSuzj9>g z+bUp2u)m^)wh|=3>Hm6V(n2VSCQa(3XxpByn^x^h#?;`#u9{TDdb$YHS@ZR;KDG_T zCXp|7!_c?_qS7B$5`p1q02SVO8N5#ObWZT1hNSla82KhCpvjdSW3`n4^*HgXy*4(& zX*#Wbg~p763)(qqWdFEu6p4q`>G8yJ#IOoUnd`FRfUoqhZjwbV}S44r(-x zz|j6VN>0LYKp{s&Wd`xxZ70ph&8Y-QuVc(#IDM%~ z0YMLLLuRP#4+I^_MBbw(RMLpPC-7vCaHf=|2=Vteq7MSn1GYX^!o9J4eoe zaDu{p#~1GJ9y_AljTLk|-w_bJ!N8WpXUsqw4HM<_qa!cMYG5vaEzS_#2#-s{@D?AV2%x3QU=sU-JZm5~ z)q3trR66Zbp7dQh6#+-&YDVA`G0xmER^^TX^E z9==a!9E8NhVrbF}FsZ9X}G%N4wm@>`6MjytqFyGrf4 z4nFeNDjjoq?mvj!#^%GsWQBWZy2ptjXxrkK_XX8IG_BZOS)SUtJC+^wGqt@{Sz)kK zHIwkPayC0f(UPCvSMSNaTNUEmAC$XuxAH|oRwlF&;U{T$EG3f1_#*w6N6(eLOL*AZ);JC+8gPC?KmV!0ZuW>Jfn8p-W4-$u5&g>!!2GbCL@jj%b2+zAuk6vqT?)U%8l4!+b4wGx5s2=lJPmg zv?j#VuH#w#n4W>E@AbsQlE7gQ1cCsw02VS?W(6C*4gn{?Vz+r@Sug85zoFVB@*f6t zfx(mU_BxpfsGOpkKpkx*E9WvAGT{&ii9DY%DQ_z$lzKH?fF@;lb1(ZUHn%!!#5&Gv z6lxXP%A_XWJuMfXxZW+auzoO%3r-*W$pVHmegfd#mUER#*(+LzZxnDA8x$_b!Dou* zy92|;9KnNqRB5#@ssCv$lT}0p^2U+L&|slqhfpLw)nN|xWvuy?gp(B>!D-xQ`)Yc5M07%t z5wxPB9Jiub4g^Rn=CT)D4jqghC!{UGJ8?iu7XS40RapCdRD5YEceMCH>Z2aFW4#}a zseh(IPcxc>KvPeNGHN1HE~ocau`O;rPbXBjtkF~szX03(#A=2Mjfdb7 ziKoxvP<4L3L*+c8o>4DL2FhJ4h^>Ni3ST9B0Xu??!JxV7$aRr%A(J5-T@d1o9Und} zLa}j3nwr9p_NwU;ROddYsls+wHa|j`qTP>jT$-2=+9W);B^JMQ(S+k*YQcIojcAxa zfmdM?lgsHc&xAWfqCknx?KV>=vP(}U_p&Us2rHp;UsGEB28UVFtZ)%uaR++a>)}%= zMAIG1tWqE`WioRz%>2@;V?_DDOf2ul5qRI1pWkL?N`9&A7LN2Em=HX4Jbtl+*MfUx zZLsG4CjC8Qxfhew7DqLp407M+sRgf(e$vjq_e0sXdJ@vn8mYFe0I6T9Ngq8GW|x03 zb)31P5o9yKfRl%xCMBJQI?85*kK1WHvjj6u*u{sL#pT;ll5&I=?>xPAIV6@OLDjxD zg<-6eBGrU#w)tdXu}`ZYn`)?cL1``TKm+3i#pB?r&_5r3i#tyO3k8OWW z=Kt&c)kgc_Q@p;7_;gmr-x-?`48@F;Ui~Rjjhvo^Tw?EP65x~!Kks^cDF{}zwvTQ< zi4!NY;gPvX``g84>gl6X5rFueU*D=G7Ojlk_1GU)@E?3asU-`Kt@5+BD4x8V!#;j9 zNO6b-6%>VNw#y8q7xe0FypQtJ0j*nhw<0wz9bExXH{0>#ewPwr-+d{GW2M77stjPo zX)3ZdYe2Z`THx^ph7u#+MdudX`h)uMT#$!RJw3$2!~^lUq|jLjIFh+rMN0pj?buTF z3<=AxqkFjPR|DR=&;Q=+OZ4T}@qaS!L4)5G+`!6w^vT92z@J5Y$wap(vkUxwSC*IX zcj;)+Og-dr`0v2^eIF%*(f~8pr<;u4u@zM8>u0WdBCc;o%F+RM#XC=)pUpp_d7V0( zz*ph_fm{jTLvWXP^9*Y&tWmdu_e&52m2*c%kJk#*up>V0qb*Nx~XO|KX&7zNg>L$Vejsm z54GTb+w8yAr$lP2zoy~zzVkJ5Z0hlMv3Otw`g<0`!%t`E#@sV!?$x=~z4Fyo(=0Dt z9&Fs9*Q@QdkO+{FI^KpZ4VnN!z-(&^1ORLKL{+J&t2IAEfd4{j zmF3QxzS)kE%w_~N$G%CCV%F;?-Qr!c)dp^n>7#G;?lF5o&g4b!)w)>UC_pGg=54$+ zU*=If;a_35HB4B}5QTTBsk2AM_+KJ}sK)L~EK zcckb~idY}nJ*Y<>0<+FR%XSm+$4Rs>sGh0kkfb;- zl<>-Wlb?iSubid%orvN4Y}X;Z-+&J<*%U5iF^@P5s@h+RoZ~TzFUf zvk3-A0ha`L0xAc4Z$3FbiJvSOo}>e(2ZQKtO?76B_k=*CRzbCCGAX4I4f?9y;^4%_ z&zq{p0nJleqL}*xs7skt$s-1iKIkEH%tp)Z!u-&{7y@Vk2|NPX`ISw$(p296ytsDg z@y8M&pVAfP9iIjPV|v0WMu@N01Jy-0t~3hO1%~7V4+^Ch%p+_~g{G=!i-z33sfD(> zyW>68z~C*5!8V^k;>`(hq^zGnVU4vH z2+JL?vfN~MOCO9+Kyd%ba-^WcH!(ty;nWY0EKHXukH3#u>W~(Qf=!BrvdCnb8TY;F zy*!zwB%l>M9PXX)jk`0pe@EEd)TYxX* z#5;Yo9Xn*7yAX9&v^(-=o3gOQoi4se`5`-2cTA>h2iUMQ&*sFGG5|_W_KGJ0)^B6; zQ@XzKex3WW)%v%e>yhXgmj9~FWIF`X5DDwK{yZsiGv`cSV@!plJ!|_q)1R7pbvy=L zjRUQ@qT7o!|FkFQ6E;< z1{ASTQVQwU8^d2--v>@Iax?r3iG2Iemw}4d3?4mG?&P!?Von}lt@mlS?Z>xZfe~gZ zq7nfCDHO$UuFAx6Hv*xt%7=^miv>Lci;cZQ(Yj|k&JDh5@D2$w5@Yj63cQ{&nWZhC zZ4-Gw<-A~nO|Q-VbH2P|mgi~}DFSmHa-LI6E{6m;4+dj2$a6)xlJIhqyGok)piI#Q zBZNKLz%s7zOkd)gKcGh6HF1?IF6$rQH2Q?}YkI{wzf)XQ!@Cadlv77qTr#we@Im;c zGr^wWVB^G^PHoV773MbPyjGYT0HKZTsY@21@^+!D*j?mIM0~jUSJPQTCGXQAl{Bp% zx*l6|dtJ_@vAp^c&;Ytk>s}q=X_JGsDa(d_<|ReNKY9AclpCtCSgut02SYM-Y32O z2FwjVJc9O4VCqYTVv^L)=(g7_%73E&``!uIk!l^CIF0D=}DtsbsZ#(LZ z`N&~^cQ~?1^GWUuBQqdCbxHp z2wWREh<-HAYt0l5?h+jECj{*d-eOol-!}l!zJF%JpTZr%4B-KF@I;|_|(1w2-f+IZwaG( zZOO1#4Q6+J=|Mh}+Qntnr}yJVOzN!j)6Fd6Dc$ipIn`vw-_QyI?Iwqj%|}{L-m9#T znA&*zvHKs+W*$da1}}4cc#1V?Lq-zjaDx0kDJg*e&EjLEirJ1HN&d(%um5M>pIg%# z_eMFvkUhmKO5ax>{UkmEP00%?dT%4C*xQu@nAFNk zuUDT~(^-S4)}8rHKq~*(>tIO%YyIHVrQY;WP!)T3iTG1+7^p(Bba$Ov@v+18&BU~v zJW(MsuuzS-bkzv4`XlF`TT`m~>yvLd@w%VH&%z0%aWKVM9E8h5#pK`tr-fq$k^7R+ zGXB;-jV2rk80+31y3n7?x_*4LBB~#>k@?rqG?*Wcae|#0*$bw^4Jm+Wyo&u5GDyoy z1zlt5c?;Xi-*K8s|Fm|ZQ=&%0-JT4Sri_^rEK;fp`I`8>Pus)jQ>&nEORTE?cMKMP z({N-CE+I2H5y6I(P;T)s^6_@&DTJ`9Z})SLJf&;|75}#`4VF>wyNi9<7w_ZL4&^IM z9qoH9?8pO{aEaNmWr(PH&7}0NQG=Wgv7IOPCHC-W^`V0NA`ugHb^CZ-0GsBXfSvFJTLFQ`#rZ>-OG zef{;|muA3m>h?s8@k*)Xp`BnOdxCZdUYVmM=10nMefyeL$JF^iZ{D|jsvseYbyhQ+ z_9q(DjbI~E^{X@8p9c)qN+K^0N;eh1z>USH!2<*v!uWbpxGq z9Q=KW*^{k2RGBr=|7fo!Hx!#}Zdmjl0>YhsN5pGM-dL9LaS`DKZaL)x>Qzb}W8(+Q z*{V_cO{vxG>1A!jQ?FE<^+ioT-cyjLbt8Q+d0ZHa*X^gSbazp(tB|P&WaSn*;&cKE zgCT_V27ZmsA(1Q{32!)y=V{+`r0iGOq_naHpcf0SeaH)?Y4^7ZLD0Iu(6P zyXtReafRW~i%sn~oN(>Bdjyiu^UYrH-Me0rza#6-e^(9Tmz;-?C-QUaOU!}H!GcTl zlWac7{<>8nXb&E3E9`Uq28>l{pJO+ZyA1jC3ncRBY?#(*$WJk@B>nB@@HM^^ke2Xn z^%r6B4#@j$0ZqJoef9_x#tkj}soN%);3DPbKo{ODP!codtT7t2w&bqR+5|~D+oJ*L z))GfF;gm?Ae48yp@afS>+@Lff?wx6iXylv;Lo<^Uz&G$(gu%eKJ4_r;4-@AU^xyVa z=q5x4z~;w)OWi=f0|?|c+QvJR$b0b$sG4{|ntdX4-%-g!Xc_J+LNvCz7(J#qG2}_* zJwtxm=M<95=zn6(&wu8y*B`@OXC|wf=?LnR7Fkj!O{rr;h0ck}5mQYGT8b@Ui=QWB zK~2^|@{g4y26w)LC1N?%dmoy97i|1m{*fIV_crcyDqS?_t?yF{TK;KeT{{qhZzqm3B2&`) zpVawgmKg>WS?6`pw#5)gWY@T|^?*pVFcpmKlWwIw;obE+Ix3F%5FxNG*tCc!6#9Lt zdfg-relgQo$RC;=GXt7{;bevx2-E!yHBPV};C2;fi$m_^$!s^-)>~NX?#+BI|Lmu*LU=qO9`MNiRZ4s-U zy57u;Jd?7z`~BfM1S1u#29@_hEck7dN)4hlOGZ-!&kK^mKr+?4MT2c>(|ho}tM{RT z^OUJ-*jd{{_r7+JyoE7?#Fn4OiloKDWcKw{de+x0X2Tr(W=+%4AlG3vW&(#oNaQro zB`1d!BfXMPxEeKpDL*>}Y!l| zPp#JM(`*5wVQ%(7aW?Qu$DHa4}D#XcIZh}>@c zYZp`YwoqgW`Q2?tS1DyLF+y-uW%+TBoo{IA9q@H?V6C?k+#&)`zKL-~f|CDnPHn&h zRj8Q?8;$~-P;^<^%a43d<4t&>KwE{P)mLd$)aE{hx^olyn%j^vX1+MkTumfsUvcv~ zeJL_}d61}xXl@KSbHfOFUZ(=OY|J)ULy<<0i6sF{Zhd(l^*Qi_D_L~T(G`nkBi|pK zhh#N)b!XgKKX}jiu`hkp)ezt~IIh_THNqc+E0b?lPs1ET1k8t%Y9*vYx$kT7q~8Gw zBow47Zks<{)rL`^zRJ&|d%nBv92@Kh&Vsm|o<#9XfN$|o1>kIW`0HsqWPpRWsrddr zq})B=D|GTB=aFW=LIrRtiSe^Hvw`5uO()D=SSujkuGoL>_wYE?F|GxdC@WB{X_7I_ znIi2hdsz1d_4(%>?FQyey3QZHLC=Htu565F8Lx%*g5XW8+wTKmX~7$?IBs_aCY(D8 zPTX*U36se0#=H*#MOv=(J0Ii{?baSR@rHoYLSO_Xy1Rp;nzFpVoTcVKc@O9;nMkr# zH(uTH(sxQ#<||1))_L0ip|95-Q#>*LmE)PE>s|mqF)+uV z4-#2>56I2t>n15>h|<{s8{xHh_G6-x;x+J9yOB6oD-;c?;8q!K255L)#3klXrvoQb zYM@`swgtBfEuVp?LNx;oyHs>PBJYQ$L_`l1zI82N;qI@pGY3}}STBAP6L_>~0wymw z-bMZf>8S+tvZjB*+Ds(I2ss)kQJ(xN3EfHRgkgiTTU@QB{=a(x&{a^tQc5DEd2V!S zDqq0yxtbUVxSf5On3P4({J*rMh0*2+x@UG)dR8A(AQl8we#<`My*#`12?qC7FZj-n zzugP>0#mJy!WeT5fz2P4##t$Hwcjc|cmN863p565f02h4to{}+5zQ8x=Mgc(t)BP- z(ARVtjln?rbw5p`k6l{oGz2{HfbeI`WlKnP5cnz-c^T(T(BV()U^J@oj>!iA5G)!b z(Z`se_BgOlI~vihS2fUWnR$em<^Z!VbC-+B3PE3a4hf_1yv#vP(7Yua)HmC{eN&F9 zs&yf$#g|*U3;k>iP%(psZ0{*wA!%>HV&@}ghX*8dC#~jRhi?DLP<$eqe=OnU67&K( z0yS8l4?FqXXmPY2Ko*r;8*CAg0Y|}1Y(rmOR@T(m0_JBmIjcRCp^5@Y@p!O5jm_j_ zAXQ)w;&m5zh=71LiTzqzZ1PJ^g*z|=08V&^=Y19kJs^LUDuFD7E|CGbIWeIzzsZKa z3U0%C*?yv-00`lN2kXr@8tRu|lN~~Vi3AA4Pq`n5BCYt;v-Hp_LMUX;$90D-2>+>& z#yXoPa%luHO_Ulf+OyFw)Fvs1qCyaCzWbiJYsEw|EVplY zc@Ra`U0Xj~KgKbw98CVPnu&3zh`#-?e9Dbum!{ zfDW9x0k6Qns$Q4Yl*0qZ=SDV+Hyf5z1HqLnFqPIN8ijrdMAde2{MT@S9d>N&ez60t4nMG2gUWz=YI(H&78wl_p07`nVh#RNGobP8e=F;k25+t8 zVg2ljc0X4d{2pN%=*K7ZML zdan(=p{VdMt`x`ipQ}$8m^Co2jN4kbf^|D4MEeOre+Y1+qzMY_>n~AhOz`;NOq}cM z_{X-s;C^xO_K>~37cVV3uR+0BgmPnUZ&|HRQQpW%=e{_5@+B_fQ8$lPQ?>4i|D9jO z(FLGxXG$*lzgGPBXh>$fr>)U)DRv7rzgwlcOyd#5@}D=Sr$mujMI0}_%)1knMxQV7 zz6RH)f>DtK-NY)U2p_o2_orAv`Uo0}w4P(ib1GyW_e>~%*quy1KR?;D8%c2D5O2}Y zIc+H28|pKS3gvQnvv1$=tdX39A^nhPhOU1j2gpJ1_YSzI7$w#FdiOm5v=k z%+Sr~dR};bL%DIgM>vmW=keJ9i|+$@H^ENjpJZ|3+>66qi(h5)2p%|oMt6QL-r{|h zSh^clfNZ`Cyr@IumYiLq45I0s(A;Rlqp#tmA)4}jc%xLqBAlYU0>3%~ujhnQbaCCE za5*otcSPFyMxgkWyWPYQkf*MKmvF}n@O1p1tnP(`S;n;A8f9U#DsPrhUxI(x$7XkI zM)1Ke{2E!7f0!YieQSI;e?*{7g)H`^1(vf>$zw;i&0BmK!cOE-5`y>14k=y1YEmlr(&z@llFU%yb; z@$GDAZc5qBbo^VfBwZS`w;$2_+EmMOZq~x~rbf$KoQy4Ne9M_B=sgblVwJJq)UBw} ziu#C}x5a>aJgucij=U-kgY8SFmK8)>aA3qIn?6jq#b{asH;{N!S&?rta~}?rfB#5$ zJ+;FROL&F-duv0CxMOR8XP=@#;Vs&>JC0nohkC##VNCFU;Eev7Seo#;!)~oFb4cX+ z=o>jh!)Wc3m@CVZm0EjC?>3w2-gs<2TKFIV4=^0K6gFTRRY{Zl4R7;tkLVOdF!c}^ z&+UEotmx4R-tDY3FCf?R&9>M$uTq%z8!;~7NX57cIA^a}{aGE}pX?Rv23vH5rY_5Y z3=__8<#i&F0e!@s-EFuIX6!|Bj0XmOduKEtJ_Ba|lINgj|W*L^IgY zClN&rG0Z!+E!rOKCil5ItNPIEpB^8;_XzsciR+YT*>J93;HY^JGX78eff={V@i1X? zCzV^l#ot>e(ys>zS6C0JATqR1@gG=X&=! zr;5bAtsGs`Bdnqgje5S8n;%S`PSEkmrLVC4G2%*Nd9N@qqBoETPQIsePl%)mllhm| z!Dll#=N0X*U6Yo3xHg{I*T#@u?BfMcbMZZ+@eSR3vjCs$R>^fQZy6w__0T3vxXPWw z)YI)sSwH4uaFdQH`h}jF$pSaJV)N-~{XOFct(cgVq#kc@?u~ixx>F5g_KYVzJy}!| zN_Y__Vbx$eKEwl_+H1k}Khy&sVK6=OgZ8~V`xwPfdB9kz3*p8(CERM zh@r!LYZ!sJ_D5U)+D|`Z&CY6uE|NK zlPcmPTKBfTePYAq%gib}=fvWQpjdCNp$V)B!5f&78i%(-{Nx7#`Y zA6ah!Rb|(_59<*LQR$Fw5TubVC8a|^X#oYKyGyzoq)R|Rx*KVb?(Xi6Lw)<;^FHtU z`~GX)>nzWbbKm>kd-lvVGuO->AHhLBg#{OQ%U^)1^tM_AK!Qvm4^uG4<8p9CPDC@7cB2XftmuhTwM~j8@eb1i7 zb6X7d^>zTHQfQ1f^5Hy@AFowN1onE-t5^Cs41PT+EU!4mxH!n{-rCPm*wy;gb%kFl z&a9^&XNS=FMa~8@erGP$j@dDFT$~X>i0Rym!7>~tP^T}v`l+Wo6)wAKqeXDj!}VK% zC3=T8Yv)^L-4jZ$ca0^VGm7WP797xMmio$?m9XmH5FFzP>3$ipHE{2XUu z-dJzlcks)$r}}eZ8>QHyq`6{vtIVlxd~7<&CzuV^%WIz)lINyL0aaH-0Pw227HVe= z)P5(C62eoy8!FTxGiiA3;bK=fr6ChZ@mZ-P+ZmQ@$?yrzqq&ta%s{T-Uq!fOCH*2} zfY@lUO2n@I`Bt%mcx{)r)cVa4iR=5yf_iS79i2NJi$~CBX$kNSmT^^uTPcV=FW$q| zs4KDS-!+H*GWV@1_1m$5xRi)`e-Z24Yc3H(>GY2nKja$pv~2I*hF=e{k|~OkqO1*g zS*!iB@a@Y&rkAxuFALFM*22Hcc<{0iN>g}(I6G)V*>X%Kr*!!cI?I+}K8LKEv7LV~ zO#oLOWRAFhUPF1hG}`vsc~(o+b6JKpw-xYZSPqt>ktqaHPY#{G4U}dU2u2 zC$y77B+UMd>`!YF|Lws0+m6Yj`TnRITj)iGVkSy(hbuFIi=5rcIyB=PKo*P4tjW_U z5TSR?sV%$OI4jy2e158fc3+!A^KkN1+#yOGIv+2`$ zv{BtZ+FQ-YSs^@_0()}K6CsFrxWDlEjos>~X9sRdeKGq^Y&h)aPdpwgD(wJ2;z;zC zf>T0U@V2#R<~#o+TG^wWL>Tn{us4B*utqt8S?u%b;*C3STvu?cNX%<1){sov@HM$`)$y3|)rSBr zW~KG!N!KMn-zs0@8I>BVtdAT_y6X8-Mqhoer)2~AGvoOJ4W58zAK#yEkk_3r#!k+& zWi@%(Egf6^J~Z4Fh0WdY*zU~K8x`Jtwy!%d8lR@a_Mj3I20T*Ng4!@!`#>v=4}YnO zz;d8q$c1chmYTcX_FmAEej8u6T%POU;%{!-=j?i!qx#N{I>$B5!F1=pK9rp1Z|N~2`F2Rsed-iI9I%dQf;JJSDmImnir1N3)Uq|?W!K3Ty%XlJ91!HsLO4-pw8lpH3c@}+Ggz>MFJ|Uaxrn!@z z`)Vxau>i2z3e~&#m7svSNerRClY^-TRViGR+ulR?{c2JzVn|RTW|g;{--;pVR65`%oHX zI5KGOW%m$P8?l$F)?T^n*w5;#`DzUf@|<&V__uJ)CilglK!KE?ZX{vx-&|m;7;A~= zNkBlag)z4Owd%b6R(Avw7~;{DICzgCn$%68$StvBrkbPq{p3X1F2p35K7C`cwBk~FC9$hFKy5U#77=>OG86UQ1O8^hFH0LK5s0>H8RS0p_x7XsXoWV|d^>2nQde;!)MZo|R$^)ns>F_|4! zZMmzEBuDRhW}WMk%kAOet-T4w$o$Wh*p&M1eNJZPBR^y`YVCF>YwwB%2U+JG?5z55 z)`>s-`K0ki;+k$u2dgTai&p)%z8nw}x!q5OOPU zMkE7m%3e54orAiv%gd^9ycgz?;dHh!T&-A{_DHNl){RlusBLu%C*sfuWj^o)A3fVj zFiPxxSdbuu@%_zfr>T;>LJ*$sJa6!*#1WPE($F)c&h zkNG^;{s`Q)f6Hk=)CI(;K%7vy&B3(JW_zV;MmMEjpy&e$qKiUAb9>pEFXE4HSJ={j z!$Wcq4}b-Ku_%9FeL*^726GMoNil>Na933EYv%cJ4XU^ifAtn-j9o4+XI0P9_zI^w zY};CI%tR}@pMru;X;&vD+ZK#2+SNJx3ghWpS0VBV3W!_fLfGr-(TFYtF=?{!4E=`E z{fgE6(UfvzMD0jf)v}}GVY^9G{M&&r4mcgb&xhw|pAn*eb^IhoNnp`D>78N z-I>DLi^)a$o01N>K7HDdA~cE{R1X>kSeExbl4S^abVU8?=S-5#cJYsTM2}l3&`I?K zAE@F{^zVnaR9`>2tuNOXG;RYbv1P#xm*bYRDqDwzh9evb9xJK!!ht&=q4H~Ae4oW} z#Tu6gi&?HpeNKoFLNsqCZV%+x@aT+?XPfqpUIzRTF1r3o>qo2ctig-cVFr?gdP0Qr z*$SzTC0{Nss-Exi6r(jm8@Ozx2)5bt`*cs;>!-JCY&YLT!okDW54vr9myetP9I;lG z{>dW&sP}UUB+qYClHDjNzvxrBWRr@*qMWqPR}bY`-$lO_QpH9K4*1?Yrij7gHjAKj zf`Tt)b-*E8Yx{6_s@$k_6ilV{#=vHUHH;?Lx(w zh@>P%dMHeeckxU~2KG#U>B&X%c z4&OomhQb1Z6PZd=H}5t+F1;Y&3Qr_t`_ep3>{495qwK27$`x&Qd^wW2ZIB@5;Yb-6#D&ZuMm)T!7KiYp{P<3Ph(#_ST z?j9HPl4IhI$iM$~DoUk+EKBeYXxv)v_X->(XeNYy_=9pyQnX+3m<;tjEJ84fp8EAk zhs88)qxDUuStw#ul+ru;eaXr-N$hy5UBmvcTZ*Zz#K>=)o2T>r^F>x-vv%Liq0EkJ zIuYzlKkMxo(6Btj30&U?mDBqLn0?&A@c^MrTxJTN6)q5SQ_O6X_zK^ZcNW1(?i-9D zCO)q&(Ps&G;3F$^uX`y%7B@Wkf8TWG05cnnKtrKx3p-3BqBC?sE z*eh&+b{cGH6QwjbEU9`kT#|@%=;IFF_{&u;RL+(pesHInit-P0Pw? zoia#bOlV>XZJ#I!lz|Q5{Ompdp18)TVM+E4>+Yp}`Pse|mTU-)YtqrDvxG;gdsYGA z_EY7^8zaTY^KRdHzT6d^)~UIFR4l z_?H)6!9zsI@jnQMvHm0>48t5mbHccFpr2dnKacIZ6mfuazu|kO*>1!=tANpqn(0rhlR(kA3m$9RnD1r z;GWKI>2bO2s^$9E2S;`QcAS1n6TcP_Eadl$x7 zxUuH6@lb18oS!WozbfPS_-Wy4u-gGr3kW=h3Qv$g-mx4zJaK#4-}~%+;yb z9N$NhLbdnRb~2Z?4znlAYE(oY>1y#+B5>2RUe)4*BvHa+#hFFu`Ww)kR=DfoB?ibC z?bTn_n(&~5R4r&S-RIHN3t0C9W(IKO{>U+Jte(pxkPVz|nHl&SSsEEfMQGmf`A?=< zjbE!V8n-g@!`;B-%$PhJDt0kI6CoD z<;GYBekZVW8-t35H>?%Pui_fRU9Ytbb2*Wo71KjpY8IRDZ+y7fkUNl&e3Sf^0|JEb zSHsr-$%xRpe5l!%#8-6V4A~xN&^y?bcvFRUq`h=J$01SFmi7`DA7CPW`2C zooRpXyzTsjlID5asg|wA-ACJ4i{0#`@xAW7A$->fi&H1NsB=O(P6$-G_8c#1Y$DK?MV4+MN>1(zzcyQKqe~7a^c|AoT+INKR>O;hm@4byKRge>R;Bnt@%XOj!#@=ds<4aaw*MO|!W)P7BaEx(@ksZ?HPHTseBl$?hN{xz z*BbTZZt}hUOY5R}$4x|IT9fKWXuxqzMiKYv?YQ(@8GmBdL|lZ%2Yy*Ryt|y zU{mA)I#}^sdlADWLRNZr{=)?zmovZGugk*Ov#k#9Pegr18M)JNXfS+9#~NzpLhhy@ z-iHhI-th7@5cp$+V$x{2e(XbhK4VXTDrSY3!YziC15)|IBt0W)#V(>Rs94%aiQ8C1QX(#?6E!`BA+ITGSi9jlN# zCZ({L0Kxhz6wE|)=Q7X)z;20I?Pt=hzwUB=u#yCF!_H7OenNi}hbYMOwWvCyo2tQ; zB#qhiYZe&tE1s!sHZV@BU*-$>%9x$tL;KW>_+ElWi8^QoAky7n5cMYMuUrFH0kMh( z(koDOA=MVnKD)bx_jXxx_i|uo@Ym^A`#rBwgvfxNyN9y;qOQ*wS+cq1=S#525QWNc>M&wJ>=xiO%{YI9XEH^%R{|>d$U4U zLq0b?BRs;`)qiKRxE9F4Z+5}F9WyF&s}zd)EGitPKjIrd*GYz9AzsitRF3#q#oThL z47j9iJ&v)vr&G%)h))5bV6tX))|vm)?ZVL>!~(b4|+ z8{*2lKWLyUGQck2!Vw|4l9opjQGI*W-j(~p`*=qdH}N$K1rP7}#Cp{S9S{>WKB2Yf zRsqof^w2`IrG7Zux(GK>9LBvAjs{siZ#$M&r1)9c%@h zg;&*`dZE+Gr&wym-?AEgLqju0*EkFM-G7G<czI2)i%(!VgDO^k)D)0!@*`|(+3$ySU&UD^uGvv@Y;gnI%}ZqN`ZB~)Ynl}D zi3%1ca6*#1@sZ#ZZUn|YcYX&%2=z39}CON8~f3GZGAq`=0oNu{+i_L z&f~$+4@I8s%^FJ@=nP%^40Dv#Y#D<$ZBO|_=J)qXPUury4u|yDuX=h|_iy(0dYo;) z@YC?{6&Bg9O_g*J8_UF}blfdv(c^MiD2p2_h`M$qZ{OvbD5|&~B_w6As^Gz^eTbQJ z9&14vmJvxs`k3cn^PFLCHjmD!<4uI<+hv6@qK5opf}>4hw2f~6JB45e$v;l~!f{Mg zo=+$;^!{+oQYO?PQV?A)uVYB)QNRmabWC=cNOU*f&R4$0I z?e7Y+FE%Yt?R7~Zr@JTT?u|`|58xbS+}{&4JQ0&c5-XSw^J+Q8mv1J$p(3GWAfYw= zsa5nx&MY=N7OIEF0~=p+MND zJM5H&r`Z^R;x*EO8Hgiua||K-=2T(ri@fO4?t+so#GnB@AcIt>tQtTmg=3!@Uwwg8 zdJMjPNCsLrqcT}QC>F)BmkegarPck&RV*%O3HT@z_cl3nVvDCMXdqYwH7{dIOGHN_ zLpP&e)6$wO7LXsMkGWWf608~jisG@3PnUx~L~rhp8Ct8$+QS*Vb?##@F zbqXlnM`xGwWz{zEn$_D|sc$?TDNQ3;_;KVIM{x^pfUN_{^eB~lcNgUlcUg~vGMuR%U4P@dUNb1rZvO;#L(`^ zuHe{Z?S1EpTdTdsPoL?rhH#RC4q%P^+mv;pBJm8`bDQLz)?O?|!C&=()GFmt}e8!0G$KCcvwBGcw=HYCg7`tx4^Ch-R&=mD)Kh8BV zAsnMG9HJUcgdS`r8sY0KNp3Cz*>_~P*rWeI+_ zS{F5^c`Nvf0ZMX~i{Apo#CQE!qc-xNbj!K~fYd%eV{qjs^{GA)gAkCRN^k#1>A{RU zjN0|iF~a_95S%cYc+UIWJ7;Yk&dUqJmsw)k)3e#jAq7K<50{Q)E4DiK#>~$6u8W~v z`&kHZ^eosAA2LXr^!DaQ!uGcW7T?^H;egW7Dmo7HZ5(S^G-RK7@QlzhM0gN3{RHU? z0ncNtC<6LMR;O8yB!P@FGH?|`Tj;j=Yijp0YNr#DmCJ6^sk^4wPk}+e!{(EL`}|oK zM}SX%>uC2Rw#J~|?ftKf$m+&5Rtm^>s7HixBsgSJp_C!&T;`95gUNyGNOU(OH!S z3C%D8g9B}S@7Vfd)V;B7GE`k-35mYjq}YW1Yiol$&u=pUSuI+JpWf*T)kf-y)dv+X zG@)Heo{wX4Xz`p1~QoPY?wY_ z;k9Su!ZhI|wOEjK;q?s<^=;+=mCca|{I$+I9}O2Tca1{7_ULf>tKV{+E-Dft-1$km zNj$+9;J+nq@z)Zg(9(h`vm|*$3)bknnPdGE=Mro(MiO_Fo_H=JMvW2sGzQ>DyzCYx z4hR&qFo5cs+Ih>D;gF$Lcs_dgh_c9f{zYM`c>F$*pisfa!6?^kBy3sEva)Lnoo6XU zvYk@$M?*DbzE|c-;Ed~xMmbB(^?=Z7s%Zr*) z^z>of>=GnB5(|>QXuuG#v~^oqVUM~x@kXQ=>%&!}L1Zs?GOen1lptW^w<)s24&9xs z+7hx194=W@8(u8*t#UNyFfy9PC{O9`;LY?7ejhSZWwWQ^fGs3GD0a(SkSTzki|Wy1 zi--K|Uqa^wtq1g)P)7ipEbND_f3_&BK0*&OGZQ1SdGTHZq{YndbZ@0Em@)7S6otz zfkjAomG6&ieX*735n<(cg#PPSHJjyOTur6J$` zI`8tq8_8f8&HItYW1UwVs7pIM5GOM?4wqBYes?BGIwOm$1mo&-@@_8cZz0K7`4%GC z(^vVYguV?l)hq3#llW($y&urA1uTAQg=Llp|B*{^|5;UKh`eU}b7JbkFgtp$0ctaJ zT^BY%!6Sy#{=HUKP}8N9S7o#X2RZP$7{w2V$089VE9nPB3B?qRi#{`2Qj_M_u3PD+ z9)r3LqR5hYKMyyzLuOX_k1NL;C-XsB%y@^EfA!bt5xQIksE?=>_)NW7Ehp+GSHteouO8b^223Z{3D-kqeMfj7^g_jg5IQe=+=o z#mZ~g8&LxA0`+;yYn#WquLc;8KAd7)DlvcVsL^HU+l#?g<{2Zz7#6t_U(I-jQS#~z z^Y|5g{#&2mAmZ1C$6Jnr9p*c=IIiH=-YYxA1vi{rHPA~RytW*H8i#I?R3Oh^cuGBe z{ua~U!>i|Db*$}PS&Y&k8en?FC(Q4f^x@(!!Ixyk54m}Xw@Sm&&D z>Xsc~o_oxlb$<92lRm;vFmN3Uug$(?;~Vek;_!uhBmxRi5AO0*sAqj(ifrevmvqmg zW@;SHa59X-dA0onxv3n@|L2@IVTg+4+;w6g5zt6;mBImwfFh@dDdY+_X$SXpN>hp7 zRrBn?w?wv~qb8+cIVi#@5Qvp$^38sJ?2A=g9*_FUMm0sd;KISlxsx*DkbY)c9X~Bu z2z6*(B|0LR9C2`YLE<$7M{VagPv_w8Xd?ki@8F2tBk0d9SGu!6$$7~T&UOhBivk4p z{~`|1{WCyzcQVu;5iO`9xn(2kwgAe&|C3bzP7QwIGZrnvI}77y&3r)_ z&;-Ug1F+=&p+|m)vAt(;cS!hpMMP^1#*Q#1Pj#NB4)9 z(LStuTN7N2-uW}z2aOlJC>N>$R3RxWOfY47#=y)>#qRJhmH}#4#kz>bK|f94mk|te zQnfkZ@bCeApK3x-X-A*Sj&&{QpC@(BWBmoU)gFaf^4}3Z0^?~PY7Pn=1eerO>iskS zy2k@b;Js=_`n^g&0hZ$k4!L#IeT>URxXE2OHB}zTWkekFzI=%!6&4_AA&`5a3)rV6$+4mBI?2aBFM*KE8!{BLf2@d(W6!6>}^I0`8l3Jn(RZ&1s++Y#p1N0i!%3 zNbjI*8Z1%VE*m!9eG^sKL<~HGED3Y%V7@>IbLS^Rb={rqkF5I%cpneo%FqUA zAg?(%@@g+OyjeZcmy6Ilo%PepXH&(2irwIWAQ0z}LY^)B>^jMfF-8~DGQ^2m(~a<$$0?#YAg8phll^Npr7EE*TLTH|I%Nqqk+Ja z?;esFlabiozJsHE^~wv;D+m7mMuOm%B#?V$7KhF`nm!kCK8I3{-B0&}pYJK^2JJ%& z0#1R?UsbZ-F8qfh1D*y@l56+-c)AXW)B;8fNi|fV>pIfSc5!| zWK`HbXJh+Wd(i~jGs1gay}qy~Jpx4#aeXC8{f(S}bj8`=wy(~;=9mWO^o1oOdF?JxJi_PQMfce7 zgTp%-UEkl>dXISh??M6Xhd8pnpBjQu;km7lg3$*L4(F7s6kF=Nm&O}#m?JDe0~1w6 zm~84@=&^hPnm)yWt_<@(en+Y=n5{S|;t6AXGSf%y(SkPuDS>$ZC@`>l91nWH?x{VA z|9!869KD+|@xLC9s|7Iw+&xXIUdTp3CWk`p8FoKGe|0jVI(-h1O3lr0>0urqNbpld zbd~1*WB@3vB(PHkw$9pF;K9#E?7QA?V~M2ZQJ$```g_98BKkYE?t&^{4Om7QiZ9C~ zGZ3SalBBn&fHF_<*BAjN`2hq9ERtSUWFvHj-~cFDCKJeb!6(YFDQ9@Yn*k6situs% ze|I++3$bJN&vaSXy>~YuWiSe0Dn4V_&*(ZZ(s|O@;soY$Xp%{dfiD`8sG6o z_rKE)G`ldGAM+O<4KcRK3D}*Ak#u0?noVUevB~aI9&QL8fN|n=VFf!A9U4B^0x&&( z({w+F_mh-}?sp0$Sk;q#z2;#i*dV5J^kCIfO}I#~*Krd_*nIzsd5+r;JhN#6Y33GJAF?Qw zI!8fr8;>>p+r|(N@gD&M_gWJLTk+Eqd_M^{aL*u@w+{}1Rr!tu1{IccKVB(thY$3& zGcR-v-%Ud8po>TlbVxd)p6M~?-}VxJm(4obeZnrnI`04z?rDmkwJ>D1<*xz-pHZE- z$avA(%2vM&?t5qAzVgVP&x@AGyg=*4H8L<*NSTA)UE$nlh{&GZKBDt@dM5ft8w@TB z2KN?2e+ALKJ)|R~11kI3|EO#$a+0&8puBNkgEy&4nP55{72ynk_HakSu!q*G?%12x z78S|Owjl_Uuxh;1Zr*>!_6$xc8O-q0ImcLcd#Zua2uG`gjyF#KU132t$mu1I0Yke` z+Rm)z3yDV_t}sxyqW^S25G<=Anf3>=0a?cXssRsWEU*WAF)W~;Qa>*!3BnDz%^@Vi z7U}-_A|r_Dkxq{Ov@XH-Ku{3&4ILf*Lbj`zF!81Iiwt_$TmGX4;)kR?E5KxahqWm^ z3V*8L_!j(mh2CoXWzX~Y|Iz>4h&{4#5_BHsO!~4lshvD>Fac>Vd!P!=y40ouU;Zf^ zW(9!CAhlgGOSO>mxfeijLkO|3CH;E|<{Wq->gCq!uo}irTxLfLA|WAJ>$1Xh)c39( z+P_&!cp0z)aWc1f7cTw>;D=BTFnz2ql26rG+bkBUI>W!u{0}rj9S{X02Igz0@;N>& z#A6O-^2+@MErv_3K4}Ni{(UkxB~uugoRd>6XlL2}UG>>J`1>KHrT{Rym4ArRy$E-2 zoJ?5xVSwx&8v=DcFW^ch<0A<7)@}+H$uG&xPcTWQvH89X8y;+%RM&W8!im@yFi_;~ zo(P7iOJMZEvS*1?F6W^2`o8+@9|hws3R`5DNzwEqJwHUnM>L=yAwqnDCeA-2`UIwi zaADoz{;5nQKq7GdVXBnV_R*;wx9`U&XWg6hWVoS-lD5sK!HPuUe@o;3juJp+{d06v zA3&=Mdn3J1h6@}0fOOM>aB7BZuLZmEd7xJwOfm+x!7{x#a_<(`RpTv`!}KVK8PN^+ z5628PPl7TqBVRl|GBIHKV^+Y+q!0Y!6iPz)_#V#81F!?vd+)dPz#z31QPHXVv{67p z+h!2`$Lgb(C_nyr+k3rAgO#jPm=g;9LW2zlg;~9ZgglY1e@7Cxykb^3FG>Swa7`O9 zXBCJn)H>0q<)V58BV#Xc<(^9>UeBnBF?=PML97~ozeTi6$iqw$G-)mE@K2dp6KaOgaH zFzYy^U-pQY5bi5jjCaBJae>DF6BiJL=;$LMKsGl%EJb)=pms!nod=L664JiOYv9n; zt_!I|{Z$~~uKxl=F4!C`=+cruD=bdaNF2w-;Zpejjh7c`L6D?g`orUYxd6MXWX4<% z<>3@)qt#&_OXk4B^{<=ALttWl^5mf>Xjj+B+%Y+!=|C?J>-&bdA-nMYPXen)YY2}r zqzi#vd=viRVODdo;2KxGw=!&Z-CqXeB$LPm#c3|PCA28sX5!i>i#I9O8QX28W$Mm+ zln!a7k!qIBiTL`iTee*F$%odn^UI=Hj?Yi&I`cP9n{%4#)e;~#WI~V(No4$&#j?TV z(V;Q)6R#O;<0F?*+rKyWW}EKM^5+jeK*nh!@)LxHwgSro7WomtI;d>au${#u2Bzn! zIl*T<(oD+Ffsfu2ApbCVj=1@+D0~qITJA@(g0=A5KW*bNG0ME3-;a2ip2G)nB&F%t znedM8S~~LSp8a~p%Y=;lr&gNLsoq&rThD;EkkWeMCx7m@fO=PGN1S2|nhA^Y3T9+z z9PWs1JFal*!?+=ldoLsv2C3ILFZ1qh9?F72DZ;#1srD~7^HN31zV_lt_ges&-aRTq20J(kDAM~n z24LRBfhKwwk|9O)W5dsG{kM)7XE27~e{~j<5M)Wyoao8tJPCR<59j)Cdm0z@c`nU$ znX60IyZ{_SM&{kl%A&m-PyC`lSOse85P2*AEQ&e}2&2Sss{!yc-E+{HIMFtKv%+@k z=rr;!ARjQn+C{>DEz)~_YT9Ll+Tlfgp7^@uBN1pJ_K*1iX9mEvJ|Bt^7~d8bCTahm z(%)C@3Kdhq@&3RfoXWptMm%+=J&^jFz~-&GBk`z?a9e;KVTC8_goj(@qiGOyyqI_= zbn^{omuqbIEj+L8s^|LQuvOwLAI2BPJjaW-y1e+ZyokY)7UmYn_>ncMJs83KK8Xf9 zhxjaN7=h3Jj|c@BIDfWIld$zlNaj8F{i7vL^#;J0e+SwV;9m7~BQzQ#_}T7Jv|tdk z3QpVUu)x;*&7W=>)b*tox&V!3k5l&dytwp&8jLP8tiFDypAG{3RP2iCAgfe$mzNMr zT;EEUt0X$r4pO0C+v01C@YK+lO<68mrTRuTbUXdqi5f{uUl&iX1qi}`69fP4kjNd! z-tO-1&W)Ip6WEM#6NEl%VE5rtJ!F8?-@WJoT3X7|`J3pefJfW$lg+&&IU3?TP)~ZO z|K;_d=YM@r_XlVf0L^aUF}DM|j23 zIoN{p28XtD)l`olj%a2nclmjf()}q00BH7*y2+-;*MGWmDm0tuOpaoAcMzCxipPsk zbCuDhcqnhNf`J#CKBzB8LKPd!{s3`;#mmV&u0;TBPWC~JI4;s+O#GtMj=-@DwJky zYyb-wetA9nzsu0HPb@GQ5iOZSW-8Y&jp-4ClFPqKJOf;0uqKGVQQG?H>AeUQ1GfIB3d4mFm5C5puD&O z`6N&(D51f;FKcUQEhezAGct&4SXq7=q{GvcG65mr>pFCqxh1lW?-5vTKFo%}aR15D zF|g0vEp0{-E$CEhrQ^d)x=*n1~bmPZE{s>tnh zj;tcvaS-0BM%*0S%6^0RC}ObTg{K{6Kj&S2VfLCog`2s<#czD(&-X-pR^E4uYbN^J8|(OZ94xOnoYwv08{fTUNz5jD zmWaeAS6bsD&xl05$Nvzil!w1TltTYRM8idcs@$77%Y;(SB%$VDM(cPhp_1KoYW#3R z%XPE&Zb0pop=N_mX>%;2IGAd3H=yAba z%E;gn+I8;8lHo zHe#7st;FIQxxa66dyqK4+Ff;p#P-?TGdZ8g(wT$vXLQrHZz426%VPF2qv7}P&+zJu ze>1$ZL`YxcGeXOC<6rTvmBV(0VkPHeUCVfHjumv6DCK5;?FBUYug#o1} z6$(I-C*GU5uS~$>TUrR)cRo7JH0#x$Lx7z__|N?4Ln1QV?Hhk)RmDMFm*NC@#)-|8 zaySY%QG-P{c=N5seIo11ysE48li~U2cZm}w z(Tk4U6wV2r$b?Mq=t7kNKR>ukyQ2L3N13ecA@6yAsOQs`)1;5=*5?U*Tk_s0C3*KM zWx7U$BqB*iEDPI&^G#}NQJ1ZSWg{>ixl3}FH^3|cA=mMt4!71b{M4p+(Ri3amBf4S zqQAsxxb~5_ZGphv>Y^;A6*))&nGQ?t)qSoOo?=EU;$jj3 zi<7ze?VC{L1)b4nT@}~;jwyB&yxIyW>~;AZRqnEbT(H*^IFDil&d?7Ae-8n@Macg*#CtC zx;-EzIO0o)A0A$jb|{s)Yb1~^E*dJHGh=f)=RNPR2sRgZuaBZrEPJWu#|_RqaX&Ow z^L5PDs~l`@f=dM=g#hST9LfFXeLxI$^S#&)?!7AM5H)T}n3 z(tDf;NKsEgHW22Oef%%_+nu<_=g4~Jz4thl&*+ie!P(QEGBfkaRiCLHgzcmD=*u1h#1jU>Ab1m`k(VP3$xkU{oCOhB zA}<+Xr+eS~Dm{_zqL2NUsTdwDA+!(tLexSU$yJEOPG0wK(0o(&Rd|Q5K(i#4N9vuX z_$Ie-YP*ly)O0yzbpKC90$2po%PuQ4sQ~3g+uTf1iMbN?Z~@!6|RpM8lWuf z{kYBGS8*QM05Ky_tGxk=QpRXHGtv}H2>pk<4xPFGzeBv>Wp;=a>nwWBe-W&ixfgT*km=88*o0C@1gsZ83gTUT)em`n`s`H(Bm+3lQhDQP2+c6WJW5DHQ~8? z5lzKmt9~su@%_DBN)t%oUyjC87h+=(Bl}BRo+Fi&6x*DhJj09rUSn|6j)Af=8Lq<# z_f!TB+L+RNNPX#JB}4){?G%>FF=#@N`GW4Q=iG^#;c_5Qe^Tnu_atrfUmqe%I+fqe zm-CYt`{}oz#57t+t&AdKR7dJYF;U^H93Yt)0vO&VpRE=Ql7-@Gc<$IbOn>q%}7_E5Q57IsmbNnPP*o@`Hy58p#8oIIX_|}n6W_y zP^uji+4TT=$HgBU%t)FF7^jeTc5qaqQc7VuOVefH$?T);&^fy5!&fAEM@ideSQ)bU0J5~|E6jok=g-sP(F7nsyqXuQi5DsvMyTUXE>U6~Xpj zUpZJ$)!pO^D8{9S*ZkD&P4^6R0#>FAaQ=gTHp3H|eZOF)WjLLrjicK*BhnuIGlDenbVvU+G`Nnzk z|G1d7x#y-PPfh}#A_eVLrl1n#IF}j!F0d#brofLs?gKW}yRH~$X4jhw*5PFMx7+`N z_M2jUsRx(px+NwIO$;z>?i*rwJl}O|Lbk9ZAS03=&Q;Kt>0gdr%PK^Z9HxS4?$@p5 zy4Wm6YpTqFGiP$vJqvCh91{wNXd7kexs`9chEAD5u<0fM&*WpSomMt&%^)3EZf^Oj zoC@4l*2oZLzL;7YB^Z-0f{`l%Cy&QFK8D*h*|guaftFYju(|;B{>e4Z@L17y-AUmi zb}RwT@m~GSEU_5eA;;#miOmvaHT@O?S8b>xoYzs1GJD0`Z~3`5^4BkK@X-@~$h(qc zlG0FFj7_l|*~!}@gy8Dx&KK8&Khdh$|Fx%W`KP~&@Z=+X+3klw&p`agsl5k?i1`jj z@hbAC2j0u5-mSxZgIr9GznbkPw2>ui*hUzumTnm_KP=6xk`})MSNfM_z_7#EoCo@X zCJ<3w7k`|%etls{=Ji+BIv){C4byC$uJ24{Sp7Pm49m+86~RuPl33V$>}x8oi3=|R zTvRR)VjQ9O(*~;m?*$SK?WC}IH8C`7CD(2LUNJjbt6?w8GNinK zjUBVZ$l#=q#cKvUc70rKP=f;`$-1YKzAwJx&D~3ip~xOodkH*dJ@)VF~r^stOKfGJ1OgLRroW^(^>Q_&e514aKD$0xPW?WY3-f`(L;XRI! z5lJ0NxU)Dt$y5c4q_+|a^t7_=`qfZEKRZEVN*&4kR3D5xV2$W{ z074Ir1~fuv+UiE@4Kv|(BChUcUcd(Wi%gC?p=he!{tWBtwA$c^3r`(%9BjflKm%F2 zEd=DAq>pm66*4dQ1L6g-!Vz0>kDmp93F4}%lKog=B0XDvLoa}(b@OG^BeZSJt36Zh zuVnluk0l0aCxiGu(ry1>F>dF(kdPm^-uspJRb{1*kOsXN0WOTkr&7ATS?HwwOP>^4 z^*ZJ9o$$>UYHOouG&Ce~GV~c=dwIqf{4(-x-BDx$G`$F`PX?I(#InAlz(^Po);6u# zAO+lB5H&HL$?8$Ho`aI2dVOhRVMK?o`ZkK!l%4U+^Vea&R*8eT9JA!C@_hg*IC`21$5|(EkAYQ z(E^sI`}n!`69CZTr*|EgfO+Ml<8C)nj5UkJsoGo-a`b#vSVv-)iYXtd9RxJ90WXXG zagLbv2;fA{ik<(2GYvy*-6rHPdYQx|oID!pMx0U|0a?cH7#x*(OtkkB{uNGuXm)SL z5yqGGZrz_Iim@~H?7Gs2N8MD#TXoPiu*J`2Z&JRC+qT_k&DLGpcLAFmB_nDEPAk8D zcYM48(FB+c5NPG_sTn7QnazbT0Wbo^LG+F18Lim>trUJjd+(>G&+E^c{2Uf$2eC6A zIXnChjyC?-c> zA*7NIQzCxE{+Hun%PM1!elFtwcqq>xDa6%m0-tm1QpmI9e8q-lhk#be9bu(nT=k}) z?lDx#0bbgwtcC{WQHxEPzo1d9l0R5eGp(y|+$})K1uH6^JU-WF0b*ZuC}%k#w`wQU zV5eJOFXXrhlgt_|IcdN}{B&#;W>co81>DF8&**I2Ktu|E0)5DfzNhYc;%jF6ACUAv z87d83=Zmg?BFDJc#>Y$eHRwSd5dTEiSfpGc;kY@y#k!?cwm-bepG;2heWK`TW`(rI z&4t~RMF_yGRh!j_WtSu50ZiKVbrrZ2;oFx{F`75>-s;MmSZLxw0&MIb3mzQG!J-uU zIFnr5D*W~g>~AnVW?Ud=mH!`W?;Ve2`~Q#E)m2tzL`Eng8A*|>D|=*BMrKjjl)brb zQQ0!fjAVsGL}pgVCfUi}dvjgC*U9^SzwgiI^ZkB5|NQ>BA0FM;c^=2{I$q=Xn&%#y z0eh@9Yh8?<(s?1eWAaEUBGCX7$$tf<%OF9@EMk^!xRfkbe_}~<;XyZ)WkYkqQ^(C) zF=g0~5){Hz$ImH12LY-HF+s#%Bu9>SZ^Y2{l zwcW`R6oLr4Ur^VCX8(K7e0TV;SG3upsPq+D4u4GXIDO0R+gG&FaY>a|RunnQCeNw$ zb@1F>>G&jI)F4(w8(pgF@g;jY<6WfzCAMY@LKW;9FH|Qj-8Yq4g((%Ou~&+^UKC4< zRE(U+dz1fGvJ~BqLCUhO)Yf7a7>K3xD${jG(zyN1K73GbPwPekhdzOHLa*JSI^BGY ze@xmqWH_{!-q^D45~{d_lPztuSfn~;QO_Fkk%XC(FJB9+5Ph!ewAa-z54u5N z{6p&PyKTxjGLw}%k4;(rr34|t0!pwC!c$_*OnzI&v@T9cMTFoeP5v1CLE>b$KIRAR zdHgEhm<#}-niT$!yW+1*=FAnFYPICD&eBd?`=MaSw4oXOC$Av{Qj70M`K&hU>F&4^ zEcQA3pKc4dH+2hg+jZBc1fycK?pDN7=(=qc7JkfPE_+8hAgkKYF>%2kW2RJOYBxG< zR=oI5tsx{^0sX0<@a^iet5KT!Q{zchOcJt;!cPmQ&YwuJa`7ii3~fKP^*q)$HS(cH zptjQHT5`CygP8rD+w!?DFw_-30lMp>!wAVY_3*UE1;p)AofW9DD-6~zqNUxQ z&)9K2SRsh5Rr*N!48k5SFk!!&b zTM>9vj+y02rsIB9b$sMB7xy9eF2e#r`aQ82F^jV6S34dgifpkDD~nuzf*!uh)L%7S z*v;Lm5 zG=nUtmsh3TdjHZ#EBCjiL7bEY&$(~{Dj@2bs>}Hb8H{q2rPXCzK8Jz_&|n|x?c$5e>t6%%$}%wL!PVHI7f5vmgq%hVV&FMV`k0a zJ*IjR@fQvYK#vf#$r2cPlq zoDTIR;8O9J>7ERD(Belt^y8)vfr(9SPueffrHn6llB%AvuD;8oiv-f?lIO8XLR~8Y zIyac!`;SK9@)q^C;un?<0>#5?Q8k@U9iE51iD}4R9PE2%b^pWHXXWLYla*hdKbR8d zE_&{JXQO6oI<64%P>NlqQ*BsL>c)b1mLG_}71&l#wIx3&Ey4TdR8)BGEA9@@wpPrK zE#k|)vPTzp6Ahh~RrhBDc=s}vFSDWaUFV0Ke$I-wKTT8Mb#NW_#AOHfv@VgTt2(gYAuXVdRZ_X<}90`zO9Ufj-Ay^Tm>0`5r+GF`whenFVTVO zXs*5|MlvmDhxinff6UpBNlCZ`627$3$oNbe$UZ*s|A?L|h>olNzoX}mgU&l{SAH4) zlNCQ3Qh!o)W#eQ)Vd1*kmaN=`$E`YErubtnL9XxHJ`U8|#fU0xlWBx{-F;~4u0PG> zxei@-T4QrBPX=jyae+YRmh17_;9L6TPn@7xg1wh~5zoeX|I5NztB0n08OKyz>U4uz z(^P&uW&T5RmN82t+F7%$J7qp?BhKTt7tyMZtODjjo@vYlPebK)u0;6@AGYr(8@+ri zEFDAu*^oR+XTvqB;Xa+?mxGw8uXrfsze!c7>EJeWP?xyesA^NNJj&tT-nti&@nM$y zsYm|1T{iJr5)XFv77@SM+Z6m_Dz&uxcAO;O9?vz%z_`H-a&%A^tQ0^Ib#WkAOGWRUjn7 z;Tz)rT2#o)(?HhKtYsm^VkW2Az)*$EgAJv=2VQ1;-K|LhmlJ*gEfiR3dRZ%>fhhmY zz`VIRO9xtJujynw!{)?+cQ6P&Sy%O7v)JWhv?dI`O`uw-)^iSN;He0{Kr$eqJDEeODs^0P*R5 zRC=Y~npPr{l>RZ8e3i)9q%gA!i0)N?>l)CB$#>zddpAPV&#}=gu8(e_3>x&Ynl$a}X*1mXZO6 zi7QBEngWXiGjr2S0$torXr9(@*G4T8sJsb{6c$qzO`P~$9tEvempE`)JX(Mfu%1k5 zU-=Bb=-Qv!_3u&HXEC6%0^a(WoBnp!0?G)&P87AC-IE+3qBz&)9r#AMyyH*Sa9iWq z64rI0$2o(SsUK7YRSbip>rL};wLB9>!QmQ>; z45>;8MT46fF;rDpNEQ*#@A&S|+ZcUDx}N`^G9PAKNczv>m2%`lPtn+o zsIk~LB^2P2)oi-NCSK9VSeo0;N}5Em%qTYOme^-xop2Z-UZo#%Q7Vi(r7QH{R^7z4 zb<*){NV^qfb|IMxyZvQI?u^-$PUPNwk?RCF7JM_@4~JJd+<4ZmFTczp)IW8|&&^7r z&%Mj$T89*UU+)cDYX}oHou+Po{ifN(lk0o-@7S&FZ9iLPNYY5u2-Xqaq0LScvJpBd z#8)vR$Hz`eo7Pijk`tj9DXOerfSuvFZm(3T2rY#l)+Pj&U)Av1Y`=W>0lc9<8vHTV zFEI8xRK~aJRZNY725`pjBZ@3w=GjV?s0?-G*txbLT|E00g?knSG!TdV*vL9QR1EV#az{O}RhhoN;~C^4g6BHLE)SJ& zoS#_>JR5c!+NjG&DppZo{%*MZ&Igxi;O5AL$M!FQ%m9YGb|w?EzJ6hA1AQ+54r6V$ z%MRPYN(FuI3&$?#n?nU0HZQR?R@oUGW~B+MtUibNy4Q)kjN6Zg9cgSxa>WE)lVkK% zbyX?94+{l`$Ur)6B`S(}pvN|AdHZ#Vmu0iWEs~FP#!8cmUD`I1dN;^BdK;8ep#74^ zA4AE?B=U`vgzhYjVANLiVUF?OzbWUTJnI1zp%wCm7Or`o!UCNAYd~>^e724u>12f+ z?szSuKx`u ziBo5-mhEVYNGM?wen7T~C43m@V|^^77~)ip!MuAX0^;9fdld+O9S(|z`jQI`oGQ7+ zyXd=O?yOHK63HOGc2v7xc+ShqP8d2sxI|edUi~6*D(k=gRB=Ibd8Uz`rmX4o!i{qV z=X6hMpQBdR&-3}@upWLxR^?QHqhv;8nAoZmCK`)1(R(`9DJH4S>8 zrb$vJ8nR?+>m`lCA=Hs=X{j&f;Umlbo>!-0x#k%3ajXd(9i>6|rQ_S`p62E{F;!7! z(u3|9cDLf{h%w&?`IL*>x#t-eaAr0=%TlFX%d7IZx1|F~Wla;!-)Z^c#kP)@tqbO6 z(DH>1+AeoPPI#qRs0Pb#%+3B_p*wu|4zIPI@HW%@@dpncxIoH}>bXkd%th3)CO6nP zmEU`Bb4_LLYO4j-(SPMa@gwyqnqzY#;l}|VK#!iR92>EHcT(j zr`tRqoypMqY@0YT!XzQ+&wTBk zXXNe1Lj5E#z5VzVF(3Egh$oFde z81^bK`9c+4Y<}MDKNwZoIm@IYNT|`?`o+0WXek8_W+&S->#mM|$A-ALxmFggiW;V| z>D0%fUSMi_a3L2YL}&^)MLj&T^jF6s^|-q&1D z<>t+kgjt?@UqwY!&zu$ucGJ<;f$*}dy$>N<$7OSvx8uY{k>c6l#=eE*&C;aQez=Lq zs2G;Triql4%tk3d>uDCb-dpmNb-BgJ0q4^cG;$ZIAjo1=O!2Ls>MB>5h}?x+8CG{p ztaA!Kv%W9pw@*v`GN#7`5eHOzXwUBj9>Vb|jO6w%lPAt+ywk5Y)d z>LudRaDhXJyjUQ0>)A=#<8;e*aqd^?!Lg!#Yp|SXbv}WfgfU*w#%s3q?t9a=D+UD7 zLb0i*^{r_u@@qRzke>Z8+CyRV`r~e}w|W4=2=))_8N8ZbU1=bkY;0KEdOr!X1HfiV zX*s;W+!N?o(e3(AN^(E%{Ojv428;FwTLWt7Gt8O%I8lJ#{FPqR=pmLe*0gmZ{|~!| zCH?#^*uNER^(_I zlFfUrS+Sp#hoXXVhRjXX1_&<}yEw!ZUV7cz$>D8wX~-&-_cimWv>rO+;G6}h4_vt- z6z?woyzO!w%t=xGbN;m&I7QLSGOQ(FDXs~o!1&le-;j7VgKU_(BjMVc;eY-FHzgLh z6$Z*olW=;v2G=o1M+1YINcnE%+nC7I7Z*aEBoee|%Y@pM#=lTpnz4k`*KmU>v5?DY zA{n{3Q!gQC{1gKEW8*)*_e)hF!RYJIUU`InC=IDUc6g0}puWPRdwRBdrMsI$xM0EZ zxQc9*QnsSn){MA8IfY|IpYqnpf|Ey^rouVd1Qk;DFoq{@^1sag85LF$@J-}N4IRU7 zu;J#a{UwI})ZLaDGFjZ)*8N)VYdaq#e*XFWNA{?xfGA4RBB6BRktP^g&-rC;$KV!d z52q=whN(igS>X`1zbQFI65lqgf!HRMMCgXVg$5Knd-44*SM3X zY(;34PI&NZYwK89?R7m$4=JQ_E_qm?#YG^ChuUq*sWu$Jo~-TvNa)H*_em!~?VR5i z$MlaNH~#m=3ZF|hkl;VA3F?c10_M0<7px)i*52c!I$Eb9Syne{X0Rv2|E~dJE9<_F zby}=SmuF@+#qy7LDHL zc{V|_{dTv=#J$4ZMy;#W7fx^|&i2F173-lzvQHlQB&=UAw})X`2$4$dmUXsVnTlAhOJAJDirI+ zPo3HWhuJ*(^lHLb7z)Y<;M{nO4Xwj!JN^3Gu09P#i2w>Nm@x3)eL zJNC?h1!=HUT!gO$yYKG|q$j-V5m60=K_NDX)kCA6yaV*|icjsIw8^ESGMFLq>c-U* z+@2~fC(4CKs()6Q$qps>?^f92VFb_P#p|4z*H3-YYzj!`^Mm!>pBIGwdPiEnXx9qm zB}H+bjJS=_$B5hap1!!z*`|yKOX?wzMr(O!bJzecSQq9Q`{s4Q@qS zZ-z_SDT(|9soV2Zcb?@jafH9DxCAAtlV77ijVk#n;(UpRKHi(2S8x_rCfL0}Leb5Bsv*7}D6 zH*34cWxL&U#(_3rZ|jczt6&QPCWG9}gOckPI!$5k8blS^BN)G9| zI@2#&3l@;cZkDirKaMI>N`ikb!&f>!*_TLPR0z7dzBn0oWS7 zQ2{MmX8!v@t5_JzM7Hi`H}-Mix#St?$OW7IduPNI*PPDG2ynZ`rC8LH=Vs3{M$Ox> z5d@u6gRH}T%8lT5cGW8vczWNN>@frn_mpi@@O8?JlqowiW$^sb8!i`-P%Ei{ubv$> z@>V5PLYteKs%5=xq`QiR0Y#=7qaZ@#n``gG$*0eoxr`q#K9>3-F+Y$Wki*k?wqh&s z^%sH+-6k)mzT8uqe#Xl64hH6o3W#iUJPKS68lB2aFhRXM+EhV@z$`zGA1#sfYW?qd zil0k>|$%SaDbWwHP%=0%jukSkN`nTC*5Hd|GZ`QIqq{LDQQc1ee;CS zFM@mh?4yiUFb!{CXfQ6G{*tYK?Mki26^L}d3*?=i^Kp1ZXNQGq5^34r? z6TP{Dk&#homspT0{g6G}zunnJ)&%ijlUpuA%Vh(tzodjRM6Jdn2DinpJmo5G2!h&) zWU4xjBh}A_Qv&Wm&sZ3fTEt$SPtFgUJ(sL&T83Lv8K0h_w#Yfi^aHHNWJoZ ztqG=2EZ?2!xtnWxOK0F|L2R~9c%j`5TwIyEQ$cLuXmpLygH4H}kZ2DUzh+AF4sXcj zllc_45p4LEuC@+f%`ASw9e45|<)2fPr)v35)Wy^(OBSbnLEkPHWB1^{T!%{jb2XFC z#u4SQCo+G%p6(Rwz?vSq&wYl{!~4X^ke<^%Wb`+9+dHx(GDB^!T%Il*&8?m4!GwC} zj9xB7aJPwu#lRBK!_?$4Fxju{wxyAb&wZ~ZReGPdx=?pXB$XmTwfn-G=mo~+LN5p3 zxJ}vEGhsljgF|2UGO_|BJ--ACQkp^t&=o&pV+sDob=eY^g=p~K8}j@6g@ezAz1pl2 z?{4=Bz&(WTgnhn)NX-;8C8zx_PKB~Rod&d6DC^~o%569JoZeM6q(G*bfcnRkdsphB zY!CYV>RL`99bP5S>JGC=I(O54fnopGgSfVp=QiWPYAsc*> z`peg`S?gxs7P1V1U{IL&$9`oG+C;ZHe z@gw8eYurWz=_vJNn+mO>?B_&MjahFOF#`rFNgkm6@KN6cl3cvnz z&eP&>972<0bME|5rj^SDL4cD%O1%!-i7Q$1XP%&TbBhFe&x?rcTJ}9EjT&teerx3y?$iILVj%3lR1C;n0X+BDfRocY^n-NQHpk<- zqX#>`)THICsX*N{EeENI1u6YiXX_pMZQ(Ks>{u>!Dt8O_7#}CT=l@nRz?3z|ipp62 zcZ|vz#tBe3q~AZBmD1I7%yE>*Fm86Xf!xb1Cq$ZM^wD46Z&p$qlrFcihy|n0g|ZHu zx?!ZP4z=3Mh|4%}Z-0v2>bIb)Vw9lJasaE<^l2+=Q8Av)!Mnes1XQI>c8oq26vA*p zPGP|O3L@Cxxa+YUZoDYpz=X;w0J+nv4CuTWmHATF5zLm95Ie5y93)N1c&%@EdV|Iv z0)Sy-b5vF&eI*n|62Jf^HWk+rsdeEtW4Fuhmn6&@jhx?d-op9X3#{o!mkN11?AqFl#ktZBO&k&I8)d z7sjP3FCgEfC`_0|VLxuYoNImV^dw@zsTK@jahh)`O}1UcL&^%ePfmge!6vff zhpqsc3JOWQNoj59c9;9ixlnnjf@q#!GHp=nd7AH~W2hIklMms$f8!m@ZyuxFSi?(lOs}+-YpZW+8n!+^MbP}o;f-fGwDj#1n-q={Ke`{W% ztKYH5qj3BpNsqbx=?c0iEkU!jw>27{qlYzHJ{5Y(Peb+gj?vWJN=TrR2b`^Mf|@@X z5=x(G2slqp{RkipKEro9D@5OYJvJ#u+C1Jm1(?=f!f0Sj#du?heB|cNvtWvN8A{XP zc;*_VWKv4`cl_Rk4KE<OYq(OMmmnqQHgd+O8B6lHXY2Tlmu0t_TqzVy79}1ijF(g+>N+7xnh_MfqIAP;&BIj9s`@rwxta^yL5Q zGJ)wbPzxYGr&)CZro2L}_L2IP69%8fJ1usuVkdT3P}4pn;w){*FVbA z;c?cl?Yu%tFl*@=sR^;=enXD{2lpvXDeR0DxmF_CRbeELnVe1j+UmI6l<$9I2W)*a z;9i}*n{`p8C-TycGQeCR4y0!s7wVOCuFJ$#Iq{ci4*9uI@h`uRq2j47OH-y#D|tM6 zsS-=@d5SEbKT} zJ~e+v8=59`g&`H1aFz9vooj-#cypBp&+%d!EtNej-5hYip*h$^DvED_r)2uPLqTR& zW(xiS8RC+&PZ@XKV1sHKTYQrDNa+$3agAwRd<5AoYN_5r5-3K5+=9~+N81$Xmw9fT zW?a(sBz+KpGE|pJfD%82MkxIIJI@&U4^~6I%i6H3B7YQXfK2aLdcJpz<}Jc%HL{3u zTB|zFOfdz$^DKlau9Win1qtiFM<&L#_NP+E9D&vTnKa@%NE#WQ49tUS+8QOQuchN0 zuReXNd*`oJd%uJg)o!K`$j>D5_T@F({>HlC|1D{hQ5p(q>n6jCc|Tq;w5FHjoe8K_ zI;4GU4B@+0XW8dSu}HL~u-vAgvE{dzz-EgXm@Nvec+iu@$GAN~UVF~*VZDeizax@7 z%lJp~Opfd9?HfWf8$(RAB0Ul*W;P*R-1XfZSJM)JT-6_#0yaMfa z$Urw&1(up7(ID`>`-DrD$cKMr^zKM~@7-_jSM@A3ZRJ;xRS$o%Nt6z~ywKjpG(-C% z;8UU9FFbC-HkmL&!x{5~J&$(5wdiSE#6b2Rjb&YP7%vPnRcpQ3CEFp%o}LXX`^&dh^@GbwNq^Xf^pdGFbk=58=MxEL9bd!Dp9#cd zN+-1t{Q$3}%)?TAT^=uVYds~Jm)Isj1462=)VtVB)tjRJt_7eohRBK{NkV{wLeN%h4rWia0N3XO1EFp8NUkZDZD0@%Jn|y*V{Za|NWPQcirdl@-L_F zwk3a4vcWy)Qht*tH=V407>{3sDKYdFd!SWUY$3%|Q%a?K7>y5eKJiRL0;m5fI)MyK zkQmrj|6ETg#5BFYoFlC+3W5*X6>s&`l^9pW)$x2^V{QmNn-9WkRZJE+oEG0XrOZkX z$?I9It{23BR3IO-UKdHAr+>pyk$S(OFt4!bb-qIK5vWgq7PK*O2p|7BZTE`MCSljt zf9F1qtf5;aQTAEQ${aK~kF``+*RNzjTVPY}ZADNS)IJZzPHifv>VISMdmfUiN0s7U z&(8JEvR|e_W4jaj?riO+wrEg~#$@3mZBU{8Bcbq>L^o4u>6oWHWh?9bz|TcRS^oiq zQ?v-Id7I_K_2V_Di)!YT^OA@`qacD-2$N58j*gC6yN|r4%};#R8Ejj!ew{o-EOzl?@Nj>#tedY}EPVf9Mg%1mr6H@ zH=gYVe|^XBdXE~KMD{+=49*8CJUxvrw$%p3%y z@e==9h?iyE9}rymPd$YhCS&t&??ZG=o)M-Id(&;*F{VUvZrw^7CB?2PbRw%iiw)hb zv^DDLh}U$V=eOPo5|EhYO>^B`Z&2ukJS^9M`&RNP0=G2CErFbLzU};9qy1X~L6HeL zyKX<0*a+Mvp(mQ2iSy|{BmD|5UFlPOCyzypRPUuA9agQk3+Iz7Y+$N{8;tv0$%=rS zw9Cwv3k?3ebKCZ+?N<8A(}$*U9U@;~2z?_vKNJEb#zoBk8B2H*bFsaHEn%(TzlZxt zm{Y#hK~DPzlX#~4-2Fwyq`-8jO#ejp;^;p-&y$F%JJG=;N%vk6z7~y)9qcyWz@3L# z*p>CQgycxT>jzYxCbjfb#WZ9mWxqzI8b@ytxT#v$bw-tMZaCS`H7^l$$_PR42l34H zD`LDJBcJwzVBqiP#RdEdxnLSM=SMsDqSv>-%{?+A8n}Qs-<5T^=A%^B_~D^JucolG zYuLn!v2E6^M^>ZX%gg=WUe?abTgsuxb2f9QmfZL&j$$O$U1CO4J})F zEiB%uSeov~UsU$V*=t-(z*~5Uq&kl#dd`+oOKce@zG+=)#;-f!x^njx_EJN{Hu@Jm z@MT{=B<@Yv#8;S%%O}mT_el~CZ%2EsrGyM^Z}XKcy)^V(kz&UCCT_3e<9JtJ%;U51 z0$=xScHc|vzEySK7{xc8O7vI>@!GMgz>lcnI&FkkXSA_+yfvrW@K#HO(5}Qp>>F_k z)Hp^5XYpJzsa!BFB5M;RnN%a~edH(#O;1IES}#vd^=>96#Oe$U6}g}ZDZUdCVxM8; z2!DLV4X>D#n^kLkvlY?Y=vlHKH#f?eUTd@jy;r*Q5B-*Zfe zc%=Kv@>e*M+vf9O(RrD)iP`-hr}$(Sg=0PNvBMjri=wMyHhY~m%8BmHv%^qFZD)b= zi)3x%!!6)fgEz}vv(vUkCdqMsGtdsSZBebG)0l&BjeZ zwCh^NSgx1r4Q96p-Nsl*P36_EXoWZN&QvGvq}p?Fw%W+|QC&59p^JG4UL&h{G?9d>wMat=p73 zU0NyftQKmud1OC&32#Gxrwjzx#(i9Mg5l%d?=*?c-4teAY`a@a`L@;Yl0&Y?V4}<9 zv<;qwd9P9~cYiG#@37rGEfDR6vm4%*V&1NEN^}`y7>cNq7+$Ty<92LB!^>S4j!CQ_ zk2>K}nFlY^&E{9Eu8@1}3G5EJR4B=geuisZd)YonvzT!RHySWjXi$?nl zs%%M->U5eJLZI318wtsAjhE4S*Ra zSXj`v&zx7w@TM>|Wg=`;^2YQWe})N?VbLFUa2)nzZCmh*!X$l!Gjzy?`NG?#z1U#; zM^U82?^xSjcaq!Om`%WBnxGXy8fmOw#)iTF3nE1HQ4nmEUU(uq0>j0E=E@^_sE*bo zrX%XQKb)v>3TRMS2`gQ?#F4E#urAYDE5ygoIA&YHdpN&ilSh_+-HEF z8dH83WLB*hUL6&(eooL?e|C5No9})Ue&TCKt$Y6z0Wn`qAR3`-Uuv_l0jeJkePRfo zzJ*Y=EeQx3TjIY-!O0C9)*<+7g^H!k;V5e;MLIvWReZbNYk>gQ*HgB!KD-m}HBzUA zd$*LgRs<3*zRk0^eJ9stei+A5q3+E3nC2iupfXpQXf6RQzeU6^r?pfXWT{F?LgeOZ-5Ga>B05>;A-}i3vZP#3p#~69sfu zjVq+-HVY;Iampx7ub|)Dx)9*S^v(W;@~ej%f%pC3-_e;gTSE8?4eM&pDK<8fQKU!m zDOf(Ly(o7dD-5miXyhMn8&_|iN(g2e)TGUp#NeYbuWgC?|B z0e;rpt+yro08B-iS)~2|Ia89xf4R}(vquO`?6jn7c3(6icJ

OOhL z9n2wcU1Y~r9tDa4uK76E^T(_Q+?fiC3EovNmA>zUT)LG@)&*dfqd@;K4BQW0G7xMt zDukWl7hDflDs8JIT-xC;+9q`TwTR|`LR@XfEKVa92mYovnzZo|iGu^SQ5|J%3vND} zf9m>eI73ov3paA(m?UcW_b?h78*>gn!B7zkN~Lc~k=(`xU@!*kMDFU5paMgf6P9*+MwXW@q&X9lbh z{QHUi6@L+ zCLG;J1-j~e=X5^b1r8NiRsklxgo1bb76S0A%TEx-e*sHKQG>3E7Z&5n(zq{-hD#z| z>wS%^jV6o$`MZ7UP!;_yYw%a~#!SMUO3m%f4_KS~5K(aI1G&vozJDVUeJUdHt3^KP z_KkJ!X9o{kp8vNVOJ6%(avT(7((V5&3f8ZW^V1U`k(KLI>GOj}?y@bdX}#jG<}gtS z0hG{D`*MfqDC!ZgF4uh4=O@UHcn|M=`fC`xuuT{^>E1kZ6YEEn-yO9LKAvfAcm|?~ z7=#So82$e<I8mAF93$2Y!+ zo^j62LX=z*JG_|H5m)$dGXKmWFZPv<8xx@gNeHnkOtzjJ2Mq5(1nL+!RE;x@_UYHN zS?0nTBkI?(N%tBMml!Dh>~F@O(hg#@xuAvtYHG#dOzlqYD8^(M(~l zk-%e!bdlz*7F98|fW|R>S()qcU__;O1ZO|7X1eQI;Y7vq@g9aSVli}8EDf$k?9B0W6EDDmWoZ_uwN(2bbg$wH)gZrl{}JKZTtLIiaP{xE2%t-Iy}a}A3Q@qFl0Wr{XN{g)8g5=5KZi+*N7$sGIU?^K zP|LqDG3}5odElQPTipCP``EE=f8W|7z3lq_wMSg+;Ou^-dE#IA%R zKc>|y`neS4l2njghzqMy9&ncq8n^U%>}7ugaOkBw#T;t!pIM-U9IoBh$~_i58!YKR zRo0A0^{t}}z=+))O(yIIf^y#%e!T1-N;*{p3P(ycD;nVj$$u%yFX#K%P-t^7cI#g? z-rHNj-DFRNuTmc}C4vq7NQ$a4UCC+sp8nkKPHfbaz+}2ybBHR+;wq#jG!) zf69ATwgG`XtU@koA>box)+>SiKuEhu_S$;}PE92Mx6%M-`2EBtm7)pPFz`ajB=ZXI zVV`(eO1SfqN@LXv1e5i}tN7QQDgN|CrDZhgQWXs-`&R??3%soxzyX_pMK z-rpsnpi9DNzcDAq){VO3Q^GLE2JqCck6>kC3l4>0A1q?v1>J+T|K1C%e{c8pOdtIJ zpn^Zy5%AuxgwIkH2p_T`w!;-+iEQjc86O%@pTo5#q=y&r8R-9!=JN4eImDhxd~gA~ z-3H$ndh-k;wzy~YP$K^}3a!Hq52raiS z$q0CTnudXdE%X#&K&Sl;kCDi+0bgIiiK_92B%NMjCE!j$67Gb;#r+FtTjA^Q)-{0g z5f;^3k(g=N-#|tr6a|f(J3hbbm`%9Yz8;8-3dxp7j2H|g8Y;EU8+3>%N$p3NKH>aHcIDV?2 z^(E-6+I~9iHOmuP8G8IIqi!ya4{h!;ncI9GtkXj2;1j~NZm4gw#aVxzPkyonYWG#FH1p?2W zAY`@r7g;&^59NIVcq+BWiaQje$-=E7nM4&kb6N(T;zFNR?cek~g*p?2yaWg8_LCJ| z2oYjw6>lBhhcI?HzL-((w(EKwis%RIFJ{&Z#J zk!|OlFBIwc_=@9>)Br}?1VAN}9vwXjYdym>ukYRyIN&__XBdsUHr(NrdaxlgLi;B! zuRL@JyYj`+wXB$=PS8GKhzaoHT$-%#8qw9^B@nV{bv^)fp=9!~9K0GZeR{-Bpf5Nf z6sI{@)zZHDS&4!XqA=A$RJYWeKhrnQ_kjSNltDCd#713Esf2pMagSr`o-zvkqI?Xf z3ZbVd3cswxOE78s1kFWF7!Xd8ZZ+@G4~&nEtF#3~8T%&;Mbo%^9nZejYk2|P=ppI} z`U4{aS9bfx4$rg78*pdX# z@K`0q@w!pp*=t`J^{`PP_YQDKWOslGpfGsL0gRL4sZ~Nd(h>&Tp-1gIG3%QemvE@v z(=Uobwl;XYj|Mg9;rT*8@2i)86k^;)iQT8oV!5O-FgQzt(vt=>70nYkhAlh^YfR6w3sq?$KWr)hp zMi2&ZSMJ%1ms_1h$pShp1qG|~w(<5T8qkcycgdP15021CwN-60 za4P+qt4gzrPxogvpoIN={sPg}8oro~Fa6T(glh^(`mAkpXVR1qCQp|FTlwvMgz`-I z|Jag8rshQ@5(K7(;F|6ofE14z2@T}B?RDS|Dyz{R<`;l!FQtehli_BYePu7_!OQZ0~RORdV0e()YckLysQ zYM<_Hb=Hj^2n-WkMjeBSVA3%B@yT_W`_Lhv24lbeH96Hj2-K3_K;#EtE@U0#V6>Yj z;Z>LlI9QNSoaMnE$8XI2_?yhm+w9RkN;~>Jw@V%$P{?a&{P!9^;)bNcB2k|3K~WFQ z8vv;R)m-a0|Fkg#i!{#E<})7X76grV?UqEL1VM<*OJ!`10e?KD5DoL4phS@=83)UIPbZV0h8~$?2HX z*)Y^$Ok0(Vq;FO(Iqx-imFO9?@}_@iy*5tssrHK(~1lXI8F&AnMF zDXpCT`49VrZ(kA$vp*yIstiK~`GR-Owwg9FRDC@-WI)g6fcbBu>$K8}!R}lpeqYEM`SMG+xhNVDIy4$XP@@EBF z(a&$@+aAy=G*DJD>EZWC{ztiYfuE`CAsUcp^R|%J^3plXeOk~Lr>+9?AinQm#OoQx zl^F>xcw_QG&#&`?r@$Cz_@!3LRh5OcjdwqP0#UE2s7YS#xT4vw9BnJ(zY}&co2p3j zI7&M9`@a!^#{bBO(l5E5krQ^m;UMT^UO3v?ckos~6Q-Z}#gZ#E~8 zX3)C-LSNn}p`2F9$Nr<*CXBE8q z2(Quy5qC8rBEKS^WMar@Br$hnQ&{H0q5bZom)E>{3sE@#wgoSN*&h6?iYP%Yl!1P| z5K$fdKt48ASP}_)q$m6g`+N{hG~!E;IW*TOR4;`o41utWm#!kZ%ZkJXM!QAeaBU~B zr+vXIWj2zqWN<|F!-0_Knnr;yVo4FnEBZV7A&p($8X*n!#jJ9{_XiXq#6kLz{AL&t z#T3Nu`D-!J=LQl!@yhz14z?J=0sBdL2j&X5_AZ!1q_6YN$>fP}UT* z(K|)iB*aX{GVB%x0S%f^JjB=pck361b%r>3QN*Ir!&(Q5ABZyTDKUHKNWY|zj|{{( zprUzs-Ba8JV^cYp&ST9@n{i?ULfCd{%~m^%E8iDE6Jog zCUVD1E*`344Z<%S7V`h(9!2Lw?&kXp4Op@n#q6%jU>({<0x1u;y7U62|$KYsdc=F$~}YKOSXukMw`N$_LtCfS<)%Yr0h3R|njfBW4bxYOZ^wq;dgte>umEu-xL zFZhJ+*Tdj3_}HNqZHOD0gnICl3f0|d@F@xja4OE#!hn(k=?0B{HB>R$NDzVnjgHx_ zx8RyLNUoknDW{Q0$*IO&r7}$#Y@3&mw`9eZ6F;j}AncM~ZBX0=xWUz?`!|Y0BsTXm z_qe$a@<$oEQ3lFGkM~ib&an6Oh}|kCq%h4s0DM-a%DsL=2$xZPE#OAHeAvY=KsjBp z=8=CDK-8hD?{PUPI0Kc6h-QgbDaueDAG$M^fGG~cNG3%xhj4(ztHoCyL?9%SP7CH( z-gW|MFK$dWJXD_uidp!XV(GGb{HHIbceDk%H!YfU5rPI^dg5$%`bs#(_iMd~_JUxj z+Af1u;m5D=%p13z55WgJ8UuSHIyf9qqMPw?9Ie9{nl)SZH14doWYVZ(lPd(Q(KCqV zNG&Q#*l*B*`wxX<`(|H^?P9>{RbTJn8P__XE+)ww7O=_GAnuUF>gj6{cD?mH607K4 zc^Ni*7;e4$yQ>#MDG+}8Ru`!}lY_~5pywbFJr0bIU?U`&=QOKcSh^3>u5u_$V>}ua z;bY~`(Lmeyua_4>-zXzifgD&EMiBIVTR;L@tODaDse6hC*oyEjq;6)c#TuiE4Dag` zMu;r{&?1OG;SW#Qz*EPVj<&^$Y2O6-g@B2<*J$HuM=fAAhn|GPJz$$r`MuQ)EMGZb zBX@=z*?LQ;Z@PVwep-y3+&3 zE1f~J`B4R&mM5@h3CHN`V%;)I|3#k&-q86#L8^3u$V)P&k(ivEOK7eEE+Irw&QO|i zqZ>88>yhOowD!Y2A0%);XEHr9cD)d4K^Hxg_Xvwf5pe5c>~(`La|*5I^!`#w_plBQ zgO-MgVVKqTMFj8*Q$5H$HdpU9f6f@ll35^%*srFLy#7VhY~b4oc>KN^obNG%%FiK) zWRZ^Q(KO~BzV^VI^6dE>k@NQ}DNNM{Nx<93G{G@>3FJUru>hvuSY5y8R&o62wZKa= zlb?_TD!i731FqglUupUcjkZ=#Gm{g~BGqRk6HgZmHa#i6qPn*>GU5o<0dP47s{jPN z^5;1%7GGDE_&v?>`o|uMTc#4auTnn;WHLKbQaoy{f2V5|SwbxztR^91HUA%*2%Qat zl4hxC!Y)3FE1i2&O-xSLoSq)|NZ{Xnk1OXQ|cblIVJ!7$mwT0N;F>K`I{5Fw$EJ29n>iYq=PeK7C ztbw^IZkP=4p$?_<08aqkiOAa8jy&L^gWX)d#HOg6bmRYP>$~Hr?*I37B0FSei%@2E z=1CJ-$;g&n=CKK#PRhF{d|A-r-whp@qVr6 zysqnY4))vVx;U}=GrpaBkBo6L$O|f&>r>OBRUuUT;(_h-)P}&HxOdd;E~{aWYQ7EX zA`n81uWuw0=>C{9u(Y<Fh&t!ZLwZc3pR6VWaFONuv3dr z0=#x%zO^3(Cum~GTZwRyKzN^qCxDgm^jwcgL6@P}X3G;ki3HS43=#!!oA98nmtOU@bhX^-R!eiq|T!3O@{TeoFY)7b4h$BR3A=C+)=q~?V6M+D&*#cvm>z>5u+{@#orGaV#QUDbu0@fjMbV&x~6IDxP=gK!eg!}ZHrC>#_7&K8kt zT8H+p^B1~Ua(iU=S7~r_Wg24UP(Mns+R}{9yH8OLXZnm8bHmPulP6b*AE(J0@KXpl zKD=v0)>YXue7oWaB&}&^FCEOHzpg^1=&Ms*zIiYi9%FczWe}98Af+8T8uhIm7vRW% z?J4tI9+hqMNO_DO(<1B2K2B_V2--mPLPfW*=3+AjWhP|GYdcS&jOUTmZ+~x_aJYIT zd^p*!?VI1684g5R5Nycm-D=%br9}ka7tDuNa_z>*=Y~hJ>fgdPlkV!_4K-NE`G{vH z7Bh8_;&P-fMb0M6q|;Ytfhp{?&Ik15lEeu?6W6uB4{fW94`Lh>O5bet{q6;Fh`r0c z$x1H^aVfMp%^WDGJP)~0(*~pjJqmkB{W>Kpf1NV)TZ}VH08|8seRlD}Gmi6gS)9zj zf(m4m^YDkdS2g{@I1JqUfUCusp5oW~Ht-};BZ z7pBCCC+fRBiu3gR2$d+ePGXJ2T7H^*sN2|f?ki*L`ibd;8o=M1C?@3T3rFXE%@$QG z*qQ);fmMbO5ToGgYO#C*MeWIQAuR$nSR4%*veo!@c&7~ZI%CtsNbx&;e*t8|w1S#2 zs@eJE;eIUjBtgdxf7g(!u8yepArZ61yjxXq|NwzlU6k2FuWk^k%I4K^p><7GQD zv~Kb^@nPdAP0yQ7U;lGVE@0O#vO;p|3W@QnLuwU^A!#vVu|Io>$7iS|^^>d$6M;8s zQ^U>=-;XPia^l3ckVCKC%yl@bDAqt5I^5*0RY@Nv?Id~f(6l@4NvaJ4;qfT{Q$QhT{*jzuNBp6)HU zPS_pGLTKSBcygA#OE9)g{k&0>Sj;1XXX(sNre01@qSm+N~5m76?w$Wxh zQH2E~()~A6*i=)ds|}>u#fr>e(Tg``!m1sj@7~-Y#BADLbM6S{s%SdZQjFZf1?h`) zFvhPRc5w_HkBOYq91cL8Xm22T@7EAhx)rmkip$6|sRL($H? zJWfZUbEmI=h)(?6ER&gAX%88gn(?X_q1Egoelcz3>UG!xw!UVElpchQO87dqyfT{X zr=+;=H@wA!f|sVNVVA#$v6a15bQMc$FjUr4C6lU>=P(|A140UPx;u9M?Wok_IalRd z){!JK!(u+RUX9TNmj_TjqrL9(Qfo5jdg=Ca2T(uN2Yz>yND$^K#*ewkr<9B6j8O-( zL2VI*v8!HL-CL~XXq9I#f+!v2Yf&F?)#%`J#N($iYL;h%J5|A>(t}s?#Q2Y03 z$5Q->qx8ui9)9vrk4^Um3Oc+yWk3sU(Y7FBh0o4dR>yghGvF{cu=AVM7s-TL`8<<9=-i&~~n+0c)ZC=-hDJd%>d#UJ=3X=p0(57mRH=9r+_+Pp(VGs}tsGSL3 z1SGzV7^6QxEgM(Q=`+LJYDSl*Z+1lHAtH8(@x7RiQB9|(l`EBfc z>?_!w__VXHQMa5TNs2%6==e)b)fpOw_GdP`5NZp-&4*}`i|GTyAz*{fcN*-1D_Kmc zPQmD$jfC2>&y1tqj%9~z9gYzhBQp$fHJr%fO{5!x5(=+E4hes|U0Ig`BGtHYy)MK0 z$Ge)#1na3FiF|d zXzdh^h2B_4B(BoR<<$U}_fev{n%V2U^z9__B28|ei|K3TrB{oi55aZB4X;^lsq^s= z8;0IBp>EtLy2UNq5ty{?yjZI7j%>4caNA!cvR`T=2p$NK`P$uDMjC7ZFIW(WT>>8% zAn1XoD)@k~O_q$Tq7xf7kId%ys{oo3M?Qgn4gnhPgNtOfmg#w2xlZ9NC`WMRH}XCv}LsfyQ&PhD4#0H}=s zMl&bn_IhMb^|yU4piW^bbr0k*qUL$ogVw%Ia0;{s3d~57C8twbl+7X=?ZN^Qk>Vct zmZ1ot@E39s7QUGgd9BLQy|IV{=L>N`&jX=3)^)IeWnXrt>`zIBw=*S}k(AHCRKITp znc;2Wc`GyGZGot}e2-|eIvqXC%)5V=F(1$7?<#cxjkB+RIpz-t!f>FfcH7@tolVM` z!`>Y`%IH#fs1C%Ps5hg`%hh`PfJbM8?Z}KpG{_dMV{u7{DOvhp_3XL2XT;2sV}|VV z(WsCUa&l=05gP2ccizfdkuXnK8+`O;4;P0jFiMajFX-Q7h=Z`;qRA}EL8tmF;~mGC zc*{c=abd`}gcx4$1QpgaB@g>pZsqb@Slx^#EAV%1GHEY1VaRk-EKFdlq4z_3WWV4_ z5b(DHB%MfTc>4XC*kQECZW9;mwU6%Gi0kC>j~ODbkWE%zt6hE{(QDdcAlr&>w-Y%rIPw;utu&c z$D7Ipq;x@ip`ZpM7TWjo{p|T6MKln}ffGIvvR{=V#stGBoBnv=0KrVM?XRbv2*!@K z!g??>iE7{Y(Q||HA=*8e>xTaio13M+c8Eq3Bw=Mg$p%W5*)037{6!vfYUClhY0x>9 zKr+2OA6uz|LLMau+lycjEXT;d;?d)XXxx>X+-m;vqyZM8frANO`5gI_mG}sL- zxB7ELDSB?MH~9ApN3k7SvySJ-DRoc&*P zs;^1{gNkdb_6VNz%f@)85 zn>-;_KVejLwqf7==Ov zRDhBkL6N|q+e2sMH^0Y)=cyOykrnNl-KSL*+c9E9z|aK-2s)ynBX?Lr?o6I>I)i$m zbZs-}O-{GI7X84DL)Rn1@*RA@7qJSHp3S^t!^6P{20NPdBh!>jG@zitOE2rZ&NIG9 z6|?-!!W2y>6QpbQCpO?me;-Wt&88Jpdp6-ZTq>fYq!5nqVk7O@&qA6gH+QKv1>O!v z$n-mT^P)(nm_>6~R9T*0!B6Jl2p*4Cfb6FEV@~I3S5|HjHL8ic&0-(xUUqe{QS8B0 z-L)=5Ygy6`1w>0~O|G~#P${{FDK%g8Q>Z9114DK8x?E}B^_=UJigcU}<2N}oVADV@NiYjxE+*_5H0y!s@wuT~6GIBYFhR0*2Ob6z`M zq>(WMk|Zk4k;T=`mUmYBRkx)j2?WXwb{!xOoT>5FiEiYX`AYn?f+&4Ji&t%fQxpu!} zwPuAbei9uS9Au}c!#jvFP)G1r&Wa?(ogbBjGZ@rOFN@E4P@rQqfEZJF>8b}AqD>cK z-pVj58BG>UzNz^rj1|RbRORr{3hmfGRDHOq&^WrYzxybf%r0oMuw05mmAOhU{Jb0+ z6t5UDHoUxW$91j=hX0VuE85UkB`Z>7nf}}` z-Ir2&OyLa@o1;LD62q3{Dy|c0;va4hj?Sx{cR|N?%ZVV0dqA25xCyqCLSHKV)Pu3_ zHGTS;p!wo4s?BV{@Z&1y&T%@_2Qq++utpxc#*Y@dD&Di|+;sxb_pR7k^qey0kd|S9 z*2mHKyVe0mB(99jil}O2ZFCR&bl?>7BSi*_nv@)^|)w-lxasxDlvEoIt4XDl+LGSV4ypD@@PzIO%plR z;J7WTMM}5h9WyvCmI$OU`M4^-`QZVS54`;}LugRDkxm&7XunBy9TqN0Qz8T*vKYbq z0&D+ZG0c8q$(M(+5c>CC9RR) z*!Es!eN?*H9i2(%keU^u^sjU8uTG*L636z^Sn3`Ye(x(9{yKVJm8^57sO65KBN*+S zIFCR9Z%tsL&?Nu^wy4^%M&j@)Y-P1*&{MM|3Ke6~8pKe)d~08w{j_CNKL33D++lUY z-DZZBi!j{K{Q2{;;qh#dS8=^mK;oK~%i)JjN;!SWp6_eayj2v)RqR%^!+4dtc**q| z135|Qbn>7pjp(%64P&w*7xAe6TE-#QZ%9uVi^5kNxvX1cO4mw#45M4Rz-Bmv55P)h zGhb=XeA+1&5g*A*@L7<^G8_3EVaj;mZ!s~acf|0k3bi@PWx~-)Ch4-Sat6hd&d1U1 zWt7&;f0*FEA`GM%bFcEg5PDGwRYqC+mR%{4jfz2aDGaCl z;b?4TeoZ5BPRo;}JSWM3XNO)xo1+D)!0w@NzhE(WITi2a@j7WCNdu95(S66=6K+B@ zy6Ej6G1e&O@&-fmXF&f@-*DdAn;V*>o zxf$!t$Xq^2=VC&z1C%AROo6S~Ige(c!H9IUDWwff6GiQ(gNp-%%()RQ_dAKZrt zc#tV~JW&{}%%7G<5#xjG4mz4w!y`GRkE3-bPZ;KD`d`j?tWeY zSd&gU>L7#T`ZQ1U0{m$x*;jD00?lzdpBn@@H~|Fmsw`DrcM_z;Mo^em&>!qsq-yd< zBe?4==OFgW?T!7u%yKDl5*nw$36qXy#_!BeKXNWaQb!EzQPGyF8@`$v0cu>IEu;HO z+CCP}p@fpUpIU^=21Fq=E#ibyrl+Yu+vCwjJ z-CXA#S55d|C(NDA<$5f>$vm)k=9fUj^?nOc$CFn3*AvO%5(N8DvRMVa>~|Rizdv@$ zZ9z-1N?xf{@w}I}lnR~mfu$7dhb5D2{V?>L%W=L>T=ng6VGnLYh*y=L`f@T7*U;VB zX!Q$|-j{gKpewzm(XRMSjdS4265udUwuqBq<1N&ye$8!ePaAf#*Xefdn@edw>~Iro ze$+i^B*;O68LtL{Lgrw%!`=>}N!otJ-Qb{&&Q7ihsasnfzs4wAxsthD_s@IydyZ?* zx{X&~bvIbwE~jpa6`BJ>;@d03$Y};ord``!&ipX2=DvL+aqXoCM>1D7rHad69rM}2 zh9VJTzVeb{d)q`r)KY4fF5FBJwRpcA!NylF+?O~~A6?g6 zZoN=$=2wW$X*+HUsKzY)AB)B@l^Si3ybBU*Wb`5f?kW|{pW5(F!M|#y%2hHe zFV{*DVb=<^j;5}4YHx;l;;tPGzUS!aJNi7FTI1;R8Bh6y>o*$O9T+Yv48E`?s(60t z1h<*?o-IXXj#*{vWvbu7No&h1H?KOARKFGoTDqd+~%(E1R>*;$$=Ts zPFDPpquZ2uu^^?_LHL$$7Z)G_>R}IHkp+or|at@eh4dt1d%prtkYGaykO@t zYnL)+*Rm$p{co6qkw*K;y~jyhxyhUL0#j^-yOw3bGm`ilQ|JN%vz=sT*Eb{u6$aaK zB|mL_nqZ!!=0lb7G*4r3hT_s9`70g`b`AJQ%vMN??KgboZNIdJg_|?)ns&_J&@i&~ zNMMZtfn&NLM2cZO(Uq;`42&LJ0|2k)9ZNeaUm!b$c44@wE@8zZjX)Uv!zLW*tVCS} zeOb)}{NgZ=q@Tb}SX%CXYvktH8OLno?@8jRGS+bYu3vXk@EGSH#m!qmIt>Cg&x!j$ z?LihZi59BhrY7&p>gf#tH!ZLEps-v!@jX6|LPPJd_5FfiPlMD@4FIBXa<86W$mD9$9;Ho8law^R5nRAf(`De2496ohVhR5wl&xr>sK1x(t zJ!?iGXUI_>Ar*By3*RbpF}QB;)$DVs{&Dn74x*7}>#@fzWNik4bjqo8Q(Nh(=9yqy zVZv>d!={UHqL8VrdDxlIBD7s~~n?##E^|6lRkubygabg+rZ)2IBj}o%gwUsx;dA~(y&*I&0UUmnHtn-2j z)uoQ(WefnmL_)){Z)C#XRzf*;iN3+0Rs&T^{I2wat13 zVz7o+g>QHl@&~)RDz8UK^9h>7>{U(!`wd@>qn>gJZEqcucgoxYIGAqb29c@1DyxAq7_&0yF z+Snj|&gJ`tC0pcvaIl!V^>Zm#=trA0$%;+;6o=s3sf4RCbPbcI@of`uabQR-u#I?;Lygn;2Y({KC5WYYUI6vD&e^yi zfxY@B`b;cxR}4-W^5)o^PQZ`1-*EtT&gXNXSZeH?O*Z9DwR5fk_mH3e?3-mhi>JYJ zn~Qq`Tbr9fK@%FwYfmK3;)Vaq#yg3?^>e|&Uvd$$7QCXlX&v_*CaUM`{nuk-J>K5K zcqTiVIwUfrWKC!mPG+UhhbA)Vgte8^xUF)&cM4h>8pyGUEc)N z$ISaBbiG$E>GD*+=rd{%laiUV%ZxS*cHU#IJ#Ru|{BEWV!Q(3efonpjTh z+bMtlen#-K=ik=ZG|~T_gF_k`NI+prc3dGI^1T*+^x9dYjP~hz1#%Lk~^P!Z&@Kf*O3qa1_Fz^uEX zM1*SSU%!Tgl>utV$h6lIzkA95f2<>@5V&4I9mGsTc;NqC=3z8kLoQC>wDlAI%kK_H z#MXi)_gFP0(SO+3|DDh_2gM~WFxTTkYN&{|FQ(aQv*TSzrL)e z|C<>5zt2ZzX1N5af!d!ac#F6HJ`b!iX!Evzy*m3Fm-_dD#eG2@JmPbN=-<0U_z9W| zrWv? 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 @@ -238,35 +242,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 +272,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. From 3842b4c75be349e1557bb281e44f6eee357de684 Mon Sep 17 00:00:00 2001 From: Flynn Date: Sun, 29 Jun 2025 22:36:31 -0400 Subject: [PATCH 059/148] Oops. It's GEP-3779, not GEP-3379. (#3888) Signed-off-by: Flynn --- mkdocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 4688e7f585..1753230778 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -130,7 +130,7 @@ nav: - geps/gep-1494/index.md - geps/gep-1651/index.md - geps/gep-2648/index.md - - geps/gep-3379/index.md + - geps/gep-3779/index.md - geps/gep-3792/index.md - geps/gep-3793/index.md - Implementable: From 564720a533f9ff28e65bdf898c1274ace1865245 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Tue, 1 Jul 2025 13:05:25 +0200 Subject: [PATCH 060/148] feat(conformance): validate implementation flags (#3715) * feat(conformance): validate implementation flags Signed-off-by: Mattia Lavacca * chore: gofumpt Signed-off-by: Mattia Lavacca --------- Signed-off-by: Mattia Lavacca --- conformance/conformance.go | 5 +- conformance/utils/suite/suite.go | 26 +++++++- conformance/utils/suite/suite_test.go | 86 +++++++++++++++++++++++++++ pkg/test/cel/grpcroute_test.go | 3 +- 4 files changed, 114 insertions(+), 6 deletions(-) diff --git a/conformance/conformance.go b/conformance/conformance.go index 12e5884968..8ea5799e58 100644 --- a/conformance/conformance.go +++ b/conformance/conformance.go @@ -72,13 +72,14 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { namespaceAnnotations := suite.ParseKeyValuePairs(*flags.NamespaceAnnotations) conformanceProfiles := suite.ParseConformanceProfiles(*flags.ConformanceProfiles) - implementation := suite.ParseImplementation( + implementation, err := suite.ParseImplementation( *flags.ImplementationOrganization, *flags.ImplementationProject, *flags.ImplementationURL, *flags.ImplementationVersion, *flags.ImplementationContact, ) + require.NoError(t, err, "error parsing implementation details") return suite.ConformanceOptions{ AllowCRDsMismatch: *flags.AllowCRDsMismatch, @@ -92,7 +93,7 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { ExemptFeatures: exemptFeatures, ManifestFS: []fs.FS{&Manifests}, GatewayClassName: *flags.GatewayClassName, - Implementation: implementation, + Implementation: *implementation, Mode: *flags.Mode, NamespaceAnnotations: namespaceAnnotations, NamespaceLabels: namespaceLabels, diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index f1164fa2fe..2402821e6f 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "io/fs" + neturl "net/url" "slices" "sort" "strings" @@ -558,14 +559,33 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) { // ParseImplementation parses implementation-specific flag arguments and // creates a *confv1a1.Implementation. -func ParseImplementation(org, project, url, version, contact string) confv1.Implementation { - return confv1.Implementation{ +func ParseImplementation(org, project, url, version, contact string) (*confv1.Implementation, error) { + if org == "" { + return nil, errors.New("organization must be set") + } + if project == "" { + return nil, errors.New("project must be set") + } + if url == "" { + return nil, errors.New("url must be set") + } + if version == "" { + return nil, errors.New("version must be set") + } + if contact == "" { + return nil, errors.New("contact must be set") + } + if _, err := neturl.ParseRequestURI(url); err != nil { + return nil, errors.New("url is malformed") + } + + return &confv1.Implementation{ Organization: org, Project: project, URL: url, Version: version, Contact: strings.Split(contact, ","), - } + }, nil } // ParseConformanceProfiles parses flag arguments and converts the string to diff --git a/conformance/utils/suite/suite_test.go b/conformance/utils/suite/suite_test.go index ccb259adb0..69b7d3d979 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -538,3 +538,89 @@ func namesToFeatureSet(names []string) FeaturesSet { } return featureSet } + +func TestParseImplementation(t *testing.T) { + testCases := []struct { + name string + org string + project string + url string + version string + contact string + expected *confv1.Implementation + expectedErr error + }{ + { + name: "missing organization", + project: "test-project", + url: "https://example.com", + version: "v1.0.0", + contact: "test@example.com", + expectedErr: errors.New("organization must be set"), + }, + { + name: "missing project", + org: "test-org", + url: "https://example.com", + version: "v1.0.0", + contact: "test@example.com", + expectedErr: errors.New("project must be set"), + }, + { + name: "missing url", + org: "test-org", + project: "test-project", + version: "v1.0.0", + contact: "test@example.com", + expectedErr: errors.New("url must be set"), + }, + { + name: "missing version", + org: "test-org", + project: "test-project", + url: "https://example.com", + contact: "test@example.com", + expectedErr: errors.New("version must be set"), + }, + { + name: "missing contact", + org: "test-org", + project: "test-project", + url: "https://example.com", + version: "v1.0.0", + expectedErr: errors.New("contact must be set"), + }, + { + name: "malformed url", + org: "test-org", + project: "test-project", + url: "invalid-url", + version: "v1.0.0", + contact: "test@example.com", + expectedErr: errors.New("url is malformed"), + }, + { + name: "valid input", + org: "test-org", + project: "test-project", + url: "https://example.com", + version: "v1.0.0", + contact: "test@example.com,test2@example.com", + expected: &confv1.Implementation{ + Organization: "test-org", + Project: "test-project", + URL: "https://example.com", + Version: "v1.0.0", + Contact: []string{"test@example.com", "test2@example.com"}, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result, err := ParseImplementation(tc.org, tc.project, tc.url, tc.version, tc.contact) + assert.Equal(t, tc.expected, result) + assert.Equal(t, tc.expectedErr, err) + }) + } +} diff --git a/pkg/test/cel/grpcroute_test.go b/pkg/test/cel/grpcroute_test.go index 628de66ae9..2940ce3291 100644 --- a/pkg/test/cel/grpcroute_test.go +++ b/pkg/test/cel/grpcroute_test.go @@ -341,7 +341,8 @@ func TestGRPCRouteRule(t *testing.T) { } return rules }(), - }} + }, + } for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { From 63921d1e14fee57b6c63d29cc1dafeee461820af Mon Sep 17 00:00:00 2001 From: Guilherme Cassolato Date: Thu, 3 Jul 2025 13:19:27 +0200 Subject: [PATCH 061/148] Move HTTPRouteRule and GRPCRouteRule 'name' fields to Standard (#3826) * Promote HTTPRouteRule and GRPCRouteRule 'name' fields to Standard Signed-off-by: Guilherme Cassolato * tests: conformance: httproute and grpcroute named rules Signed-off-by: Guilherme Cassolato * tests: mesh conformance tests for httproute Signed-off-by: Guilherme Cassolato * feature names: HTTPRouteNamedRouteRule and GRPCRouteNamedRouteRule Signed-off-by: Guilherme Cassolato * fix: mesh conformance features and object name/namespace Signed-off-by: Guilherme Cassolato * lint: fix var declaration and comment Signed-off-by: Guilherme Cassolato * different name for HTTPRouteRuleNamedRouteRule feature for mesh Signed-off-by: Guilherme Cassolato * conformance tests flagged as provisional Signed-off-by: Guilherme Cassolato * fix: typo Signed-off-by: Guilherme Cassolato --------- Signed-off-by: Guilherme Cassolato --- apis/v1/grpcroute_types.go | 1 - apis/v1/httproute_types.go | 1 - .../gateway.networking.k8s.io_grpcroutes.yaml | 9 +++ .../gateway.networking.k8s.io_httproutes.yaml | 18 +++++ conformance/tests/grpcroute-named-rule.go | 72 +++++++++++++++++++ conformance/tests/grpcroute-named-rule.yaml | 24 +++++++ conformance/tests/httproute-named-rule.go | 71 ++++++++++++++++++ conformance/tests/httproute-named-rule.yaml | 24 +++++++ .../tests/mesh/httproute-named-rule.go | 68 ++++++++++++++++++ .../tests/mesh/httproute-named-rule.yaml | 27 +++++++ geps/gep-995/index.md | 2 +- geps/gep-995/metadata.yaml | 2 +- mkdocs.yml | 2 +- pkg/features/grpcroute.go | 24 ++++++- pkg/features/httproute.go | 9 +++ pkg/features/mesh.go | 10 +++ pkg/generated/openapi/zz_generated.openapi.go | 4 +- 17 files changed, 360 insertions(+), 8 deletions(-) create mode 100644 conformance/tests/grpcroute-named-rule.go create mode 100644 conformance/tests/grpcroute-named-rule.yaml create mode 100644 conformance/tests/httproute-named-rule.go create mode 100644 conformance/tests/httproute-named-rule.yaml create mode 100644 conformance/tests/mesh/httproute-named-rule.go create mode 100644 conformance/tests/mesh/httproute-named-rule.yaml diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index 0cae5e5020..c6eeb0f3ea 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -156,7 +156,6 @@ type GRPCRouteRule struct { // // Support: Extended // +optional - // Name *SectionName `json:"name,omitempty"` // Matches define conditions used for matching the rule against incoming diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 6fec27d6e0..f0aa550559 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -138,7 +138,6 @@ type HTTPRouteRule struct { // // Support: Extended // +optional - // Name *SectionName `json:"name,omitempty"` // Matches define conditions used for matching the rule against incoming diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 3bbc0af4ca..4f7d8f1323 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -1760,6 +1760,15 @@ spec: type: object maxItems: 64 type: array + 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 diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 7f3b970a7a..8533381fc2 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -2432,6 +2432,15 @@ spec: type: object maxItems: 64 type: array + 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. @@ -5227,6 +5236,15 @@ spec: type: object maxItems: 64 type: array + 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. diff --git a/conformance/tests/grpcroute-named-rule.go b/conformance/tests/grpcroute-named-rule.go new file mode 100644 index 0000000000..223e22b595 --- /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{}, 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/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/geps/gep-995/index.md b/geps/gep-995/index.md index 972fde1080..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 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/mkdocs.yml b/mkdocs.yml index 1753230778..7765e320d3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -137,7 +137,6 @@ nav: - geps/gep-91/index.md - geps/gep-3567/index.md - Experimental: - - geps/gep-995/index.md - geps/gep-1619/index.md - geps/gep-1713/index.md - geps/gep-1731/index.md @@ -158,6 +157,7 @@ nav: - geps/gep-820/index.md - geps/gep-851/index.md - geps/gep-957/index.md + - geps/gep-995/index.md - geps/gep-1016/index.md - geps/gep-1294/index.md - geps/gep-1323/index.md diff --git a/pkg/features/grpcroute.go b/pkg/features/grpcroute.go index ffa3f38318..3ee21b41f5 100644 --- a/pkg/features/grpcroute.go +++ b/pkg/features/grpcroute.go @@ -19,7 +19,7 @@ package features import "k8s.io/apimachinery/pkg/util/sets" // ----------------------------------------------------------------------------- -// Features - GRPCRoute Conformance +// Features - GRPCRoute Conformance (Core) // ----------------------------------------------------------------------------- const ( @@ -38,3 +38,25 @@ var GRPCRouteFeature = Feature{ var GRPCRouteCoreFeatures = sets.New( GRPCRouteFeature, ) + +// ----------------------------------------------------------------------------- +// Features - GRPCRoute Conformance (Extended) +// ----------------------------------------------------------------------------- + +const ( + // This option indicates support for the name field in the GRPCRouteRule (extended conformance) + SupportGRPCRouteNamedRouteRule FeatureName = "GRPCRouteNamedRouteRule" +) + +// GRPCRouteNamedRouteRule contains metadata for the SupportGRPCRouteNamedRouteRule feature. +var GRPCRouteNamedRouteRule = Feature{ + Name: SupportGRPCRouteNamedRouteRule, + Channel: FeatureChannelStandard, +} + +// GRPCRouteExtendedFeatures includes all extended features for GRPCRoute +// conformance and can be used to opt-in to run all GRPCRoute extended features tests. +// This does not include any Core Features. +var GRPCRouteExtendedFeatures = sets.New( + GRPCRouteNamedRouteRule, +) diff --git a/pkg/features/httproute.go b/pkg/features/httproute.go index dbc62ce1a0..6c484da96c 100644 --- a/pkg/features/httproute.go +++ b/pkg/features/httproute.go @@ -97,6 +97,9 @@ const ( // This option indicates support for HTTPRoute with a backendref with an appProtocol 'kubernetes.io/ws' (extended conformance) SupportHTTPRouteBackendProtocolWebSocket FeatureName = "HTTPRouteBackendProtocolWebSocket" + + // This option indicates support for the name field in the HTTPRouteRule (extended conformance) + SupportHTTPRouteNamedRouteRule FeatureName = "HTTPRouteNamedRouteRule" ) var ( @@ -190,6 +193,11 @@ var ( Name: SupportHTTPRouteBackendProtocolWebSocket, Channel: FeatureChannelStandard, } + // HTTPRouteNamedRouteRule contains metadata for the SupportHTTPRouteNamedRouteRule feature. + HTTPRouteNamedRouteRule = Feature{ + Name: SupportHTTPRouteNamedRouteRule, + Channel: FeatureChannelStandard, + } ) // HTTPRouteExtendedFeatures includes all extended features for HTTPRoute @@ -214,4 +222,5 @@ var HTTPRouteExtendedFeatures = sets.New( HTTPRouteParentRefPortFeature, HTTPRouteBackendProtocolH2CFeature, HTTPRouteBackendProtocolWebSocketFeature, + HTTPRouteNamedRouteRule, ) diff --git a/pkg/features/mesh.go b/pkg/features/mesh.go index 4d7ca20b29..910e3c9687 100644 --- a/pkg/features/mesh.go +++ b/pkg/features/mesh.go @@ -60,6 +60,8 @@ const ( SupportMeshHTTPRouteBackendRequestHeaderModification FeatureName = "MeshHTTPRouteBackendRequestHeaderModification" // This option indicates mesh support for HTTPRoute query param matching (extended conformance). SupportMeshHTTPRouteQueryParamMatching FeatureName = "MeshHTTPRouteQueryParamMatching" + // This option indicates support for the name field in the HTTPRouteRule (extended conformance) + SupportMeshHTTPRouteNamedRouteRule FeatureName = "MeshHTTPRouteNamedRouteRule" ) var ( @@ -103,11 +105,18 @@ var ( Name: SupportMeshHTTPRouteBackendRequestHeaderModification, Channel: FeatureChannelStandard, } + // MeshHTTPRouteRedirectPath contains metadata for the MeshHTTPRouteRedirectPath feature. MeshHTTPRouteQueryParamMatching = Feature{ Name: SupportMeshHTTPRouteQueryParamMatching, Channel: FeatureChannelStandard, } + + // MeshHTTPRouteNamedRouteRule contains metadata for the MeshHTTPRouteNamedRouteRule feature. + MeshHTTPRouteNamedRouteRule = Feature{ + Name: SupportMeshHTTPRouteNamedRouteRule, + Channel: FeatureChannelStandard, + } ) // MeshExtendedFeatures includes all the supported features for the service mesh at @@ -121,4 +130,5 @@ var MeshExtendedFeatures = sets.New( MeshHTTPRouteRedirectPath, MeshHTTPRouteBackendRequestHeaderModification, MeshHTTPRouteQueryParamMatching, + MeshHTTPRouteNamedRouteRule, ) diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index c91725bc50..99214c9fcd 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3439,7 +3439,7 @@ 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: "", }, @@ -5018,7 +5018,7 @@ 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: "", }, From 9f27e4ba99f1bd6ac2f04c7a0ee75f0078daa433 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 04:57:25 -0700 Subject: [PATCH 062/148] build(deps): bump golang.org/x/sync from 0.13.0 to 0.15.0 (#3889) Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.13.0 to 0.15.0. - [Commits](https://github.com/golang/sync/compare/v0.13.0...v0.15.0) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-version: 0.15.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a9db23934e..53b9c32c69 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( 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 + golang.org/x/sync v0.15.0 google.golang.org/grpc v1.73.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.36.6 diff --git a/go.sum b/go.sum index 2b6eb53c72..75b64fe43f 100644 --- a/go.sum +++ b/go.sum @@ -178,8 +178,8 @@ golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT 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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= +golang.org/x/sync v0.15.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= From 4dcfc5618b184c504228a900dd41167298b5943a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:09:30 -0700 Subject: [PATCH 063/148] build(deps): bump github.com/miekg/dns from 1.1.65 to 1.1.66 (#3790) Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.65 to 1.1.66. - [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release) - [Commits](https://github.com/miekg/dns/compare/v1.1.65...v1.1.66) --- updated-dependencies: - dependency-name: github.com/miekg/dns dependency-version: 1.1.66 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 53b9c32c69..294f724987 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/elastic/crd-ref-docs v0.1.0 - github.com/miekg/dns v1.1.65 + github.com/miekg/dns v1.1.66 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.39.0 golang.org/x/sync v0.15.0 @@ -67,13 +67,13 @@ require ( 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/mod v0.24.0 // indirect golang.org/x/oauth2 v0.28.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.9.0 // indirect - golang.org/x/tools v0.30.0 // indirect + golang.org/x/tools v0.32.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/go.sum b/go.sum index 75b64fe43f..8e1d8223a4 100644 --- a/go.sum +++ b/go.sum @@ -88,8 +88,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.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= +github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= 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= @@ -165,8 +165,8 @@ 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/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.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= +golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 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= @@ -199,8 +199,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm 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.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= +golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= 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= From 33e9aa990d0c159961edb123d50fcc2e02b86f59 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:27:28 -0700 Subject: [PATCH 064/148] build(deps): bump sigs.k8s.io/controller-tools from 0.17.3 to 0.18.0 (#3791) Bumps [sigs.k8s.io/controller-tools](https://github.com/kubernetes-sigs/controller-tools) from 0.17.3 to 0.18.0. - [Release notes](https://github.com/kubernetes-sigs/controller-tools/releases) - [Changelog](https://github.com/kubernetes-sigs/controller-tools/blob/main/envtest-releases.yaml) - [Commits](https://github.com/kubernetes-sigs/controller-tools/compare/v0.17.3...v0.18.0) --- updated-dependencies: - dependency-name: sigs.k8s.io/controller-tools dependency-version: 0.18.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 294f724987..0819f5d332 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( 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-tools v0.18.0 sigs.k8s.io/structured-merge-diff/v4 v4.7.0 sigs.k8s.io/yaml v1.4.0 ) diff --git a/go.sum b/go.sum index 8e1d8223a4..bbde100af4 100644 --- a/go.sum +++ b/go.sum @@ -111,8 +111,8 @@ 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= @@ -250,8 +250,8 @@ k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6J 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-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/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY= From 3c2c3d90d3a1ce92fb58f493e468f2a02fde5bca Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:27:35 -0700 Subject: [PATCH 065/148] build(deps): bump mkdocs-material in /hack/mkdocs/image (#3797) Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.6.11 to 9.6.14. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.11...9.6.14) --- updated-dependencies: - dependency-name: mkdocs-material dependency-version: 9.6.14 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 6164a48242..896f6e0ca6 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -10,7 +10,7 @@ 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.15 mkdocs-redirects==1.2.2 mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 From 67456850b0b8ebc0365d1de6b74ead35e5ae22e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:27:41 -0700 Subject: [PATCH 066/148] build(deps): bump tornado from 6.4.2 to 6.5.1 in /hack/mkdocs/image (#3815) Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.4.2 to 6.5.1. - [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst) - [Commits](https://github.com/tornadoweb/tornado/compare/v6.4.2...v6.5.1) --- updated-dependencies: - dependency-name: tornado dependency-version: 6.5.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 896f6e0ca6..4dfa0a2359 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -20,4 +20,4 @@ pymdown-extensions==10.14.3 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.1 \ No newline at end of file From 3987a0814e49d925e69438d847033d1e4ff63d51 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:27:48 -0700 Subject: [PATCH 067/148] build(deps): bump pymdown-extensions in /hack/mkdocs/image (#3878) Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.14.3 to 10.16. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.14.3...10.16) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-version: '10.16' dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 4dfa0a2359..3550d265df 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -16,7 +16,7 @@ mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 pep562==1.1 Pygments==2.19.1 -pymdown-extensions==10.14.3 +pymdown-extensions==10.16 PyYAML==6.0.2 six==1.17.0 tabulate==0.9.0 From e6eff8779d3355ca2629726426c3f2c82c3e8ab8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 06:43:26 -0700 Subject: [PATCH 068/148] build(deps): bump pygments from 2.19.1 to 2.19.2 in /hack/mkdocs/image (#3879) Bumps [pygments](https://github.com/pygments/pygments) from 2.19.1 to 2.19.2. - [Release notes](https://github.com/pygments/pygments/releases) - [Changelog](https://github.com/pygments/pygments/blob/master/CHANGES) - [Commits](https://github.com/pygments/pygments/compare/2.19.1...2.19.2) --- updated-dependencies: - dependency-name: pygments dependency-version: 2.19.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 3550d265df..a075a43182 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -15,7 +15,7 @@ mkdocs-redirects==1.2.2 mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 pep562==1.1 -Pygments==2.19.1 +Pygments==2.19.2 pymdown-extensions==10.16 PyYAML==6.0.2 six==1.17.0 From 1b2b35fadc59c34fa95f6c1166ee6a02e23ef857 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 07:03:26 -0700 Subject: [PATCH 069/148] build(deps): bump golang.org/x/net from 0.39.0 to 0.41.0 (#3843) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.39.0 to 0.41.0. - [Commits](https://github.com/golang/net/compare/v0.39.0...v0.41.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.41.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 14 +++++++------- go.sum | 28 ++++++++++++++-------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/go.mod b/go.mod index 0819f5d332..60ab92ab6c 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/elastic/crd-ref-docs v0.1.0 github.com/miekg/dns v1.1.66 github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.39.0 + golang.org/x/net v0.41.0 golang.org/x/sync v0.15.0 google.golang.org/grpc v1.73.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 @@ -66,14 +66,14 @@ 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.24.0 // indirect + golang.org/x/crypto v0.39.0 // indirect + golang.org/x/mod v0.25.0 // indirect golang.org/x/oauth2 v0.28.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/sys v0.33.0 // indirect + golang.org/x/term v0.32.0 // indirect + golang.org/x/text v0.26.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.32.0 // indirect + golang.org/x/tools v0.33.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect diff --git a/go.sum b/go.sum index bbde100af4..599f1c0700 100644 --- a/go.sum +++ b/go.sum @@ -161,18 +161,18 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= 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.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= +golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= 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.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= +golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 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/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= +golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -185,22 +185,22 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w 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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= +golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= +golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= 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/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= +golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= 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.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU= -golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s= +golang.org/x/tools v0.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= +golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= 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= From a241e4a9624df39ac8792753e5a9f085eca6dda1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 07:03:33 -0700 Subject: [PATCH 070/148] build(deps): bump sigs.k8s.io/controller-runtime from 0.20.4 to 0.21.0 (#3858) Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.20.4 to 0.21.0. - [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases) - [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.20.4...v0.21.0) --- updated-dependencies: - dependency-name: sigs.k8s.io/controller-runtime dependency-version: 0.21.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 60ab92ab6c..a2eca0cfc6 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( k8s.io/code-generator v0.33.2 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-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 diff --git a/go.sum b/go.sum index 599f1c0700..e08b99f8e9 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ 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/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= 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= @@ -248,8 +250,8 @@ k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUy 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-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= From ef544aefc24b9974ad752006025633ace19e4975 Mon Sep 17 00:00:00 2001 From: Kundan Kumar Date: Thu, 3 Jul 2025 23:11:25 +0530 Subject: [PATCH 071/148] kubecon talk link updated. (#3660) * kubecon talk link updated. * Update site-src/contributing/index.md Co-authored-by: Nick Young * Apply suggestions from code review --------- Co-authored-by: Shane Utt Co-authored-by: Nick Young --- site-src/contributing/index.md | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/site-src/contributing/index.md b/site-src/contributing/index.md index 613b15decc..05798beb42 100644 --- a/site-src/contributing/index.md +++ b/site-src/contributing/index.md @@ -102,13 +102,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 From 28504b14171ca202859e572cb8d0680cd71c36d9 Mon Sep 17 00:00:00 2001 From: Mattia Lavacca Date: Fri, 4 Jul 2025 09:01:25 +0200 Subject: [PATCH 072/148] gep: update the possible statuses in GEP-696 (#3901) Signed-off-by: Mattia Lavacca --- geps/gep-696/index.md | 2 +- geps/gep-696/metadata.yaml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/geps/gep-696/index.md b/geps/gep-696/index.md index 4a4a97dd19..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).) 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 From 24803c32d8070e38cf90f020987d4d3656ad5896 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Tue, 8 Jul 2025 17:05:26 -0600 Subject: [PATCH 073/148] Update NGINX Gateway Fabric conformance (#3907) Missed a conformance test in the report that is passing. --- .../experimental-2.0.0-default-report.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 index d6d0353a10..571ab045c8 100644 --- 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 @@ -25,11 +25,11 @@ profiles: Passed: 1 Skipped: 0 supportedFeatures: + - GatewayAddressEmpty - GatewayHTTPListenerIsolation - GatewayInfrastructurePropagation - GatewayPort8080 unsupportedFeatures: - - GatewayAddressEmpty - GatewayStaticAddresses name: GATEWAY-GRPC summary: Core tests succeeded. Extended tests succeeded. @@ -43,9 +43,10 @@ profiles: result: success statistics: Failed: 0 - Passed: 14 + Passed: 15 Skipped: 0 supportedFeatures: + - GatewayAddressEmpty - GatewayHTTPListenerIsolation - GatewayInfrastructurePropagation - GatewayPort8080 @@ -60,7 +61,6 @@ profiles: - HTTPRouteResponseHeaderModification - HTTPRouteSchemeRedirect unsupportedFeatures: - - GatewayAddressEmpty - GatewayStaticAddresses - HTTPRouteBackendProtocolH2C - HTTPRouteBackendProtocolWebSocket @@ -85,11 +85,11 @@ profiles: Passed: 1 Skipped: 0 supportedFeatures: + - GatewayAddressEmpty - GatewayHTTPListenerIsolation - GatewayInfrastructurePropagation - GatewayPort8080 unsupportedFeatures: - - GatewayAddressEmpty - GatewayStaticAddresses name: GATEWAY-TLS summary: Core tests succeeded. Extended tests succeeded. From 2322922004a5d4d4f4bf2d49d82717f1f38c33a4 Mon Sep 17 00:00:00 2001 From: John Howard Date: Wed, 9 Jul 2025 15:55:27 -0700 Subject: [PATCH 074/148] conformance: add Agent Gateway (#3908) * conformance: add Agent Gateway * Update site-src/implementations.md Co-authored-by: Rob Scott --------- Co-authored-by: Rob Scott --- .../agentgateway-agentgateway/README.md | 22 ++++++++ .../experimental-0.6.0-report.yaml | 55 +++++++++++++++++++ site-src/implementations.md | 7 +++ 3 files changed, 84 insertions(+) create mode 100644 conformance/reports/v1.3.0/agentgateway-agentgateway/README.md create mode 100644 conformance/reports/v1.3.0/agentgateway-agentgateway/experimental-0.6.0-report.yaml 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/site-src/implementations.md b/site-src/implementations.md index 1b11204072..93f6dc2c89 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -84,6 +84,7 @@ other functions (like managing DNS or creating certificates). ## Gateway Controller Implementation Status - [Acnodal EPIC][1] +- [Agent Gateway][40] - [Airlock Microgateway][34] - [Amazon Elastic Kubernetes Service][23] (GA) - [Apache APISIX][2] (beta) @@ -168,6 +169,7 @@ other functions (like managing DNS or creating certificates). [37]:#kgateway [38]:#google-cloud-service-mesh [39]:#kubvernor +[40]:#agentgateway-with-kgateway [gamma]:mesh/index.md @@ -187,6 +189,11 @@ 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.3.0-Airlock%20Microgateway-green)](https://github.com/kubernetes-sigs/gateway-api/blob/main/conformance/reports/v1.3.0/airlock-microgateway) From 682a03fefa41037adc8863ba80e17eca1fbe6f1f Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 10 Jul 2025 08:55:47 -0400 Subject: [PATCH 075/148] docs: update GEP 1767 to remove TrueField type Signed-off-by: Shane Utt --- geps/gep-1767/index.md | 84 +++++++++++++++++++++++++------------ geps/gep-1767/metadata.yaml | 1 + 2 files changed, 58 insertions(+), 27 deletions(-) diff --git a/geps/gep-1767/index.md b/geps/gep-1767/index.md index 3f1018bdb1..c115dbf116 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: ["*"] @@ -590,7 +578,7 @@ spec: - 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 From b8de0b89f98e9d6458edf017ce6d08fa5f5543fb Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 10 Jul 2025 08:54:59 -0400 Subject: [PATCH 076/148] chore: remove the TrueField API type Signed-off-by: Shane Utt --- apis/v1/httproute_types.go | 2 +- apis/v1/shared_types.go | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index f0aa550559..93d4f4d4b3 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1371,7 +1371,7 @@ type HTTPCORSFilter struct { // 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. diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index e059b98145..226c776372 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -764,11 +764,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 From 8d0a087933462069f4eb102c56da3c061f653009 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 10 Jul 2025 08:56:10 -0400 Subject: [PATCH 077/148] docs: update godoc for new AllowCredentials Signed-off-by: Shane Utt --- apis/v1/httproute_types.go | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 93d4f4d4b3..e59ebf7bcc 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1344,9 +1344,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 @@ -1361,12 +1361,12 @@ 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). // - // 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 // @@ -1400,9 +1400,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 @@ -1442,9 +1442,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 @@ -1487,8 +1487,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 // From 1f2525f31256608353e136fdfb0665b1ac186ed9 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 10 Jul 2025 08:56:34 -0400 Subject: [PATCH 078/148] chore: run golang generators Signed-off-by: Shane Utt --- apis/v1/zz_generated.deepcopy.go | 5 +++++ applyconfiguration/apis/v1/httpcorsfilter.go | 4 ++-- pkg/generated/openapi/zz_generated.openapi.go | 10 +++++----- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index 0f32a067ee..9bc1c8c53e 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -910,6 +910,11 @@ func (in *HTTPCORSFilter) DeepCopyInto(out *HTTPCORSFilter) { *out = make([]AbsoluteURI, 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)) diff --git a/applyconfiguration/apis/v1/httpcorsfilter.go b/applyconfiguration/apis/v1/httpcorsfilter.go index c2cf023c25..cc556b3e8a 100644 --- a/applyconfiguration/apis/v1/httpcorsfilter.go +++ b/applyconfiguration/apis/v1/httpcorsfilter.go @@ -26,7 +26,7 @@ import ( // with apply. type HTTPCORSFilterApplyConfiguration struct { AllowOrigins []apisv1.AbsoluteURI `json:"allowOrigins,omitempty"` - AllowCredentials *apisv1.TrueField `json:"allowCredentials,omitempty"` + AllowCredentials *bool `json:"allowCredentials,omitempty"` AllowMethods []apisv1.HTTPMethodWithWildcard `json:"allowMethods,omitempty"` AllowHeaders []apisv1.HTTPHeaderName `json:"allowHeaders,omitempty"` ExposeHeaders []apisv1.HTTPHeaderName `json:"exposeHeaders,omitempty"` @@ -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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 99214c9fcd..13ff9ab516 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -4306,7 +4306,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{ @@ -4321,7 +4321,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: "", }, @@ -4333,7 +4333,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{ @@ -4353,7 +4353,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{ @@ -4373,7 +4373,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{ From fb6aa5cd3a72d5686b1dfcef76c9f5dad1d64e6c Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 10 Jul 2025 08:56:42 -0400 Subject: [PATCH 079/148] chore: generate manifests Signed-off-by: Shane Utt --- .../gateway.networking.k8s.io_httproutes.yaml | 108 ++++++++---------- 1 file changed, 48 insertions(+), 60 deletions(-) diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 9f5f93d222..cf2b274655 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -468,16 +468,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 +502,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 +565,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 +643,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 @@ -698,8 +696,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: @@ -1695,16 +1692,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 +1726,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 +1789,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 +1867,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 @@ -1925,8 +1920,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: @@ -4094,16 +4088,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 +4122,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 +4185,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 +4263,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 @@ -4324,8 +4316,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: @@ -5321,16 +5312,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 +5346,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 +5409,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 +5487,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 @@ -5551,8 +5540,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: From 6d76ec6e574cab4719351767ae6c42ef23e62240 Mon Sep 17 00:00:00 2001 From: Rostislav Bobrovsky Date: Mon, 14 Jul 2025 20:00:23 +0200 Subject: [PATCH 080/148] TLSRoute: Require hostnames and bump version to v1alpha3 (#3872) * TLSRoute: Require hostnames * TLSRoute: Move to v1alpha3 TLSRoute: Update config crd TLSRoute: Update pkg TLSRoute: Update hack example * TLSRoute: Bring TLSRoute back to v1alpha2 * TLSRoute: Update conformance helpers * TLSRoute: Remove storageversion from v1alpha3 * TLSRoute: Update invalid example * TLSRoute: v1alpha3 example * TLSRoute: Make v1alpha3 storage --- apis/v1alpha2/tlsroute_types.go | 1 - apis/v1alpha3/shared_types.go | 89 ++ apis/v1alpha3/tlsroute_types.go | 106 +++ apis/v1alpha3/zz_generated.deepcopy.go | 87 ++ apis/v1alpha3/zz_generated.register.go | 2 + applyconfiguration/apis/v1alpha3/tlsroute.go | 265 ++++++ .../apis/v1alpha3/tlsrouterule.go | 58 ++ .../apis/v1alpha3/tlsroutespec.go | 75 ++ .../apis/v1alpha3/tlsroutestatus.go | 48 ++ applyconfiguration/internal/internal.go | 42 + applyconfiguration/utils.go | 4 + .../gateway.networking.k8s.io_tlsroutes.yaml | 770 ++++++++++++++++++ .../v1alpha2/tls-routing/gateway.yaml | 12 + .../v1alpha2/tls-routing/tls-route.yaml | 12 + .../v1alpha3/tls-routing/gateway.yaml | 12 + .../v1alpha3/tls-routing/tls-route.yaml | 14 + .../experimental/tlsroute/no-hostname.yaml | 8 + .../typed/apis/v1alpha3/apis_client.go | 5 + .../apis/v1alpha3/fake/fake_apis_client.go | 4 + .../typed/apis/v1alpha3/fake/fake_tlsroute.go | 51 ++ .../apis/v1alpha3/generated_expansion.go | 2 + .../versioned/typed/apis/v1alpha3/tlsroute.go | 74 ++ .../apis/v1alpha3/interface.go | 7 + .../apis/v1alpha3/tlsroute.go | 102 +++ .../informers/externalversions/generic.go | 2 + .../apis/v1alpha3/expansion_generated.go | 8 + pkg/client/listers/apis/v1alpha3/tlsroute.go | 70 ++ pkg/generated/openapi/zz_generated.openapi.go | 161 ++++ 28 files changed, 2090 insertions(+), 1 deletion(-) create mode 100644 apis/v1alpha3/shared_types.go create mode 100644 apis/v1alpha3/tlsroute_types.go create mode 100644 applyconfiguration/apis/v1alpha3/tlsroute.go create mode 100644 applyconfiguration/apis/v1alpha3/tlsrouterule.go create mode 100644 applyconfiguration/apis/v1alpha3/tlsroutespec.go create mode 100644 applyconfiguration/apis/v1alpha3/tlsroutestatus.go create mode 100644 examples/experimental/v1alpha2/tls-routing/gateway.yaml create mode 100644 examples/experimental/v1alpha2/tls-routing/tls-route.yaml create mode 100644 examples/experimental/v1alpha3/tls-routing/gateway.yaml create mode 100644 examples/experimental/v1alpha3/tls-routing/tls-route.yaml create mode 100644 hack/invalid-examples/experimental/tlsroute/no-hostname.yaml create mode 100644 pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_tlsroute.go create mode 100644 pkg/client/clientset/versioned/typed/apis/v1alpha3/tlsroute.go create mode 100644 pkg/client/informers/externalversions/apis/v1alpha3/tlsroute.go create mode 100644 pkg/client/listers/apis/v1alpha3/tlsroute.go diff --git a/apis/v1alpha2/tlsroute_types.go b/apis/v1alpha2/tlsroute_types.go index f21fe3fc50..f1b3814cf7 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 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..7bcb48e74b --- /dev/null +++ b/apis/v1alpha3/tlsroute_types.go @@ -0,0 +1,106 @@ +/* +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"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + // Spec defines the desired state of TLSRoute. + Spec TLSRouteSpec `json:"spec"` + + // Status defines the current state of TLSRoute. + 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 either not specified any hostnames, or have specified at + // least one of `test.example.com` or `*.example.com`. + // * A Listener with `*.example.com` as the hostname matches TLSRoutes + // that have either not specified any hostnames or 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 + // + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + Hostnames []Hostname `json:"hostnames,omitempty"` + + // Rules are a list of TLS matchers and actions. + // + // +kubebuilder:validation:MinItems=1 + // +kubebuilder:validation:MaxItems=16 + // + Rules []v1alpha2.TLSRouteRule `json:"rules"` +} + +// +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/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/internal/internal.go b/applyconfiguration/internal/internal.go index 7a69ee3876..0403df0d63 100644 --- a/applyconfiguration/internal/internal.go +++ b/applyconfiguration/internal/internal.go @@ -1585,6 +1585,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: diff --git a/applyconfiguration/utils.go b/applyconfiguration/utils.go index 8e23441166..8014f68c7c 100644 --- a/applyconfiguration/utils.go +++ b/applyconfiguration/utils.go @@ -212,6 +212,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_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index eaac6b6692..4392eff57f 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -721,6 +721,776 @@ spec: 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: + - controllerName + - parentRef + type: object + maxItems: 32 + type: array + 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 either not specified any hostnames, or have specified at + least one of `test.example.com` or `*.example.com`. + * A Listener with `*.example.com` as the hostname matches TLSRoutes + that have either not specified any hostnames or 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 + 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-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 TLS matchers and 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 + 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 + minItems: 1 + type: array + 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. 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/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/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go index 681d5090ed..e98418eee4 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/apis_client.go @@ -29,6 +29,7 @@ import ( type GatewayV1alpha3Interface interface { RESTClient() rest.Interface BackendTLSPoliciesGetter + TLSRoutesGetter } // GatewayV1alpha3Client is used to interact with features provided by the gateway.networking.k8s.io group. @@ -40,6 +41,10 @@ func (c *GatewayV1alpha3Client) BackendTLSPolicies(namespace string) BackendTLSP return newBackendTLSPolicies(c, namespace) } +func (c *GatewayV1alpha3Client) TLSRoutes(namespace string) TLSRouteInterface { + return newTLSRoutes(c, namespace) +} + // NewForConfig creates a new GatewayV1alpha3Client for the given config. // NewForConfig is equivalent to NewForConfigAndClient(c, httpClient), // where httpClient was generated with rest.HTTPClientFor(c). diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_apis_client.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_apis_client.go index 0ab453c2a8..e3144393ea 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_apis_client.go +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_apis_client.go @@ -32,6 +32,10 @@ func (c *FakeGatewayV1alpha3) BackendTLSPolicies(namespace string) v1alpha3.Back return newFakeBackendTLSPolicies(c, namespace) } +func (c *FakeGatewayV1alpha3) TLSRoutes(namespace string) v1alpha3.TLSRouteInterface { + return newFakeTLSRoutes(c, namespace) +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeGatewayV1alpha3) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_tlsroute.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_tlsroute.go new file mode 100644 index 0000000000..03542e1060 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/fake/fake_tlsroute.go @@ -0,0 +1,51 @@ +/* +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 client-gen. DO NOT EDIT. + +package fake + +import ( + gentype "k8s.io/client-go/gentype" + v1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + apisv1alpha3 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1alpha3" + typedapisv1alpha3 "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/typed/apis/v1alpha3" +) + +// fakeTLSRoutes implements TLSRouteInterface +type fakeTLSRoutes struct { + *gentype.FakeClientWithListAndApply[*v1alpha3.TLSRoute, *v1alpha3.TLSRouteList, *apisv1alpha3.TLSRouteApplyConfiguration] + Fake *FakeGatewayV1alpha3 +} + +func newFakeTLSRoutes(fake *FakeGatewayV1alpha3, namespace string) typedapisv1alpha3.TLSRouteInterface { + return &fakeTLSRoutes{ + gentype.NewFakeClientWithListAndApply[*v1alpha3.TLSRoute, *v1alpha3.TLSRouteList, *apisv1alpha3.TLSRouteApplyConfiguration]( + fake.Fake, + namespace, + v1alpha3.SchemeGroupVersion.WithResource("tlsroutes"), + v1alpha3.SchemeGroupVersion.WithKind("TLSRoute"), + func() *v1alpha3.TLSRoute { return &v1alpha3.TLSRoute{} }, + func() *v1alpha3.TLSRouteList { return &v1alpha3.TLSRouteList{} }, + func(dst, src *v1alpha3.TLSRouteList) { dst.ListMeta = src.ListMeta }, + func(list *v1alpha3.TLSRouteList) []*v1alpha3.TLSRoute { return gentype.ToPointerSlice(list.Items) }, + func(list *v1alpha3.TLSRouteList, items []*v1alpha3.TLSRoute) { + list.Items = gentype.FromPointerSlice(items) + }, + ), + fake, + } +} diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha3/generated_expansion.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/generated_expansion.go index 68c5693b88..1c0cd8245b 100644 --- a/pkg/client/clientset/versioned/typed/apis/v1alpha3/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/generated_expansion.go @@ -19,3 +19,5 @@ limitations under the License. package v1alpha3 type BackendTLSPolicyExpansion interface{} + +type TLSRouteExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/apis/v1alpha3/tlsroute.go b/pkg/client/clientset/versioned/typed/apis/v1alpha3/tlsroute.go new file mode 100644 index 0000000000..e5b3aaa581 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/apis/v1alpha3/tlsroute.go @@ -0,0 +1,74 @@ +/* +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 client-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + gentype "k8s.io/client-go/gentype" + apisv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + applyconfigurationapisv1alpha3 "sigs.k8s.io/gateway-api/applyconfiguration/apis/v1alpha3" + scheme "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned/scheme" +) + +// TLSRoutesGetter has a method to return a TLSRouteInterface. +// A group's client should implement this interface. +type TLSRoutesGetter interface { + TLSRoutes(namespace string) TLSRouteInterface +} + +// TLSRouteInterface has methods to work with TLSRoute resources. +type TLSRouteInterface interface { + Create(ctx context.Context, tLSRoute *apisv1alpha3.TLSRoute, opts v1.CreateOptions) (*apisv1alpha3.TLSRoute, error) + Update(ctx context.Context, tLSRoute *apisv1alpha3.TLSRoute, opts v1.UpdateOptions) (*apisv1alpha3.TLSRoute, error) + // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + UpdateStatus(ctx context.Context, tLSRoute *apisv1alpha3.TLSRoute, opts v1.UpdateOptions) (*apisv1alpha3.TLSRoute, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*apisv1alpha3.TLSRoute, error) + List(ctx context.Context, opts v1.ListOptions) (*apisv1alpha3.TLSRouteList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *apisv1alpha3.TLSRoute, err error) + Apply(ctx context.Context, tLSRoute *applyconfigurationapisv1alpha3.TLSRouteApplyConfiguration, opts v1.ApplyOptions) (result *apisv1alpha3.TLSRoute, err error) + // Add a +genclient:noStatus comment above the type to avoid generating ApplyStatus(). + ApplyStatus(ctx context.Context, tLSRoute *applyconfigurationapisv1alpha3.TLSRouteApplyConfiguration, opts v1.ApplyOptions) (result *apisv1alpha3.TLSRoute, err error) + TLSRouteExpansion +} + +// tLSRoutes implements TLSRouteInterface +type tLSRoutes struct { + *gentype.ClientWithListAndApply[*apisv1alpha3.TLSRoute, *apisv1alpha3.TLSRouteList, *applyconfigurationapisv1alpha3.TLSRouteApplyConfiguration] +} + +// newTLSRoutes returns a TLSRoutes +func newTLSRoutes(c *GatewayV1alpha3Client, namespace string) *tLSRoutes { + return &tLSRoutes{ + gentype.NewClientWithListAndApply[*apisv1alpha3.TLSRoute, *apisv1alpha3.TLSRouteList, *applyconfigurationapisv1alpha3.TLSRouteApplyConfiguration]( + "tlsroutes", + c.RESTClient(), + scheme.ParameterCodec, + namespace, + func() *apisv1alpha3.TLSRoute { return &apisv1alpha3.TLSRoute{} }, + func() *apisv1alpha3.TLSRouteList { return &apisv1alpha3.TLSRouteList{} }, + ), + } +} diff --git a/pkg/client/informers/externalversions/apis/v1alpha3/interface.go b/pkg/client/informers/externalversions/apis/v1alpha3/interface.go index 468614d4f4..adeb3dc54c 100644 --- a/pkg/client/informers/externalversions/apis/v1alpha3/interface.go +++ b/pkg/client/informers/externalversions/apis/v1alpha3/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // BackendTLSPolicies returns a BackendTLSPolicyInformer. BackendTLSPolicies() BackendTLSPolicyInformer + // TLSRoutes returns a TLSRouteInformer. + TLSRoutes() TLSRouteInformer } type version struct { @@ -43,3 +45,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (v *version) BackendTLSPolicies() BackendTLSPolicyInformer { return &backendTLSPolicyInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } + +// TLSRoutes returns a TLSRouteInformer. +func (v *version) TLSRoutes() TLSRouteInformer { + return &tLSRouteInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/apis/v1alpha3/tlsroute.go b/pkg/client/informers/externalversions/apis/v1alpha3/tlsroute.go new file mode 100644 index 0000000000..11d171c8b3 --- /dev/null +++ b/pkg/client/informers/externalversions/apis/v1alpha3/tlsroute.go @@ -0,0 +1,102 @@ +/* +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 informer-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + context "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + gatewayapiapisv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" + versioned "sigs.k8s.io/gateway-api/pkg/client/clientset/versioned" + internalinterfaces "sigs.k8s.io/gateway-api/pkg/client/informers/externalversions/internalinterfaces" + apisv1alpha3 "sigs.k8s.io/gateway-api/pkg/client/listers/apis/v1alpha3" +) + +// TLSRouteInformer provides access to a shared informer and lister for +// TLSRoutes. +type TLSRouteInformer interface { + Informer() cache.SharedIndexInformer + Lister() apisv1alpha3.TLSRouteLister +} + +type tLSRouteInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTLSRouteInformer constructs a new informer for TLSRoute type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTLSRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTLSRouteInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTLSRouteInformer constructs a new informer for TLSRoute type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTLSRouteInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().TLSRoutes(namespace).List(context.Background(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().TLSRoutes(namespace).Watch(context.Background(), options) + }, + ListWithContextFunc: func(ctx context.Context, options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().TLSRoutes(namespace).List(ctx, options) + }, + WatchFuncWithContext: func(ctx context.Context, options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.GatewayV1alpha3().TLSRoutes(namespace).Watch(ctx, options) + }, + }, + &gatewayapiapisv1alpha3.TLSRoute{}, + resyncPeriod, + indexers, + ) +} + +func (f *tLSRouteInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTLSRouteInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *tLSRouteInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&gatewayapiapisv1alpha3.TLSRoute{}, f.defaultInformer) +} + +func (f *tLSRouteInformer) Lister() apisv1alpha3.TLSRouteLister { + return apisv1alpha3.NewTLSRouteLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 1d90930c0c..b777993d4e 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -81,6 +81,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=gateway.networking.k8s.io, Version=v1alpha3 case v1alpha3.SchemeGroupVersion.WithResource("backendtlspolicies"): return &genericInformer{resource: resource.GroupResource(), informer: f.Gateway().V1alpha3().BackendTLSPolicies().Informer()}, nil + case v1alpha3.SchemeGroupVersion.WithResource("tlsroutes"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Gateway().V1alpha3().TLSRoutes().Informer()}, nil // Group=gateway.networking.k8s.io, Version=v1beta1 case v1beta1.SchemeGroupVersion.WithResource("gateways"): diff --git a/pkg/client/listers/apis/v1alpha3/expansion_generated.go b/pkg/client/listers/apis/v1alpha3/expansion_generated.go index 5cba22fc90..a47937d93c 100644 --- a/pkg/client/listers/apis/v1alpha3/expansion_generated.go +++ b/pkg/client/listers/apis/v1alpha3/expansion_generated.go @@ -25,3 +25,11 @@ type BackendTLSPolicyListerExpansion interface{} // BackendTLSPolicyNamespaceListerExpansion allows custom methods to be added to // BackendTLSPolicyNamespaceLister. type BackendTLSPolicyNamespaceListerExpansion interface{} + +// TLSRouteListerExpansion allows custom methods to be added to +// TLSRouteLister. +type TLSRouteListerExpansion interface{} + +// TLSRouteNamespaceListerExpansion allows custom methods to be added to +// TLSRouteNamespaceLister. +type TLSRouteNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/apis/v1alpha3/tlsroute.go b/pkg/client/listers/apis/v1alpha3/tlsroute.go new file mode 100644 index 0000000000..efc0e9016c --- /dev/null +++ b/pkg/client/listers/apis/v1alpha3/tlsroute.go @@ -0,0 +1,70 @@ +/* +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 lister-gen. DO NOT EDIT. + +package v1alpha3 + +import ( + labels "k8s.io/apimachinery/pkg/labels" + listers "k8s.io/client-go/listers" + cache "k8s.io/client-go/tools/cache" + apisv1alpha3 "sigs.k8s.io/gateway-api/apis/v1alpha3" +) + +// TLSRouteLister helps list TLSRoutes. +// All objects returned here must be treated as read-only. +type TLSRouteLister interface { + // List lists all TLSRoutes in the indexer. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apisv1alpha3.TLSRoute, err error) + // TLSRoutes returns an object that can list and get TLSRoutes. + TLSRoutes(namespace string) TLSRouteNamespaceLister + TLSRouteListerExpansion +} + +// tLSRouteLister implements the TLSRouteLister interface. +type tLSRouteLister struct { + listers.ResourceIndexer[*apisv1alpha3.TLSRoute] +} + +// NewTLSRouteLister returns a new TLSRouteLister. +func NewTLSRouteLister(indexer cache.Indexer) TLSRouteLister { + return &tLSRouteLister{listers.New[*apisv1alpha3.TLSRoute](indexer, apisv1alpha3.Resource("tlsroute"))} +} + +// TLSRoutes returns an object that can list and get TLSRoutes. +func (s *tLSRouteLister) TLSRoutes(namespace string) TLSRouteNamespaceLister { + return tLSRouteNamespaceLister{listers.NewNamespaced[*apisv1alpha3.TLSRoute](s.ResourceIndexer, namespace)} +} + +// TLSRouteNamespaceLister helps list and get TLSRoutes. +// All objects returned here must be treated as read-only. +type TLSRouteNamespaceLister interface { + // List lists all TLSRoutes in the indexer for a given namespace. + // Objects returned here must be treated as read-only. + List(selector labels.Selector) (ret []*apisv1alpha3.TLSRoute, err error) + // Get retrieves the TLSRoute from the indexer for a given namespace and name. + // Objects returned here must be treated as read-only. + Get(name string) (*apisv1alpha3.TLSRoute, error) + TLSRouteNamespaceListerExpansion +} + +// tLSRouteNamespaceLister implements the TLSRouteNamespaceLister +// interface. +type tLSRouteNamespaceLister struct { + listers.ResourceIndexer[*apisv1alpha3.TLSRoute] +} diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 13ff9ab516..b26723bcec 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -178,6 +178,9 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1alpha3.BackendTLSPolicySpec": schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicySpec(ref), "sigs.k8s.io/gateway-api/apis/v1alpha3.BackendTLSPolicyValidation": schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref), "sigs.k8s.io/gateway-api/apis/v1alpha3.SubjectAltName": schema_sigsk8sio_gateway_api_apis_v1alpha3_SubjectAltName(ref), + "sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRoute": schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRoute(ref), + "sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRouteList": schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteList(ref), + "sigs.k8s.io/gateway-api/apis/v1alpha3.TLSRouteSpec": schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteSpec(ref), "sigs.k8s.io/gateway-api/apis/v1beta1.Gateway": schema_sigsk8sio_gateway_api_apis_v1beta1_Gateway(ref), "sigs.k8s.io/gateway-api/apis/v1beta1.GatewayClass": schema_sigsk8sio_gateway_api_apis_v1beta1_GatewayClass(ref), "sigs.k8s.io/gateway-api/apis/v1beta1.GatewayClassList": schema_sigsk8sio_gateway_api_apis_v1beta1_GatewayClassList(ref), @@ -7168,6 +7171,164 @@ 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": { + 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": { + 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 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"}, + Items: &spec.SchemaOrArray{ + Schema: &spec.Schema{ + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "rules": { + SchemaProps: spec.SchemaProps{ + Description: "Rules are a list of TLS matchers and 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{"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{ From a07680f5ade11bbd90278e586322eedabeb29d44 Mon Sep 17 00:00:00 2001 From: Rostislav Bobrovsky Date: Tue, 15 Jul 2025 16:22:24 +0200 Subject: [PATCH 081/148] TLSRoute: Require hostnames via +required (#3918) * TLSRoute: Require hostnames, no omitempty * TLSRoute: Require hostnames using +required --- apis/v1alpha3/tlsroute_types.go | 1 + .../crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml | 1 + pkg/generated/openapi/zz_generated.openapi.go | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go index 7bcb48e74b..60e2dc7b99 100644 --- a/apis/v1alpha3/tlsroute_types.go +++ b/apis/v1alpha3/tlsroute_types.go @@ -86,6 +86,7 @@ type TLSRouteSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 + // +required Hostnames []Hostname `json:"hostnames,omitempty"` // Rules are a list of TLS matchers and actions. diff --git a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index 4392eff57f..923fa49ba5 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -1277,6 +1277,7 @@ spec: rule: self.all(l1, !has(l1.name) || self.exists_one(l2, has(l2.name) && l1.name == l2.name)) required: + - hostnames - rules type: object status: diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index b26723bcec..7dcbaa33b6 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7321,7 +7321,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteSpec(ref common.Referenc }, }, }, - Required: []string{"rules"}, + Required: []string{"hostnames", "rules"}, }, }, Dependencies: []string{ From 35e6bea8424431d96f1cb8f61a96130ea6d573ff Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 15 Jul 2025 09:04:24 -0700 Subject: [PATCH 082/148] Revert "feat(conformance): validate implementation flags (#3715)" (#3920) This reverts commit 564720a533f9ff28e65bdf898c1274ace1865245. --- conformance/conformance.go | 5 +- conformance/utils/suite/suite.go | 26 +------- conformance/utils/suite/suite_test.go | 86 --------------------------- pkg/test/cel/grpcroute_test.go | 3 +- 4 files changed, 6 insertions(+), 114 deletions(-) diff --git a/conformance/conformance.go b/conformance/conformance.go index 8ea5799e58..12e5884968 100644 --- a/conformance/conformance.go +++ b/conformance/conformance.go @@ -72,14 +72,13 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { namespaceAnnotations := suite.ParseKeyValuePairs(*flags.NamespaceAnnotations) conformanceProfiles := suite.ParseConformanceProfiles(*flags.ConformanceProfiles) - implementation, err := suite.ParseImplementation( + implementation := suite.ParseImplementation( *flags.ImplementationOrganization, *flags.ImplementationProject, *flags.ImplementationURL, *flags.ImplementationVersion, *flags.ImplementationContact, ) - require.NoError(t, err, "error parsing implementation details") return suite.ConformanceOptions{ AllowCRDsMismatch: *flags.AllowCRDsMismatch, @@ -93,7 +92,7 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { ExemptFeatures: exemptFeatures, ManifestFS: []fs.FS{&Manifests}, GatewayClassName: *flags.GatewayClassName, - Implementation: *implementation, + Implementation: implementation, Mode: *flags.Mode, NamespaceAnnotations: namespaceAnnotations, NamespaceLabels: namespaceLabels, diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 2402821e6f..f1164fa2fe 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -21,7 +21,6 @@ import ( "errors" "fmt" "io/fs" - neturl "net/url" "slices" "sort" "strings" @@ -559,33 +558,14 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) { // ParseImplementation parses implementation-specific flag arguments and // creates a *confv1a1.Implementation. -func ParseImplementation(org, project, url, version, contact string) (*confv1.Implementation, error) { - if org == "" { - return nil, errors.New("organization must be set") - } - if project == "" { - return nil, errors.New("project must be set") - } - if url == "" { - return nil, errors.New("url must be set") - } - if version == "" { - return nil, errors.New("version must be set") - } - if contact == "" { - return nil, errors.New("contact must be set") - } - if _, err := neturl.ParseRequestURI(url); err != nil { - return nil, errors.New("url is malformed") - } - - return &confv1.Implementation{ +func ParseImplementation(org, project, url, version, contact string) confv1.Implementation { + return confv1.Implementation{ Organization: org, Project: project, URL: url, Version: version, Contact: strings.Split(contact, ","), - }, nil + } } // ParseConformanceProfiles parses flag arguments and converts the string to diff --git a/conformance/utils/suite/suite_test.go b/conformance/utils/suite/suite_test.go index 69b7d3d979..ccb259adb0 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -538,89 +538,3 @@ func namesToFeatureSet(names []string) FeaturesSet { } return featureSet } - -func TestParseImplementation(t *testing.T) { - testCases := []struct { - name string - org string - project string - url string - version string - contact string - expected *confv1.Implementation - expectedErr error - }{ - { - name: "missing organization", - project: "test-project", - url: "https://example.com", - version: "v1.0.0", - contact: "test@example.com", - expectedErr: errors.New("organization must be set"), - }, - { - name: "missing project", - org: "test-org", - url: "https://example.com", - version: "v1.0.0", - contact: "test@example.com", - expectedErr: errors.New("project must be set"), - }, - { - name: "missing url", - org: "test-org", - project: "test-project", - version: "v1.0.0", - contact: "test@example.com", - expectedErr: errors.New("url must be set"), - }, - { - name: "missing version", - org: "test-org", - project: "test-project", - url: "https://example.com", - contact: "test@example.com", - expectedErr: errors.New("version must be set"), - }, - { - name: "missing contact", - org: "test-org", - project: "test-project", - url: "https://example.com", - version: "v1.0.0", - expectedErr: errors.New("contact must be set"), - }, - { - name: "malformed url", - org: "test-org", - project: "test-project", - url: "invalid-url", - version: "v1.0.0", - contact: "test@example.com", - expectedErr: errors.New("url is malformed"), - }, - { - name: "valid input", - org: "test-org", - project: "test-project", - url: "https://example.com", - version: "v1.0.0", - contact: "test@example.com,test2@example.com", - expected: &confv1.Implementation{ - Organization: "test-org", - Project: "test-project", - URL: "https://example.com", - Version: "v1.0.0", - Contact: []string{"test@example.com", "test2@example.com"}, - }, - }, - } - - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - result, err := ParseImplementation(tc.org, tc.project, tc.url, tc.version, tc.contact) - assert.Equal(t, tc.expected, result) - assert.Equal(t, tc.expectedErr, err) - }) - } -} diff --git a/pkg/test/cel/grpcroute_test.go b/pkg/test/cel/grpcroute_test.go index 2940ce3291..628de66ae9 100644 --- a/pkg/test/cel/grpcroute_test.go +++ b/pkg/test/cel/grpcroute_test.go @@ -341,8 +341,7 @@ func TestGRPCRouteRule(t *testing.T) { } return rules }(), - }, - } + }} for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { From b7ebf2a137c52c739e59f857128f38d8261b5d14 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 15 Jul 2025 23:18:24 -0700 Subject: [PATCH 083/148] build(deps): bump golang.org/x/sync from 0.15.0 to 0.16.0 (#3915) --- updated-dependencies: - dependency-name: golang.org/x/sync dependency-version: 0.16.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a2eca0cfc6..82f05190d0 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/miekg/dns v1.1.66 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.41.0 - golang.org/x/sync v0.15.0 + golang.org/x/sync v0.16.0 google.golang.org/grpc v1.73.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.36.6 diff --git a/go.sum b/go.sum index e08b99f8e9..85b14c3ac1 100644 --- a/go.sum +++ b/go.sum @@ -180,8 +180,8 @@ golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT 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.15.0 h1:KWH3jNZsfyT6xfAfKiz6MRNmd46ByHDYaZ7KSkCtdW8= -golang.org/x/sync v0.15.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= From b285585b881d49b0c7961c9f6c5efe374d79b5e2 Mon Sep 17 00:00:00 2001 From: Mayuka Channankaiah <57181320+mayuka-c@users.noreply.github.com> Date: Wed, 16 Jul 2025 17:22:27 +0530 Subject: [PATCH 084/148] Fix Godoc for BackendTLSPolicyValidation struct for Hostname field (#3923) * Fix Godoc for BackendTLSPolicyValidation struct for Hostname field * Run make generate --- apis/v1alpha3/backendtlspolicy_types.go | 2 -- .../gateway.networking.k8s.io_backendtlspolicies.yaml | 2 -- pkg/generated/openapi/zz_generated.openapi.go | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/apis/v1alpha3/backendtlspolicy_types.go b/apis/v1alpha3/backendtlspolicy_types.go index 394fa46c23..75655f5d63 100644 --- a/apis/v1alpha3/backendtlspolicy_types.go +++ b/apis/v1alpha3/backendtlspolicy_types.go @@ -152,8 +152,6 @@ 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 Hostname v1.PreciseHostname `json:"hostname"` diff --git a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml index 6a9e653a31..a2a5506c17 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml @@ -233,8 +233,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 diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 7dcbaa33b6..8d76a3bf19 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7106,7 +7106,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c }, "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: "", From d7c5992fc896a11a12c28f0fba746825a0c554df Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Wed, 16 Jul 2025 12:20:25 -0300 Subject: [PATCH 085/148] Enable Kubernetes API Linter (#3917) * Add kubeapi linter * Enable duplicatemarkers linter * Enable jsontags linter * Enable nofloats linter * Enable nomaps linter * Enable nophase linter * Enable requiredfields linter * Enable statussubresource linter * Enable uniquemarkers linter * Enable Kube API Linter Github Workflow * Pin lint version correctly and fix config file spacing * Fix kal github actions spacing and remove requiredfields linter --- .custom-gcl.yml | 6 ++++ .github/workflows/kal.yml | 25 +++++++++++++ .golangci-kal.yml | 36 +++++++++++++++++++ apis/v1/httproute_types.go | 1 - .../gateway.networking.k8s.io_httproutes.yaml | 8 ----- .../gateway.networking.k8s.io_httproutes.yaml | 8 ----- 6 files changed, 67 insertions(+), 17 deletions(-) create mode 100644 .custom-gcl.yml create mode 100644 .github/workflows/kal.yml create mode 100644 .golangci-kal.yml 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/workflows/kal.yml b/.github/workflows/kal.yml new file mode 100644 index 0000000000..d657969f5d --- /dev/null +++ b/.github/workflows/kal.yml @@ -0,0 +1,25 @@ +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: 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..aad23ab40d --- /dev/null +++ b/.golangci-kal.yml @@ -0,0 +1,36 @@ +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. + - "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/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index e59ebf7bcc..157932e971 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1590,7 +1590,6 @@ type HTTPBackendRef struct { // +optional // +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/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index cf2b274655..fe5b7f0330 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -1524,10 +1524,6 @@ spec: maxItems: 16 type: array 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'') @@ -5144,10 +5140,6 @@ spec: maxItems: 16 type: array 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'') diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 8533381fc2..1824bd5e19 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -1191,10 +1191,6 @@ spec: maxItems: 16 type: array 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'') @@ -3995,10 +3991,6 @@ spec: maxItems: 16 type: array 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'') From b92e49bedd0c7c71de0c366e14752d5433162338 Mon Sep 17 00:00:00 2001 From: Rostislav Bobrovsky Date: Wed, 16 Jul 2025 18:52:28 +0200 Subject: [PATCH 086/148] TLSRoute: Hostnames godoc (#3925) --- apis/v1alpha3/tlsroute_types.go | 12 ++++++------ .../gateway.networking.k8s.io_tlsroutes.yaml | 12 ++++++------ pkg/generated/openapi/zz_generated.openapi.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go index 60e2dc7b99..82345f9080 100644 --- a/apis/v1alpha3/tlsroute_types.go +++ b/apis/v1alpha3/tlsroute_types.go @@ -63,13 +63,13 @@ type TLSRouteSpec struct { // attached to the Listener. For example: // // * A Listener with `test.example.com` as the hostname matches TLSRoutes - // that have either not specified any hostnames, or have specified at - // least one of `test.example.com` or `*.example.com`. + // 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 either not specified any hostnames or 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. + // 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 diff --git a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index 923fa49ba5..8843c2f0d3 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -837,13 +837,13 @@ spec: attached to the Listener. For example: * A Listener with `test.example.com` as the hostname matches TLSRoutes - that have either not specified any hostnames, or have specified at - least one of `test.example.com` or `*.example.com`. + 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 either not specified any hostnames or 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. + 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 diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 8d76a3bf19..cc919c61da 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7293,7 +7293,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteSpec(ref common.Referenc }, "hostnames": { 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 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", + 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{ From 25f974cee49a8096a0d79712df8253dab65f749f Mon Sep 17 00:00:00 2001 From: Beka Modebadze <58038950+bexxmodd@users.noreply.github.com> Date: Wed, 16 Jul 2025 10:12:25 -0700 Subject: [PATCH 087/148] [GEP-2162] Updated a new field on supported features inference from boolean to enum and remove from report. (#3885) * Update inferred supported features report from bool to enum to account for exceptional case when only Mesh profile is being tested and no GWC available to determine supported features. * Changed enum names. * Added comment to report enum * Revert change caused by merge. * Converted enums from int to string for better readability. * Removed unused import. * Updated unit tests to reflect enum change to strings. * Removed skip tests from determining if supported features are inferred or manually selected. * Removed source update. * Updated unit tests. * Removed source enum from report. * start error string with lowercase. * Removed source getter. * removed undefined enum and added check for mesh features. * return error if mesh features are populated in gwc. * Updated unit tests. * Removed check for mesh profile before throwing error for publishing mesh features. As with this error we want to prevent mesh features under GWC, not mesh profiles for testing. * removed extra else * Removed not needed field from function. * Cleanup of extra field --- conformance/apis/v1/conformancereport.go | 4 -- conformance/utils/suite/suite.go | 42 +++++++++------ conformance/utils/suite/suite_test.go | 69 ++++++++++++++++++++---- 3 files changed, 86 insertions(+), 29 deletions(-) diff --git a/conformance/apis/v1/conformancereport.go b/conformance/apis/v1/conformancereport.go index dcea92dffc..7f4f4d5325 100644 --- a/conformance/apis/v1/conformancereport.go +++ b/conformance/apis/v1/conformancereport.go @@ -50,10 +50,6 @@ type ConformanceReport struct { // SucceededProvisionalTests is a list of the names of the provisional tests that // have been successfully run. SucceededProvisionalTests []string `json:"succeededProvisionalTests,omitempty"` - - // InferredSupportedFeatures indicates whether the supported features were - // automatically detected by the conformance suite. - InferredSupportedFeatures bool `json:"inferredSupportedFeatures"` } // Implementation provides metadata information on the downstream diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index f1164fa2fe..5b30598886 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -84,7 +84,7 @@ type ConformanceTestSuite struct { // 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. - isInferredSupportedFeatures bool + supportedFeaturesSource supportedFeaturesSource // mode is the operating mode of the implementation. // The default value for it is "default". @@ -188,24 +188,37 @@ 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) { supportedFeatures := options.SupportedFeatures.Difference(options.ExemptFeatures) - isInferred := false - switch { - case options.EnableAllSupportedFeatures: + source := supportedFeaturesSourceManual + if options.EnableAllSupportedFeatures { supportedFeatures = features.SetsToNamesSet(features.AllFeatures) - case shouldInferSupportedFeatures(&options): + } 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) + return nil, fmt.Errorf("cannot infer supported features: %w", err) + } + + if hasMeshFeatures(supportedFeatures) { + return nil, fmt.Errorf("mesh features should not be populated in GatewayClass") } - isInferred = true + source = supportedFeaturesSourceInferred } // If features were not inferred from Status, it's a GWC issue. - if isInferred && supportedFeatures.Len() == 0 { + if source == supportedFeaturesSourceInferred && supportedFeatures.Len() == 0 { return nil, fmt.Errorf("no supported features were determined for test suite") } @@ -273,7 +286,7 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, mode: mode, apiVersion: apiVersion, apiChannel: apiChannel, - isInferredSupportedFeatures: isInferred, + supportedFeaturesSource: source, Hook: options.Hook, } @@ -394,10 +407,6 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest) } } -func (suite *ConformanceTestSuite) IsInferredSupportedFeatures() bool { - return suite.isInferredSupportedFeatures -} - func (suite *ConformanceTestSuite) setClientsetForTest(test ConformanceTest) error { featureNames := []string{} for _, v := range test.Features { @@ -552,7 +561,6 @@ func (suite *ConformanceTestSuite) Report() (*confv1.ConformanceReport, error) { GatewayAPIChannel: suite.apiChannel, ProfileReports: profileReports.list(), SucceededProvisionalTests: succeededProvisionalTests, - InferredSupportedFeatures: suite.IsInferredSupportedFeatures(), }, nil } @@ -610,8 +618,6 @@ func shouldInferSupportedFeatures(opts *ConformanceOptions) bool { return !opts.EnableAllSupportedFeatures && opts.SupportedFeatures.Len() == 0 && opts.ExemptFeatures.Len() == 0 && - opts.ConformanceProfiles.Len() == 0 && - len(opts.SkipTests) == 0 && opts.RunTest == "" } @@ -645,3 +651,7 @@ func getAPIVersionAndChannel(crds []apiextensionsv1.CustomResourceDefinition) (v return version, channel, nil } + +func hasMeshFeatures(f FeaturesSet) bool { + return f.HasAny(features.SetsToNamesSet(features.MeshCoreFeatures, features.MeshExtendedFeatures).UnsortedList()...) +} diff --git a/conformance/utils/suite/suite_test.go b/conformance/utils/suite/suite_test.go index ccb259adb0..311da616a2 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -280,7 +280,6 @@ func TestSuiteReport(t *testing.T) { coreProvisionalTest.ShortName, extendedProvisionalTest.ShortName, }, - InferredSupportedFeatures: true, }, }, { @@ -390,7 +389,6 @@ func TestSuiteReport(t *testing.T) { }, }, }, - InferredSupportedFeatures: true, }, }, } @@ -434,33 +432,37 @@ func TestInferSupportedFeatures(t *testing.T) { exemptFeatures FeaturesSet ConformanceProfile sets.Set[ConformanceProfileName] expectedFeatures FeaturesSet - expectedIsInferred bool + expectedSource supportedFeaturesSource }{ { - name: "properly infer supported features", - expectedFeatures: namesToFeatureSet(statusFeatureNames), - expectedIsInferred: true, + 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([]string{"Gateway", "HTTPRoute", "ReferenceGrant"}), + expectedFeatures: namesToFeatureSet(statusFeatureNames), + expectedSource: supportedFeaturesSourceInferred, }, } @@ -512,8 +514,8 @@ func TestInferSupportedFeatures(t *testing.T) { t.Fatalf("error initializing conformance suite: %v", err) } - if cSuite.IsInferredSupportedFeatures() != tc.expectedIsInferred { - t.Errorf("InferredSupportedFeatures mismatch: got %v, want %v", cSuite.IsInferredSupportedFeatures(), tc.expectedIsInferred) + 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 { @@ -523,6 +525,55 @@ func TestInferSupportedFeatures(t *testing.T) { } } +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.SupportGatewayStaticAddresses), + string(features.SupportMeshClusterIPMatching), + string(features.SupportMeshConsumerRoute), + }), + }, + } + 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, + } + + _, err := NewConformanceTestSuite(options) + if err == nil { + t.Fatalf("expected an error but got nil") + } +} + func featureNamesToSet(set []string) []gatewayv1.SupportedFeature { var features []gatewayv1.SupportedFeature for _, feature := range set { From bc08c0ff375ad76fdda7089121c6e1e06662c137 Mon Sep 17 00:00:00 2001 From: HaeyoonJo Date: Wed, 16 Jul 2025 23:38:24 +0300 Subject: [PATCH 088/148] Fix malformed URL typo in index.md (#3926) --- geps/gep-3792/index.md | 4 ++-- geps/gep-3793/index.md | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/geps/gep-3792/index.md b/geps/gep-3792/index.md index b0c5d80b6b..802d729c97 100644 --- a/geps/gep-3792/index.md +++ b/geps/gep-3792/index.md @@ -19,8 +19,8 @@ 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://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro -[Ian]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian +[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 diff --git a/geps/gep-3793/index.md b/geps/gep-3793/index.md index 0c8ba3e6ae..9f15ead87d 100644 --- a/geps/gep-3793/index.md +++ b/geps/gep-3793/index.md @@ -19,7 +19,7 @@ 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]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana +[Ana]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana ## Goals @@ -156,8 +156,8 @@ 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. -[Chihiro]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#chihiro -[Ian]: https://https//gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ian +[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 From 0fd1805d4f97b4ee6a57339f3a411a26018ad699 Mon Sep 17 00:00:00 2001 From: Candace Holman Date: Mon, 21 Jul 2025 11:44:28 -0400 Subject: [PATCH 089/148] Issue 3138 - Conformance Tests for BackendTLSPolicy - normative (#3212) * Issue 3138 - add normative conformance test for BackendTLSPolicy. * Fix where the new go module needed by echo-basic resides, but keep the original as well. See https://github.com/kubernetes-sigs/gateway-api/pull/2745/files#diff-cf5b4a9b433acc91f8c7cc2dc802e29aa712c8d820887742f3bc5ae45b7a9d0fR24-R28 * Rebase and make requested updates. * Update tests after implementation testing conformance/base/manifests.yaml - fix yaml conformance/tests/backendtlspolicy.yaml - fix yaml conformance/tests/tlsroute-simple-same-namespace.go - rename cert for sharing conformance/utils/suite/conformance.go - fix a bug in cleanup-base-resources flag application conformance/utils/suite/suite.go - rename cert for sharing * Incorporate Shane and Flynn's feedback * Add unit testing for generateCACert, new HTTPS call, some debugging, and fix yaml * Update echo-basic images * Fix lint errors and condition evaluation in tests * Fix yaml for httpRoute and backendTLSPolicy. Fix CA generation. Fix certificate unit test. * Refactor test, fix yaml * Fix the tests for normative BackendTLSPolicy # Conflicts: # conformance/utils/http/http.go * Make changes from review comments. Add conformance profiles to logged information. * Address further review comments * Address review comments: Remove echo-basic changes, fix cert building, and adjust the port used for gateways with multiple listeners Co-authored-by: Norwin Schnyder * Address the last of the review comments --------- Co-authored-by: Norwin Schnyder --- conformance/base/manifests.yaml | 4 +- conformance/conformance.go | 4 - conformance/tests/backendtlspolicy.go | 90 +++++++++++ conformance/tests/backendtlspolicy.yaml | 153 ++++++++++++++++++ .../tests/grpcroute-exact-method-matching.go | 2 +- .../tests/grpcroute-header-matching.go | 2 +- .../grpcroute-listener-hostname-matching.go | 6 +- conformance/tests/grpcroute-named-rule.go | 2 +- conformance/tests/httproute-weight.go | 2 +- .../tests/tlsroute-simple-same-namespace.go | 2 +- conformance/utils/http/http.go | 22 ++- conformance/utils/kubernetes/certificate.go | 152 ++++++++++++++++- .../utils/kubernetes/certificate_test.go | 101 ++++++++++++ conformance/utils/kubernetes/helpers.go | 48 ++++-- .../utils/roundtripper/roundtripper.go | 20 +++ conformance/utils/suite/conformance.go | 2 +- conformance/utils/suite/suite.go | 4 + conformance/utils/tls/tls.go | 3 +- docker/Dockerfile.echo-basic | 9 +- pkg/features/backendtlspolicy.go | 40 +++++ pkg/features/features.go | 3 +- 21 files changed, 624 insertions(+), 47 deletions(-) create mode 100644 conformance/tests/backendtlspolicy.go create mode 100644 conformance/tests/backendtlspolicy.yaml create mode 100644 conformance/utils/kubernetes/certificate_test.go create mode 100644 pkg/features/backendtlspolicy.go diff --git a/conformance/base/manifests.yaml b/conformance/base/manifests.yaml index a3163bf837..9380223ea0 100644 --- a/conformance/base/manifests.yaml +++ b/conformance/base/manifests.yaml @@ -138,7 +138,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 +300,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 12e5884968..ce7a465c60 100644 --- a/conformance/conformance.go +++ b/conformance/conformance.go @@ -29,14 +29,11 @@ import ( "sigs.k8s.io/gateway-api/conformance/tests" conformanceconfig "sigs.k8s.io/gateway-api/conformance/utils/config" "sigs.k8s.io/gateway-api/conformance/utils/flags" - "sigs.k8s.io/gateway-api/conformance/utils/suite" "github.com/stretchr/testify/require" apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" - clientset "k8s.io/client-go/kubernetes" - "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/config" "sigs.k8s.io/yaml" @@ -66,7 +63,6 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions { supportedFeatures := suite.ParseSupportedFeatures(*flags.SupportedFeatures) exemptFeatures := suite.ParseSupportedFeatures(*flags.ExemptFeatures) - skipTests := suite.ParseSkipTests(*flags.SkipTests) namespaceLabels := suite.ParseKeyValuePairs(*flags.NamespaceLabels) namespaceAnnotations := suite.ParseKeyValuePairs(*flags.NamespaceAnnotations) diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go new file mode 100644 index 0000000000..1d55627816 --- /dev/null +++ b/conformance/tests/backendtlspolicy.go @@ -0,0 +1,90 @@ +/* +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 tests + +import ( + "testing" + + "k8s.io/apimachinery/pkg/types" + + gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" + 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: "A single service that is targeted by a BackendTLSPolicy must successfully complete TLS termination", + 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) + + serverStr := "abc.example.com" + + // Verify that the response to a backend-tls-only call to /backendTLS will return the matching SNI. + t.Run("Simple HTTP request targeting BackendTLSPolicy should reach infra-backend", 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 response to a re-encrypted call to /backendTLS will return the matching SNI. + t.Run("Re-encrypt HTTPS request targeting BackendTLSPolicy should reach infra-backend", 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}, + }) + }) + }, +} diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml new file mode 100644 index 0000000000..91f6a590f9 --- /dev/null +++ b/conformance/tests/backendtlspolicy.yaml @@ -0,0 +1,153 @@ +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: 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/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 +--- +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 +--- +# 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 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 index 223e22b595..2c738a5660 100644 --- a/conformance/tests/grpcroute-named-rule.go +++ b/conformance/tests/grpcroute-named-rule.go @@ -47,7 +47,7 @@ var GRPCRouteNamedRule = suite.ConformanceTest{ 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{}, 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/httproute-weight.go b/conformance/tests/httproute-weight.go index 2a3e21afee..2c1a520dc0 100644 --- a/conformance/tests/httproute-weight.go +++ b/conformance/tests/httproute-weight.go @@ -105,7 +105,7 @@ func testDistribution(t *testing.T, suite *suite.ConformanceTestSuite, gwAddr st 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/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/http/http.go b/conformance/utils/http/http.go index 18b5e1feb0..e1aca27d54 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -58,6 +58,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 @@ -71,6 +75,7 @@ type Request struct { UnfollowRedirect bool Protocol string Body string + SNI string } // ExpectedRequest defines expected properties of a request that reaches a backend. @@ -130,7 +135,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, @@ -172,7 +177,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" { @@ -243,7 +251,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 } @@ -253,14 +261,14 @@ 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 { +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 } } if expected.Response.StatusCode != cRes.StatusCode { - return fmt.Errorf("expected status code to be %d, got %d", expected.Response.StatusCode, cRes.StatusCode) + return fmt.Errorf("expected status code to be %d, got %d. CRes: %v", expected.Response.StatusCode, cRes.StatusCode, cRes) } if cRes.StatusCode == 200 { // The request expected to arrive at the backend is @@ -353,6 +361,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 diff --git a/conformance/utils/kubernetes/certificate.go b/conformance/utils/kubernetes/certificate.go index a0f70ddd14..07c3c80787 100644 --- a/conformance/utils/kubernetes/certificate.go +++ b/conformance/utils/kubernetes/certificate.go @@ -27,12 +27,14 @@ import ( "io" "math/big" "net" + "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 +48,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 +84,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 +117,20 @@ 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) } } - 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 +145,117 @@ 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) + } + } + + // 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..9e385b4caa 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -331,14 +331,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 +409,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 +417,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 +427,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 +444,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) { 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) { diff --git a/conformance/utils/roundtripper/roundtripper.go b/conformance/utils/roundtripper/roundtripper.go index f79508784f..9490b648e2 100644 --- a/conformance/utils/roundtripper/roundtripper.go +++ b/conformance/utils/roundtripper/roundtripper.go @@ -88,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 @@ -228,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 12db14d6df..436b3ed2ce 100644 --- a/conformance/utils/suite/conformance.go +++ b/conformance/utils/suite/conformance.go @@ -68,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 != "" { diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 5b30598886..63a6b93a16 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -383,6 +383,10 @@ 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) + 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) tlog.Logf(t, "Test Setup: Ensuring Gateways and Pods from base manifests are ready") namespaces := []string{ 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/pkg/features/backendtlspolicy.go b/pkg/features/backendtlspolicy.go new file mode 100644 index 0000000000..8763b32dd1 --- /dev/null +++ b/pkg/features/backendtlspolicy.go @@ -0,0 +1,40 @@ +/* +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 features + +import "k8s.io/apimachinery/pkg/util/sets" + +// ----------------------------------------------------------------------------- +// Features - BackendTLSPolicy Conformance (Core) +// ----------------------------------------------------------------------------- + +const ( + // This option indicates support for BackendTLSPolicy. + SupportBackendTLSPolicy FeatureName = "BackendTLSPolicy" +) + +// TLSRouteFeature contains metadata for the TLSRoute feature. +var BackendTLSPolicyFeature = Feature{ + Name: SupportBackendTLSPolicy, + Channel: FeatureChannelExperimental, +} + +// BackendTLSPolicyCoreFeatures includes all the supported features for the +// BackendTLSPolicy API at a Core level of support. +var BackendTLSPolicyCoreFeatures = sets.New( + BackendTLSPolicyFeature, +) diff --git a/pkg/features/features.go b/pkg/features/features.go index 8406c4b891..2a67d0065f 100644 --- a/pkg/features/features.go +++ b/pkg/features/features.go @@ -60,7 +60,8 @@ var ( Insert(TLSRouteCoreFeatures.UnsortedList()...). Insert(MeshCoreFeatures.UnsortedList()...). Insert(MeshExtendedFeatures.UnsortedList()...). - Insert(GRPCRouteCoreFeatures.UnsortedList()...) + Insert(GRPCRouteCoreFeatures.UnsortedList()...). + Insert(BackendTLSPolicyCoreFeatures.UnsortedList()...) featureMap = map[FeatureName]Feature{} ) From f0ae2ccbd1605d095398d0f18c0cfb487a5e18b6 Mon Sep 17 00:00:00 2001 From: Nick Young Date: Wed, 23 Jul 2025 11:44:27 +1000 Subject: [PATCH 090/148] Update Auth GEP with Implementable details (#3884) This commit adds the design rationale and API design for phase 1 of the Auth GEP, adding a Filter to HTTPRoute. Signed-off-by: Nick Young --- geps/gep-1494/index.md | 382 +++++++++++++++++++++++++++++++++++- geps/gep-1494/metadata.yaml | 12 +- 2 files changed, 383 insertions(+), 11 deletions(-) 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 From a48921a745f5b9367c7cc96106137ea480d54052 Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Wed, 23 Jul 2025 02:14:28 -0400 Subject: [PATCH 091/148] Update RELEASE_MANAGEMENT.md (#3943) --- RELEASE_MANAGEMENT.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/RELEASE_MANAGEMENT.md b/RELEASE_MANAGEMENT.md index 94e2c724de..78d0020843 100644 --- a/RELEASE_MANAGEMENT.md +++ b/RELEASE_MANAGEMENT.md @@ -113,3 +113,19 @@ 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. From 18bd80558884697be5aaeaa75e5091af3553176f Mon Sep 17 00:00:00 2001 From: Shane Utt Date: Thu, 24 Jul 2025 00:20:28 -0400 Subject: [PATCH 092/148] docs: move GEP-3798 to Deferred for now (#3947) Signed-off-by: Shane Utt --- geps/gep-3798/index.md | 17 +++++++++++++++-- geps/gep-3798/metadata.yaml | 2 +- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/geps/gep-3798/index.md b/geps/gep-3798/index.md index 84b4a603c8..16080b1e8e 100644 --- a/geps/gep-3798/index.md +++ b/geps/gep-3798/index.md @@ -1,13 +1,26 @@ # GEP-3798: Client IP-Based Session Persistence * Issue: [#3798](https://github.com/kubernetes-sigs/gateway-api/issues/3798) -* Status: Provisional +* Status: Deferred (See [status definitions](../overview.md#gep-states).) ## Notes and Disclaimers -* This is currently targeting release as `Experimental` in [v1.4.0](https://github.com/kubernetes-sigs/gateway-api/milestone/22). However there was notable concern in [PR#3844](https://github.com/kubernetes-sigs/gateway-api/pull/3844) that it may be difficult to get multiple implementations who will be ready to implement this and move it forward. As such, the primary focus at this point should be finding representatives of implementations who may be interested in implementing this. Otherwise, this GEP may need to be `Deferred` and revisited as part of a later release. +* **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 diff --git a/geps/gep-3798/metadata.yaml b/geps/gep-3798/metadata.yaml index e7d33a7c8b..85a47289c0 100644 --- a/geps/gep-3798/metadata.yaml +++ b/geps/gep-3798/metadata.yaml @@ -2,7 +2,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 3798 name: Client IP-Based Session Persistence -status: Provisional +status: Deferred # Any authors who contribute to the GEP in any way should be listed here using # their GitHub handle. authors: From 222a1f8afcefe673505db18bba05f45b1619eb73 Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Thu, 24 Jul 2025 02:04:28 -0300 Subject: [PATCH 093/148] Mark grpcroutes.spec as required (#3937) --- apis/v1/grpcroute_types.go | 1 + .../crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml | 2 ++ config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml | 2 ++ pkg/generated/openapi/zz_generated.openapi.go | 2 ++ 4 files changed, 7 insertions(+) diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index c6eeb0f3ea..5e77a897c1 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -60,6 +60,7 @@ type GRPCRoute struct { 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. diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index 9e8dd64201..f04363ab31 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -2204,6 +2204,8 @@ spec: required: - parents type: object + required: + - spec type: object served: true storage: true diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 4f7d8f1323..4982ec8453 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -2047,6 +2047,8 @@ spec: required: - parents type: object + required: + - spec type: object served: true storage: true diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index cc919c61da..92162b5a1b 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3286,6 +3286,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRoute(ref common.ReferenceCallback }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ @@ -5927,6 +5928,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_GRPCRoute(ref common.ReferenceCa }, }, }, + Required: []string{"spec"}, }, }, Dependencies: []string{ From ff47627990d2e8845c6728077ee7a414f648bc0b Mon Sep 17 00:00:00 2001 From: kl52752 <89914070+kl52752@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:18:27 +0200 Subject: [PATCH 094/148] Gep-91: Address connection coalescing security issue (#3942) * GEP 91: Update API Relates to https://github.com/kubernetes-sigs/gateway-api/discussions/3760#discussioncomment-12997389 Signed-off-by: Arko Dasgupta * GEP-91: Address connection coalescing security issue * remove changes in API --------- Signed-off-by: Arko Dasgupta Co-authored-by: Arko Dasgupta --- geps/gep-91/index.md | 215 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 175 insertions(+), 40 deletions(-) diff --git a/geps/gep-91/index.md b/geps/gep-91/index.md index 5d28c9a117..8eedb7bd62 100644 --- a/geps/gep-91/index.md +++ b/geps/gep-91/index.md @@ -10,24 +10,37 @@ This GEP proposes a way to validate the TLS certificate presented by the frontend client to the server (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 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). -* Supporting a mode where validating client certificates is optional, useful for debugging and migrating to strict TLS. ## Non-Goals * Define other fields that can be used to verify the client certificate such as the Certificate Hash. ### API -* 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 two new structs `TLSConfig` and `FrontendTLSValidation` allowing for the definition of certificate validation used to authenticate the peer (frontend) in a TLS connection. A new `tls` field, storing an array of `TLSConfigs`, will be added to the gateway object. +* 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. -* 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. +* 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` + 2) `AllowInvalidOrMissingCert` +* Introduce a `ObjectReference` structure that can be used to specify `caCertificateRefs` references. +* Introduce a `tls` field within the Gateway Spec to allow for a common TLS configuration to apply across all listeners. + +### Impact on listeners + +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 that match the configuration. #### GO @@ -65,50 +78,118 @@ type ObjectReference struct { Namespace *Namespace `json:"namespace,omitempty"` } -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"` +// GatewayTLSConfigs stores TLS configurations for a Gateway. +// +// * If the `port` field in `TLSConfig` is not set, the TLS configuration applies +// to all listeners in the gateway. We call this `default` configuration. +// * If the `port` field in `TLSConfig` is set, the TLS configuration applies +// only to listeners with a matching port. Each port requires a unique TLS configuration. +// * Per-port configurations can override the `default` configuration. +// * The `default` configuration is optional. Clients can apply TLS configuration +// to a subset of listeners by creating only per-port configurations. Listeners +// with a port that does not match any TLS configuration will not have +// `frontendValidation` set. +type GatewayTLSConfigs = []TLSConfig + +// TLSConfig describes a TLS configuration that can be applied to all Gateway +// Listeners or to all Listeners matching the Port if set. +type TLSConfig struct { + // The Port indicates the Port Number to which the TLS configuration will be + // applied. If the field is not set the TLS Configuration will be applied to + // all Listeners. + // + // Support: Extended + // + // +optional + // + Port *PortNumber + // 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. + // + // Each field may be overidden by an equivalent setting applied at the Listener level. + // + // Support: Extended + // + // +optional + // + FrontendValidation *FrontendTLSValidation `json:"frontendValidation,omitempty"` } // 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`. + // - AllowInvalidOrMissingCert: In this mode, the gateway will accept + // connections even if the client certificate is not presented or fails verification. + // + // Defaults to AllowValidOnly. + // + // Support: Extended + // + // +optional + // +kubebuilder:default=AllowValidOnly + Mode *FrontendValidationModeType `json:"mode,omitempty"` +} + +// FrontendValidationModeType type defines how a Gateway or Listener validates client certificates. +// +// +kubebuilder:validation:Enum=AllowValidOnly;AllowInvalidOrMissingCert +type FrontendValidationModeType string + +const ( + // AllowValidOnly indicates that a client certificate is required + // during the TLS handshake and MUST pass validation. + AllowValidOnly FrontendValidationModeType = "AllowValidOnly" + + // AllowInvalidOrMissingCert indicates that a client certificate may not be + // presented during the handshake or the validation against CA certificates may fail. + AllowInvalidOrMissingCert FrontendValidationModeType = "AllowInvalidOrMissingCert" +) + +type GatewaySpec struct { + ... + // TLSConfigs stores TLS configurations for a Gateway. + TLSConfigs GatewayTLSConfigs } ``` #### YAML +1. Setting default `frontendValidation` config. + ```yaml apiVersion: gateway.networking.k8s.io/v1beta1 kind: Gateway @@ -116,6 +197,12 @@ metadata: name: client-validation-basic spec: gatewayClassName: acme-lb + tls: + - frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: default-cert listeners: - name: foo-https protocol: HTTPS @@ -126,11 +213,58 @@ 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: + - port: 443 frontendValidation: caCertificateRefs: - kind: ConfigMap group: "" name: foo-example-com-ca-cert + - frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: default-cert + mode: AllowInvalidOrMissingCert + 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 @@ -143,7 +277,7 @@ This section highlights use cases that may be covered in a future iteration of t ## Existing support in Implementations -This feature is already widely supported by implementations that conform to the Gateway API. +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. @@ -191,3 +325,4 @@ This GEP aims to standardize this behavior as an official part of the upstream s [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/ From cb2d8f1413b4624b4851cc3319de2b5c27375788 Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Thu, 24 Jul 2025 17:44:28 -0300 Subject: [PATCH 095/148] Use envtest for CRD validation tests (#3948) * Use envtest for cel validation instead of a KinD cluster * Add CRD validation tests to gh actions * Move manifest test to use envtest * Remove the crd testing shell script * Fix boilerplate of test file --- .github/workflows/crd-validation.yml | 32 +++++ Makefile | 7 +- go.mod | 1 + go.sum | 14 +++ hack/test-crds-validation.sh | 152 ----------------------- pkg/test/cel/main_test.go | 78 +++++++++--- pkg/test/crd/crd_test.go | 177 +++++++++++++++++++++++++++ 7 files changed, 294 insertions(+), 167 deletions(-) create mode 100644 .github/workflows/crd-validation.yml delete mode 100755 hack/test-crds-validation.sh create mode 100644 pkg/test/crd/crd_test.go 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/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/go.mod b/go.mod index 82f05190d0..f0828e05cc 100644 --- a/go.mod +++ b/go.mod @@ -28,6 +28,7 @@ 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 diff --git a/go.sum b/go.sum index 85b14c3ac1..85aff8e13d 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,12 @@ 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= @@ -120,6 +124,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE 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/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= @@ -209,6 +221,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T 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= +gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= +gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= 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< Date: Thu, 24 Jul 2025 19:56:26 -0700 Subject: [PATCH 096/148] build(deps): bump sigs.k8s.io/yaml from 1.4.0 to 1.5.0 (#3904) Bumps [sigs.k8s.io/yaml](https://github.com/kubernetes-sigs/yaml) from 1.4.0 to 1.5.0. - [Release notes](https://github.com/kubernetes-sigs/yaml/releases) - [Changelog](https://github.com/kubernetes-sigs/yaml/blob/master/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/yaml/compare/v1.4.0...v1.5.0) --- updated-dependencies: - dependency-name: sigs.k8s.io/yaml dependency-version: 1.5.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 3 ++- go.sum | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index f0828e05cc..b2fd9f7a0d 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( 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 ( @@ -67,6 +67,7 @@ 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 + go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/crypto v0.39.0 // indirect golang.org/x/mod v0.25.0 // indirect golang.org/x/oauth2 v0.28.0 // indirect diff --git a/go.sum b/go.sum index 85aff8e13d..560828c789 100644 --- a/go.sum +++ b/go.sum @@ -172,6 +172,10 @@ 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= @@ -275,5 +279,6 @@ 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= From f00522647bafdd4c3d40d396b6360726f469f923 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 19:56:33 -0700 Subject: [PATCH 097/148] build(deps): bump the k8s-io group with 5 updates (#3931) Bumps the k8s-io group with 5 updates: | Package | From | To | | --- | --- | --- | | [k8s.io/api](https://github.com/kubernetes/api) | `0.33.2` | `0.33.3` | | [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.33.2` | `0.33.3` | | [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.33.2` | `0.33.3` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.33.2` | `0.33.3` | | [k8s.io/code-generator](https://github.com/kubernetes/code-generator) | `0.33.2` | `0.33.3` | Updates `k8s.io/api` from 0.33.2 to 0.33.3 - [Commits](https://github.com/kubernetes/api/compare/v0.33.2...v0.33.3) Updates `k8s.io/apiextensions-apiserver` from 0.33.2 to 0.33.3 - [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases) - [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.33.2...v0.33.3) Updates `k8s.io/apimachinery` from 0.33.2 to 0.33.3 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.33.2...v0.33.3) Updates `k8s.io/client-go` from 0.33.2 to 0.33.3 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.33.2...v0.33.3) Updates `k8s.io/code-generator` from 0.33.2 to 0.33.3 - [Commits](https://github.com/kubernetes/code-generator/compare/v0.33.2...v0.33.3) --- updated-dependencies: - dependency-name: k8s.io/api dependency-version: 0.33.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apiextensions-apiserver dependency-version: 0.33.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-version: 0.33.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-version: 0.33.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/code-generator dependency-version: 0.33.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index b2fd9f7a0d..e02beb946a 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,11 @@ require ( google.golang.org/grpc v1.73.0 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.36.6 - k8s.io/api v0.33.2 - k8s.io/apiextensions-apiserver v0.33.2 - k8s.io/apimachinery v0.33.2 - k8s.io/client-go v0.33.2 - k8s.io/code-generator v0.33.2 + k8s.io/api v0.33.3 + k8s.io/apiextensions-apiserver v0.33.3 + k8s.io/apimachinery v0.33.3 + k8s.io/client-go v0.33.3 + k8s.io/code-generator v0.33.3 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 sigs.k8s.io/controller-runtime v0.21.0 diff --git a/go.sum b/go.sum index 560828c789..60714d401a 100644 --- a/go.sum +++ b/go.sum @@ -250,16 +250,16 @@ 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.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY= -k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs= -k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8= -k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8= -k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY= -k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E= -k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo= -k8s.io/code-generator v0.33.2 h1:PCJ0Y6viTCxxJHMOyGqYwWEteM4q6y1Hqo2rNpl6jF4= -k8s.io/code-generator v0.33.2/go.mod h1:hBjCA9kPMpjLWwxcr75ReaQfFXY8u+9bEJJ7kRw3J8c= +k8s.io/api v0.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= +k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= +k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= +k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= +k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= +k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= +k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= +k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= +k8s.io/code-generator v0.33.3 h1:6+34LhYkIuQ/yn/E3qlpVqjQaP8smzCu4NE1A8b0LWs= +k8s.io/code-generator v0.33.3/go.mod h1:6Y02+HQJYgNphv9z3wJB5w+sjYDIEBQW7sh62PkufvA= 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= From c60a5e0352b80badc442e884d3a9cc6878e1c856 Mon Sep 17 00:00:00 2001 From: Saylor Berman Date: Fri, 25 Jul 2025 11:58:28 -0600 Subject: [PATCH 098/148] NGINX v2.0.2 conformance report for 1.2.1 (#3954) Adding conformance report for NGINX Gateway Fabric v2.0.2 for Gateway API version v1.2.1. --- .../nginx-nginx-gateway-fabric/README.md | 1 + .../experimental-2.0.2-default-report.yaml | 93 +++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 conformance/reports/v1.2.1/nginx-nginx-gateway-fabric/experimental-2.0.2-default-report.yaml 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 From 040c2a04b9da6c0f7d0eb394cf0ba9c28495e2ec Mon Sep 17 00:00:00 2001 From: Flynn Date: Fri, 25 Jul 2025 20:22:27 -0400 Subject: [PATCH 099/148] API for Default Gateways (#3887) * Add API to GEP-3793. Signed-off-by: Flynn * Minor fixes in text, more important fixes in list formatting. Signed-off-by: Flynn * Major update for multiple default Gateways, including clarification of goals and non-goals as needed and acknowledgment that a defaulted Route gives up some control. Signed-off-by: Flynn * Rearrange Prior Art based on feedback; also split the explicit/implicit bit into its own paragraph. Signed-off-by: Flynn * :man_facepalming: I can count, really. Signed-off-by: Flynn * Massive update for `defaultOK: true` instead of "no parentRefs". Signed-off-by: Flynn * Use `spec.defaultOK` to parallel `spec.isDefault`. Signed-off-by: Flynn * Minor tweaks for feedback. Signed-off-by: Flynn * Mark as implementable Signed-off-by: Flynn * Change `defaultOK` to `useDefaultGateway`. Signed-off-by: Flynn * Move 3793 to Implementable in mkdocs.yml Signed-off-by: Flynn * Define default "scopes", with the only currently-defined scope being All. Update isDefault to defaultScope; switch both it and useDefaultGateway to scopes instead of bools. Signed-off-by: Flynn * Add RFC8174 definitions Signed-off-by: Flynn --------- Signed-off-by: Flynn --- geps/gep-3793/index.md | 577 +++++++++++++++++++++++++++++++----- geps/gep-3793/metadata.yaml | 2 +- mkdocs.yml | 2 +- 3 files changed, 510 insertions(+), 71 deletions(-) diff --git a/geps/gep-3793/index.md b/geps/gep-3793/index.md index 9f15ead87d..f0cad9a72d 100644 --- a/geps/gep-3793/index.md +++ b/geps/gep-3793/index.md @@ -1,10 +1,17 @@ # GEP-3793: Default Gateways * Issue: [#3793](https://github.com/kubernetes-sigs/gateway-api/issues/3793) -* Status: Provisional +* 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.** @@ -17,44 +24,73 @@ 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. +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. -[Ana]: https://gateway-api.sigs.k8s.io/concepts/roles-and-personas/#ana +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. + 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 Gateway is the default, and which of - her Routes are bound to it. +- 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 exactly - one of them to be the default Gateway. +- 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 Gateway is the default, so that - they can ensure that it meets their requirements for security, performance, - and other operational concerns. +- 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 a default Gateway. +- Allow Chihiro to choose not to provide any default Gateways at all. -- Allow Chihiro to rename, reconfigure, or replace the default Gateway at +- Allow Chihiro to define the scope of a default Gateway. + +- Allow Chihiro to rename, reconfigure, or replace any default Gateway at runtime. - - If Chihiro renames the default Gateway, Routes using the default Gateway - MUST remain bound to the new default Gateway. Ana shouldn't need to go - recreate all her Routes just because Chihiro is being indecisive. + - 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 the default - Gateway implementation is changed. For example, suppose that Chihiro - switches the default Gateway from an implementation that supports the + - 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 the default Gateway, and - to enumerate which Routes are currently bound to the default Gateway. +- 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. @@ -63,20 +99,11 @@ she doesn't have to explicitly name, and can simply trust to exist. ## Non-Goals -- Support multiple "default" Gateways in a single cluster. If Ana has to make - a choice about which Gateway she wants to use, she'll need to be explicit - about that. - - Loosening this restriction later is a possibility. For example, we may later - want to consider allowing a default Gateway per namespace, or a default - Gateway per implementation running in a cluster. However, these examples are - not in scope for this GEP, in order to have a fighting chance of getting - functionality into Gateway API 1.4. +- 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. -- Allow Ana to override Chihiro's choice for the default Gateway for a given - Route without explicitly specifying the Gateway. - -- Require that every possible routing use case be met by a Route using the +- 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. @@ -112,37 +139,70 @@ 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 -This is very much not a new problem: there are many other systems out there -where being unambiguous is crucial, but where being completely explicit is a -burden. One of the simplest examples 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. +- **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. -The Ingress resource, of course, is another 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: + (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.) -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. +- **Emissary Mapping** -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. + 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. -(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.) + In Emissary: -It's rare to find systems that are completely explicit or completely implicit: -in practice, the trick is to find a usable balance between explicitness and -simplicity, while managing ambiguity. + - 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 @@ -156,15 +216,16 @@ 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 -Most of the API work for this GEP is TBD at this point. The challenge 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 the Gateway and its configuration. +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 @@ -184,15 +245,371 @@ 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. This is obviously a key point that -will need resolution before this GEP can graduate. +`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 @@ -204,14 +621,36 @@ 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. +- 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 index 060426f033..db611f5988 100644 --- a/geps/gep-3793/metadata.yaml +++ b/geps/gep-3793/metadata.yaml @@ -2,7 +2,7 @@ apiVersion: internal.gateway.networking.k8s.io/v1alpha1 kind: GEPDetails number: 3793 name: Default Gateways -status: Provisional +status: Implementable # Any authors who contribute to the GEP in any way should be listed here using # their GitHub handle. authors: diff --git a/mkdocs.yml b/mkdocs.yml index 7765e320d3..d29e212746 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -132,10 +132,10 @@ nav: - geps/gep-2648/index.md - geps/gep-3779/index.md - geps/gep-3792/index.md - - geps/gep-3793/index.md - Implementable: - geps/gep-91/index.md - geps/gep-3567/index.md + - geps/gep-3793/index.md - Experimental: - geps/gep-1619/index.md - geps/gep-1713/index.md From d3b3a089087ac7767dd54bf79eda24870045f324 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 22:18:30 -0700 Subject: [PATCH 100/148] build(deps): bump google.golang.org/grpc from 1.73.0 to 1.74.2 (#3957) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.73.0 to 1.74.2. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.73.0...v1.74.2) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-version: 1.74.2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 8 ++++---- go.sum | 36 ++++++++++++++++++------------------ 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index e02beb946a..2ef20f67d1 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/stretchr/testify v1.10.0 golang.org/x/net v0.41.0 golang.org/x/sync v0.16.0 - google.golang.org/grpc v1.73.0 + google.golang.org/grpc v1.74.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.36.6 k8s.io/api v0.33.3 @@ -34,7 +34,7 @@ require ( 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 @@ -70,14 +70,14 @@ require ( go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/crypto v0.39.0 // indirect golang.org/x/mod v0.25.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.33.0 // indirect golang.org/x/term v0.32.0 // indirect golang.org/x/text v0.26.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.33.0 // indirect golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a // 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 diff --git a/go.sum b/go.sum index 60714d401a..7050b8ff32 100644 --- a/go.sum +++ b/go.sum @@ -29,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= @@ -156,16 +156,16 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= -go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= -go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= -go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= -go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY= -go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg= -go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o= -go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w= -go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= -go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= +go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= +go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= +go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= +go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= +go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= +go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= +go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= +go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= +go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= 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= @@ -191,8 +191,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +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= @@ -227,10 +227,10 @@ golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSm golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 h1:e0AIkUUhxyBKh6ssZNrAMeqhA7RKUj42346d1y02i2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.73.0 h1:VIWSmpI2MegBtTuFt5/JWy2oXxtjJ/e89Z70ImfD2ok= -google.golang.org/grpc v1.73.0/go.mod h1:50sbHOUqWoCQGI8V2HQLJM0B+LMlIUjNSZmow7EVBQc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= +google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= 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= From 08b0c9b36376db6b26c928e0e08d187e83f64f89 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jul 2025 22:36:29 -0700 Subject: [PATCH 101/148] build(deps): bump mkdocs-material in /hack/mkdocs/image (#3959) Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.6.15 to 9.6.16. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.15...9.6.16) --- updated-dependencies: - dependency-name: mkdocs-material dependency-version: 9.6.16 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index a075a43182..7a5fc4adde 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -10,7 +10,7 @@ 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.15 +mkdocs-material==9.6.16 mkdocs-redirects==1.2.2 mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 From 0f6f9a35677b86ced94e1ebf5060471fd8e75e75 Mon Sep 17 00:00:00 2001 From: Flynn Date: Wed, 30 Jul 2025 12:42:29 -0400 Subject: [PATCH 102/148] Mesh resource definition (#3950) * GEP-3949, Mesh resource Signed-off-by: Flynn * Tweak punctuation Signed-off-by: Flynn * Update to experimental API group and resource name Signed-off-by: Flynn * More tweak Signed-off-by: Flynn * Indentation fix Signed-off-by: Flynn * Note that changing GAMMA's position on multiple meshes is a non-goal Signed-off-by: Flynn * Review feedback Signed-off-by: Flynn * Fix list-element indentation Signed-off-by: Flynn * Add a mkdocs.yml entry. :man_facepalming: Signed-off-by: Flynn * Review feedback Signed-off-by: Flynn * Initial type definition Signed-off-by: Flynn * Drop comment that was breaking rendering? Signed-off-by: Flynn * Tabs -> spaces Signed-off-by: Flynn * Implementable, not Provisional Signed-off-by: Flynn * Fix the other place a kubebuilder default was breaking rendering Signed-off-by: Flynn * Tweak Signed-off-by: Flynn * Formatting fixes Signed-off-by: Flynn * Review feedback. Signed-off-by: Flynn * Review feedback Signed-off-by: Flynn * :man_facepalming: Cluster-scoped resources don't have namespaces. Signed-off-by: Flynn --------- Signed-off-by: Flynn --- geps/gep-3792/index.md | 32 +-- geps/gep-3949/index.md | 539 ++++++++++++++++++++++++++++++++++++ geps/gep-3949/metadata.yaml | 34 +++ mkdocs.yml | 2 +- 4 files changed, 590 insertions(+), 17 deletions(-) create mode 100644 geps/gep-3949/index.md create mode 100644 geps/gep-3949/metadata.yaml diff --git a/geps/gep-3792/index.md b/geps/gep-3792/index.md index 802d729c97..2441074466 100644 --- a/geps/gep-3792/index.md +++ b/geps/gep-3792/index.md @@ -42,10 +42,10 @@ In this GEP: 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. + **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 @@ -56,21 +56,21 @@ In this GEP: 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). + **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. + 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. + 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 @@ -197,7 +197,7 @@ 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.) -#### 4. The Discovery Problem +#### 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 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/mkdocs.yml b/mkdocs.yml index d29e212746..18393ce4c6 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -135,7 +135,7 @@ nav: - Implementable: - geps/gep-91/index.md - geps/gep-3567/index.md - - geps/gep-3793/index.md + - geps/gep-3949/index.md - Experimental: - geps/gep-1619/index.md - geps/gep-1713/index.md From 657b26558bc495d7c35a7a4a2bf5cbd5d0ca6fba Mon Sep 17 00:00:00 2001 From: Ricardo Katz Date: Thu, 31 Jul 2025 20:27:15 -0300 Subject: [PATCH 103/148] Lint required optional (#3929) * Add missing required markers on gateway types * Add missing required markers on grpcroute types * Add missing required markers on httproute types * Add missing required markers on obj_reference types * Add missing required markers on shared types * Add missing required markers on experimental types * Add missing required markers on v1beta1 types * Add missing required markers on v1alpha3 types * Add missing required markers on v1alpha2 types * Enable optionalorrequired linter * Revert objectmeta field doc * Revert minItems changes --- .github/workflows/kal.yml | 3 +++ .golangci-kal.yml | 1 + apis/v1/gateway_types.go | 20 ++++++++++++++++++- apis/v1/gatewayclass_types.go | 10 +++++++++- apis/v1/gatewayclass_types_overrides.go | 1 + apis/v1/grpcroute_types.go | 7 ++++++- apis/v1/httproute_types.go | 17 +++++++++++++++- apis/v1/object_reference_types.go | 8 ++++++++ apis/v1/shared_types.go | 6 ++++++ apis/v1alpha2/policy_types.go | 10 ++++++++++ apis/v1alpha2/tcproute_types.go | 7 ++++++- apis/v1alpha2/tlsroute_types.go | 7 ++++++- apis/v1alpha2/udproute_types.go | 7 ++++++- apis/v1alpha3/backendtlspolicy_types.go | 11 +++++++++- apis/v1alpha3/tlsroute_types.go | 6 +++++- apis/v1beta1/referencegrant_types.go | 15 +++++++++++++- apisx/v1alpha1/shared_types.go | 3 +++ apisx/v1alpha1/xbackendtrafficpolicy_types.go | 6 +++++- apisx/v1alpha1/xlistenerset_types.go | 15 +++++++++++++- ....networking.k8s.io_backendtlspolicies.yaml | 1 + .../gateway.networking.k8s.io_gateways.yaml | 4 ++++ .../gateway.networking.k8s.io_grpcroutes.yaml | 1 + .../gateway.networking.k8s.io_httproutes.yaml | 2 ++ .../gateway.networking.k8s.io_tcproutes.yaml | 3 +++ .../gateway.networking.k8s.io_tlsroutes.yaml | 6 ++++++ .../gateway.networking.k8s.io_udproutes.yaml | 3 +++ ...king.x-k8s.io_xbackendtrafficpolicies.yaml | 1 + ...way.networking.x-k8s.io_xlistenersets.yaml | 2 ++ .../gateway.networking.k8s.io_grpcroutes.yaml | 1 + .../gateway.networking.k8s.io_httproutes.yaml | 2 ++ pkg/generated/openapi/zz_generated.openapi.go | 8 ++++++-- 31 files changed, 180 insertions(+), 14 deletions(-) diff --git a/.github/workflows/kal.yml b/.github/workflows/kal.yml index d657969f5d..618256e886 100644 --- a/.github/workflows/kal.yml +++ b/.github/workflows/kal.yml @@ -15,6 +15,9 @@ jobs: 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 diff --git a/.golangci-kal.yml b/.golangci-kal.yml index aad23ab40d..d2b764e868 100644 --- a/.golangci-kal.yml +++ b/.golangci-kal.yml @@ -16,6 +16,7 @@ linters: - "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`. - "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: diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index f54e5d10ce..ea8667af61 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 @@ -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,11 +396,13 @@ type Listener struct { // same port, subject to the Listener compatibility rules. // // Support: Core + // +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 @@ -637,6 +645,7 @@ type FrontendTLSValidation struct { // // +kubebuilder:validation:MaxItems=8 // +kubebuilder:validation:MinItems=1 + // +required CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"` } @@ -721,6 +730,7 @@ type RouteGroupKind struct { Group *Group `json:"group,omitempty"` // Kind is the kind of the Route. + // +required Kind Kind `json:"kind"` } @@ -764,6 +774,7 @@ type GatewayStatusAddress struct { // // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 + // +required Value string `json:"value"` } @@ -873,15 +884,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"` } @@ -1096,6 +1110,7 @@ const ( // 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 @@ -1109,6 +1124,7 @@ type ListenerStatus struct { // reference the valid Route kinds that have been specified. // // +kubebuilder:validation:MaxItems=8 + // +required SupportedKinds []RouteGroupKind `json:"supportedKinds"` // AttachedRoutes represents the total number of Routes that have been @@ -1128,6 +1144,7 @@ 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. @@ -1135,6 +1152,7 @@ type ListenerStatus struct { // +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..655195ce6d 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. @@ -287,5 +294,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 5e77a897c1..c6480c3857 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -56,7 +56,8 @@ 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. @@ -64,6 +65,7 @@ type GRPCRoute struct { Spec GRPCRouteSpec `json:"spec,omitempty"` // Status defines the current state of GRPCRoute. + // +optional Status GRPCRouteStatus `json:"status,omitempty"` } @@ -405,12 +407,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 +525,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 diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 157932e971..96e245c386 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"` } @@ -608,12 +611,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"` } @@ -675,12 +680,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"` } @@ -830,6 +837,7 @@ 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 @@ -977,12 +985,14 @@ 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"` } @@ -1101,6 +1111,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 @@ -1274,6 +1285,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 @@ -1356,6 +1368,7 @@ type HTTPCORSFilter struct { // Support: Extended // +listType=set // +kubebuilder:validation:MaxItems=64 + // +optional AllowOrigins []AbsoluteURI `json:"allowOrigins,omitempty"` // AllowCredentials indicates whether the actual cross-origin request allows @@ -1417,6 +1430,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 @@ -1458,6 +1472,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 diff --git a/apis/v1/object_reference_types.go b/apis/v1/object_reference_types.go index dd507b2136..54e34fa2ed 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 @@ -157,12 +162,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 226c776372..e874c2f905 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 @@ -436,6 +437,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 +453,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. @@ -477,6 +480,7 @@ type RouteParentStatus struct { // +listMapKey=type // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=8 + // +required Conditions []metav1.Condition `json:"conditions,omitempty"` } @@ -499,6 +503,7 @@ type RouteStatus struct { // means the route has not been attached to any Gateway. // // +kubebuilder:validation:MaxItems=32 + // +required Parents []RouteParentStatus `json:"parents"` } @@ -913,6 +918,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/v1alpha2/policy_types.go b/apis/v1alpha2/policy_types.go index bc2ef766a9..b38ff00327 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,12 @@ 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. // + // +required // +listType=map // +listMapKey=type // +kubebuilder:validation:MinItems=1 @@ -234,5 +243,6 @@ type PolicyStatus struct { // the BackendTLSPolicy. // // +kubebuilder:validation:MaxItems=16 + // +required Ancestors []PolicyAncestorStatus `json:"ancestors"` } diff --git a/apis/v1alpha2/tcproute_types.go b/apis/v1alpha2/tcproute_types.go index e383af495d..99446bedcb 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,7 @@ type TCPRouteSpec struct { // Rules are a list of TCP matchers and actions. // + // +required // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -81,6 +85,7 @@ type TCPRouteRule struct { // // Support for weight: Extended // + // +required // +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 f1b3814cf7..5cd56ca201 100644 --- a/apis/v1alpha2/tlsroute_types.go +++ b/apis/v1alpha2/tlsroute_types.go @@ -33,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"` } @@ -87,6 +90,7 @@ type TLSRouteSpec struct { // Rules are a list of TLS matchers and actions. // + // +required // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -124,6 +128,7 @@ type TLSRouteRule struct { // // Support for weight: Extended // + // +required // +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..82afedc6bb 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,7 @@ type UDPRouteSpec struct { // Rules are a list of UDP matchers and actions. // + // +required // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -81,6 +85,7 @@ type UDPRouteRule struct { // // Support for weight: Extended // + // +required // +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 75655f5d63..93c47d72bb 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"` } @@ -79,11 +82,13 @@ type BackendTLSPolicySpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 + // +required // +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))" // +kubebuilder:validation:XValidation:message="sectionName must be unique when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))" 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 @@ -154,6 +159,8 @@ type BackendTLSPolicyValidation struct { // 2. Hostname MUST be used for authentication and MUST match the certificate served by the matching backend, unless SubjectAltNames is specified. // // Support: Core + // + // +required Hostname v1.PreciseHostname `json:"hostname"` // SubjectAltNames contains one or more Subject Alternative Names. @@ -176,6 +183,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. diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go index 82345f9080..5d2f9c5879 100644 --- a/apis/v1alpha3/tlsroute_types.go +++ b/apis/v1alpha3/tlsroute_types.go @@ -36,13 +36,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 v1alpha2.TLSRouteStatus `json:"status,omitempty"` } @@ -91,6 +94,7 @@ type TLSRouteSpec struct { // Rules are a list of TLS matchers and actions. // + // +required // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // diff --git a/apis/v1beta1/referencegrant_types.go b/apis/v1beta1/referencegrant_types.go index 0b0caf7088..6321515238 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 @@ -72,6 +74,7 @@ type ReferenceGrantSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 + // +required From []ReferenceGrantFrom `json:"from"` // To describes the resources that may be referenced by the resources @@ -83,6 +86,7 @@ type ReferenceGrantSpec struct { // // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 + // +required To []ReferenceGrantTo `json:"to"` } @@ -92,6 +96,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 +115,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 +133,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 +143,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/apisx/v1alpha1/shared_types.go b/apisx/v1alpha1/shared_types.go index f811ace877..441d4758c1 100644 --- a/apisx/v1alpha1/shared_types.go +++ b/apisx/v1alpha1/shared_types.go @@ -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 92cca1b735..5eb6942b1b 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -57,21 +57,25 @@ import ( // - 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 @@ -110,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"` } @@ -120,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 @@ -152,9 +158,11 @@ type ListenerEntry struct { // Port is the network port. Multiple listeners may use the // same port, subject to the Listener compatibility rules. + // +required Port PortNumber `json:"port"` // 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 @@ -230,9 +238,11 @@ 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. + // +required Port PortNumber `json:"port"` // SupportedKinds is the list indicating the Kinds supported by this @@ -246,6 +256,7 @@ type ListenerEntryStatus struct { // reference the valid Route kinds that have been specified. // // +kubebuilder:validation:MaxItems=8 + // +required SupportedKinds []RouteGroupKind `json:"supportedKinds"` // AttachedRoutes represents the total number of Routes that have been @@ -265,6 +276,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. @@ -272,6 +284,7 @@ type ListenerEntryStatus struct { // +listType=map // +listMapKey=type // +kubebuilder:validation:MaxItems=8 + // +required Conditions []metav1.Condition `json:"conditions"` } diff --git a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml index a2a5506c17..f431e98faf 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml @@ -623,6 +623,7 @@ spec: type: string required: - ancestorRef + - conditions - controllerName type: object maxItems: 16 diff --git a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml index 328999eee9..6ad00cb433 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml @@ -973,6 +973,8 @@ spec: maxItems: 8 minItems: 1 type: array + required: + - caCertificateRefs type: object mode: default: Terminate @@ -2311,6 +2313,8 @@ spec: maxItems: 8 minItems: 1 type: array + required: + - caCertificateRefs type: object mode: default: Terminate diff --git a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml index f04363ab31..25575f3150 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_grpcroutes.yaml @@ -2196,6 +2196,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index fe5b7f0330..dc198cf154 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -3619,6 +3619,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object @@ -7235,6 +7236,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object diff --git a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml index 7365304e2a..8d094e012d 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tcproutes.yaml @@ -435,6 +435,8 @@ 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 @@ -709,6 +711,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef 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 8843c2f0d3..597a3178c1 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -498,6 +498,8 @@ 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 @@ -772,6 +774,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object @@ -1268,6 +1271,8 @@ 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 @@ -1543,6 +1548,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef 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..6c5cd46b0b 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_udproutes.yaml @@ -435,6 +435,8 @@ 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 @@ -709,6 +711,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef 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..6c69c96b40 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml @@ -583,6 +583,7 @@ spec: type: string required: - ancestorRef + - conditions - controllerName type: object maxItems: 16 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 2454521c2e..637a9ed365 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml @@ -487,6 +487,8 @@ spec: maxItems: 8 minItems: 1 type: array + required: + - caCertificateRefs type: object mode: default: Terminate diff --git a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml index 4982ec8453..989e24e844 100644 --- a/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml @@ -2039,6 +2039,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object diff --git a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 1824bd5e19..12c0639a2f 100644 --- a/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml @@ -2803,6 +2803,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object @@ -5603,6 +5604,7 @@ spec: - name type: object required: + - conditions - controllerName - parentRef type: object diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 92162b5a1b..4c70dd18b1 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3093,6 +3093,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.Refer }, }, }, + Required: []string{"caCertificateRefs"}, }, }, Dependencies: []string{ @@ -5717,7 +5718,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_RouteParentStatus(ref common.Reference }, }, }, - Required: []string{"parentRef", "controllerName"}, + Required: []string{"parentRef", "controllerName", "conditions"}, }, }, Dependencies: []string{ @@ -6156,7 +6157,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_PolicyAncestorStatus(ref common. }, }, }, - Required: []string{"ancestorRef", "controllerName"}, + Required: []string{"ancestorRef", "controllerName", "conditions"}, }, }, Dependencies: []string{ @@ -6412,6 +6413,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ @@ -6621,6 +6623,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ @@ -6845,6 +6848,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteRule(ref common.Referenc }, }, }, + Required: []string{"backendRefs"}, }, }, Dependencies: []string{ From 7cf2dab3557f04a645b91608acb701855f6421e6 Mon Sep 17 00:00:00 2001 From: Zhen Zhang Date: Fri, 1 Aug 2025 22:33:38 +0800 Subject: [PATCH 104/148] add OpenKruise Rollouts as one of the integration solution (#3968) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 守辰 --- site-src/implementations.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/site-src/implementations.md b/site-src/implementations.md index 93f6dc2c89..791f5450d3 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -130,6 +130,7 @@ other functions (like managing DNS or creating certificates). - [argo-rollouts][22] (alpha) - [Knative][24] (alpha) - [Kuadrant][26] (GA) +- [kruise-rollouts][41] (alpha) [1]:#acnodal-epic [2]:#apisix @@ -170,6 +171,7 @@ other functions (like managing DNS or creating certificates). [38]:#google-cloud-service-mesh [39]:#kubvernor [40]:#agentgateway-with-kgateway +[41]:#kruise-rollouts [gamma]:mesh/index.md @@ -685,6 +687,10 @@ For help and support with Kuadrant's implementation please feel free to [create [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 From 30a0767956c5063b48e56744476885156ae1aaa8 Mon Sep 17 00:00:00 2001 From: Sneha Chhabria <59101963+snehachhabria@users.noreply.github.com> Date: Fri, 1 Aug 2025 08:51:38 -0700 Subject: [PATCH 105/148] add conformance report for AGC (#3939) --- .../README.md | 13 ++++ .../standard-v1.2.1-default-report.yaml | 59 +++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 conformance/reports/v1.2.1/azure-application-gateway-for-containers/README.md create mode 100644 conformance/reports/v1.2.1/azure-application-gateway-for-containers/standard-v1.2.1-default-report.yaml 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. From eaaf985df500b39c14836f068673446998e7b4d9 Mon Sep 17 00:00:00 2001 From: Bob Tian Date: Fri, 1 Aug 2025 15:55:37 -0700 Subject: [PATCH 106/148] Skip test in report if RunTest is configured. (#3966) --- conformance/utils/suite/suite.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 63a6b93a16..b34a1ea3ff 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -461,6 +461,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 } From b6b242839ebd353b25ee41f83d2ce69dd177ea56 Mon Sep 17 00:00:00 2001 From: Rostislav Bobrovsky Date: Mon, 4 Aug 2025 05:57:37 +0200 Subject: [PATCH 107/148] TLSRoute: Set MaxItems=1 for rules[] in v1alpha3 (#3971) * TLSRoute: Set Rules MaxItems to 1 * TLSRoute: Add omitempty to Rules * TLSRoute: Rules godoc --- apis/v1alpha3/tlsroute_types.go | 6 +++--- .../experimental/gateway.networking.k8s.io_tlsroutes.yaml | 4 ++-- pkg/generated/openapi/zz_generated.openapi.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go index 5d2f9c5879..68900b3c9a 100644 --- a/apis/v1alpha3/tlsroute_types.go +++ b/apis/v1alpha3/tlsroute_types.go @@ -92,13 +92,13 @@ type TLSRouteSpec struct { // +required Hostnames []Hostname `json:"hostnames,omitempty"` - // Rules are a list of TLS matchers and actions. + // Rules are a list of actions. // // +required // +kubebuilder:validation:MinItems=1 - // +kubebuilder:validation:MaxItems=16 + // +kubebuilder:validation:MaxItems=1 // - Rules []v1alpha2.TLSRouteRule `json:"rules"` + Rules []v1alpha2.TLSRouteRule `json:"rules,omitempty"` } // +kubebuilder:object:root=true diff --git a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml index 597a3178c1..cdeecdd31c 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_tlsroutes.yaml @@ -1119,7 +1119,7 @@ spec: || p2.port == 0)) || (has(p1.port) && has(p2.port) && p1.port == p2.port)))) rules: - description: Rules are a list of TLS matchers and actions. + description: Rules are a list of actions. items: description: TLSRouteRule is the configuration for a given rule. properties: @@ -1274,7 +1274,7 @@ spec: required: - backendRefs type: object - maxItems: 16 + maxItems: 1 minItems: 1 type: array x-kubernetes-validations: diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 4c70dd18b1..cf47507b1f 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7314,7 +7314,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_TLSRouteSpec(ref common.Referenc }, "rules": { SchemaProps: spec.SchemaProps{ - Description: "Rules are a list of TLS matchers and actions.\n\n", + Description: "Rules are a list of actions.\n\n", Type: []string{"array"}, Items: &spec.SchemaOrArray{ Schema: &spec.Schema{ From c011e670b155414f9ab52c6ecb697edd807c9f64 Mon Sep 17 00:00:00 2001 From: jgreeer Date: Mon, 4 Aug 2025 16:31:39 -0400 Subject: [PATCH 108/148] Fix Gateway API community meeting schedule documentation (#3975) Update meeting schedule to reflect the correct alternating weekly pattern: - Week A: Mondays at 3pm Pacific Time (23:00 UTC) - Week B: Tuesdays at 8am Pacific Time (16:00 UTC) This replaces the incorrect information about first Tuesday monthly + weekly Monday meetings. --- site-src/contributing/index.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/site-src/contributing/index.md b/site-src/contributing/index.md index 05798beb42..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 From 5836f6fad0953d2ef1778627471e575ace55a92e Mon Sep 17 00:00:00 2001 From: Dave Protasowski Date: Tue, 5 Aug 2025 16:41:27 -0400 Subject: [PATCH 109/148] ListenerSet adjust PortNumber kubebuilder validations (#3750) * use a custom min/max marker controller-tools only allows this to work on object types and not ref types * update GEP with optional port * adjust markers * make generate --- apis/v1/gateway_types.go | 4 ++ apis/v1/httproute_types.go | 3 + apis/v1/object_reference_types.go | 2 + apis/v1/shared_types.go | 6 +- apis/v1alpha2/shared_types.go | 3 - apis/v1beta1/shared_types.go | 3 - apisx/v1alpha1/xlistenerset_types.go | 18 ++++- applyconfiguration/internal/internal.go | 1 - ...way.networking.x-k8s.io_xlistenersets.yaml | 9 ++- geps/gep-1713/index.md | 17 ++++- pkg/generated/openapi/zz_generated.openapi.go | 5 +- pkg/generator/main.go | 2 + pkg/generator/markers.go | 66 +++++++++++++++++++ 13 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 pkg/generator/markers.go diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index ea8667af61..8425231530 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -396,6 +396,10 @@ 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"` diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 96e245c386..d051df1046 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1219,6 +1219,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. diff --git a/apis/v1/object_reference_types.go b/apis/v1/object_reference_types.go index 54e34fa2ed..414e39b947 100644 --- a/apis/v1/object_reference_types.go +++ b/apis/v1/object_reference_types.go @@ -148,6 +148,8 @@ type BackendObjectReference struct { // resource or this field. // // +optional + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 Port *PortNumber `json:"port,omitempty"` } diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index e874c2f905..231a22a746 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -149,6 +149,9 @@ type ParentReference struct { // Support: Extended // // +optional + // + // +kubebuilder:validation:Minimum=1 + // +kubebuilder:validation:Maximum=65535 Port *PortNumber `json:"port,omitempty"` } @@ -228,9 +231,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 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/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/xlistenerset_types.go b/apisx/v1alpha1/xlistenerset_types.go index 5eb6942b1b..a4cedc6949 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -158,8 +158,18 @@ type ListenerEntry struct { // Port is the network port. Multiple listeners may use the // same port, subject to the Listener compatibility rules. - // +required - 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 @@ -242,6 +252,10 @@ type ListenerEntryStatus struct { 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"` diff --git a/applyconfiguration/internal/internal.go b/applyconfiguration/internal/internal.go index 0403df0d63..92508d3a05 100644 --- a/applyconfiguration/internal/internal.go +++ b/applyconfiguration/internal/internal.go @@ -1795,7 +1795,6 @@ var schemaYAML = typed.YAMLObject(`types: - name: port type: scalar: numeric - default: 0 - name: protocol type: scalar: string 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 637a9ed365..9a21d52e81 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml @@ -296,12 +296,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 @@ -541,7 +547,6 @@ spec: > 0 || size(self.options) > 0 : true' required: - name - - port - protocol type: object maxItems: 64 diff --git a/geps/gep-1713/index.md b/geps/gep-1713/index.md index 4cad39fde1..c720b35794 100644 --- a/geps/gep-1713/index.md +++ b/geps/gep-1713/index.md @@ -163,8 +163,19 @@ 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 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 + // + // +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. @@ -380,6 +391,10 @@ spec: `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 ### Gateway Changes diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index cf47507b1f..62c65b8e74 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7944,8 +7944,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", }, @@ -7971,7 +7970,7 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntry(ref common.Refere }, }, }, - Required: []string{"name", "port", "protocol"}, + Required: []string{"name", "protocol"}, }, }, Dependencies: []string{ 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 +} From 78496d8f897031a5335fb1fbcdfe422721646f4b Mon Sep 17 00:00:00 2001 From: Erik Godding Boye Date: Wed, 6 Aug 2025 06:37:26 +0200 Subject: [PATCH 110/148] Fix OpenAPI validations by adding API list markers (#3964) --- .golangci-kal.yml | 1 + apis/v1/gateway_types.go | 11 +- apis/v1/grpcroute_types.go | 6 + apis/v1/httproute_types.go | 7 + apis/v1/shared_types.go | 4 +- apis/v1alpha2/policy_types.go | 3 +- apis/v1alpha2/tcproute_types.go | 2 + apis/v1alpha2/tlsroute_types.go | 3 + apis/v1alpha2/udproute_types.go | 2 + apis/v1alpha3/backendtlspolicy_types.go | 8 +- apis/v1alpha3/tlsroute_types.go | 4 +- apis/v1beta1/referencegrant_types.go | 6 +- apisx/v1alpha1/xlistenerset_types.go | 3 +- ....networking.k8s.io_backendtlspolicies.yaml | 4 + .../gateway.networking.k8s.io_gateways.yaml | 12 + .../gateway.networking.k8s.io_grpcroutes.yaml | 8 + .../gateway.networking.k8s.io_httproutes.yaml | 18 ++ ...way.networking.k8s.io_referencegrants.yaml | 2 + .../gateway.networking.k8s.io_tcproutes.yaml | 4 + .../gateway.networking.k8s.io_tlsroutes.yaml | 10 + .../gateway.networking.k8s.io_udproutes.yaml | 4 + ...king.x-k8s.io_xbackendtrafficpolicies.yaml | 1 + ...way.networking.x-k8s.io_xlistenersets.yaml | 4 + .../gateway.networking.k8s.io_gateways.yaml | 10 + .../gateway.networking.k8s.io_grpcroutes.yaml | 8 + .../gateway.networking.k8s.io_httproutes.yaml | 16 ++ ...way.networking.k8s.io_referencegrants.yaml | 2 + pkg/generated/openapi/zz_generated.openapi.go | 250 ++++++++++++++++++ 28 files changed, 403 insertions(+), 10 deletions(-) diff --git a/.golangci-kal.yml b/.golangci-kal.yml index d2b764e868..27fdabbef1 100644 --- a/.golangci-kal.yml +++ b/.golangci-kal.yml @@ -17,6 +17,7 @@ linters: - "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: diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index 8425231530..86de1bad59 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -265,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 )" @@ -573,6 +574,7 @@ 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"` @@ -647,9 +649,10 @@ 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 - // +required CACertificateRefs []ObjectReference `json:"caCertificateRefs,omitempty"` } @@ -661,6 +664,7 @@ type AllowedRoutes struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:default={from: Same} Namespaces *RouteNamespaces `json:"namespaces,omitempty"` @@ -677,6 +681,7 @@ type AllowedRoutes struct { // Support: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=8 Kinds []RouteGroupKind `json:"kinds,omitempty"` } @@ -795,6 +800,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"` @@ -1127,8 +1133,9 @@ type ListenerStatus struct { // and invalid Route kinds are specified, the implementation MUST // reference the valid Route kinds that have been specified. // - // +kubebuilder:validation:MaxItems=8 // +required + // +listType=atomic + // +kubebuilder:validation:MaxItems=8 SupportedKinds []RouteGroupKind `json:"supportedKinds"` // AttachedRoutes represents the total number of Routes that have been diff --git a/apis/v1/grpcroute_types.go b/apis/v1/grpcroute_types.go index c6480c3857..5f9bde7a8e 100644 --- a/apis/v1/grpcroute_types.go +++ b/apis/v1/grpcroute_types.go @@ -139,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" // @@ -212,6 +214,7 @@ type GRPCRouteRule struct { // the above criteria. // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=64 Matches []GRPCRouteMatch `json:"matches,omitempty"` @@ -241,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" @@ -276,6 +280,7 @@ type GRPCRouteRule struct { // Support for weight: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 BackendRefs []GRPCBackendRef `json:"backendRefs,omitempty"` @@ -636,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 d051df1046..39a01f27f1 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -114,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: "/"}}}}} @@ -201,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"` @@ -243,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" @@ -288,6 +292,7 @@ type HTTPRouteRule struct { // Support for weight: Core // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=16 BackendRefs []HTTPBackendRef `json:"backendRefs,omitempty"` @@ -382,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 @@ -1606,6 +1612,7 @@ 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="RequestHeaderModifier filter cannot be repeated",rule="self.filter(f, f.type == 'RequestHeaderModifier').size() <= 1" diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index 231a22a746..b98a9e812f 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -222,6 +222,7 @@ type CommonRouteSpec struct { // // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=32 // // @@ -502,8 +503,9 @@ 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. // - // +kubebuilder:validation:MaxItems=32 // +required + // +listType=atomic + // +kubebuilder:validation:MaxItems=32 Parents []RouteParentStatus `json:"parents"` } diff --git a/apis/v1alpha2/policy_types.go b/apis/v1alpha2/policy_types.go index b38ff00327..dc2f8f7f09 100644 --- a/apis/v1alpha2/policy_types.go +++ b/apis/v1alpha2/policy_types.go @@ -242,7 +242,8 @@ type PolicyStatus struct { // additional Gateways would be able to reference the Service targeted by // the BackendTLSPolicy. // - // +kubebuilder:validation:MaxItems=16 // +required + // +listType=atomic + // +kubebuilder:validation:MaxItems=16 Ancestors []PolicyAncestorStatus `json:"ancestors"` } diff --git a/apis/v1alpha2/tcproute_types.go b/apis/v1alpha2/tcproute_types.go index 99446bedcb..e545e6fdab 100644 --- a/apis/v1alpha2/tcproute_types.go +++ b/apis/v1alpha2/tcproute_types.go @@ -51,6 +51,7 @@ type TCPRouteSpec struct { // Rules are a list of TCP matchers and actions. // // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -86,6 +87,7 @@ 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 5cd56ca201..8ca02d370d 100644 --- a/apis/v1alpha2/tlsroute_types.go +++ b/apis/v1alpha2/tlsroute_types.go @@ -85,12 +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 // @@ -129,6 +131,7 @@ 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 82afedc6bb..f5f8feff77 100644 --- a/apis/v1alpha2/udproute_types.go +++ b/apis/v1alpha2/udproute_types.go @@ -51,6 +51,7 @@ type UDPRouteSpec struct { // Rules are a list of UDP matchers and actions. // // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 // @@ -86,6 +87,7 @@ 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 93c47d72bb..e00491908c 100644 --- a/apis/v1alpha3/backendtlspolicy_types.go +++ b/apis/v1alpha3/backendtlspolicy_types.go @@ -80,9 +80,10 @@ type BackendTLSPolicySpec struct { // // Support: Implementation-specific for any other resource // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +required // +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))" // +kubebuilder:validation:XValidation:message="sectionName must be unique when targetRefs includes 2 or more references to the same target",rule="self.all(p1, self.exists_one(p2, p1.group == p2.group && p1.kind == p2.kind && p1.name == p2.name && (((!has(p1.sectionName) || p1.sectionName == '') && (!has(p2.sectionName) || p2.sectionName == '')) || (has(p1.sectionName) && has(p2.sectionName) && p1.sectionName == p2.sectionName))))" TargetRefs []v1alpha2.LocalPolicyTargetReferenceWithSectionName `json:"targetRefs"` @@ -133,8 +134,9 @@ type BackendTLSPolicyValidation struct { // Support: Implementation-specific (More than one reference, or other kinds // of resources). // - // +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 @@ -150,6 +152,7 @@ type BackendTLSPolicyValidation struct { // Support: Implementation-specific // // +optional + // +listType=atomic WellKnownCACertificates *WellKnownCACertificatesType `json:"wellKnownCACertificates,omitempty"` // Hostname is used for two purposes in the connection between Gateways and @@ -170,6 +173,7 @@ type BackendTLSPolicyValidation struct { // Support: Extended // // +optional + // +listType=atomic // +kubebuilder:validation:MaxItems=5 SubjectAltNames []SubjectAltName `json:"subjectAltNames,omitempty"` } diff --git a/apis/v1alpha3/tlsroute_types.go b/apis/v1alpha3/tlsroute_types.go index 68900b3c9a..8ae5b51866 100644 --- a/apis/v1alpha3/tlsroute_types.go +++ b/apis/v1alpha3/tlsroute_types.go @@ -87,14 +87,16 @@ type TLSRouteSpec struct { // // Support: Core // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +required Hostnames []Hostname `json:"hostnames,omitempty"` // Rules are a list of actions. // // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=1 // diff --git a/apis/v1beta1/referencegrant_types.go b/apis/v1beta1/referencegrant_types.go index 6321515238..bed43bc957 100644 --- a/apis/v1beta1/referencegrant_types.go +++ b/apis/v1beta1/referencegrant_types.go @@ -72,9 +72,10 @@ type ReferenceGrantSpec struct { // // Support: Core // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +required From []ReferenceGrantFrom `json:"from"` // To describes the resources that may be referenced by the resources @@ -84,9 +85,10 @@ type ReferenceGrantSpec struct { // // Support: Core // + // +required + // +listType=atomic // +kubebuilder:validation:MinItems=1 // +kubebuilder:validation:MaxItems=16 - // +required To []ReferenceGrantTo `json:"to"` } diff --git a/apisx/v1alpha1/xlistenerset_types.go b/apisx/v1alpha1/xlistenerset_types.go index a4cedc6949..fd108e2bed 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -269,8 +269,9 @@ type ListenerEntryStatus struct { // and invalid Route kinds are specified, the implementation MUST // reference the valid Route kinds that have been specified. // - // +kubebuilder:validation:MaxItems=8 // +required + // +listType=atomic + // +kubebuilder:validation:MaxItems=8 SupportedKinds []RouteGroupKind `json:"supportedKinds"` // AttachedRoutes represents the total number of Routes that have been diff --git a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml index f431e98faf..8622def679 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 @@ -226,6 +227,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 @@ -302,6 +304,7 @@ spec: "")' maxItems: 5 type: array + x-kubernetes-list-type: atomic wellKnownCACertificates: description: |- WellKnownCACertificates specifies whether system CA certificates may be used in @@ -628,6 +631,7 @@ spec: 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 6ad00cb433..2e2462a087 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, @@ -633,6 +634,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -887,6 +889,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic frontendValidation: description: |- FrontendValidation holds configuration information for validating the frontend (client). @@ -973,6 +976,7 @@ spec: maxItems: 8 minItems: 1 type: array + x-kubernetes-list-type: atomic required: - caCertificateRefs type: object @@ -1128,6 +1132,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -1341,6 +1346,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic required: - attachedRoutes - conditions @@ -1466,6 +1472,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, @@ -1973,6 +1980,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -2227,6 +2235,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic frontendValidation: description: |- FrontendValidation holds configuration information for validating the frontend (client). @@ -2313,6 +2322,7 @@ spec: maxItems: 8 minItems: 1 type: array + x-kubernetes-list-type: atomic required: - caCertificateRefs type: object @@ -2468,6 +2478,7 @@ spec: true' maxItems: 16 type: array + x-kubernetes-list-type: atomic conditions: default: - lastTransitionTime: "1970-01-01T00:00:00Z" @@ -2681,6 +2692,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 25575f3150..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 @@ -2202,6 +2209,7 @@ spec: 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_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index dc198cf154..65515a4e22 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 @@ -1523,6 +1525,7 @@ spec: rule: '!(!has(self.cors) && self.type == ''CORS'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -1629,6 +1632,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 @@ -2736,6 +2740,7 @@ spec: rule: '!(!has(self.cors) && self.type == ''CORS'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -3047,6 +3052,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. @@ -3142,6 +3148,7 @@ spec: minimum: 400 type: integer type: array + x-kubernetes-list-type: atomic type: object sessionPersistence: description: |- @@ -3337,6 +3344,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 @@ -3625,6 +3633,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object @@ -3748,6 +3757,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 @@ -3960,6 +3970,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 @@ -5140,6 +5151,7 @@ spec: rule: '!(!has(self.cors) && self.type == ''CORS'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -5246,6 +5258,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 @@ -6353,6 +6366,7 @@ spec: rule: '!(!has(self.cors) && self.type == ''CORS'')' maxItems: 16 type: array + x-kubernetes-list-type: atomic x-kubernetes-validations: - message: May specify either httpRouteFilterRequestRedirect or httpRouteFilterRequestRewrite, but not both @@ -6664,6 +6678,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. @@ -6759,6 +6774,7 @@ spec: minimum: 400 type: integer type: array + x-kubernetes-list-type: atomic type: object sessionPersistence: description: |- @@ -6954,6 +6970,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 @@ -7242,6 +7259,7 @@ spec: 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 8d094e012d..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. @@ -441,6 +443,7 @@ spec: 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) @@ -717,6 +720,7 @@ spec: 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 cdeecdd31c..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. @@ -504,6 +507,7 @@ spec: 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) @@ -780,6 +784,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object @@ -883,6 +888,7 @@ spec: maxItems: 16 minItems: 1 type: array + x-kubernetes-list-type: atomic parentRefs: description: |- ParentRefs references the resources (usually Gateways) that a Route wants @@ -1095,6 +1101,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 @@ -1262,6 +1269,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. @@ -1277,6 +1285,7 @@ spec: 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) @@ -1554,6 +1563,7 @@ spec: 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 6c5cd46b0b..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. @@ -441,6 +443,7 @@ spec: 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) @@ -717,6 +720,7 @@ spec: 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 6c69c96b40..3e6d06b210 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xbackendtrafficpolicies.yaml @@ -588,6 +588,7 @@ spec: 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 9a21d52e81..1a266cca60 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml @@ -174,6 +174,7 @@ spec: type: object maxItems: 8 type: array + x-kubernetes-list-type: atomic namespaces: default: from: Same @@ -407,6 +408,7 @@ spec: type: object maxItems: 64 type: array + x-kubernetes-list-type: atomic frontendValidation: description: |- FrontendValidation holds configuration information for validating the frontend (client). @@ -493,6 +495,7 @@ spec: maxItems: 8 minItems: 1 type: array + x-kubernetes-list-type: atomic required: - caCertificateRefs type: object @@ -846,6 +849,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..bcb648812d 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 @@ -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 @@ -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 989e24e844..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,6 +1765,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. @@ -1772,6 +1778,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 @@ -2045,6 +2052,7 @@ spec: 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_httproutes.yaml b/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml index 12c0639a2f..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,6 +1192,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 @@ -1296,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 @@ -2117,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 @@ -2428,6 +2433,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. @@ -2542,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 @@ -2809,6 +2816,7 @@ spec: type: object maxItems: 32 type: array + x-kubernetes-list-type: atomic required: - parents type: object @@ -2932,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 @@ -3115,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 @@ -3991,6 +4001,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 @@ -4097,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 @@ -4918,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 @@ -5229,6 +5242,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. @@ -5343,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 @@ -5610,6 +5625,7 @@ spec: 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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 62c65b8e74..9885f10471 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -2862,12 +2862,22 @@ func schema_sigsk8sio_gateway_api_apis_v1_AllowedRoutes(ref common.ReferenceCall Type: []string{"object"}, Properties: map[string]spec.Schema{ "namespaces": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Namespaces indicates namespaces from which Routes may be attached to this Listener. This is restricted to the namespace of this Gateway by default.\n\nSupport: Core", Ref: ref("sigs.k8s.io/gateway-api/apis/v1.RouteNamespaces"), }, }, "kinds": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "atomic", + }, + }, SchemaProps: spec.SchemaProps{ Description: "Kinds specifies the groups and kinds of Routes that are allowed to bind to this Gateway Listener. When unspecified or empty, the kinds of Routes selected are determined using the Listener protocol.\n\nA RouteGroupKind MUST correspond to kinds of Routes that are compatible with the application protocol specified in the Listener's Protocol field. If an implementation does not support or recognize this resource type, it MUST set the \"ResolvedRefs\" condition to False for this Listener with the \"InvalidRouteKinds\" reason.\n\nSupport: Core", Type: []string{"array"}, @@ -3004,6 +3014,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_CommonRouteSpec(ref common.ReferenceCa 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"}, @@ -3079,6 +3094,11 @@ 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.", Type: []string{"array"}, @@ -3152,6 +3172,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"}, @@ -3450,6 +3475,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteRule(ref common.ReferenceCall }, }, "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"}, @@ -3464,6 +3494,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"}, @@ -3478,6 +3513,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"}, @@ -3513,6 +3553,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"}, @@ -3527,6 +3572,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"}, @@ -3542,6 +3592,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"}, @@ -3571,6 +3626,11 @@ 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.", Type: []string{"array"}, @@ -3998,6 +4058,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"}, @@ -4073,6 +4138,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"}, @@ -4181,6 +4251,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref common.ReferenceC }, }, "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"}, @@ -4275,6 +4350,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"}, @@ -4980,6 +5060,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"}, @@ -5029,6 +5114,11 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteRule(ref common.ReferenceCall }, }, "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"}, @@ -5043,6 +5133,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"}, @@ -5057,6 +5152,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"}, @@ -5104,6 +5204,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"}, @@ -5118,6 +5223,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"}, @@ -5133,6 +5243,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"}, @@ -5162,6 +5277,11 @@ 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.", Type: []string{"array"}, @@ -5342,6 +5462,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"}, @@ -5734,6 +5859,11 @@ 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.", Type: []string{"array"}, @@ -6172,6 +6302,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"}, @@ -6399,6 +6534,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"}, @@ -6429,6 +6569,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"}, @@ -6443,6 +6588,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"}, @@ -6473,6 +6623,11 @@ 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.", Type: []string{"array"}, @@ -6609,6 +6764,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"}, @@ -6639,6 +6799,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"}, @@ -6653,6 +6818,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"}, @@ -6668,6 +6838,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"}, @@ -6698,6 +6873,11 @@ 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.", Type: []string{"array"}, @@ -6834,6 +7014,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"}, @@ -6864,6 +7049,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"}, @@ -6878,6 +7068,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"}, @@ -6908,6 +7103,11 @@ 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.", Type: []string{"array"}, @@ -7037,6 +7237,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"}, @@ -7090,6 +7295,11 @@ 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).", Type: []string{"array"}, @@ -7104,6 +7314,11 @@ 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", Type: []string{"string"}, @@ -7119,6 +7334,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c }, }, "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"}, @@ -7284,6 +7504,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_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"}, @@ -7298,6 +7523,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_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 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"}, @@ -7313,6 +7543,11 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_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 actions.\n\n", Type: []string{"array"}, @@ -7769,6 +8004,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"}, @@ -7783,6 +8023,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"}, @@ -8002,6 +8247,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"}, From bee090d4eaab79948f05b15f17bf6c5824cf01bf Mon Sep 17 00:00:00 2001 From: kl52752 <89914070+kl52752@users.noreply.github.com> Date: Thu, 7 Aug 2025 16:01:43 +0200 Subject: [PATCH 111/148] Invalid BackendTLSPolicy conformance test (#3930) --- conformance/tests/backendtlspolicy.go | 56 +++++++++-- conformance/tests/backendtlspolicy.yaml | 124 ++++++++++++++++++++---- conformance/utils/http/http.go | 34 +++++++ conformance/utils/kubernetes/helpers.go | 33 +++++++ conformance/utils/suite/suite.go | 2 + pkg/features/backendtlspolicy.go | 2 +- 6 files changed, 225 insertions(+), 26 deletions(-) diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go index 1d55627816..fc6c6576eb 100644 --- a/conformance/tests/backendtlspolicy.go +++ b/conformance/tests/backendtlspolicy.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Kubernetes Authors. +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. @@ -19,9 +19,12 @@ 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" @@ -35,7 +38,7 @@ func init() { var BackendTLSPolicy = suite.ConformanceTest{ ShortName: "BackendTLSPolicy", - Description: "A single service that is targeted by a BackendTLSPolicy must successfully complete TLS termination", + Description: "BackendTLSPolicy must be used to configure TLS connection between gateway and backend", Features: []features.FeatureName{ features.SupportGateway, features.SupportHTTPRoute, @@ -51,10 +54,25 @@ var BackendTLSPolicy = suite.ConformanceTest{ 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), + } + + validPolicyNN := types.NamespacedName{Name: "normative-test-backendtlspolicy", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, policyCond) + + invalidPolicyNN := types.NamespacedName{Name: "backendtlspolicy-host-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidPolicyNN, gwNN, policyCond) + + invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, policyCond) + serverStr := "abc.example.com" - // Verify that the response to a backend-tls-only call to /backendTLS will return the matching SNI. - t.Run("Simple HTTP request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) { + // 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, @@ -73,8 +91,8 @@ var BackendTLSPolicy = suite.ConformanceTest{ if err != nil { t.Fatalf("unexpected error finding TLS secret: %v", err) } - // Verify that the response to a re-encrypted call to /backendTLS will return the matching SNI. - t.Run("Re-encrypt HTTPS request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) { + // 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, @@ -86,5 +104,31 @@ var BackendTLSPolicy = suite.ConformanceTest{ 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) { + 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) { + 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 index 91f6a590f9..e048cc2e7b 100644 --- a/conformance/tests/backendtlspolicy.yaml +++ b/conformance/tests/backendtlspolicy.yaml @@ -31,25 +31,6 @@ spec: kinds: - kind: HTTPRoute --- -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/v1 kind: HTTPRoute metadata: @@ -71,6 +52,24 @@ spec: - 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 @@ -86,6 +85,36 @@ spec: 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 @@ -151,3 +180,60 @@ spec: 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/utils/http/http.go b/conformance/utils/http/http.go index e1aca27d54..91ebf2254e 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -117,6 +117,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() @@ -261,6 +272,29 @@ func WaitForConsistentResponse(t *testing.T, r roundtripper.RoundTripper, req ro tlog.Logf(t, "Request passed") } +// 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) { diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index 9e385b4caa..8075132da1 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" ) @@ -993,3 +994,35 @@ 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: %w", 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 status to have a Condition %v", condition) +} diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index b34a1ea3ff..858fea2ed1 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -383,6 +383,8 @@ 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) diff --git a/pkg/features/backendtlspolicy.go b/pkg/features/backendtlspolicy.go index 8763b32dd1..95d5017164 100644 --- a/pkg/features/backendtlspolicy.go +++ b/pkg/features/backendtlspolicy.go @@ -1,5 +1,5 @@ /* -Copyright 2024 The Kubernetes Authors. +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. From fb75360bd54bb7e380b8fa56c725cbec4d492ce5 Mon Sep 17 00:00:00 2001 From: Mahesh Rijal <62394512+maheshrijal@users.noreply.github.com> Date: Thu, 7 Aug 2025 21:43:42 +0530 Subject: [PATCH 112/148] fix typo (#3976) --- site-src/implementations.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site-src/implementations.md b/site-src/implementations.md index 791f5450d3..46335451c9 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -271,7 +271,7 @@ 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. -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 From b167eedffc15a90ad1a3926a1b9066a70791a2bb Mon Sep 17 00:00:00 2001 From: John Howard Date: Thu, 7 Aug 2025 17:21:43 -0700 Subject: [PATCH 113/148] Add gateway class label to generated objects (#3955) This proposes adding an optional new label to generated objects. This is useful for general querying, such as "find the total CPU usage of all pods created by ". --- geps/gep-1762/index.md | 1 + 1 file changed, 1 insertion(+) 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` (`-`). From 372a5b06624cff12117f41dcd26c08cb1def22e7 Mon Sep 17 00:00:00 2001 From: carson <127476216+carsontham@users.noreply.github.com> Date: Tue, 12 Aug 2025 00:05:13 +0800 Subject: [PATCH 114/148] added entropy to HTTPRoute-weight (#3880) Signed-off-by: carsontham --- conformance/tests/httproute-weight.go | 6 ++- conformance/tests/mesh/httproute-weight.go | 56 +--------------------- conformance/utils/http/http.go | 53 ++++++++++++++++++++ 3 files changed, 59 insertions(+), 56 deletions(-) diff --git a/conformance/tests/httproute-weight.go b/conformance/tests/httproute-weight.go index 2c1a520dc0..fa85deb9bf 100644 --- a/conformance/tests/httproute-weight.go +++ b/conformance/tests/httproute-weight.go @@ -91,7 +91,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,6 +100,11 @@ 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) diff --git a/conformance/tests/mesh/httproute-weight.go b/conformance/tests/mesh/httproute-weight.go index cc296d92d5..844d5471e7 100644 --- a/conformance/tests/mesh/httproute-weight.go +++ b/conformance/tests/mesh/httproute-weight.go @@ -18,16 +18,13 @@ package meshtests import ( "cmp" - "crypto/rand" "errors" "fmt" "math" - "math/big" "slices" "strings" "sync" "testing" - "time" "golang.org/x/sync/errgroup" @@ -93,7 +90,7 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR for i := 0.0; i < totalRequests; i++ { g.Go(func() error { uniqueExpected := expected - if err := addEntropy(&uniqueExpected); err != nil { + if err := http.AddEntropy(&uniqueExpected); err != nil { return fmt.Errorf("error adding entropy: %w", err) } _, cRes, err := client.CaptureRequestResponseAndCompare(t, uniqueExpected) @@ -148,54 +145,3 @@ func testDistribution(t *testing.T, client echo.MeshPod, expected http.ExpectedR }) return errors.Join(errs...) } - -// 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 *http.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/http/http.go b/conformance/utils/http/http.go index 91ebf2254e..da7036daf6 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -17,7 +17,9 @@ limitations under the License. package http import ( + "crypto/rand" "fmt" + "math/big" "net" "net/url" "strings" @@ -478,3 +480,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) + } +} From 51488fae6b89900326939784f4bfb1a15de579a7 Mon Sep 17 00:00:00 2001 From: Beka Modebadze <58038950+bexxmodd@users.noreply.github.com> Date: Mon, 11 Aug 2025 13:35:07 -0700 Subject: [PATCH 115/148] Change to ignore Mesh features in GWC instead of erroring out. (#3938) * Change to ignore Mesh features in GWC instead of erroring out. * Added comment on what new code does. * Punctuation. * Added extended mesh feture for test suite unit test. --- conformance/utils/suite/suite.go | 13 +++++++------ conformance/utils/suite/suite_test.go | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 858fea2ed1..23c936536a 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -211,8 +211,13 @@ func NewConformanceTestSuite(options ConformanceOptions) (*ConformanceTestSuite, return nil, fmt.Errorf("cannot infer supported features: %w", err) } - if hasMeshFeatures(supportedFeatures) { - return nil, fmt.Errorf("mesh features should not be populated in GatewayClass") + // 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 } @@ -660,7 +665,3 @@ func getAPIVersionAndChannel(crds []apiextensionsv1.CustomResourceDefinition) (v return version, channel, nil } - -func hasMeshFeatures(f FeaturesSet) bool { - return f.HasAny(features.SetsToNamesSet(features.MeshCoreFeatures, features.MeshExtendedFeatures).UnsortedList()...) -} diff --git a/conformance/utils/suite/suite_test.go b/conformance/utils/suite/suite_test.go index 311da616a2..778afa7180 100644 --- a/conformance/utils/suite/suite_test.go +++ b/conformance/utils/suite/suite_test.go @@ -22,7 +22,6 @@ 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" @@ -545,9 +544,8 @@ func TestGWCPublishedMeshFeatures(t *testing.T) { }, SupportedFeatures: featureNamesToSet([]string{ string(features.SupportGateway), - string(features.SupportGatewayStaticAddresses), + string(features.SupportMesh), string(features.SupportMeshClusterIPMatching), - string(features.SupportMeshConsumerRoute), }), }, } @@ -568,9 +566,12 @@ func TestGWCPublishedMeshFeatures(t *testing.T) { Client: fakeClient, } - _, err := NewConformanceTestSuite(options) - if err == nil { - t.Fatalf("expected an error but got nil") + 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()) } } From 60cdac35c276fa9a5b9d92da05694c97490041e8 Mon Sep 17 00:00:00 2001 From: EyalPazz <67443108+EyalPazz@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:35:08 +0300 Subject: [PATCH 116/148] fix(docs): remove unnecessary array in incorrect example @ gep-1767 (#3991) --- geps/gep-1767/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/geps/gep-1767/index.md b/geps/gep-1767/index.md index c115dbf116..14315e190c 100644 --- a/geps/gep-1767/index.md +++ b/geps/gep-1767/index.md @@ -516,7 +516,7 @@ spec: value: /resource/foo filters: - cors: - - allowOrigins: + allowOrigins: - * allowMethods: - GET @@ -575,7 +575,7 @@ spec: value: /resource/foo filters: - cors: - - allowOrigins: + allowOrigins: - https://foo.example - http://foo.example allowCredentials: true From bb58b0d1a1fa10bc1fedd3ef1b11e664a0a94efd Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Wed, 13 Aug 2025 18:11:11 +0200 Subject: [PATCH 117/148] gep: standardizing behavior for invalid BackendTLSPolicy (#3909) * gep: standardizing behavior for invalid BackendTLSPolicy Signed-off-by: Norwin Schnyder * Apply PR feedback Signed-off-by: Norwin Schnyder * Incorporate feedback from various discussions Signed-off-by: Norwin Schnyder * Introduce ResolvedRefs status condition for BackendTLSPolicy * Apply PR suggestions and feedback Signed-off-by: Norwin Schnyder * Fix typos Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- geps/gep-1897/index.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/geps/gep-1897/index.md b/geps/gep-1897/index.md index 4571c70335..8e24b8bf09 100644 --- a/geps/gep-1897/index.md +++ b/geps/gep-1897/index.md @@ -214,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: UnsupportedFeature`. +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 `NoCACertificates` 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 @@ -222,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 `UnsupportedFeature` 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. From 85839c80afb50239bf442e80503b5deae7501156 Mon Sep 17 00:00:00 2001 From: Beka Modebadze <58038950+bexxmodd@users.noreply.github.com> Date: Wed, 13 Aug 2025 14:21:07 -0700 Subject: [PATCH 118/148] Updated index.md to reflect changes in GEP-2162 (#3898) * Updated index doc and corrected formatting. * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Added details about Mesh and staying compliant. * Wording update. * TODO for what GWC reports. * Added mesh stuff. * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Added summary paragraph for Staying Compliant section. * Update geps/gep-2162/index.md Co-authored-by: Rob Scott * Update geps/gep-2162/index.md Co-authored-by: Rob Scott * Formatting changes. * Added info that suite will throw an error if Mesh features are added to GWC. * Apply suggestions from code review Co-authored-by: Lior Lieberman * Update geps/gep-2162/index.md Co-authored-by: Lior Lieberman * Link issue for populating mesh features in its crd. * Update geps/gep-2162/index.md Co-authored-by: Rob Scott * Update geps/gep-2162/index.md Co-authored-by: Rob Scott --------- Co-authored-by: Lior Lieberman Co-authored-by: Rob Scott --- geps/gep-2162/index.md | 52 +++++++++++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/geps/gep-2162/index.md b/geps/gep-2162/index.md index a8959acc8e..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,7 +117,7 @@ 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 @@ -130,6 +131,26 @@ We should treat this guidance as "best effort" because we might have test files 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. From da623ce324472b445cb36dfcfeb65bac81c9d74d Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 14 Aug 2025 06:51:08 +0800 Subject: [PATCH 119/148] update conformance report for EnvoyGateway v1.5.0 (#3987) * update EnvoyGateway conformance report * update * update version --- .../reports/v1.3.0/envoy-gateway/README.md | 21 +++- ...> experimental-v1.5.0-default-report.yaml} | 20 ++-- ...-v1.5.0-gateway-namespace-mode-report.yaml | 98 +++++++++++++++++++ 3 files changed, 125 insertions(+), 14 deletions(-) rename conformance/reports/v1.3.0/envoy-gateway/{experimental-v1.4.0-default-report.yaml => experimental-v1.5.0-default-report.yaml} (97%) create mode 100644 conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-gateway-namespace-mode-report.yaml diff --git a/conformance/reports/v1.3.0/envoy-gateway/README.md b/conformance/reports/v1.3.0/envoy-gateway/README.md index d48c5c9ac0..6baa7b7b2d 100644 --- a/conformance/reports/v1.3.0/envoy-gateway/README.md +++ b/conformance/reports/v1.3.0/envoy-gateway/README.md @@ -2,9 +2,17 @@ ## Table of Contents -|API channel|Implementation version|Mode|Report| -|-----------|----------------------|----|------| -| experimental |[v1.4.0](https://github.com/envoyproxy/gateway/releases/tag/v1.4.0)| default |[link](./experimental-v1.4.0-default-report.yaml)| +| 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 @@ -23,8 +31,13 @@ 3. Run the conformance tests + ```bash + KUBE_DEPLOY_PROFILE=default CONFORMANCE_REPORT_PATH=conformance-report-k8s.yaml make experimental-conformance + ``` + or + ```bash - CONFORMANCE_REPORT_PATH=conformance-report-k8s.yaml make experimental-conformance + KUBE_DEPLOY_PROFILE=gateway-namespace-mode CONFORMANCE_REPORT_PATH=conformance-report-k8s.yaml make experimental-conformance ``` 4. Check the produced report diff --git a/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml similarity index 97% rename from conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml rename to conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml index 4504a506da..14775c504e 100644 --- a/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.4.0-default-report.yaml +++ b/conformance/reports/v1.3.0/envoy-gateway/experimental-v1.5.0-default-report.yaml @@ -1,5 +1,5 @@ apiVersion: gateway.networking.k8s.io/v1 -date: "2025-05-14T03:12:24Z" +date: "2025-08-08T05:23:48Z" gatewayAPIChannel: experimental gatewayAPIVersion: v1.3.0 implementation: @@ -8,18 +8,10 @@ implementation: organization: envoyproxy project: envoy-gateway url: https://github.com/envoyproxy/gateway - version: latest + version: v1.5.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: @@ -67,5 +59,13 @@ profiles: 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 From 3f2b1eee89144073a245404b6055c2d6461715dd Mon Sep 17 00:00:00 2001 From: zirain Date: Thu, 14 Aug 2025 08:45:08 +0800 Subject: [PATCH 120/148] support protocol in ExpectedResponse (#3986) --- conformance/utils/http/http.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go index da7036daf6..50f8d1efdd 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -94,6 +94,7 @@ type Response struct { StatusCode int Headers map[string]string AbsentHeaders []string + Protocol string } type BackendRef struct { @@ -306,6 +307,10 @@ func CompareRoundTrip(t *testing.T, req *roundtripper.Request, cReq *roundtrippe if expected.Response.StatusCode != cRes.StatusCode { return fmt.Errorf("expected status code to be %d, got %d. CRes: %v", expected.Response.StatusCode, 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 From db957baec4f34bf52f68b14e9e1b4b5e69aa66b9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 05:55:08 -0700 Subject: [PATCH 121/148] build(deps): bump github.com/elastic/crd-ref-docs from 0.1.0 to 0.2.0 (#3958) Bumps [github.com/elastic/crd-ref-docs](https://github.com/elastic/crd-ref-docs) from 0.1.0 to 0.2.0. - [Release notes](https://github.com/elastic/crd-ref-docs/releases) - [Changelog](https://github.com/elastic/crd-ref-docs/blob/master/.goreleaser.yaml) - [Commits](https://github.com/elastic/crd-ref-docs/compare/v0.1.0...v0.2.0) --- updated-dependencies: - dependency-name: github.com/elastic/crd-ref-docs dependency-version: 0.2.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 20 ++++++++++---------- go.sum | 50 ++++++++++++++++++++++---------------------------- 2 files changed, 32 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index 2ef20f67d1..ce0e7cc3e8 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,10 @@ module sigs.k8s.io/gateway-api go 1.24.0 require ( - github.com/elastic/crd-ref-docs v0.1.0 + github.com/elastic/crd-ref-docs v0.2.0 github.com/miekg/dns v1.1.66 github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.41.0 + golang.org/x/net v0.42.0 golang.org/x/sync v0.16.0 google.golang.org/grpc v1.74.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 @@ -39,7 +39,7 @@ require ( 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/google/gnostic-models v0.6.9 // indirect github.com/google/go-cmp v0.7.0 // indirect @@ -68,15 +68,15 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.39.0 // indirect - golang.org/x/mod v0.25.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/mod v0.26.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.32.0 // indirect - golang.org/x/text v0.26.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.33.0 // indirect - golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // 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-20250528174236-200df99c418a // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index 7050b8ff32..e61c8f378d 100644 --- a/go.sum +++ b/go.sum @@ -17,8 +17,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs 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= @@ -41,18 +41,12 @@ 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= @@ -85,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= @@ -179,18 +171,18 @@ 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.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= -golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= 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.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w= -golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +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.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw= -golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= 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= @@ -203,28 +195,30 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w 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.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg= -golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= 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.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M= -golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= 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.33.0 h1:4qz2S3zmRxbGIhDIAgjxvFutSvH5EfnsYrRBj0UI0bc= -golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI= +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= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= From 5ecdaaca639e383e52a8f8537120739df0a224de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 06:25:08 -0700 Subject: [PATCH 122/148] build(deps): bump github.com/miekg/dns from 1.1.66 to 1.1.68 (#3973) Bumps [github.com/miekg/dns](https://github.com/miekg/dns) from 1.1.66 to 1.1.68. - [Changelog](https://github.com/miekg/dns/blob/master/Makefile.release) - [Commits](https://github.com/miekg/dns/compare/v1.1.66...v1.1.68) --- updated-dependencies: - dependency-name: github.com/miekg/dns dependency-version: 1.1.68 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ce0e7cc3e8..fba26cda4e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.24.0 require ( github.com/elastic/crd-ref-docs v0.2.0 - github.com/miekg/dns v1.1.66 + github.com/miekg/dns v1.1.68 github.com/stretchr/testify v1.10.0 golang.org/x/net v0.42.0 golang.org/x/sync v0.16.0 diff --git a/go.sum b/go.sum index e61c8f378d..48a569160f 100644 --- a/go.sum +++ b/go.sum @@ -86,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.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= -github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= +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= From 8af898c0076b0d024634af5932135d4b6f70b414 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 06:43:06 -0700 Subject: [PATCH 123/148] build(deps): bump pymdown-extensions in /hack/mkdocs/image (#3974) Bumps [pymdown-extensions](https://github.com/facelessuser/pymdown-extensions) from 10.16 to 10.16.1. - [Release notes](https://github.com/facelessuser/pymdown-extensions/releases) - [Commits](https://github.com/facelessuser/pymdown-extensions/compare/10.16...10.16.1) --- updated-dependencies: - dependency-name: pymdown-extensions dependency-version: 10.16.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 7a5fc4adde..8cd6c310ff 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -16,7 +16,7 @@ mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3 pep562==1.1 Pygments==2.19.2 -pymdown-extensions==10.16 +pymdown-extensions==10.16.1 PyYAML==6.0.2 six==1.17.0 tabulate==0.9.0 From 07f7675de6892434bb7b48f0419e9a051a4406c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 06:43:13 -0700 Subject: [PATCH 124/148] build(deps): bump google.golang.org/protobuf from 1.36.6 to 1.36.7 (#3980) Bumps google.golang.org/protobuf from 1.36.6 to 1.36.7. --- updated-dependencies: - dependency-name: google.golang.org/protobuf dependency-version: 1.36.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fba26cda4e..8bf6146a56 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( golang.org/x/sync v0.16.0 google.golang.org/grpc v1.74.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 - google.golang.org/protobuf v1.36.6 + google.golang.org/protobuf v1.36.7 k8s.io/api v0.33.3 k8s.io/apiextensions-apiserver v0.33.3 k8s.io/apimachinery v0.33.3 diff --git a/go.sum b/go.sum index 48a569160f..5134a920f2 100644 --- a/go.sum +++ b/go.sum @@ -227,8 +227,8 @@ google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= 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= From 5244a392eb3f94ca26747faad1424def30e0f24c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 06:43:20 -0700 Subject: [PATCH 125/148] build(deps): bump tornado from 6.5.1 to 6.5.2 in /hack/mkdocs/image (#3982) Bumps [tornado](https://github.com/tornadoweb/tornado) from 6.5.1 to 6.5.2. - [Changelog](https://github.com/tornadoweb/tornado/blob/master/docs/releases.rst) - [Commits](https://github.com/tornadoweb/tornado/compare/v6.5.1...v6.5.2) --- updated-dependencies: - dependency-name: tornado dependency-version: 6.5.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index 8cd6c310ff..e4d6677b63 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -20,4 +20,4 @@ pymdown-extensions==10.16.1 PyYAML==6.0.2 six==1.17.0 tabulate==0.9.0 -tornado==6.5.1 \ No newline at end of file +tornado==6.5.2 \ No newline at end of file From 02e495200afe41422b3b03f346541d0851ede147 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 08:25:08 -0700 Subject: [PATCH 126/148] build(deps): bump golang.org/x/net from 0.41.0 to 0.43.0 (#3981) Bumps [golang.org/x/net](https://github.com/golang/net) from 0.41.0 to 0.43.0. - [Commits](https://github.com/golang/net/compare/v0.41.0...v0.43.0) --- updated-dependencies: - dependency-name: golang.org/x/net dependency-version: 0.43.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 8bf6146a56..dcb0a21eb6 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/elastic/crd-ref-docs v0.2.0 github.com/miekg/dns v1.1.68 github.com/stretchr/testify v1.10.0 - golang.org/x/net v0.42.0 + golang.org/x/net v0.43.0 golang.org/x/sync v0.16.0 google.golang.org/grpc v1.74.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 @@ -68,12 +68,12 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect go.yaml.in/yaml/v2 v2.4.2 // indirect - golang.org/x/crypto v0.40.0 // 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.34.0 // indirect - golang.org/x/term v0.33.0 // indirect - golang.org/x/text v0.27.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 diff --git a/go.sum b/go.sum index 5134a920f2..67c2a445ef 100644 --- a/go.sum +++ b/go.sum @@ -171,8 +171,8 @@ 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.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= -golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= +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.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= @@ -181,8 +181,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn 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.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= -golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +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= @@ -195,14 +195,14 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w 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.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= -golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= -golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= +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.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= -golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +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= From 804d644e6217377a9694c0df3946681e2d85d1eb Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Mon, 18 Aug 2025 17:45:10 +0200 Subject: [PATCH 127/148] BackendTLSPolicy conformance tests for observedGeneration bump (#3997) * BackendTLSPolicy conformance tests for observedGeneration bump Signed-off-by: Norwin Schnyder * Apply PR feedback Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- ...ckendtlspolicy-observed-generation-bump.go | 88 +++++++++++++++++++ ...endtlspolicy-observed-generation-bump.yaml | 45 ++++++++++ conformance/utils/kubernetes/helpers.go | 12 +++ 3 files changed, 145 insertions(+) create mode 100644 conformance/tests/backendtlspolicy-observed-generation-bump.go create mode 100644 conformance/tests/backendtlspolicy-observed-generation-bump.yaml 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/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index 8075132da1..1501d93571 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -1026,3 +1026,15 @@ func BackendTLSPolicyMustHaveCondition(t *testing.T, client client.Client, timeo require.NoErrorf(t, waitErr, "error waiting for BackendTLSPolicy status to have a Condition %v", 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) + } + } +} From a516fa4097fa4a8396c6bccdedccb31dfd70ea74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Aug 2025 15:05:12 -0700 Subject: [PATCH 128/148] build(deps): bump the k8s-io group with 5 updates (#4002) Bumps the k8s-io group with 5 updates: | Package | From | To | | --- | --- | --- | | [k8s.io/api](https://github.com/kubernetes/api) | `0.33.3` | `0.33.4` | | [k8s.io/apiextensions-apiserver](https://github.com/kubernetes/apiextensions-apiserver) | `0.33.3` | `0.33.4` | | [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery) | `0.33.3` | `0.33.4` | | [k8s.io/client-go](https://github.com/kubernetes/client-go) | `0.33.3` | `0.33.4` | | [k8s.io/code-generator](https://github.com/kubernetes/code-generator) | `0.33.3` | `0.33.4` | Updates `k8s.io/api` from 0.33.3 to 0.33.4 - [Commits](https://github.com/kubernetes/api/compare/v0.33.3...v0.33.4) Updates `k8s.io/apiextensions-apiserver` from 0.33.3 to 0.33.4 - [Release notes](https://github.com/kubernetes/apiextensions-apiserver/releases) - [Commits](https://github.com/kubernetes/apiextensions-apiserver/compare/v0.33.3...v0.33.4) Updates `k8s.io/apimachinery` from 0.33.3 to 0.33.4 - [Commits](https://github.com/kubernetes/apimachinery/compare/v0.33.3...v0.33.4) Updates `k8s.io/client-go` from 0.33.3 to 0.33.4 - [Changelog](https://github.com/kubernetes/client-go/blob/master/CHANGELOG.md) - [Commits](https://github.com/kubernetes/client-go/compare/v0.33.3...v0.33.4) Updates `k8s.io/code-generator` from 0.33.3 to 0.33.4 - [Commits](https://github.com/kubernetes/code-generator/compare/v0.33.3...v0.33.4) --- updated-dependencies: - dependency-name: k8s.io/api dependency-version: 0.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apiextensions-apiserver dependency-version: 0.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/apimachinery dependency-version: 0.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/client-go dependency-version: 0.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io - dependency-name: k8s.io/code-generator dependency-version: 0.33.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: k8s-io ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index dcb0a21eb6..c818773daf 100644 --- a/go.mod +++ b/go.mod @@ -11,11 +11,11 @@ require ( google.golang.org/grpc v1.74.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.5.1 google.golang.org/protobuf v1.36.7 - k8s.io/api v0.33.3 - k8s.io/apiextensions-apiserver v0.33.3 - k8s.io/apimachinery v0.33.3 - k8s.io/client-go v0.33.3 - k8s.io/code-generator v0.33.3 + 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.21.0 diff --git a/go.sum b/go.sum index 67c2a445ef..b6f7fbce18 100644 --- a/go.sum +++ b/go.sum @@ -244,16 +244,16 @@ 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.33.3 h1:SRd5t//hhkI1buzxb288fy2xvjubstenEKL9K51KBI8= -k8s.io/api v0.33.3/go.mod h1:01Y/iLUjNBM3TAvypct7DIj0M0NIZc+PzAHCIo0CYGE= -k8s.io/apiextensions-apiserver v0.33.3 h1:qmOcAHN6DjfD0v9kxL5udB27SRP6SG/MTopmge3MwEs= -k8s.io/apiextensions-apiserver v0.33.3/go.mod h1:oROuctgo27mUsyp9+Obahos6CWcMISSAPzQ77CAQGz8= -k8s.io/apimachinery v0.33.3 h1:4ZSrmNa0c/ZpZJhAgRdcsFcZOw1PQU1bALVQ0B3I5LA= -k8s.io/apimachinery v0.33.3/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM= -k8s.io/client-go v0.33.3 h1:M5AfDnKfYmVJif92ngN532gFqakcGi6RvaOF16efrpA= -k8s.io/client-go v0.33.3/go.mod h1:luqKBQggEf3shbxHY4uVENAxrDISLOarxpTKMiUuujg= -k8s.io/code-generator v0.33.3 h1:6+34LhYkIuQ/yn/E3qlpVqjQaP8smzCu4NE1A8b0LWs= -k8s.io/code-generator v0.33.3/go.mod h1:6Y02+HQJYgNphv9z3wJB5w+sjYDIEBQW7sh62PkufvA= +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= From 7fae5d7139a663667c72372f3ccfbabe749f6751 Mon Sep 17 00:00:00 2001 From: Ricardo Pchevuzinske Katz Date: Mon, 18 Aug 2025 20:03:08 -0300 Subject: [PATCH 129/148] Enable dark mode switch on docs (#3977) --- mkdocs.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mkdocs.yml b/mkdocs.yml index 18393ce4c6..1052a44512 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -27,7 +27,16 @@ theme: - navigation.top - navigation.expand palette: - primary: custom + - scheme: default + primary: custom + toggle: + icon: material/brightness-7 + name: Switch to dark mode + - scheme: slate + primary: custom + toggle: + icon: material/brightness-4 + name: Switch to light mode custom_dir: site-src/overrides edit_uri: edit/main/site-src/ plugins: From 4adc82ed2bce7f012aa5217cc996a0689bfef347 Mon Sep 17 00:00:00 2001 From: Pronomita Dey Date: Wed, 20 Aug 2025 10:23:26 +0530 Subject: [PATCH 130/148] Update devguide.md to include docker as a pre-req for verify (#4000) * Update devguide.md * added docker and buildx added docker and buildx to the prereqs section & removed docker as a prereq for make verify specifically * KinD naming change --- site-src/contributing/devguide.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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. From 43b0cf775513e5caada14384269a6e6cda522bbe Mon Sep 17 00:00:00 2001 From: kl52752 <89914070+kl52752@users.noreply.github.com> Date: Wed, 20 Aug 2025 09:09:07 +0200 Subject: [PATCH 131/148] GEP-91: Address connection coalescing security issue - API updates (#3960) --- apis/v1/gateway_types.go | 150 +++- apis/v1/zz_generated.deepcopy.go | 97 ++- apis/v1beta1/gateway_types.go | 4 +- apisx/v1alpha1/shared_types.go | 2 +- apisx/v1alpha1/xlistenerset_types.go | 4 +- apisx/v1alpha1/zz_generated.deepcopy.go | 2 +- .../apis/v1/frontendtlsvalidation.go | 13 + applyconfiguration/apis/v1/gatewayspec.go | 9 + .../apis/v1/gatewaytlsconfig.go | 50 +- applyconfiguration/apis/v1/listener.go | 14 +- .../apis/v1/listenertlsconfig.go | 72 ++ applyconfiguration/apis/v1/tlsconfig.go | 39 + applyconfiguration/apis/v1/tlsportconfig.go | 52 ++ .../apisx/v1alpha1/listenerentry.go | 14 +- applyconfiguration/internal/internal.go | 68 +- applyconfiguration/utils.go | 6 + .../gateway.networking.k8s.io_gateways.yaml | 766 +++++++++++++----- ...way.networking.x-k8s.io_xlistenersets.yaml | 92 +-- .../gateway.networking.k8s.io_gateways.yaml | 4 +- .../frontend-cert-validation.yaml | 12 +- geps/gep-91/index.md | 153 ++-- pkg/generated/openapi/zz_generated.openapi.go | 188 ++++- pkg/test/cel/gateway_test.go | 22 +- 23 files changed, 1327 insertions(+), 506 deletions(-) create mode 100644 applyconfiguration/apis/v1/listenertlsconfig.go create mode 100644 applyconfiguration/apis/v1/tlsconfig.go create mode 100644 applyconfiguration/apis/v1/tlsportconfig.go diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index 86de1bad59..fdb31043cd 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -295,6 +295,14 @@ type GatewaySpec struct { // // +optional AllowedListeners *AllowedListeners `json:"allowedListeners,omitempty"` + // + // GatewayTLSConfig specifies frontend tls configuration for gateway. + // + // Support: Extended + // + // +optional + // + TLS *GatewayTLSConfig `json:"tls,omitempty"` } // AllowedListeners defines which ListenerSets can be attached to this Gateway. @@ -414,7 +422,7 @@ type Listener struct { // 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 @@ -423,7 +431,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 @@ -526,10 +534,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: // @@ -578,18 +586,6 @@ type GatewayTLSConfig struct { // +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. @@ -606,6 +602,35 @@ type GatewayTLSConfig struct { Options map[AnnotationKey]AnnotationValue `json:"options,omitempty"` } +// GatewayTLSConfig specifies frontend tls configuration for gateway. +type GatewayTLSConfig 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 @@ -624,6 +649,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 { + // 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: Core + // + // +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 + // +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 { @@ -640,8 +705,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 @@ -653,9 +718,49 @@ type FrontendTLSValidation struct { // +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 @@ -993,6 +1098,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 ( diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index 9bc1c8c53e..d7e4a6c2f4 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -752,6 +752,11 @@ func (in *GatewaySpec) DeepCopyInto(out *GatewaySpec) { *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,30 +848,14 @@ 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)) + 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]) } } - if in.FrontendValidation != nil { - in, out := &in.FrontendValidation, &out.FrontendValidation - *out = new(FrontendTLSValidation) - (*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 - } - } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GatewayTLSConfig. @@ -1481,7 +1470,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 { @@ -1555,6 +1544,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 @@ -1839,3 +1862,35 @@ 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 + in.FrontendValidation.DeepCopyInto(&out.FrontendValidation) +} + +// 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/v1beta1/gateway_types.go b/apis/v1beta1/gateway_types.go index 1998c2ac27..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. // diff --git a/apisx/v1alpha1/shared_types.go b/apisx/v1alpha1/shared_types.go index 441d4758c1..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 diff --git a/apisx/v1alpha1/xlistenerset_types.go b/apisx/v1alpha1/xlistenerset_types.go index fd108e2bed..f8198c8659 100644 --- a/apisx/v1alpha1/xlistenerset_types.go +++ b/apisx/v1alpha1/xlistenerset_types.go @@ -179,14 +179,14 @@ type ListenerEntry struct { // 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 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/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..b123a40f9c 100644 --- a/applyconfiguration/apis/v1/gatewayspec.go +++ b/applyconfiguration/apis/v1/gatewayspec.go @@ -31,6 +31,7 @@ type GatewaySpecApplyConfiguration struct { 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 @@ -96,3 +97,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..dbd3f443b1 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"` + Default *TLSConfigApplyConfiguration `json:"default,omitempty"` + PerPort []TLSPortConfigApplyConfiguration `json:"perPort,omitempty"` } // GatewayTLSConfigApplyConfiguration constructs a declarative configuration of the GatewayTLSConfig type for use with @@ -37,45 +31,23 @@ func GatewayTLSConfig() *GatewayTLSConfigApplyConfiguration { return &GatewayTLSConfigApplyConfiguration{} } -// WithMode sets the Mode field in the declarative configuration to the given value +// 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 Mode field is set to the value of the last call. -func (b *GatewayTLSConfigApplyConfiguration) WithMode(value apisv1.TLSModeType) *GatewayTLSConfigApplyConfiguration { - b.Mode = &value +// If called multiple times, the Default field is set to the value of the last call. +func (b *GatewayTLSConfigApplyConfiguration) WithDefault(value *TLSConfigApplyConfiguration) *GatewayTLSConfigApplyConfiguration { + b.Default = value return b } -// WithCertificateRefs adds the given value to the CertificateRefs field in the declarative configuration +// 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 CertificateRefs field. -func (b *GatewayTLSConfigApplyConfiguration) WithCertificateRefs(values ...*SecretObjectReferenceApplyConfiguration) *GatewayTLSConfigApplyConfiguration { +// If called multiple times, values provided by each call will be appended to the PerPort field. +func (b *GatewayTLSConfigApplyConfiguration) WithPerPort(values ...*TLSPortConfigApplyConfiguration) *GatewayTLSConfigApplyConfiguration { for i := range values { if values[i] == nil { - panic("nil value passed to WithCertificateRefs") + panic("nil value passed to WithPerPort") } - b.CertificateRefs = append(b.CertificateRefs, *values[i]) - } - return b -} - -// WithFrontendValidation sets the FrontendValidation 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 + b.PerPort = append(b.PerPort, *values[i]) } return b } 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..1dfa5e024e --- /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 { + FrontendValidation *FrontendTLSValidationApplyConfiguration `json:"frontendValidation,omitempty"` +} + +// TLSConfigApplyConfiguration constructs a declarative configuration of the TLSConfig type for use with +// apply. +func TLSConfig() *TLSConfigApplyConfiguration { + return &TLSConfigApplyConfiguration{} +} + +// WithFrontendValidation sets the FrontendValidation 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 *TLSConfigApplyConfiguration) WithFrontendValidation(value *FrontendTLSValidationApplyConfiguration) *TLSConfigApplyConfiguration { + b.FrontendValidation = 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/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 92508d3a05..f71080402f 100644 --- a/applyconfiguration/internal/internal.go +++ b/applyconfiguration/internal/internal.go @@ -307,6 +307,9 @@ 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.GRPCBackendRef map: fields: @@ -598,6 +601,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 +651,18 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig map: fields: - - name: certificateRefs + - name: default type: - list: - elementType: - namedType: io.k8s.sigs.gateway-api.apis.v1.SecretObjectReference - elementRelationship: atomic - - name: frontendValidation - type: - namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation - - name: mode - type: - scalar: string - - name: options + namedType: io.k8s.sigs.gateway-api.apis.v1.TLSConfig + default: {} + - name: perPort type: - map: + list: elementType: - scalar: string + namedType: io.k8s.sigs.gateway-api.apis.v1.TLSPortConfig + elementRelationship: associative + keys: + - port - name: io.k8s.sigs.gateway-api.apis.v1.HTTPBackendRef map: fields: @@ -1033,7 +1034,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 +1069,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 +1253,24 @@ var schemaYAML = typed.YAMLObject(`types: type: scalar: string default: "" +- name: io.k8s.sigs.gateway-api.apis.v1.TLSConfig + map: + fields: + - name: frontendValidation + type: + namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation + default: {} +- 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: @@ -1801,7 +1837,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.apisx.v1alpha1.ListenerEntryStatus map: fields: diff --git a/applyconfiguration/utils.go b/applyconfiguration/utils.go index 8014f68c7c..71851d893d 100644 --- a/applyconfiguration/utils.go +++ b/applyconfiguration/utils.go @@ -140,6 +140,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 +166,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"): diff --git a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml index 2e2462a087..f04f7b978a 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml @@ -802,7 +802,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 @@ -890,96 +890,6 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic - 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 - x-kubernetes-list-type: atomic - required: - - caCertificateRefs - type: object mode: default: Terminate description: |- @@ -1058,6 +968,297 @@ 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: |- + GatewayTLSConfig specifies frontend tls configuration for gateway. + + Support: Extended + 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: + frontendValidation: + description: |- + 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: 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 + required: + - frontendValidation + 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: + frontendValidation: + description: |- + 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: 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 + required: + - frontendValidation + 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 required: - gatewayClassName - listeners @@ -2148,7 +2349,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 @@ -2236,96 +2437,6 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic - 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 - x-kubernetes-list-type: atomic - required: - - caCertificateRefs - type: object mode: default: Terminate description: |- @@ -2404,6 +2515,297 @@ 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: |- + GatewayTLSConfig specifies frontend tls configuration for gateway. + + Support: Extended + 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: + frontendValidation: + description: |- + 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: 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 + required: + - frontendValidation + 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: + frontendValidation: + description: |- + 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: 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 + required: + - frontendValidation + 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 required: - gatewayClassName - listeners 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 1a266cca60..6d5a5bd5f9 100644 --- a/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml +++ b/config/crd/experimental/gateway.networking.x-k8s.io_xlistenersets.yaml @@ -323,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 @@ -409,96 +409,6 @@ spec: maxItems: 64 type: array x-kubernetes-list-type: atomic - 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 - x-kubernetes-list-type: atomic - required: - - caCertificateRefs - type: object mode: default: Terminate description: |- diff --git a/config/crd/standard/gateway.networking.k8s.io_gateways.yaml b/config/crd/standard/gateway.networking.k8s.io_gateways.yaml index bcb648812d..8b7b0a02e5 100644 --- a/config/crd/standard/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/standard/gateway.networking.k8s.io_gateways.yaml @@ -657,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 @@ -1768,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 diff --git a/examples/experimental/frontend-cert-validation.yaml b/examples/experimental/frontend-cert-validation.yaml index 7f103aed8e..a7a9d4a14d 100644 --- a/examples/experimental/frontend-cert-validation.yaml +++ b/examples/experimental/frontend-cert-validation.yaml @@ -4,6 +4,13 @@ metadata: name: client-validation-basic spec: gatewayClassName: acme-lb + tls: + default: + frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: foo-example-com-ca-cert listeners: - name: foo-https protocol: HTTPS @@ -14,10 +21,5 @@ spec: - kind: Secret group: "" name: foo-example-com-cert - frontendValidation: - caCertificateRefs: - - kind: ConfigMap - group: "" - name: foo-example-com-ca-cert --- diff --git a/geps/gep-91/index.md b/geps/gep-91/index.md index 8eedb7bd62..d71aef7650 100644 --- a/geps/gep-91/index.md +++ b/geps/gep-91/index.md @@ -26,21 +26,28 @@ This use case has been highlighted in the [TLS Configuration GEP][] under segmen ### API -* Introduce two new structs `TLSConfig` and `FrontendTLSValidation` allowing for the definition of certificate validation used to authenticate the peer (frontend) in a TLS connection. A new `tls` field, storing an array of `TLSConfigs`, will be added to the gateway object. +* 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` - 2) `AllowInvalidOrMissingCert` + 1) `AllowValidOnly` (Core Support) + 2) `AllowInsecureFallback` (Extended Support) + + `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. -* Introduce a `tls` field within the Gateway Spec to allow for a common TLS configuration to apply across all listeners. ### Impact on listeners 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 that match the configuration. + 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,43 +85,58 @@ type ObjectReference struct { Namespace *Namespace `json:"namespace,omitempty"` } -// GatewayTLSConfigs stores TLS configurations for a Gateway. -// -// * If the `port` field in `TLSConfig` is not set, the TLS configuration applies -// to all listeners in the gateway. We call this `default` configuration. -// * If the `port` field in `TLSConfig` is set, the TLS configuration applies -// only to listeners with a matching port. Each port requires a unique TLS configuration. -// * Per-port configurations can override the `default` configuration. -// * The `default` configuration is optional. Clients can apply TLS configuration -// to a subset of listeners by creating only per-port configurations. Listeners -// with a port that does not match any TLS configuration will not have -// `frontendValidation` set. -type GatewayTLSConfigs = []TLSConfig - -// TLSConfig describes a TLS configuration that can be applied to all Gateway -// Listeners or to all Listeners matching the Port if set. +// GatewayTLSConfig specifies frontend tls configuration for gateway. +type GatewayTLSConfig 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 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 { - // The Port indicates the Port Number to which the TLS configuration will be - // applied. If the field is not set the TLS Configuration will be applied to - // all Listeners. - // - // Support: Extended - // - // +optional - // - Port *PortNumber // 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 + // 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. // - // Each field may be overidden by an equivalent setting applied at the Listener level. - // // Support: Extended // - // +optional + // +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 // - FrontendValidation *FrontendTLSValidation `json:"frontendValidation,omitempty"` + 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 @@ -151,21 +173,25 @@ type FrontendTLSValidation struct { // - 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`. - // - AllowInvalidOrMissingCert: In this mode, the gateway will accept - // connections even if the client certificate is not presented or fails verification. + // - 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: Extended + // Support: Core // // +optional // +kubebuilder:default=AllowValidOnly - Mode *FrontendValidationModeType `json:"mode,omitempty"` + Mode FrontendValidationModeType `json:"mode,omitempty"` } -// FrontendValidationModeType type defines how a Gateway or Listener validates client certificates. +// FrontendValidationModeType type defines how a Gateway validates client certificates. // -// +kubebuilder:validation:Enum=AllowValidOnly;AllowInvalidOrMissingCert +// +kubebuilder:validation:Enum=AllowValidOnly;AllowInsecureFallback type FrontendValidationModeType string const ( @@ -173,15 +199,20 @@ const ( // during the TLS handshake and MUST pass validation. AllowValidOnly FrontendValidationModeType = "AllowValidOnly" - // AllowInvalidOrMissingCert indicates that a client certificate may not be + // AllowInsecureFallback indicates that a client certificate may not be // presented during the handshake or the validation against CA certificates may fail. - AllowInvalidOrMissingCert FrontendValidationModeType = "AllowInvalidOrMissingCert" + AllowInsecureFallback FrontendValidationModeType = "AllowInsecureFallback" ) type GatewaySpec struct { ... - // TLSConfigs stores TLS configurations for a Gateway. - TLSConfigs GatewayTLSConfigs + // GatewayTLSConfig specifies frontend tls configuration for gateway. + // + // Support: Core + // + // +optional + // + TLS *GatewayTLSConfig `json:"tls,omitempty"` } ``` @@ -198,11 +229,12 @@ metadata: spec: gatewayClassName: acme-lb tls: - - frontendValidation: - caCertificateRefs: - - kind: ConfigMap - group: "" - name: default-cert + default: + frontendValidation: + caCertificateRefs: + - kind: ConfigMap + group: "" + name: default-cert listeners: - name: foo-https protocol: HTTPS @@ -234,18 +266,20 @@ metadata: spec: gatewayClassName: acme-lb tls: - - port: 443 + default: frontendValidation: caCertificateRefs: - - kind: ConfigMap - group: "" - name: foo-example-com-ca-cert - - frontendValidation: - caCertificateRefs: - - kind: ConfigMap - group: "" - name: default-cert - mode: AllowInvalidOrMissingCert + - 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 @@ -321,7 +355,6 @@ This GEP aims to standardize this behavior as an official part of the upstream s [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]: ../../reference/spec.md#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 diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 9885f10471..d412463a01 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -136,6 +136,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.Listener": schema_sigsk8sio_gateway_api_apis_v1_Listener(ref), "sigs.k8s.io/gateway-api/apis/v1.ListenerNamespaces": schema_sigsk8sio_gateway_api_apis_v1_ListenerNamespaces(ref), "sigs.k8s.io/gateway-api/apis/v1.ListenerStatus": schema_sigsk8sio_gateway_api_apis_v1_ListenerStatus(ref), + "sigs.k8s.io/gateway-api/apis/v1.ListenerTLSConfig": schema_sigsk8sio_gateway_api_apis_v1_ListenerTLSConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.LocalObjectReference": schema_sigsk8sio_gateway_api_apis_v1_LocalObjectReference(ref), "sigs.k8s.io/gateway-api/apis/v1.LocalParametersReference": schema_sigsk8sio_gateway_api_apis_v1_LocalParametersReference(ref), "sigs.k8s.io/gateway-api/apis/v1.ObjectReference": schema_sigsk8sio_gateway_api_apis_v1_ObjectReference(ref), @@ -148,6 +149,8 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference": schema_sigsk8sio_gateway_api_apis_v1_SecretObjectReference(ref), "sigs.k8s.io/gateway-api/apis/v1.SessionPersistence": schema_sigsk8sio_gateway_api_apis_v1_SessionPersistence(ref), "sigs.k8s.io/gateway-api/apis/v1.SupportedFeature": schema_sigsk8sio_gateway_api_apis_v1_SupportedFeature(ref), + "sigs.k8s.io/gateway-api/apis/v1.TLSConfig": schema_sigsk8sio_gateway_api_apis_v1_TLSConfig(ref), + "sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig": schema_sigsk8sio_gateway_api_apis_v1_TLSPortConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.supportedFeatureInternal": schema_sigsk8sio_gateway_api_apis_v1_supportedFeatureInternal(ref), "sigs.k8s.io/gateway-api/apis/v1alpha2.GRPCRoute": schema_sigsk8sio_gateway_api_apis_v1alpha2_GRPCRoute(ref), "sigs.k8s.io/gateway-api/apis/v1alpha2.GRPCRouteList": schema_sigsk8sio_gateway_api_apis_v1alpha2_GRPCRouteList(ref), @@ -3100,7 +3103,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref common.Refer }, }, 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{ @@ -3112,6 +3115,13 @@ 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"}, }, @@ -4094,12 +4104,18 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpec(ref common.ReferenceCallba Ref: ref("sigs.k8s.io/gateway-api/apis/v1.AllowedListeners"), }, }, + "tls": { + SchemaProps: spec.SchemaProps{ + Description: "GatewayTLSConfig specifies frontend tls configuration for 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.GatewayBackendTLS", "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"}, } } @@ -4241,61 +4257,44 @@ 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 tls configuration for gateway.", + Type: []string{"object"}, Properties: map[string]spec.Schema{ - "mode": { + "default": { 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: "", + 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"), }, }, - "certificateRefs": { + "perPort": { VendorExtensible: spec.VendorExtensible{ Extensions: spec.Extensions{ - "x-kubernetes-list-type": "atomic", + "x-kubernetes-list-map-keys": []interface{}{ + "port", + }, + "x-kubernetes-list-type": "map", }, }, 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: "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.SecretObjectReference"), - }, - }, - }, - }, - }, - "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"), - }, - }, - "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: "", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig"), }, }, }, }, }, }, + Required: []string{"default"}, }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation", "sigs.k8s.io/gateway-api/apis/v1.SecretObjectReference"}, + "sigs.k8s.io/gateway-api/apis/v1.TLSConfig", "sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig"}, } } @@ -5399,8 +5398,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": { @@ -5414,7 +5413,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"}, } } @@ -5519,6 +5518,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{ @@ -5997,6 +6052,59 @@ 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{ + "frontendValidation": { + SchemaProps: spec.SchemaProps{ + Description: "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.\n\nSupport: Core\n\n", + Default: map[string]interface{}{}, + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation"), + }, + }, + }, + Required: []string{"frontendValidation"}, + }, + }, + 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{ @@ -8204,8 +8312,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": { @@ -8219,7 +8327,7 @@ func schema_sigsk8sio_gateway_api_apisx_v1alpha1_ListenerEntry(ref common.Refere }, }, 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"}, } } 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")}, }, From c703df92906dff5a95e2644f17799093f81dff34 Mon Sep 17 00:00:00 2001 From: bjee19 <139261241+bjee19@users.noreply.github.com> Date: Wed, 20 Aug 2025 12:03:05 -0700 Subject: [PATCH 132/148] Add NGINX Gateway Fabric v2.1.0 conformance report (#4005) * Add NGINX v2.1.0 conformance report * Remove backtick * Add end of file new line --- .../nginx-nginx-gateway-fabric/README.md | 1 + .../experimental-2.1.0-default-report.yaml | 98 +++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/experimental-2.1.0-default-report.yaml 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 index ae54954fae..6074dc7bf6 100644 --- a/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md +++ b/conformance/reports/v1.3.0/nginx-nginx-gateway-fabric/README.md @@ -5,6 +5,7 @@ | 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 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 From 8fe8316f5792a7830a49c800f89fe689e0df042e Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Wed, 20 Aug 2025 21:37:07 +0200 Subject: [PATCH 133/148] Add ResolvedRefs condition for BackendTLSPolicy (#3994) * Add ResolvedRefs condition for BackendTLSPolicy Signed-off-by: Norwin Schnyder * Apply PR feedback Signed-off-by: Norwin Schnyder * Refined implementation-specific behavior of CACertificateRefs Signed-off-by: Norwin Schnyder * Apply PR suggestions Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- apis/v1alpha3/backendtlspolicy_types.go | 81 +++++++++++++++++-- ....networking.k8s.io_backendtlspolicies.yaml | 40 +++++++-- geps/gep-1897/index.md | 6 +- pkg/generated/openapi/zz_generated.openapi.go | 4 +- 4 files changed, 110 insertions(+), 21 deletions(-) diff --git a/apis/v1alpha3/backendtlspolicy_types.go b/apis/v1alpha3/backendtlspolicy_types.go index e00491908c..9c5c019d46 100644 --- a/apis/v1alpha3/backendtlspolicy_types.go +++ b/apis/v1alpha3/backendtlspolicy_types.go @@ -121,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 @@ -131,8 +155,8 @@ 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. // // +optional // +listType=atomic @@ -144,10 +168,11 @@ 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 // @@ -235,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/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml index 8622def679..b5a05f1be6 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_backendtlspolicies.yaml @@ -178,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 @@ -188,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 @@ -312,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: diff --git a/geps/gep-1897/index.md b/geps/gep-1897/index.md index 8e24b8bf09..149d6c649e 100644 --- a/geps/gep-1897/index.md +++ b/geps/gep-1897/index.md @@ -215,11 +215,11 @@ named object references, each containing a single cert. We originally proposed t [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: UnsupportedFeature`. +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 `NoCACertificates` and a message explaining this. +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 @@ -229,7 +229,7 @@ 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 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 `UnsupportedFeature` and a message explaining this. +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. diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index d412463a01..6774709847 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -7409,7 +7409,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c }, }, 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{ @@ -7428,7 +7428,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha3_BackendTLSPolicyValidation(ref c }, }, 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: "", }, From 99599108220e5f32a07022343b6b2c93fec19ab6 Mon Sep 17 00:00:00 2001 From: Nick Young Date: Mon, 25 Aug 2025 21:49:10 +1000 Subject: [PATCH 134/148] Update status fields with clearer definitions (#4008) Signed-off-by: Nick Young --- apis/v1/gateway_types.go | 58 +++++++++++++++++++ apis/v1/gatewayclass_types.go | 29 ++++++++++ apis/v1/shared_types.go | 53 +++++++++++++++++ apis/v1alpha2/policy_types.go | 30 ++++++++++ pkg/generated/openapi/zz_generated.openapi.go | 22 +++---- 5 files changed, 181 insertions(+), 11 deletions(-) diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index fdb31043cd..e85e81ba48 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -923,6 +923,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 @@ -1272,6 +1300,36 @@ type ListenerStatus struct { // 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 diff --git a/apis/v1/gatewayclass_types.go b/apis/v1/gatewayclass_types.go index 655195ce6d..f9b779c7b3 100644 --- a/apis/v1/gatewayclass_types.go +++ b/apis/v1/gatewayclass_types.go @@ -263,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 diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index b98a9e812f..5b5ed4cfed 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -477,6 +477,36 @@ 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 @@ -503,6 +533,29 @@ 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 diff --git a/apis/v1alpha2/policy_types.go b/apis/v1alpha2/policy_types.go index dc2f8f7f09..d24bb2ee74 100644 --- a/apis/v1alpha2/policy_types.go +++ b/apis/v1alpha2/policy_types.go @@ -201,6 +201,36 @@ type PolicyAncestorStatus struct { // 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 diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 6774709847..e674ba5140 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -3642,7 +3642,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GRPCRouteStatus(ref common.ReferenceCa }, }, 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{ @@ -3887,7 +3887,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{ @@ -4182,7 +4182,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{ @@ -5282,7 +5282,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPRouteStatus(ref common.ReferenceCa }, }, 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{ @@ -5497,7 +5497,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{ @@ -5885,7 +5885,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{ @@ -5920,7 +5920,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_RouteStatus(ref common.ReferenceCallba }, }, 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{ @@ -6382,7 +6382,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{ @@ -6737,7 +6737,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TCPRouteStatus(ref common.Refere }, }, 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{ @@ -6987,7 +6987,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_TLSRouteStatus(ref common.Refere }, }, 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{ @@ -7217,7 +7217,7 @@ func schema_sigsk8sio_gateway_api_apis_v1alpha2_UDPRouteStatus(ref common.Refere }, }, 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{ From 230b20454c19302684ebcbab5b72023b8f5bbd7e Mon Sep 17 00:00:00 2001 From: idb <71566757+idebeijer@users.noreply.github.com> Date: Mon, 25 Aug 2025 20:35:07 +0200 Subject: [PATCH 135/148] docs: update cilium impl docs for gateway-api v1.3.0 conformance (#4018) --- site-src/implementations.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site-src/implementations.md b/site-src/implementations.md index 46335451c9..0d97e76468 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -261,15 +261,15 @@ 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 Graduated project. @@ -280,7 +280,7 @@ 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 From 110bcaf60d1178b18af7588feddcc1f22474dd4a Mon Sep 17 00:00:00 2001 From: Nick Young Date: Tue, 26 Aug 2025 04:51:07 +1000 Subject: [PATCH 136/148] Add API changes for HTTP External Auth (#4001) Updates #1494. Signed-off-by: Nick Young --- apis/v1/httproute_types.go | 226 +++- apis/v1/zz_generated.deepcopy.go | 96 ++ .../apis/v1/forwardbodyconfig.go | 39 + applyconfiguration/apis/v1/grpcauthconfig.go | 41 + applyconfiguration/apis/v1/httpauthconfig.go | 61 + .../apis/v1/httpexternalauthfilter.go | 79 ++ applyconfiguration/apis/v1/httproutefilter.go | 9 + applyconfiguration/internal/internal.go | 55 + applyconfiguration/utils.go | 8 + .../gateway.networking.k8s.io_httproutes.yaml | 1036 +++++++++++++++++ ...lid-filter-externalauth-bad-http-path.yaml | 12 + .../invalid-filter-externalauth-empty.yaml | 8 + ...valid-filter-externalauth-no-protocol.yaml | 9 + pkg/generated/openapi/zz_generated.openapi.go | 175 ++- pkg/test/cel/httproute_experimental_test.go | 46 + 15 files changed, 1897 insertions(+), 3 deletions(-) create mode 100644 applyconfiguration/apis/v1/forwardbodyconfig.go create mode 100644 applyconfiguration/apis/v1/grpcauthconfig.go create mode 100644 applyconfiguration/apis/v1/httpauthconfig.go create mode 100644 applyconfiguration/apis/v1/httpexternalauthfilter.go create mode 100644 hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-bad-http-path.yaml create mode 100644 hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-empty.yaml create mode 100644 hack/invalid-examples/experimental/httproute/invalid-filter-externalauth-no-protocol.yaml diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 39a01f27f1..53fae56716 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -804,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 { @@ -842,7 +844,7 @@ type HTTPRouteFilter struct { // // +unionDiscriminator // +kubebuilder:validation:Enum=RequestHeaderModifier;ResponseHeaderModifier;RequestMirror;RequestRedirect;URLRewrite;ExtensionRef - // + // // +required Type HTTPRouteFilterType `json:"type"` @@ -901,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 @@ -972,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. // @@ -1536,6 +1563,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 diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index d7e4a6c2f4..6bbf75ba62 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 @@ -212,6 +227,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 @@ -868,6 +903,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 @@ -931,6 +991,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 @@ -1192,6 +1283,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) 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/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/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/internal/internal.go b/applyconfiguration/internal/internal.go index f71080402f..953f2863cd 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: @@ -310,6 +316,15 @@ var schemaYAML = typed.YAMLObject(`types: - 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: @@ -663,6 +678,24 @@ var schemaYAML = typed.YAMLObject(`types: elementRelationship: associative keys: - port +- name: io.k8s.sigs.gateway-api.apis.v1.HTTPAuthConfig + map: + fields: + - name: allowedHeaders + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: allowedResponseHeaders + type: + list: + elementType: + scalar: string + elementRelationship: associative + - name: path + type: + scalar: string - name: io.k8s.sigs.gateway-api.apis.v1.HTTPBackendRef map: fields: @@ -724,6 +757,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: @@ -871,6 +923,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 diff --git a/applyconfiguration/utils.go b/applyconfiguration/utils.go index 71851d893d..5acafbc2c1 100644 --- a/applyconfiguration/utils.go +++ b/applyconfiguration/utils.go @@ -52,6 +52,8 @@ 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("FrontendTLSValidation"): @@ -78,6 +80,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 +100,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"): diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 65515a4e22..34876b54a0 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -773,6 +773,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 @@ -1386,6 +1639,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -1523,6 +1777,12 @@ 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 @@ -1995,6 +2255,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 @@ -2604,6 +3115,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -2738,6 +3250,12 @@ 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 @@ -4399,6 +4917,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 @@ -5012,6 +5783,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -5149,6 +5921,12 @@ 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 @@ -5621,6 +6399,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 @@ -6230,6 +7259,7 @@ spec: - URLRewrite - ExtensionRef - CORS + - ExternalAuth type: string urlRewrite: description: |- @@ -6364,6 +7394,12 @@ 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 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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index e674ba5140..588319b36e 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -88,8 +88,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.BackendRef": schema_sigsk8sio_gateway_api_apis_v1_BackendRef(ref), "sigs.k8s.io/gateway-api/apis/v1.CommonRouteSpec": schema_sigsk8sio_gateway_api_apis_v1_CommonRouteSpec(ref), "sigs.k8s.io/gateway-api/apis/v1.CookieConfig": schema_sigsk8sio_gateway_api_apis_v1_CookieConfig(ref), + "sigs.k8s.io/gateway-api/apis/v1.ForwardBodyConfig": schema_sigsk8sio_gateway_api_apis_v1_ForwardBodyConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.Fraction": schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref), "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation": schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref), + "sigs.k8s.io/gateway-api/apis/v1.GRPCAuthConfig": schema_sigsk8sio_gateway_api_apis_v1_GRPCAuthConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCBackendRef": schema_sigsk8sio_gateway_api_apis_v1_GRPCBackendRef(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCHeaderMatch": schema_sigsk8sio_gateway_api_apis_v1_GRPCHeaderMatch(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCMethodMatch": schema_sigsk8sio_gateway_api_apis_v1_GRPCMethodMatch(ref), @@ -113,8 +115,10 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.GatewayStatus": schema_sigsk8sio_gateway_api_apis_v1_GatewayStatus(ref), "sigs.k8s.io/gateway-api/apis/v1.GatewayStatusAddress": schema_sigsk8sio_gateway_api_apis_v1_GatewayStatusAddress(ref), "sigs.k8s.io/gateway-api/apis/v1.GatewayTLSConfig": schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref), + "sigs.k8s.io/gateway-api/apis/v1.HTTPAuthConfig": schema_sigsk8sio_gateway_api_apis_v1_HTTPAuthConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.HTTPBackendRef": schema_sigsk8sio_gateway_api_apis_v1_HTTPBackendRef(ref), "sigs.k8s.io/gateway-api/apis/v1.HTTPCORSFilter": schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref), + "sigs.k8s.io/gateway-api/apis/v1.HTTPExternalAuthFilter": schema_sigsk8sio_gateway_api_apis_v1_HTTPExternalAuthFilter(ref), "sigs.k8s.io/gateway-api/apis/v1.HTTPHeader": schema_sigsk8sio_gateway_api_apis_v1_HTTPHeader(ref), "sigs.k8s.io/gateway-api/apis/v1.HTTPHeaderFilter": schema_sigsk8sio_gateway_api_apis_v1_HTTPHeaderFilter(ref), "sigs.k8s.io/gateway-api/apis/v1.HTTPHeaderMatch": schema_sigsk8sio_gateway_api_apis_v1_HTTPHeaderMatch(ref), @@ -3063,6 +3067,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{ @@ -3131,6 +3155,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{ @@ -4298,6 +4355,66 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref common.ReferenceC } } +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: "", + }, + }, + "allowedHeaders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + 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: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + "allowedResponseHeaders": { + VendorExtensible: spec.VendorExtensible{ + Extensions: spec.Extensions{ + "x-kubernetes-list-type": "set", + }, + }, + SchemaProps: spec.SchemaProps{ + 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: "", + Type: []string{"string"}, + Format: "", + }, + }, + }, + }, + }, + }, + }, + }, + } +} + func schema_sigsk8sio_gateway_api_apis_v1_HTTPBackendRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -4483,6 +4600,54 @@ func schema_sigsk8sio_gateway_api_apis_v1_HTTPCORSFilter(ref common.ReferenceCal } } +func schema_sigsk8sio_gateway_api_apis_v1_HTTPExternalAuthFilter(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + 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{ @@ -4873,7 +5038,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: "", @@ -4915,6 +5080,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", @@ -4926,7 +5097,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"}, } } diff --git a/pkg/test/cel/httproute_experimental_test.go b/pkg/test/cel/httproute_experimental_test.go index f6ff0d455b..9978d4ca11 100644 --- a/pkg/test/cel/httproute_experimental_test.go +++ b/pkg/test/cel/httproute_experimental_test.go @@ -568,3 +568,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) + }) + } + +} From d008cdea2652786c1711426056e059d127954f52 Mon Sep 17 00:00:00 2001 From: Eyal Paz <67443108+EyalPazz@users.noreply.github.com> Date: Tue, 26 Aug 2025 02:53:06 +0300 Subject: [PATCH 137/148] conformance: add test for optional address value (#3689) * conformance: add test for optional address value * fix: small resolutions after CR * fix: CR Resolution 2 * fix: only overlay addresses if needed * fix: conflict resolvement mistake * fix: CR comments --- .../tests/gateway-optional-address-value.go | 70 +++++++++++++++++++ .../tests/gateway-optional-address-value.yaml | 13 ++++ conformance/utils/kubernetes/helpers.go | 2 +- 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 conformance/tests/gateway-optional-address-value.go create mode 100644 conformance/tests/gateway-optional-address-value.yaml 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/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index 1501d93571..ea9b8af63f 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -446,7 +446,7 @@ 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 } From c15b79217096f0375b971121d42098e665ee622a Mon Sep 17 00:00:00 2001 From: Norwin Schnyder Date: Tue, 26 Aug 2025 16:10:12 +0200 Subject: [PATCH 138/148] BackendTLSPolicy conformance tests for ResolvedRefs status condition (#4010) * BackendTLSPolicy conformance tests for ResolvedRefs status condition Signed-off-by: Norwin Schnyder * Apply PR feedback Signed-off-by: Norwin Schnyder * deprecate StatusCode of the excpected response in favor of StatusCodes Signed-off-by: Norwin Schnyder --------- Signed-off-by: Norwin Schnyder --- ...endtlspolicy-invalid-ca-certificate-ref.go | 98 +++++++++++++++++++ ...dtlspolicy-invalid-ca-certificate-ref.yaml | 97 ++++++++++++++++++ .../tests/backendtlspolicy-invalid-kind.go | 93 ++++++++++++++++++ .../tests/backendtlspolicy-invalid-kind.yaml | 51 ++++++++++ conformance/tests/backendtlspolicy.go | 26 +++-- conformance/utils/echo/pod.go | 20 +++- conformance/utils/http/http.go | 25 +++-- 7 files changed, 390 insertions(+), 20 deletions(-) create mode 100644 conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.go create mode 100644 conformance/tests/backendtlspolicy-invalid-ca-certificate-ref.yaml create mode 100644 conformance/tests/backendtlspolicy-invalid-kind.go create mode 100644 conformance/tests/backendtlspolicy-invalid-kind.yaml 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.go b/conformance/tests/backendtlspolicy.go index fc6c6576eb..62ed54c4af 100644 --- a/conformance/tests/backendtlspolicy.go +++ b/conformance/tests/backendtlspolicy.go @@ -20,11 +20,11 @@ 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" @@ -54,20 +54,20 @@ var BackendTLSPolicy = suite.ConformanceTest{ 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{ + 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, policyCond) - - invalidPolicyNN := types.NamespacedName{Name: "backendtlspolicy-host-mismatch", Namespace: ns} - kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidPolicyNN, gwNN, policyCond) - - invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns} - kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, policyCond) + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, acceptedCond) + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validPolicyNN, gwNN, resolvedRefsCond) serverStr := "abc.example.com" @@ -107,6 +107,10 @@ var BackendTLSPolicy = suite.ConformanceTest{ // 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, @@ -120,6 +124,10 @@ var BackendTLSPolicy = suite.ConformanceTest{ // 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, diff --git a/conformance/utils/echo/pod.go b/conformance/utils/echo/pod.go index 0222ff12dd..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" @@ -84,8 +86,14 @@ func makeRequest(t *testing.T, exp *http.ExpectedResponse) []string { exp.Request.Method = "GET" } - if exp.Response.StatusCode == 0 { - exp.Response.StatusCode = 200 + // 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 @@ -110,8 +118,12 @@ func compareRequest(exp http.ExpectedResponse, resp Response) error { } wantReq := exp.ExpectedRequest wantResp := exp.Response - if fmt.Sprint(wantResp.StatusCode) != resp.Code { - return fmt.Errorf("wanted status code %v, got %v", wantResp.StatusCode, resp.Code) + 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 { diff --git a/conformance/utils/http/http.go b/conformance/utils/http/http.go index 50f8d1efdd..6cd68dd084 100644 --- a/conformance/utils/http/http.go +++ b/conformance/utils/http/http.go @@ -22,6 +22,7 @@ import ( "math/big" "net" "net/url" + "slices" "strings" "testing" "time" @@ -91,7 +92,9 @@ 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 @@ -138,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 == "" { @@ -300,12 +308,14 @@ func WaitForConsistentFailureResponse(t *testing.T, r roundtripper.RoundTripper, 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. CRes: %v", expected.Response.StatusCode, cRes.StatusCode, cRes) + 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) @@ -467,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) { From cd9f05fdd8288a8156db1cfcce89abdefa1c7a52 Mon Sep 17 00:00:00 2001 From: Lior Lieberman Date: Tue, 26 Aug 2025 12:30:09 -0700 Subject: [PATCH 139/148] remove http non mesh features from mesh profile (#4029) --- conformance/utils/suite/profiles.go | 1 - 1 file changed, 1 deletion(-) 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()...), } From d28cd59d37887be07b879f098cff7b14a87c0080 Mon Sep 17 00:00:00 2001 From: Eyal Paz <67443108+EyalPazz@users.noreply.github.com> Date: Tue, 26 Aug 2025 22:48:10 +0300 Subject: [PATCH 140/148] conformance: add test to check for proper cors allow-credentials behvior (#3990) * conformance: add test to check for proper cors allow-credentials behavior * chore: rephrase description * fix: SupportHTTPRouteCORS FeatureName --- .../tests/cors-allow-credentials-behavior.go | 100 ++++++++++++++++++ .../cors-allow-credentials-behavior.yaml | 32 ++++++ pkg/features/httproute.go | 9 ++ 3 files changed, 141 insertions(+) create mode 100644 conformance/tests/cors-allow-credentials-behavior.go create mode 100644 conformance/tests/cors-allow-credentials-behavior.yaml 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/pkg/features/httproute.go b/pkg/features/httproute.go index 6c484da96c..53f93afdab 100644 --- a/pkg/features/httproute.go +++ b/pkg/features/httproute.go @@ -100,6 +100,9 @@ const ( // This option indicates support for the name field in the HTTPRouteRule (extended conformance) SupportHTTPRouteNamedRouteRule FeatureName = "HTTPRouteNamedRouteRule" + + // This option indicates support for the cors filter in the HTTPRouteFilter (extended conformance) + SupportHTTPRouteCORS FeatureName = "HTTPRouteCORS" ) var ( @@ -198,6 +201,11 @@ var ( Name: SupportHTTPRouteNamedRouteRule, Channel: FeatureChannelStandard, } + // HTTPRouteCORS contains metadata for the SupportHTTPRouteCORS feature. + HTTPRouteCORS = Feature{ + Name: SupportHTTPRouteCORS, + Channel: FeatureChannelExperimental, + } ) // HTTPRouteExtendedFeatures includes all extended features for HTTPRoute @@ -223,4 +231,5 @@ var HTTPRouteExtendedFeatures = sets.New( HTTPRouteBackendProtocolH2CFeature, HTTPRouteBackendProtocolWebSocketFeature, HTTPRouteNamedRouteRule, + HTTPRouteCORS, ) From 881105e859e69d4a5530b2b3fd4944448ee72784 Mon Sep 17 00:00:00 2001 From: kl52752 <89914070+kl52752@users.noreply.github.com> Date: Thu, 28 Aug 2025 01:53:10 +0200 Subject: [PATCH 141/148] Add Conformance tests for BackendTLSPolicy validating SANs with Type dsnName (#3983) * Add Conformance tests for BackendTLSPolicy validating SANs * review fixes * Validate URI SANs --- conformance/base/manifests.yaml | 33 ++ conformance/tests/backendtlspolicy-san.go | 163 ++++++++++ conformance/tests/backendtlspolicy-san.yaml | 341 ++++++++++++++++++++ conformance/tests/backendtlspolicy.yaml | 33 -- conformance/utils/kubernetes/certificate.go | 5 + conformance/utils/kubernetes/helpers.go | 4 +- conformance/utils/suite/suite.go | 5 + pkg/features/backendtlspolicy.go | 16 + 8 files changed, 565 insertions(+), 35 deletions(-) create mode 100644 conformance/tests/backendtlspolicy-san.go create mode 100644 conformance/tests/backendtlspolicy-san.yaml diff --git a/conformance/base/manifests.yaml b/conformance/base/manifests.yaml index 9380223ea0..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: 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.yaml b/conformance/tests/backendtlspolicy.yaml index e048cc2e7b..6d0cab8e3f 100644 --- a/conformance/tests/backendtlspolicy.yaml +++ b/conformance/tests/backendtlspolicy.yaml @@ -1,37 +1,4 @@ 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: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: gateway-conformance-infra-test diff --git a/conformance/utils/kubernetes/certificate.go b/conformance/utils/kubernetes/certificate.go index 07c3c80787..1b2ee3af85 100644 --- a/conformance/utils/kubernetes/certificate.go +++ b/conformance/utils/kubernetes/certificate.go @@ -27,6 +27,7 @@ import ( "io" "math/big" "net" + "net/url" "strings" "testing" "time" @@ -119,6 +120,8 @@ func generateRSACert(hosts []string, keyOut, certOut io.Writer, ca *x509.Certifi template.IPAddresses = append(template.IPAddresses, ip) } 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) } } @@ -215,6 +218,8 @@ func generateCACert(hosts []string) (*x509.Certificate, []byte, *rsa.PrivateKey, 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) } } diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index ea9b8af63f..3309c8f29b 100644 --- a/conformance/utils/kubernetes/helpers.go +++ b/conformance/utils/kubernetes/helpers.go @@ -1003,7 +1003,7 @@ func BackendTLSPolicyMustHaveCondition(t *testing.T, client client.Client, timeo policy := &v1alpha3.BackendTLSPolicy{} err := client.Get(ctx, policyNN, policy) if err != nil { - return false, fmt.Errorf("error fetching BackendTLSPolicy: %w", err) + return false, fmt.Errorf("error fetching BackendTLSPolicy %v err: %w", policyNN, err) } for _, parent := range policy.Status.Ancestors { @@ -1024,7 +1024,7 @@ func BackendTLSPolicyMustHaveCondition(t *testing.T, client client.Client, timeo return false, nil }) - require.NoErrorf(t, waitErr, "error waiting for BackendTLSPolicy status to have a Condition %v", condition) + 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 diff --git a/conformance/utils/suite/suite.go b/conformance/utils/suite/suite.go index 23c936536a..877c030f3c 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -394,6 +394,11 @@ func (suite *ConformanceTestSuite) Setup(t *testing.T, tests []ConformanceTest) 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{ diff --git a/pkg/features/backendtlspolicy.go b/pkg/features/backendtlspolicy.go index 95d5017164..12c6a24ccc 100644 --- a/pkg/features/backendtlspolicy.go +++ b/pkg/features/backendtlspolicy.go @@ -25,6 +25,9 @@ import "k8s.io/apimachinery/pkg/util/sets" const ( // This option indicates support for BackendTLSPolicy. SupportBackendTLSPolicy FeatureName = "BackendTLSPolicy" + + // This option indicates support for BackendTLSPolicy SubjectAltName Validation. + SupportBackendTLSPolicySANValidation FeatureName = "BackendTLSPolicySANValidation" ) // TLSRouteFeature contains metadata for the TLSRoute feature. @@ -33,8 +36,21 @@ var BackendTLSPolicyFeature = Feature{ Channel: FeatureChannelExperimental, } +// BackendTLSPolicySanValidationFeature contains metadata for the BackendTLSPolicy +// SubjectAltName Validation feature. +var BackendTLSPolicySanValidationFeature = Feature{ + Name: SupportBackendTLSPolicySANValidation, + Channel: FeatureChannelExperimental, +} + // BackendTLSPolicyCoreFeatures includes all the supported features for the // BackendTLSPolicy API at a Core level of support. var BackendTLSPolicyCoreFeatures = sets.New( BackendTLSPolicyFeature, ) + +// BackendTLSPolicyExtendedFeatures includes all the supported features for the +// BackendTLSPolicy API at a Extended level of support. +var BackendTLSPolicyExtendedFeatures = sets.New( + BackendTLSPolicySanValidationFeature, +) From 0eb555076f79d4f9ecef47fb1aa5f45f747fc2cc Mon Sep 17 00:00:00 2001 From: kl52752 <89914070+kl52752@users.noreply.github.com> Date: Thu, 28 Aug 2025 01:53:17 +0200 Subject: [PATCH 142/148] Move BackendTLS configuration to GatewayTLSConfig (#4009) * Move BackendTLS configuration to GatewayTLSConfig * review --- apis/v1/gateway_types.go | 44 +- apis/v1/zz_generated.deepcopy.go | 50 +- .../apis/v1/frontendtlsconfig.go | 53 + applyconfiguration/apis/v1/gatewayspec.go | 9 - .../apis/v1/gatewaytlsconfig.go | 27 +- applyconfiguration/apis/v1/tlsconfig.go | 10 +- applyconfiguration/internal/internal.go | 35 +- applyconfiguration/utils.go | 2 + .../gateway.networking.k8s.io_gateways.yaml | 1286 +++++++++-------- examples/experimental/backend-tls.yaml | 18 + .../frontend-cert-validation.yaml | 31 +- geps/gep-3155/index.md | 17 +- pkg/generated/openapi/zz_generated.openapi.go | 98 +- 13 files changed, 918 insertions(+), 762 deletions(-) create mode 100644 applyconfiguration/apis/v1/frontendtlsconfig.go create mode 100644 examples/experimental/backend-tls.yaml diff --git a/apis/v1/gateway_types.go b/apis/v1/gateway_types.go index e85e81ba48..652101ff76 100644 --- a/apis/v1/gateway_types.go +++ b/apis/v1/gateway_types.go @@ -279,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. // @@ -296,7 +287,7 @@ type GatewaySpec struct { // +optional AllowedListeners *AllowedListeners `json:"allowedListeners,omitempty"` // - // GatewayTLSConfig specifies frontend tls configuration for gateway. + // TLS specifies frontend and backend tls configuration for entire gateway. // // Support: Extended // @@ -525,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 @@ -602,8 +591,31 @@ type ListenerTLSConfig struct { Options map[AnnotationKey]AnnotationValue `json:"options,omitempty"` } -// GatewayTLSConfig specifies frontend tls configuration for gateway. +// 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. @@ -653,7 +665,7 @@ const ( // within this Gateway. 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). + // 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. @@ -661,9 +673,9 @@ type TLSConfig struct { // // Support: Core // - // +required + // +optional // - FrontendValidation FrontendTLSValidation `json:"frontendValidation"` + Validation *FrontendTLSValidation `json:"validation,omitempty"` } type TLSPortConfig struct { diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index 6bbf75ba62..bcbf489072 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -205,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 @@ -777,11 +800,6 @@ 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) @@ -883,13 +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 - 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]) - } + if in.Backend != nil { + in, out := &in.Backend, &out.Backend + *out = new(GatewayBackendTLS) + (*in).DeepCopyInto(*out) + } + if in.Frontend != nil { + in, out := &in.Frontend, &out.Frontend + *out = new(FrontendTLSConfig) + (*in).DeepCopyInto(*out) } } @@ -1962,7 +1982,11 @@ func (in *SupportedFeature) DeepCopy() *SupportedFeature { // 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 - in.FrontendValidation.DeepCopyInto(&out.FrontendValidation) + 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. 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/gatewayspec.go b/applyconfiguration/apis/v1/gatewayspec.go index b123a40f9c..e976dc4827 100644 --- a/applyconfiguration/apis/v1/gatewayspec.go +++ b/applyconfiguration/apis/v1/gatewayspec.go @@ -29,7 +29,6 @@ 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"` } @@ -82,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. diff --git a/applyconfiguration/apis/v1/gatewaytlsconfig.go b/applyconfiguration/apis/v1/gatewaytlsconfig.go index dbd3f443b1..4ec825dbee 100644 --- a/applyconfiguration/apis/v1/gatewaytlsconfig.go +++ b/applyconfiguration/apis/v1/gatewaytlsconfig.go @@ -21,8 +21,8 @@ package v1 // GatewayTLSConfigApplyConfiguration represents a declarative configuration of the GatewayTLSConfig type for use // with apply. type GatewayTLSConfigApplyConfiguration struct { - Default *TLSConfigApplyConfiguration `json:"default,omitempty"` - PerPort []TLSPortConfigApplyConfiguration `json:"perPort,omitempty"` + Backend *GatewayBackendTLSApplyConfiguration `json:"backend,omitempty"` + Frontend *FrontendTLSConfigApplyConfiguration `json:"frontend,omitempty"` } // GatewayTLSConfigApplyConfiguration constructs a declarative configuration of the GatewayTLSConfig type for use with @@ -31,23 +31,18 @@ func GatewayTLSConfig() *GatewayTLSConfigApplyConfiguration { return &GatewayTLSConfigApplyConfiguration{} } -// WithDefault sets the Default 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 Default field is set to the value of the last call. -func (b *GatewayTLSConfigApplyConfiguration) WithDefault(value *TLSConfigApplyConfiguration) *GatewayTLSConfigApplyConfiguration { - b.Default = value +// 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 } -// 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 *GatewayTLSConfigApplyConfiguration) WithPerPort(values ...*TLSPortConfigApplyConfiguration) *GatewayTLSConfigApplyConfiguration { - for i := range values { - if values[i] == nil { - panic("nil value passed to WithPerPort") - } - b.PerPort = append(b.PerPort, *values[i]) - } +// 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 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/tlsconfig.go b/applyconfiguration/apis/v1/tlsconfig.go index 1dfa5e024e..99a42ca482 100644 --- a/applyconfiguration/apis/v1/tlsconfig.go +++ b/applyconfiguration/apis/v1/tlsconfig.go @@ -21,7 +21,7 @@ package v1 // TLSConfigApplyConfiguration represents a declarative configuration of the TLSConfig type for use // with apply. type TLSConfigApplyConfiguration struct { - FrontendValidation *FrontendTLSValidationApplyConfiguration `json:"frontendValidation,omitempty"` + Validation *FrontendTLSValidationApplyConfiguration `json:"validation,omitempty"` } // TLSConfigApplyConfiguration constructs a declarative configuration of the TLSConfig type for use with @@ -30,10 +30,10 @@ func TLSConfig() *TLSConfigApplyConfiguration { return &TLSConfigApplyConfiguration{} } -// WithFrontendValidation sets the FrontendValidation field in the declarative configuration to the given value +// 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 FrontendValidation field is set to the value of the last call. -func (b *TLSConfigApplyConfiguration) WithFrontendValidation(value *FrontendTLSValidationApplyConfiguration) *TLSConfigApplyConfiguration { - b.FrontendValidation = value +// 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/internal/internal.go b/applyconfiguration/internal/internal.go index 953f2863cd..974c4bd20f 100644 --- a/applyconfiguration/internal/internal.go +++ b/applyconfiguration/internal/internal.go @@ -304,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: @@ -598,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 @@ -666,18 +678,12 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.sigs.gateway-api.apis.v1.GatewayTLSConfig map: fields: - - name: default + - name: backend type: - namedType: io.k8s.sigs.gateway-api.apis.v1.TLSConfig - default: {} - - name: perPort + namedType: io.k8s.sigs.gateway-api.apis.v1.GatewayBackendTLS + - name: frontend type: - list: - elementType: - namedType: io.k8s.sigs.gateway-api.apis.v1.TLSPortConfig - elementRelationship: associative - keys: - - port + namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSConfig - name: io.k8s.sigs.gateway-api.apis.v1.HTTPAuthConfig map: fields: @@ -1311,10 +1317,9 @@ var schemaYAML = typed.YAMLObject(`types: - name: io.k8s.sigs.gateway-api.apis.v1.TLSConfig map: fields: - - name: frontendValidation + - name: validation type: namedType: io.k8s.sigs.gateway-api.apis.v1.FrontendTLSValidation - default: {} - name: io.k8s.sigs.gateway-api.apis.v1.TLSPortConfig map: fields: diff --git a/applyconfiguration/utils.go b/applyconfiguration/utils.go index 5acafbc2c1..274736cd6c 100644 --- a/applyconfiguration/utils.go +++ b/applyconfiguration/utils.go @@ -56,6 +56,8 @@ func ForKind(kind schema.GroupVersionKind) interface{} { 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"): diff --git a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml index f04f7b978a..6e154e9548 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_gateways.yaml @@ -215,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 @@ -970,294 +906,363 @@ spec: == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' tls: description: |- - GatewayTLSConfig specifies frontend tls configuration for gateway. + TLS specifies frontend and backend tls configuration for entire gateway. Support: Extended properties: - default: + backend: description: |- - Default specifies the default client certificate validation configuration - for all Listeners handling HTTPS traffic, unless a per-port configuration - is defined. + Backend describes TLS configuration for gateway when connecting + to backends. - support: Core + 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: - frontendValidation: + clientCertificateRef: description: |- - 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. + 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: - caCertificateRefs: + group: + default: "" 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 + 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: |- - 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. + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. - 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. + 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 - enum: - - AllowValidOnly - - AllowInsecureFallback + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string required: - - caCertificateRefs + - name type: object - required: - - frontendValidation type: object - perPort: + frontend: 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. + 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: - frontendValidation: - description: |- - 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: 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: + 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: |- - 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. + 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: - 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. + - 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. - 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: + 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. - - 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. + Defaults to AllowValidOnly. - 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. + 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. - Defaults to AllowValidOnly. + 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 - enum: - - AllowValidOnly - - AllowInsecureFallback - type: string - required: - - caCertificateRefs + 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: - - frontendValidation + - port + - tls 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 + 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 @@ -1762,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 @@ -2517,294 +2458,363 @@ spec: == l2.hostname : !has(l1.hostname) && !has(l2.hostname))))' tls: description: |- - GatewayTLSConfig specifies frontend tls configuration for gateway. + TLS specifies frontend and backend tls configuration for entire gateway. Support: Extended properties: - default: + backend: description: |- - Default specifies the default client certificate validation configuration - for all Listeners handling HTTPS traffic, unless a per-port configuration - is defined. + Backend describes TLS configuration for gateway when connecting + to backends. - support: Core + 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: - frontendValidation: + clientCertificateRef: description: |- - 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. + 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: - caCertificateRefs: + group: + default: "" 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 + 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: |- - 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. + Namespace is the namespace of the referenced object. When unspecified, the local + namespace is inferred. - 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. + 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 - enum: - - AllowValidOnly - - AllowInsecureFallback + maxLength: 63 + minLength: 1 + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string required: - - caCertificateRefs + - name type: object - required: - - frontendValidation type: object - perPort: + frontend: 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. + 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: - frontendValidation: - description: |- - 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: 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: + 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: |- - 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. + 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: - 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. + - 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. - 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: + 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. - - 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. + Defaults to AllowValidOnly. - 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. + 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. - Defaults to AllowValidOnly. + 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 - enum: - - AllowValidOnly - - AllowInsecureFallback - type: string - required: - - caCertificateRefs + 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: - - frontendValidation + - port + - tls 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 + 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 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 a7a9d4a14d..34ada262b4 100644 --- a/examples/experimental/frontend-cert-validation.yaml +++ b/examples/experimental/frontend-cert-validation.yaml @@ -5,12 +5,22 @@ metadata: spec: gatewayClassName: acme-lb tls: - default: - frontendValidation: - caCertificateRefs: - - kind: ConfigMap - group: "" - name: foo-example-com-ca-cert + 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 @@ -21,5 +31,14 @@ 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 --- 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/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index 588319b36e..1451e17d9e 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -90,6 +90,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "sigs.k8s.io/gateway-api/apis/v1.CookieConfig": schema_sigsk8sio_gateway_api_apis_v1_CookieConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.ForwardBodyConfig": schema_sigsk8sio_gateway_api_apis_v1_ForwardBodyConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.Fraction": schema_sigsk8sio_gateway_api_apis_v1_Fraction(ref), + "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSConfig": schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSValidation": schema_sigsk8sio_gateway_api_apis_v1_FrontendTLSValidation(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCAuthConfig": schema_sigsk8sio_gateway_api_apis_v1_GRPCAuthConfig(ref), "sigs.k8s.io/gateway-api/apis/v1.GRPCBackendRef": schema_sigsk8sio_gateway_api_apis_v1_GRPCBackendRef(ref), @@ -3113,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{ @@ -3779,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"), }, }, @@ -4149,12 +4195,6 @@ 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", @@ -4163,7 +4203,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpec(ref common.ReferenceCallba }, "tls": { SchemaProps: spec.SchemaProps{ - Description: "GatewayTLSConfig specifies frontend tls configuration for gateway.\n\nSupport: Extended\n\n", + 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"), }, }, @@ -4172,7 +4212,7 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewaySpec(ref common.ReferenceCallba }, }, 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.GatewayTLSConfig", "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"}, } } @@ -4314,44 +4354,26 @@ func schema_sigsk8sio_gateway_api_apis_v1_GatewayTLSConfig(ref common.ReferenceC return common.OpenAPIDefinition{ Schema: spec.Schema{ SchemaProps: spec.SchemaProps{ - Description: "GatewayTLSConfig specifies frontend tls configuration for gateway.", + Description: "GatewayTLSConfig specifies frontend and backend tls configuration for gateway.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "default": { + "backend": { 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"), + 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"), }, }, - "perPort": { - VendorExtensible: spec.VendorExtensible{ - Extensions: spec.Extensions{ - "x-kubernetes-list-map-keys": []interface{}{ - "port", - }, - "x-kubernetes-list-type": "map", - }, - }, + "frontend": { 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"), - }, - }, - }, + Description: "Frontend describes TLS config when client connects to Gateway. Support: Core\n\n", + Ref: ref("sigs.k8s.io/gateway-api/apis/v1.FrontendTLSConfig"), }, }, }, - Required: []string{"default"}, }, }, Dependencies: []string{ - "sigs.k8s.io/gateway-api/apis/v1.TLSConfig", "sigs.k8s.io/gateway-api/apis/v1.TLSPortConfig"}, + "sigs.k8s.io/gateway-api/apis/v1.FrontendTLSConfig", "sigs.k8s.io/gateway-api/apis/v1.GatewayBackendTLS"}, } } @@ -6230,15 +6252,13 @@ func schema_sigsk8sio_gateway_api_apis_v1_TLSConfig(ref common.ReferenceCallback 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{ - "frontendValidation": { + "validation": { SchemaProps: spec.SchemaProps{ - Description: "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.\n\nSupport: Core\n\n", - Default: map[string]interface{}{}, + 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"), }, }, }, - Required: []string{"frontendValidation"}, }, }, Dependencies: []string{ From 45326b1e90a24f54d9cd0b5938f925d6dddc0609 Mon Sep 17 00:00:00 2001 From: Roman Willi Date: Thu, 28 Aug 2025 02:11:11 +0200 Subject: [PATCH 143/148] conformance: Add Airlock Microgateway 4.7 reports for v1.3.0 (#4035) * conformance: Add Airlock Microgateway 4.7 report for v1.3.0 * conformance: Regenerate conformance tables --- .../v1.1.0/airlock-microgateway/README.md | 15 ++--- .../standard-4.7.0-default-report.yaml | 47 ++++++++++++++++ .../v1.1.1/airlock-microgateway/README.md | 9 +-- .../standard-4.7.0-default-report.yaml | 47 ++++++++++++++++ .../v1.2.0/airlock-microgateway/README.md | 9 +-- .../standard-4.7.0-default-report.yaml | 53 ++++++++++++++++++ .../v1.2.1/airlock-microgateway/README.md | 11 ++-- .../standard-4.7.0-default-report.yaml | 53 ++++++++++++++++++ .../v1.3.0/airlock-microgateway/README.md | 11 ++-- .../experimental-4.7.0-default-report.yaml | 55 ++++++++++++++++++ site-src/implementations.md | 2 +- site-src/implementations/v1.1.md | 3 +- site-src/implementations/v1.2.md | 56 +++++++++++-------- site-src/implementations/v1.3.md | 54 +++++++++++------- 14 files changed, 354 insertions(+), 71 deletions(-) create mode 100644 conformance/reports/v1.1.0/airlock-microgateway/standard-4.7.0-default-report.yaml create mode 100644 conformance/reports/v1.1.1/airlock-microgateway/standard-4.7.0-default-report.yaml create mode 100644 conformance/reports/v1.2.0/airlock-microgateway/standard-4.7.0-default-report.yaml create mode 100644 conformance/reports/v1.2.1/airlock-microgateway/standard-4.7.0-default-report.yaml create mode 100644 conformance/reports/v1.3.0/airlock-microgateway/experimental-4.7.0-default-report.yaml diff --git a/conformance/reports/v1.1.0/airlock-microgateway/README.md b/conformance/reports/v1.1.0/airlock-microgateway/README.md index a23522a4ad..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) | -| standard | [v4.6.0](https://github.com/airlock/microgateway/releases/tag/4.6.0) | default | [v4.6.0 report](./standard-4.6.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.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 a61abd8398..66143c04c5 100644 --- a/conformance/reports/v1.1.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.1.1/airlock-microgateway/README.md @@ -6,16 +6,17 @@ |-------------|----------------------------------------------------------------------|---------|----------------------------------------------| | 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.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 a61abd8398..66143c04c5 100644 --- a/conformance/reports/v1.2.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.0/airlock-microgateway/README.md @@ -6,16 +6,17 @@ |-------------|----------------------------------------------------------------------|---------|----------------------------------------------| | 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.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 97c52418f9..e6c945bede 100644 --- a/conformance/reports/v1.2.1/airlock-microgateway/README.md +++ b/conformance/reports/v1.2.1/airlock-microgateway/README.md @@ -5,17 +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.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.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.3.0/airlock-microgateway/README.md b/conformance/reports/v1.3.0/airlock-microgateway/README.md index bae978e399..6270457010 100644 --- a/conformance/reports/v1.3.0/airlock-microgateway/README.md +++ b/conformance/reports/v1.3.0/airlock-microgateway/README.md @@ -5,16 +5,17 @@ | 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/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.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/site-src/implementations.md b/site-src/implementations.md index 0d97e76468..dc12477c22 100644 --- a/site-src/implementations.md +++ b/site-src/implementations.md @@ -205,7 +205,7 @@ Airlock Microgateway protects your applications and microservices with the tried #### Features - 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 +- 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 - Easy-to-use Grafana dashboards which provide valuable insights in allowed and blocked traffic and other metrics diff --git a/site-src/implementations/v1.1.md b/site-src/implementations/v1.1.md index 21063b28e6..69a3326bfb 100644 --- a/site-src/implementations/v1.1.md +++ b/site-src/implementations/v1.1.md @@ -19,13 +19,14 @@ Implementations only appear in this page if they pass Core conformance for the r | 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-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: | | 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: | diff --git a/site-src/implementations/v1.2.md b/site-src/implementations/v1.2.md index c26434b418..a3728f6aca 100644 --- a/site-src/implementations/v1.2.md +++ b/site-src/implementations/v1.2.md @@ -16,32 +16,39 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | Mode | HTTPRoute Host Rewrite | HTTPRoute Path Rewrite | HTTPRoute Response Header Modification | HTTPRoute Method Matching | HTTPRoute Query Param Matching | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | HTTPRoute Backend Timeout | HTTPRoute Destination Port Matching | HTTPRoute Parent Ref Port | HTTPRoute Port Redirect | HTTPRoute Request Timeout | HTTPRoute Scheme Redirect | HTTPRoute Path Redirect | 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 | 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: | -| 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: | -| 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: | -| 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: | :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: | -| envoyproxy | envoy-gateway | latest | 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: | :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: | :x: | :white_check_mark: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :white_check_mark: | :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: | :x: | :x: | :x: | :x: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :x: | -| 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: | :x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :x: | :white_check_mark: | :white_check_mark: | :x: | :x: | :x: | :x: | :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 | Gateway HTTP Listener Isolation | Gateway Infrastructure Propagation | Gateway Port 8080 | Gateway Static Addresses | -|:---------------|:------------------------------|:----------|:-----------------------|:----------------------------------|:-------------------------------------|:--------------------|:---------------------------| -| Kong | kubernetes-ingress-controller | v3.4.0 | traditional_compatible | :x: | :x: | :x: | :x: | -| Kong | kubernetes-ingress-controller | v3.4.0 | expressions | :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: | -| nginx | nginx-gateway-fabric | v1.6.0 | default | :x: | :x: | :x: | :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: | +| 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 @@ -50,7 +57,8 @@ Implementations only appear in this page if they pass Core conformance for the r | 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 | :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: | diff --git a/site-src/implementations/v1.3.md b/site-src/implementations/v1.3.md index 552e98cd54..653a8b8077 100644 --- a/site-src/implementations/v1.3.md +++ b/site-src/implementations/v1.3.md @@ -16,34 +16,48 @@ Implementations only appear in this page if they pass Core conformance for the r ### HTTPRoute -| Organization | Project | Version | Mode | Gateway Infrastructure Propagation | Gateway Port 8080 | HTTPRoute Backend Protocol H2C | HTTPRoute Backend Protocol Web Socket | 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 Timeout | HTTPRoute Response Header Modification | HTTPRoute Scheme Redirect | Gateway Address Empty | Gateway HTTP Listener Isolation | Gateway Static Addresses | HTTPRoute Backend Request Header Modification | HTTPRoute Request Mirror | HTTPRoute Request Multiple Mirrors | HTTPRoute Request Percentage Mirror | -|:---------------|:--------------|:----------|:--------|:-------------------------------------|:--------------------|:---------------------------------|:----------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:------------------------|:----------------------------------|:---------------------------|:------------------------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------| -| 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: | :x: | :x: | -| 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: | :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: | -| envoyproxy | envoy-gateway | latest | 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: | :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: | -| 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: | +| 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 | latest | default | :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: | +| 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 | latest | default | :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: | +| 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 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 | HTTPRoute Parent Ref Port | Mesh Consumer Route | -|:---------------|:----------|:----------|:--------|:---------------------------------|:----------------------------------------|:------------------------------------------------|:----------------------------|:--------------------------------------|:-------------------------|:----------------------------|:--------------------------|:-------------------------|:--------------------------|:---------------------------------|:---------------------------|:-------------------------------------|:--------------------------------------|:----------------------------|:-----------------------------------------|:----------------------------|:---------------------------|:----------------------------|:----------------------| -| 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: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :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: | :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 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 From e9fecd3f16c44f763edd938bc0f767ee0fd9c8bc Mon Sep 17 00:00:00 2001 From: Fabian Bao Date: Thu, 28 Aug 2025 08:59:10 +0800 Subject: [PATCH 144/148] fix conformance test HTTPRouteWeight (#4038) --- conformance/tests/httproute-weight.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/conformance/tests/httproute-weight.go b/conformance/tests/httproute-weight.go index fa85deb9bf..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", } From ef4c5b022f49cbeb10de2be32eed3737030f15ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 22:53:09 -0700 Subject: [PATCH 145/148] build(deps): bump google.golang.org/grpc from 1.74.2 to 1.75.0 (#4019) Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.74.2 to 1.75.0. - [Release notes](https://github.com/grpc/grpc-go/releases) - [Commits](https://github.com/grpc/grpc-go/compare/v1.74.2...v1.75.0) --- updated-dependencies: - dependency-name: google.golang.org/grpc dependency-version: 1.75.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 4 ++-- go.sum | 30 ++++++++++++++++-------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/go.mod b/go.mod index c818773daf..4f1a98f789 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/stretchr/testify v1.10.0 golang.org/x/net v0.43.0 golang.org/x/sync v0.16.0 - google.golang.org/grpc v1.74.2 + 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.7 k8s.io/api v0.33.4 @@ -77,7 +77,7 @@ require ( 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-20250528174236-200df99c418a // 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 diff --git a/go.sum b/go.sum index b6f7fbce18..4f59623791 100644 --- a/go.sum +++ b/go.sum @@ -148,16 +148,16 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de 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.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg= -go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E= -go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE= -go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs= -go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs= -go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY= -go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis= -go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4= -go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w= -go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA= +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= @@ -221,10 +221,12 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gomodules.xyz/jsonpatch/v2 v2.4.0 h1:Ci3iUJyx9UeRx7CeFN8ARgGbkESwJK+KB9lLcWxY/Zw= gomodules.xyz/jsonpatch/v2 v2.4.0/go.mod h1:AH3dM2RI6uoBZxn3LVrfvJ3E0/9dG4cSrbuBJT4moAY= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a h1:v2PbRU4K3llS09c7zodFpNePeamkAwG3mPrAery9VeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250528174236-200df99c418a/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= -google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4= -google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM= +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.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A= From 22b29c17541b3034e92bab3e135e127d5dd2f666 Mon Sep 17 00:00:00 2001 From: Ricardo Pchevuzinske Katz Date: Thu, 28 Aug 2025 02:53:16 -0300 Subject: [PATCH 146/148] Fix cors cel (#4032) * CORS: support a single wildcard entry as origin * CORS: Add test for CRD validations --- apis/v1/httproute_types.go | 3 +- apis/v1/shared_types.go | 11 ++ apis/v1/zz_generated.deepcopy.go | 2 +- applyconfiguration/apis/v1/httpcorsfilter.go | 4 +- .../gateway.networking.k8s.io_httproutes.yaml | 56 +++++--- pkg/test/cel/httproute_experimental_test.go | 129 ++++++++++++++++++ 6 files changed, 181 insertions(+), 24 deletions(-) diff --git a/apis/v1/httproute_types.go b/apis/v1/httproute_types.go index 53fae56716..5dad01e00a 100644 --- a/apis/v1/httproute_types.go +++ b/apis/v1/httproute_types.go @@ -1404,8 +1404,9 @@ type HTTPCORSFilter struct { // Support: Extended // +listType=set // +kubebuilder:validation:MaxItems=64 + // +kubebuilder:validation:XValidation:message="AllowOrigins cannot contain '*' alongside other origins",rule="!('*' in self && self.size() > 1)" // +optional - AllowOrigins []AbsoluteURI `json:"allowOrigins,omitempty"` + AllowOrigins []CORSOrigin `json:"allowOrigins,omitempty"` // AllowCredentials indicates whether the actual cross-origin request allows // to include credentials. diff --git a/apis/v1/shared_types.go b/apis/v1/shared_types.go index 5b5ed4cfed..99299acda8 100644 --- a/apis/v1/shared_types.go +++ b/apis/v1/shared_types.go @@ -608,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. // diff --git a/apis/v1/zz_generated.deepcopy.go b/apis/v1/zz_generated.deepcopy.go index bcbf489072..be8e2485c2 100644 --- a/apis/v1/zz_generated.deepcopy.go +++ b/apis/v1/zz_generated.deepcopy.go @@ -976,7 +976,7 @@ 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 { diff --git a/applyconfiguration/apis/v1/httpcorsfilter.go b/applyconfiguration/apis/v1/httpcorsfilter.go index cc556b3e8a..b4b9776b3a 100644 --- a/applyconfiguration/apis/v1/httpcorsfilter.go +++ b/applyconfiguration/apis/v1/httpcorsfilter.go @@ -25,7 +25,7 @@ import ( // HTTPCORSFilterApplyConfiguration represents a declarative configuration of the HTTPCORSFilter type for use // with apply. type HTTPCORSFilterApplyConfiguration struct { - AllowOrigins []apisv1.AbsoluteURI `json:"allowOrigins,omitempty"` + AllowOrigins []apisv1.CORSOrigin `json:"allowOrigins,omitempty"` AllowCredentials *bool `json:"allowCredentials,omitempty"` AllowMethods []apisv1.HTTPMethodWithWildcard `json:"allowMethods,omitempty"` AllowHeaders []apisv1.HTTPHeaderName `json:"allowHeaders,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]) } diff --git a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml index 34876b54a0..0329311362 100644 --- a/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml +++ b/config/crd/experimental/gateway.networking.k8s.io_httproutes.yaml @@ -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 @@ -2139,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 @@ -4801,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 @@ -6283,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 diff --git a/pkg/test/cel/httproute_experimental_test.go b/pkg/test/cel/httproute_experimental_test.go index 9978d4ca11..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 From a82c06b8f54322e1db58144b7a78bd992fb6c4d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 23:11:09 -0700 Subject: [PATCH 147/148] build(deps): bump github.com/stretchr/testify from 1.10.0 to 1.11.0 (#4020) Bumps [github.com/stretchr/testify](https://github.com/stretchr/testify) from 1.10.0 to 1.11.0. - [Release notes](https://github.com/stretchr/testify/releases) - [Commits](https://github.com/stretchr/testify/compare/v1.10.0...v1.11.0) --- updated-dependencies: - dependency-name: github.com/stretchr/testify dependency-version: 1.11.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 4f1a98f789..bd1a6d9147 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.24.0 require ( github.com/elastic/crd-ref-docs v0.2.0 github.com/miekg/dns v1.1.68 - github.com/stretchr/testify v1.10.0 + 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 diff --git a/go.sum b/go.sum index 4f59623791..4120b93f2a 100644 --- a/go.sum +++ b/go.sum @@ -140,8 +140,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV 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= From a108a1007cb1aa3caa86206e1b36f2b0e7bd49fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Aug 2025 23:11:16 -0700 Subject: [PATCH 148/148] build(deps): bump mkdocs-material in /hack/mkdocs/image (#4022) Bumps [mkdocs-material](https://github.com/squidfunk/mkdocs-material) from 9.6.16 to 9.6.18. - [Release notes](https://github.com/squidfunk/mkdocs-material/releases) - [Changelog](https://github.com/squidfunk/mkdocs-material/blob/master/CHANGELOG) - [Commits](https://github.com/squidfunk/mkdocs-material/compare/9.6.16...9.6.18) --- updated-dependencies: - dependency-name: mkdocs-material dependency-version: 9.6.18 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- hack/mkdocs/image/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/mkdocs/image/requirements.txt b/hack/mkdocs/image/requirements.txt index e4d6677b63..940b186b39 100644 --- a/hack/mkdocs/image/requirements.txt +++ b/hack/mkdocs/image/requirements.txt @@ -10,7 +10,7 @@ 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.16 +mkdocs-material==9.6.18 mkdocs-redirects==1.2.2 mkdocs-mermaid2-plugin==1.2.1 pandas>=2.0.3