Skip to content

Commit c1870b3

Browse files
davem-gitrudrakhp
authored andcommitted
test: tcp security policy e2e (#7226)
* feat(securitypolicy): Added e2e tests for tcp security policies Signed-off-by: davem-git <[email protected]> * removed commented out line Signed-off-by: davem-git <[email protected]> --------- Signed-off-by: davem-git <[email protected]>
1 parent 165399f commit c1870b3

File tree

2 files changed

+226
-0
lines changed

2 files changed

+226
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
apiVersion: gateway.networking.k8s.io/v1beta1
2+
kind: Gateway
3+
metadata:
4+
name: tcp-authorization-backend
5+
namespace: gateway-conformance-infra
6+
spec:
7+
gatewayClassName: "{GATEWAY_CLASS_NAME}"
8+
listeners:
9+
- name: ip
10+
protocol: TCP
11+
port: 8080
12+
allowedRoutes:
13+
kinds:
14+
- kind: TCPRoute
15+
- name: fqdn
16+
protocol: TCP
17+
port: 8090
18+
allowedRoutes:
19+
kinds:
20+
- kind: TCPRoute
21+
---
22+
apiVersion: gateway.networking.k8s.io/v1alpha2
23+
kind: TCPRoute
24+
metadata:
25+
name: tcp-backend-authorization-ip
26+
namespace: gateway-conformance-infra
27+
spec:
28+
parentRefs:
29+
- name: tcp-authorization-backend
30+
sectionName: ip
31+
rules:
32+
- backendRefs:
33+
- group: gateway.envoyproxy.io
34+
kind: Backend
35+
name: backend-ip
36+
port: 8080
37+
---
38+
apiVersion: gateway.networking.k8s.io/v1alpha2
39+
kind: TCPRoute
40+
metadata:
41+
name: tcp-backend-authorization-fqdn
42+
namespace: gateway-conformance-infra
43+
spec:
44+
parentRefs:
45+
- name: tcp-authorization-backend
46+
sectionName: fqdn
47+
rules:
48+
- backendRefs:
49+
- group: gateway.envoyproxy.io
50+
kind: Backend
51+
name: backend-fqdn
52+
port: 8080
53+
---
54+
apiVersion: gateway.envoyproxy.io/v1alpha1
55+
kind: Backend
56+
metadata:
57+
name: backend-fqdn
58+
namespace: gateway-conformance-infra
59+
spec:
60+
endpoints:
61+
- fqdn:
62+
hostname: infra-backend-v1.gateway-conformance-infra.svc.cluster.local
63+
port: 8080
64+
---
65+
apiVersion: gateway.envoyproxy.io/v1alpha1
66+
kind: SecurityPolicy
67+
metadata:
68+
name: tcp-backend-authorization-ip-security-policy
69+
namespace: gateway-conformance-infra
70+
spec:
71+
targetRefs:
72+
- group: gateway.networking.k8s.io
73+
kind: TCPRoute
74+
name: tcp-backend-authorization-ip
75+
authorization:
76+
defaultAction: Deny
77+
rules:
78+
- action: Allow
79+
principal:
80+
clientCIDRs:
81+
- 192.168.254.0/24
82+
---
83+
apiVersion: gateway.envoyproxy.io/v1alpha1
84+
kind: SecurityPolicy
85+
metadata:
86+
name: tcp-backend-authorization-fqdn-security-policy
87+
namespace: gateway-conformance-infra
88+
spec:
89+
targetRefs:
90+
- group: gateway.networking.k8s.io
91+
kind: TCPRoute
92+
name: tcp-backend-authorization-fqdn
93+
authorization:
94+
defaultAction: Deny
95+
rules:
96+
- action: Allow
97+
principal:
98+
clientCIDRs:
99+
- 0.0.0.0/0
100+
- ::/0
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright Envoy Gateway Authors
2+
// SPDX-License-Identifier: Apache-2.0
3+
// The full text of the Apache license is available in the LICENSE file at
4+
// the root of the repo.
5+
6+
//go:build e2e
7+
8+
package tests
9+
10+
import (
11+
"errors"
12+
"io"
13+
"net"
14+
"testing"
15+
"time"
16+
17+
"k8s.io/apimachinery/pkg/types"
18+
gwapiv1 "sigs.k8s.io/gateway-api/apis/v1"
19+
gwapiv1a2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
20+
"sigs.k8s.io/gateway-api/conformance/utils/suite"
21+
22+
"github.com/envoyproxy/gateway/internal/gatewayapi"
23+
"github.com/envoyproxy/gateway/internal/gatewayapi/resource"
24+
)
25+
26+
func init() {
27+
ConformanceTests = append(ConformanceTests, TCPRouteAuthzWithClientIP)
28+
}
29+
30+
var TCPRouteAuthzWithClientIP = suite.ConformanceTest{
31+
ShortName: "TCPRouteAuthzWithClientIP",
32+
Description: "Authorization with client IP Allow/Deny list for TCP routes",
33+
Manifests: []string{"testdata/tcproute-authorization-client-ip.yaml"},
34+
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) {
35+
ns := "gateway-conformance-infra"
36+
tcpRouteNN := types.NamespacedName{Name: "tcp-backend-authorization-ip", Namespace: ns}
37+
tcpRouteFqdnNN := types.NamespacedName{Name: "tcp-backend-authorization-fqdn", Namespace: ns}
38+
gwNN := types.NamespacedName{Name: "tcp-authorization-backend", Namespace: ns}
39+
GatewayAndTCPRoutesMustBeAccepted(t, suite.Client, &suite.TimeoutConfig, suite.ControllerName, NewGatewayRef(gwNN), tcpRouteNN, tcpRouteFqdnNN)
40+
41+
// Test the blocked route (ip section)
42+
ipSection := gwapiv1.SectionName("ip")
43+
ancestorRefIP := gwapiv1a2.ParentReference{
44+
Group: gatewayapi.GroupPtr(gwapiv1.GroupName),
45+
Kind: gatewayapi.KindPtr(resource.KindGateway),
46+
Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
47+
Name: gwapiv1.ObjectName(gwNN.Name),
48+
SectionName: &ipSection,
49+
}
50+
SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "tcp-backend-authorization-ip-security-policy", Namespace: ns}, suite.ControllerName, ancestorRefIP)
51+
52+
// Test the allowed route (fqdn section)
53+
fqdnSection := gwapiv1.SectionName("fqdn")
54+
ancestorRefFqdn := gwapiv1a2.ParentReference{
55+
Group: gatewayapi.GroupPtr(gwapiv1.GroupName),
56+
Kind: gatewayapi.KindPtr(resource.KindGateway),
57+
Namespace: gatewayapi.NamespacePtr(gwNN.Namespace),
58+
Name: gwapiv1.ObjectName(gwNN.Name),
59+
SectionName: &fqdnSection,
60+
}
61+
SecurityPolicyMustBeAccepted(t, suite.Client, types.NamespacedName{Name: "tcp-backend-authorization-fqdn-security-policy", Namespace: ns}, suite.ControllerName, ancestorRefFqdn)
62+
63+
t.Run("blocked client IP cannot connect", func(t *testing.T) {
64+
testTCPRouteWithBackendBlocked(t, suite, "tcp-authorization-backend", "tcp-backend-authorization-ip", "backend-fqdn")
65+
})
66+
67+
t.Run("allowed client IP can connect", func(t *testing.T) {
68+
testTCPRouteWithBackend(t, suite, "tcp-authorization-backend", "tcp-backend-authorization-fqdn", "backend-fqdn")
69+
})
70+
},
71+
}
72+
73+
func testTCPRouteWithBackendBlocked(t *testing.T, suite *suite.ConformanceTestSuite, gwName, routeName, backendName string) {
74+
ns := "gateway-conformance-infra"
75+
routeNN := types.NamespacedName{Name: routeName, Namespace: ns}
76+
gwNN := types.NamespacedName{Name: gwName, Namespace: ns}
77+
gwAddr := GatewayAndTCPRoutesMustBeAccepted(t, suite.Client, &suite.TimeoutConfig, suite.ControllerName, NewGatewayRef(gwNN), routeNN)
78+
BackendMustBeAccepted(t, suite.Client, types.NamespacedName{Name: backendName, Namespace: ns})
79+
80+
testTCPConnectionBlocked(t, gwAddr)
81+
}
82+
83+
func testTCPConnectionBlocked(t *testing.T, gwAddr string) {
84+
// Try to establish a raw TCP connection
85+
conn, err := net.DialTimeout("tcp", gwAddr, 5*time.Second)
86+
if err != nil {
87+
t.Logf("Connection blocked as expected: %v", err)
88+
return
89+
}
90+
defer conn.Close()
91+
92+
// If connection was established, try sending HTTP request
93+
req := "GET / HTTP/1.1\r\nHost: " + gwAddr + "\r\nUser-Agent: test-client\r\nAccept: */*\r\n\r\n"
94+
_, err = conn.Write([]byte(req))
95+
if err != nil {
96+
t.Logf("Connection blocked during write as expected: %v", err)
97+
return
98+
}
99+
100+
// Try to read response with a short timeout
101+
if err := conn.SetReadDeadline(time.Now().Add(3 * time.Second)); err != nil {
102+
t.Logf("Failed to set read deadline: %v", err)
103+
return
104+
}
105+
buf := make([]byte, 1024)
106+
n, err := conn.Read(buf)
107+
108+
if errors.Is(err, io.EOF) || n == 0 {
109+
t.Log("Got empty reply from server as expected (connection blocked)")
110+
return
111+
}
112+
113+
var netErr net.Error
114+
if errors.As(err, &netErr) && netErr.Timeout() {
115+
t.Log("Connection timed out as expected (connection blocked)")
116+
return
117+
}
118+
if err != nil {
119+
t.Logf("Connection blocked with error as expected: %v", err)
120+
return
121+
}
122+
123+
// If we got here, we received some data, which means the connection was NOT blocked
124+
response := string(buf[:n])
125+
t.Fatalf("Expected connection to be blocked, but got response: %s", response)
126+
}

0 commit comments

Comments
 (0)