From b2c36fe9a06094e4cb142adbf089219d7ecd3da1 Mon Sep 17 00:00:00 2001 From: Katarzyna Lach Date: Mon, 11 Aug 2025 16:47:11 +0000 Subject: [PATCH 1/3] Add Conformance tests for BackendTLSPolicy validating SANs --- conformance/tests/backendtlspolicy.go | 33 ++++++++++ conformance/tests/backendtlspolicy.yaml | 81 +++++++++++++++++++++++-- 2 files changed, 110 insertions(+), 4 deletions(-) diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go index fc6c6576eb..3cfc5ad600 100644 --- a/conformance/tests/backendtlspolicy.go +++ b/conformance/tests/backendtlspolicy.go @@ -69,6 +69,12 @@ var BackendTLSPolicy = suite.ConformanceTest{ invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns} kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, policyCond) + invalidSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-san-mismatch", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidSanPolicyNN, gwNN, policyCond) + + validSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-san", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validSanPolicyNN, gwNN, policyCond) + serverStr := "abc.example.com" // Verify that the request sent to Service with valid BackendTLSPolicy should succeed. @@ -130,5 +136,32 @@ var BackendTLSPolicy = suite.ConformanceTest{ }, }) }) + + // Verify that the request sent to Service with BackendTLSPolicy configured with SANs should succeed. + t.Run("HTTP request sent to Service with BackendTLSPolicy configured with SAN should succeed", func(t *testing.T) { + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSSan", + SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that request sent to Service targeted by BackendTLSPolicy with mismatched SAN should failed. + t.Run("HTTP request send to Service targeted by BackendTLSPolicy with mismatched SAN 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: "/backendTLSSanMismatch", + SNI: serverStr, + }, + }) + }) }, } diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml index e048cc2e7b..ba1f700e9d 100644 --- a/conformance/tests/backendtlspolicy.yaml +++ b/conformance/tests/backendtlspolicy.yaml @@ -70,6 +70,24 @@ spec: - path: type: Exact value: /backendTLSCertMismatch + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-mismatch-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSanMismatch + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-san-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSSan --- apiVersion: v1 kind: Service @@ -115,6 +133,36 @@ spec: port: 443 targetPort: 8443 --- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-san-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-san-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 @@ -222,18 +270,43 @@ spec: apiVersion: gateway.networking.k8s.io/v1alpha3 kind: BackendTLSPolicy metadata: - name: backendtlspolicy-cert-mismatch + name: backendtlspolicy-san namespace: gateway-conformance-infra spec: targetRefs: - group: "" kind: Service - name: "backendtlspolicy-cert-mismatch-test" + name: "backendtlspolicy-san-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" + name: "backend-tls-certificate" + subjectAltNames: + - type: Hostname + hostname: abc.example.com + hostname: "mismatch.example.com" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy +metadata: + name: backendtlspolicy-san-mismatch + namespace: gateway-conformance-infra +spec: + targetRefs: + - group: "" + kind: Service + name: "backendtlspolicy-san-mismatch-test" + sectionName: "btls" + validation: + caCertificateRefs: + - group: "" + kind: ConfigMap + # This secret is generated dynamically by the test suite. + name: "backend-tls-certificate" + subjectAltNames: + - type: Hostname + hostname: cde.example.com + hostname: "mismatch.example.com" From 190da92d1140c4a14b95a79d7f419d9403ca62e0 Mon Sep 17 00:00:00 2001 From: Katarzyna Lach Date: Tue, 12 Aug 2025 08:25:31 +0000 Subject: [PATCH 2/3] review fixes --- conformance/tests/backendtlspolicy.go | 19 +++++- conformance/tests/backendtlspolicy.yaml | 77 +++++++++++++++++++++++-- conformance/utils/kubernetes/helpers.go | 4 +- 3 files changed, 91 insertions(+), 9 deletions(-) diff --git a/conformance/tests/backendtlspolicy.go b/conformance/tests/backendtlspolicy.go index 3cfc5ad600..1af69abd11 100644 --- a/conformance/tests/backendtlspolicy.go +++ b/conformance/tests/backendtlspolicy.go @@ -20,7 +20,6 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/types" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -75,6 +74,9 @@ var BackendTLSPolicy = suite.ConformanceTest{ validSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-san", Namespace: ns} kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validSanPolicyNN, gwNN, policyCond) + validMultiSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-multiple-sans", Namespace: ns} + kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validMultiSanPolicyNN, gwNN, policyCond) + serverStr := "abc.example.com" // Verify that the request sent to Service with valid BackendTLSPolicy should succeed. @@ -145,7 +147,19 @@ var BackendTLSPolicy = suite.ConformanceTest{ Request: h.Request{ Host: serverStr, Path: "/backendTLSSan", - SNI: serverStr, + }, + Response: h.Response{StatusCode: 200}, + }) + }) + + // Verify that the request sent to Service with BackendTLSPolicy configured with multiple SANs should succeed. + t.Run("HTTP request sent to Service with BackendTLSPolicy configured with multiple SANs should succeed", func(t *testing.T) { + h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, + h.ExpectedResponse{ + Namespace: ns, + Request: h.Request{ + Host: serverStr, + Path: "/backendTLSMultiSans", }, Response: h.Response{StatusCode: 200}, }) @@ -159,7 +173,6 @@ var BackendTLSPolicy = suite.ConformanceTest{ Request: h.Request{ Host: serverStr, Path: "/backendTLSSanMismatch", - SNI: serverStr, }, }) }) diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml index ba1f700e9d..311c316e5a 100644 --- a/conformance/tests/backendtlspolicy.yaml +++ b/conformance/tests/backendtlspolicy.yaml @@ -88,6 +88,15 @@ spec: - path: type: Exact value: /backendTLSSan + - backendRefs: + - group: "" + kind: Service + name: backendtlspolicy-multiple-sans-test + port: 443 + matches: + - path: + type: Exact + value: /backendTLSMultiSans --- apiVersion: v1 kind: Service @@ -163,6 +172,21 @@ spec: port: 443 targetPort: 8443 --- +apiVersion: v1 +kind: Service +metadata: + name: backendtlspolicy-multiple-sans-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 @@ -269,6 +293,25 @@ spec: --- 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" +--- +apiVersion: gateway.networking.k8s.io/v1alpha3 +kind: BackendTLSPolicy metadata: name: backendtlspolicy-san namespace: gateway-conformance-infra @@ -283,11 +326,37 @@ spec: - group: "" kind: ConfigMap # This secret is generated dynamically by the test suite. - name: "backend-tls-certificate" + name: "backend-tls-checks-certificate" + hostname: "abc.example.com" subjectAltNames: - type: Hostname hostname: abc.example.com - hostname: "mismatch.example.com" +--- +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-checks-certificate" + hostname: "abc.example.com" + subjectAltNames: + - type: Hostname + hostname: abc.example.com + - type: Hostname + hostname: efg.example.com + - type: Hostname + hostname: yjh.example.com --- apiVersion: gateway.networking.k8s.io/v1alpha3 kind: BackendTLSPolicy @@ -305,8 +374,8 @@ spec: - group: "" kind: ConfigMap # This secret is generated dynamically by the test suite. - name: "backend-tls-certificate" + name: "backend-tls-checks-certificate" + hostname: "abc.example.com" subjectAltNames: - type: Hostname hostname: cde.example.com - hostname: "mismatch.example.com" diff --git a/conformance/utils/kubernetes/helpers.go b/conformance/utils/kubernetes/helpers.go index 8075132da1..4f8334f502 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,5 +1024,5 @@ 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) } From 664bb396297c73525f1677b8e59b7c5443e4b497 Mon Sep 17 00:00:00 2001 From: Katarzyna Lach Date: Mon, 18 Aug 2025 09:20:27 +0000 Subject: [PATCH 3/3] Validate URI SANs --- conformance/base/manifests.yaml | 33 ++ conformance/tests/backendtlspolicy-san.go | 163 ++++++++++ conformance/tests/backendtlspolicy-san.yaml | 341 ++++++++++++++++++++ conformance/tests/backendtlspolicy.go | 48 +-- conformance/tests/backendtlspolicy.yaml | 175 ---------- conformance/utils/kubernetes/certificate.go | 5 + conformance/utils/suite/suite.go | 5 + pkg/features/backendtlspolicy.go | 16 + 8 files changed, 564 insertions(+), 222 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.go b/conformance/tests/backendtlspolicy.go index 1af69abd11..fc6c6576eb 100644 --- a/conformance/tests/backendtlspolicy.go +++ b/conformance/tests/backendtlspolicy.go @@ -20,6 +20,7 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" gatewayv1 "sigs.k8s.io/gateway-api/apis/v1" @@ -68,15 +69,6 @@ var BackendTLSPolicy = suite.ConformanceTest{ invalidCertPolicyNN := types.NamespacedName{Name: "backendtlspolicy-cert-mismatch", Namespace: ns} kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidCertPolicyNN, gwNN, policyCond) - invalidSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-san-mismatch", Namespace: ns} - kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, invalidSanPolicyNN, gwNN, policyCond) - - validSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-san", Namespace: ns} - kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validSanPolicyNN, gwNN, policyCond) - - validMultiSanPolicyNN := types.NamespacedName{Name: "backendtlspolicy-multiple-sans", Namespace: ns} - kubernetes.BackendTLSPolicyMustHaveCondition(t, suite.Client, suite.TimeoutConfig, validMultiSanPolicyNN, gwNN, policyCond) - serverStr := "abc.example.com" // Verify that the request sent to Service with valid BackendTLSPolicy should succeed. @@ -138,43 +130,5 @@ var BackendTLSPolicy = suite.ConformanceTest{ }, }) }) - - // Verify that the request sent to Service with BackendTLSPolicy configured with SANs should succeed. - t.Run("HTTP request sent to Service with BackendTLSPolicy configured with SAN should succeed", func(t *testing.T) { - h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, - h.ExpectedResponse{ - Namespace: ns, - Request: h.Request{ - Host: serverStr, - Path: "/backendTLSSan", - }, - Response: h.Response{StatusCode: 200}, - }) - }) - - // Verify that the request sent to Service with BackendTLSPolicy configured with multiple SANs should succeed. - t.Run("HTTP request sent to Service with BackendTLSPolicy configured with multiple SANs should succeed", func(t *testing.T) { - h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, - h.ExpectedResponse{ - Namespace: ns, - Request: h.Request{ - Host: serverStr, - Path: "/backendTLSMultiSans", - }, - Response: h.Response{StatusCode: 200}, - }) - }) - - // Verify that request sent to Service targeted by BackendTLSPolicy with mismatched SAN should failed. - t.Run("HTTP request send to Service targeted by BackendTLSPolicy with mismatched SAN 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: "/backendTLSSanMismatch", - }, - }) - }) }, } diff --git a/conformance/tests/backendtlspolicy.yaml b/conformance/tests/backendtlspolicy.yaml index 311c316e5a..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 @@ -70,33 +37,6 @@ spec: - path: type: Exact value: /backendTLSCertMismatch - - backendRefs: - - group: "" - kind: Service - name: backendtlspolicy-san-mismatch-test - port: 443 - matches: - - path: - type: Exact - value: /backendTLSSanMismatch - - backendRefs: - - group: "" - kind: Service - name: backendtlspolicy-san-test - port: 443 - matches: - - path: - type: Exact - value: /backendTLSSan - - backendRefs: - - group: "" - kind: Service - name: backendtlspolicy-multiple-sans-test - port: 443 - matches: - - path: - type: Exact - value: /backendTLSMultiSans --- apiVersion: v1 kind: Service @@ -142,51 +82,6 @@ spec: port: 443 targetPort: 8443 --- -apiVersion: v1 -kind: Service -metadata: - name: backendtlspolicy-san-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-san-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-multiple-sans-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 @@ -309,73 +204,3 @@ spec: # This secret is generated dynamically by the test suite. name: "backend-tls-mismatch-certificate" hostname: "abc.example.com" ---- -apiVersion: gateway.networking.k8s.io/v1alpha3 -kind: BackendTLSPolicy -metadata: - name: backendtlspolicy-san - namespace: gateway-conformance-infra -spec: - targetRefs: - - group: "" - kind: Service - name: "backendtlspolicy-san-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" - subjectAltNames: - - type: Hostname - hostname: abc.example.com ---- -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-checks-certificate" - hostname: "abc.example.com" - subjectAltNames: - - type: Hostname - hostname: abc.example.com - - type: Hostname - hostname: efg.example.com - - type: Hostname - hostname: yjh.example.com ---- -apiVersion: gateway.networking.k8s.io/v1alpha3 -kind: BackendTLSPolicy -metadata: - name: backendtlspolicy-san-mismatch - namespace: gateway-conformance-infra -spec: - targetRefs: - - group: "" - kind: Service - name: "backendtlspolicy-san-mismatch-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" - subjectAltNames: - - type: Hostname - hostname: cde.example.com 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/suite/suite.go b/conformance/utils/suite/suite.go index 858fea2ed1..27c42894bf 100644 --- a/conformance/utils/suite/suite.go +++ b/conformance/utils/suite/suite.go @@ -389,6 +389,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, +)