Skip to content

Commit 0fd1805

Browse files
canditasnorwin
andauthored
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 <[email protected]> * Address the last of the review comments --------- Co-authored-by: Norwin Schnyder <[email protected]>
1 parent bc08c0f commit 0fd1805

21 files changed

+624
-47
lines changed

conformance/base/manifests.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ spec:
138138
spec:
139139
containers:
140140
- name: infra-backend-v1
141-
# From https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/images/echoserver
141+
# Originally from https://github.com/kubernetes-sigs/ingress-controller-conformance/tree/master/images/echoserver
142142
image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd
143143
env:
144144
- name: POD_NAME
@@ -300,7 +300,7 @@ spec:
300300
volumes:
301301
- name: secret-volume
302302
secret:
303-
secretName: tls-passthrough-checks-certificate
303+
secretName: tls-checks-certificate
304304
items:
305305
- key: tls.crt
306306
path: crt

conformance/conformance.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,11 @@ import (
2929
"sigs.k8s.io/gateway-api/conformance/tests"
3030
conformanceconfig "sigs.k8s.io/gateway-api/conformance/utils/config"
3131
"sigs.k8s.io/gateway-api/conformance/utils/flags"
32-
3332
"sigs.k8s.io/gateway-api/conformance/utils/suite"
3433

3534
"github.com/stretchr/testify/require"
3635
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
37-
3836
clientset "k8s.io/client-go/kubernetes"
39-
4037
"sigs.k8s.io/controller-runtime/pkg/client"
4138
"sigs.k8s.io/controller-runtime/pkg/client/config"
4239
"sigs.k8s.io/yaml"
@@ -66,7 +63,6 @@ func DefaultOptions(t *testing.T) suite.ConformanceOptions {
6663

6764
supportedFeatures := suite.ParseSupportedFeatures(*flags.SupportedFeatures)
6865
exemptFeatures := suite.ParseSupportedFeatures(*flags.ExemptFeatures)
69-
7066
skipTests := suite.ParseSkipTests(*flags.SkipTests)
7167
namespaceLabels := suite.ParseKeyValuePairs(*flags.NamespaceLabels)
7268
namespaceAnnotations := suite.ParseKeyValuePairs(*flags.NamespaceAnnotations)

conformance/tests/backendtlspolicy.go

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/*
2+
Copyright 2024 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package tests
18+
19+
import (
20+
"testing"
21+
22+
"k8s.io/apimachinery/pkg/types"
23+
24+
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
25+
h "sigs.k8s.io/gateway-api/conformance/utils/http"
26+
"sigs.k8s.io/gateway-api/conformance/utils/kubernetes"
27+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
28+
"sigs.k8s.io/gateway-api/conformance/utils/tls"
29+
"sigs.k8s.io/gateway-api/pkg/features"
30+
)
31+
32+
func init() {
33+
ConformanceTests = append(ConformanceTests, BackendTLSPolicy)
34+
}
35+
36+
var BackendTLSPolicy = suite.ConformanceTest{
37+
ShortName: "BackendTLSPolicy",
38+
Description: "A single service that is targeted by a BackendTLSPolicy must successfully complete TLS termination",
39+
Features: []features.FeatureName{
40+
features.SupportGateway,
41+
features.SupportHTTPRoute,
42+
features.SupportBackendTLSPolicy,
43+
},
44+
Manifests: []string{"tests/backendtlspolicy.yaml"},
45+
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
46+
ns := "gateway-conformance-infra"
47+
routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: ns}
48+
gwNN := types.NamespacedName{Name: "gateway-backendtlspolicy", Namespace: ns}
49+
50+
kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})
51+
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &gatewayv1.HTTPRoute{}, false, routeNN)
52+
kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN)
53+
54+
serverStr := "abc.example.com"
55+
56+
// Verify that the response to a backend-tls-only call to /backendTLS will return the matching SNI.
57+
t.Run("Simple HTTP request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) {
58+
h.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr,
59+
h.ExpectedResponse{
60+
Namespace: ns,
61+
Request: h.Request{
62+
Host: serverStr,
63+
Path: "/backendTLS",
64+
SNI: serverStr,
65+
},
66+
Response: h.Response{StatusCode: 200},
67+
})
68+
})
69+
70+
// For the re-encrypt case, we need to use the cert for the frontend tls listener.
71+
certNN := types.NamespacedName{Name: "tls-checks-certificate", Namespace: ns}
72+
cPem, keyPem, err := GetTLSSecret(suite.Client, certNN)
73+
if err != nil {
74+
t.Fatalf("unexpected error finding TLS secret: %v", err)
75+
}
76+
// Verify that the response to a re-encrypted call to /backendTLS will return the matching SNI.
77+
t.Run("Re-encrypt HTTPS request targeting BackendTLSPolicy should reach infra-backend", func(t *testing.T) {
78+
tls.MakeTLSRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, cPem, keyPem, serverStr,
79+
h.ExpectedResponse{
80+
Namespace: ns,
81+
Request: h.Request{
82+
Host: serverStr,
83+
Path: "/backendTLS",
84+
SNI: serverStr,
85+
},
86+
Response: h.Response{StatusCode: 200},
87+
})
88+
})
89+
},
90+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
apiVersion: gateway.networking.k8s.io/v1
2+
kind: Gateway
3+
metadata:
4+
name: gateway-backendtlspolicy
5+
namespace: gateway-conformance-infra
6+
spec:
7+
gatewayClassName: "{GATEWAY_CLASS_NAME}"
8+
listeners:
9+
- name: http
10+
port: 80
11+
protocol: HTTP
12+
hostname: "abc.example.com"
13+
allowedRoutes:
14+
namespaces:
15+
from: Same
16+
kinds:
17+
- kind: HTTPRoute
18+
- name: https
19+
port: 443
20+
protocol: HTTPS
21+
tls:
22+
mode: Terminate
23+
certificateRefs:
24+
- group: ""
25+
kind: Secret
26+
name: tls-checks-certificate
27+
hostname: "abc.example.com"
28+
allowedRoutes:
29+
namespaces:
30+
from: Same
31+
kinds:
32+
- kind: HTTPRoute
33+
---
34+
apiVersion: gateway.networking.k8s.io/v1alpha3
35+
kind: BackendTLSPolicy
36+
metadata:
37+
name: normative-test-backendtlspolicy
38+
namespace: gateway-conformance-infra
39+
spec:
40+
targetRefs:
41+
- group: ""
42+
kind: Service
43+
name: "backendtlspolicy-test"
44+
sectionName: "btls"
45+
validation:
46+
caCertificateRefs:
47+
- group: ""
48+
kind: ConfigMap
49+
# This secret is generated dynamically by the test suite.
50+
name: "backend-tls-checks-certificate"
51+
hostname: "abc.example.com"
52+
---
53+
apiVersion: gateway.networking.k8s.io/v1
54+
kind: HTTPRoute
55+
metadata:
56+
name: gateway-conformance-infra-test
57+
namespace: gateway-conformance-infra
58+
spec:
59+
parentRefs:
60+
- name: gateway-backendtlspolicy
61+
namespace: gateway-conformance-infra
62+
hostnames:
63+
- abc.example.com
64+
rules:
65+
- backendRefs:
66+
- group: ""
67+
kind: Service
68+
name: backendtlspolicy-test
69+
port: 443
70+
matches:
71+
- path:
72+
type: Exact
73+
value: /backendTLS
74+
---
75+
apiVersion: v1
76+
kind: Service
77+
metadata:
78+
name: backendtlspolicy-test
79+
namespace: gateway-conformance-infra
80+
spec:
81+
selector:
82+
app: backendtlspolicy-test
83+
ports:
84+
- name: "btls"
85+
protocol: TCP
86+
port: 443
87+
targetPort: 8443
88+
---
89+
# Deployment must not be applied until after the secret is generated.
90+
apiVersion: apps/v1
91+
kind: Deployment
92+
metadata:
93+
name: backendtlspolicy-test
94+
namespace: gateway-conformance-infra
95+
labels:
96+
app: backendtlspolicy-test
97+
spec:
98+
replicas: 1
99+
selector:
100+
matchLabels:
101+
app: backendtlspolicy-test
102+
template:
103+
metadata:
104+
labels:
105+
app: backendtlspolicy-test
106+
spec:
107+
containers:
108+
- name: backendtlspolicy-test
109+
image: gcr.io/k8s-staging-gateway-api/echo-basic:v20240412-v1.0.0-394-g40c666fd
110+
volumeMounts:
111+
- name: ca-volume
112+
mountPath: /etc/ca-volume
113+
- name: secret-volume
114+
mountPath: /etc/secret-volume
115+
env:
116+
- name: POD_NAME
117+
valueFrom:
118+
fieldRef:
119+
fieldPath: metadata.name
120+
- name: NAMESPACE
121+
valueFrom:
122+
fieldRef:
123+
fieldPath: metadata.namespace
124+
- name: CA_CERT
125+
value: /etc/ca-volume/crt
126+
- name: CA_CERT_KEY
127+
value: /etc/ca-volume/key
128+
- name: TLS_SERVER_CERT
129+
value: /etc/secret-volume/crt
130+
- name: TLS_SERVER_PRIVKEY
131+
value: /etc/secret-volume/key
132+
resources:
133+
requests:
134+
cpu: 10m
135+
volumes:
136+
- name: ca-volume
137+
configMap:
138+
# This configMap is generated dynamically by the test suite.
139+
name: backend-tls-checks-certificate
140+
items:
141+
- key: ca.crt
142+
path: crt
143+
- key: key.crt
144+
path: key
145+
- name: secret-volume
146+
secret:
147+
# This secret is generated dynamically by the test suite.
148+
secretName: tls-checks-certificate
149+
items:
150+
- key: tls.crt
151+
path: crt
152+
- key: tls.key
153+
path: key

conformance/tests/grpcroute-exact-method-matching.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var GRPCExactMethodMatching = suite.ConformanceTest{
4646
ns := "gateway-conformance-infra"
4747
routeNN := types.NamespacedName{Name: "exact-matching", Namespace: ns}
4848
gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
49-
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, routeNN)
49+
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN)
5050

5151
testCases := []grpc.ExpectedResponse{
5252
{

conformance/tests/grpcroute-header-matching.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ var GRPCRouteHeaderMatching = suite.ConformanceTest{
4646
ns := "gateway-conformance-infra"
4747
routeNN := types.NamespacedName{Name: "grpc-header-matching", Namespace: ns}
4848
gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
49-
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, routeNN)
49+
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN)
5050

5151
testCases := []grpc.ExpectedResponse{{
5252
EchoRequest: &pb.EchoRequest{},

conformance/tests/grpcroute-listener-hostname-matching.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ var GRPCRouteListenerHostnameMatching = suite.ConformanceTest{
5252
gwNN := types.NamespacedName{Name: "grpcroute-listener-hostname-matching", Namespace: ns}
5353

5454
_ = kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName,
55-
kubernetes.NewGatewayRef(gwNN, "listener-1"), &v1.GRPCRoute{},
55+
kubernetes.NewGatewayRef(gwNN, "listener-1"), &v1.GRPCRoute{}, true,
5656
types.NamespacedName{Namespace: ns, Name: "backend-v1"},
5757
)
5858
_ = kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName,
59-
kubernetes.NewGatewayRef(gwNN, "listener-2"), &v1.GRPCRoute{},
59+
kubernetes.NewGatewayRef(gwNN, "listener-2"), &v1.GRPCRoute{}, true,
6060
types.NamespacedName{Namespace: ns, Name: "backend-v2"},
6161
)
6262
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName,
63-
kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"), &v1.GRPCRoute{},
63+
kubernetes.NewGatewayRef(gwNN, "listener-3", "listener-4"), &v1.GRPCRoute{}, true,
6464
types.NamespacedName{Namespace: ns, Name: "backend-v3"},
6565
)
6666

conformance/tests/grpcroute-named-rule.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ var GRPCRouteNamedRule = suite.ConformanceTest{
4747
ns := "gateway-conformance-infra"
4848
routeNN := types.NamespacedName{Name: "grpc-named-rules", Namespace: ns}
4949
gwNN := types.NamespacedName{Name: "same-namespace", Namespace: ns}
50-
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, routeNN)
50+
gwAddr := kubernetes.GatewayAndRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), &v1.GRPCRoute{}, true, routeNN)
5151

5252
testCases := []grpc.ExpectedResponse{
5353
{

conformance/tests/httproute-weight.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ func testDistribution(t *testing.T, suite *suite.ConformanceTestSuite, gwAddr st
105105
if err != nil {
106106
return fmt.Errorf("failed to roundtrip request: %w", err)
107107
}
108-
if err := http.CompareRequest(t, &req, cReq, cRes, expected); err != nil {
108+
if err := http.CompareRoundTrip(t, &req, cReq, cRes, expected); err != nil {
109109
return fmt.Errorf("response expectation failed for request: %w", err)
110110
}
111111

conformance/tests/tlsroute-simple-same-namespace.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ var TLSRouteSimpleSameNamespace = suite.ConformanceTest{
4949
ns := "gateway-conformance-infra"
5050
routeNN := types.NamespacedName{Name: "gateway-conformance-infra-test", Namespace: ns}
5151
gwNN := types.NamespacedName{Name: "gateway-tlsroute", Namespace: ns}
52-
certNN := types.NamespacedName{Name: "tls-passthrough-checks-certificate", Namespace: ns}
52+
certNN := types.NamespacedName{Name: "tls-checks-certificate", Namespace: ns}
5353

5454
kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns})
5555

0 commit comments

Comments
 (0)