Skip to content

Commit 5cd8b27

Browse files
committed
test: add e2e tests for service-ca network policies
Verify that NetworkPolicy resources introduced in PR openshift#324 are correctly deployed in both the openshift-service-ca-operator and openshift-service-ca namespaces. Tests check: - existence of allow and default-deny-all policies in each namespace - pod selector targets the correct app label - ingress allows TCP 8443 for metrics scraping - egress allows port 5353 for DNS resolution - both Ingress and Egress policyTypes are declared
1 parent 503e4f5 commit 5cd8b27

File tree

1 file changed

+197
-0
lines changed

1 file changed

+197
-0
lines changed

test/e2e/network_policy.go

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
g "github.com/onsi/ginkgo/v2"
8+
networkingv1 "k8s.io/api/networking/v1"
9+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10+
"k8s.io/client-go/kubernetes"
11+
)
12+
13+
var _ = g.Describe("[sig-service-ca] service-ca-operator network policies", func() {
14+
g.Context("operator-namespace-network-policies", func() {
15+
g.It("[Operator][Serial] should have network policies deployed in the operator namespace", func() {
16+
testOperatorNamespaceNetworkPolicies(g.GinkgoTB())
17+
})
18+
})
19+
20+
g.Context("controller-namespace-network-policies", func() {
21+
g.It("[Operator][Serial] should have network policies deployed in the controller namespace", func() {
22+
testControllerNamespaceNetworkPolicies(g.GinkgoTB())
23+
})
24+
})
25+
26+
g.Context("operator-network-policy-spec", func() {
27+
g.It("[Operator][Serial] should allow metrics scraping on port 8443 and restrict other ingress in the operator namespace", func() {
28+
testOperatorNetworkPolicySpec(g.GinkgoTB())
29+
})
30+
})
31+
32+
g.Context("controller-network-policy-spec", func() {
33+
g.It("[Operator][Serial] should allow metrics scraping on port 8443 and restrict other ingress in the controller namespace", func() {
34+
testControllerNetworkPolicySpec(g.GinkgoTB())
35+
})
36+
})
37+
})
38+
39+
// testOperatorNamespaceNetworkPolicies verifies that the expected NetworkPolicy resources
40+
// exist in the openshift-service-ca-operator namespace.
41+
func testOperatorNamespaceNetworkPolicies(t testing.TB) {
42+
client, err := getKubeClient()
43+
if err != nil {
44+
t.Fatalf("error getting kube client: %v", err)
45+
}
46+
47+
checkNetworkPoliciesExist(t, client, serviceCAOperatorNamespace, []string{
48+
"service-ca-operator",
49+
"default-deny-all",
50+
})
51+
}
52+
53+
// testControllerNamespaceNetworkPolicies verifies that the expected NetworkPolicy resources
54+
// exist in the openshift-service-ca namespace.
55+
func testControllerNamespaceNetworkPolicies(t testing.TB) {
56+
client, err := getKubeClient()
57+
if err != nil {
58+
t.Fatalf("error getting kube client: %v", err)
59+
}
60+
61+
checkNetworkPoliciesExist(t, client, serviceCAControllerNamespace, []string{
62+
"service-ca",
63+
"default-deny-all",
64+
})
65+
}
66+
67+
// testOperatorNetworkPolicySpec verifies the spec of the service-ca-operator NetworkPolicy:
68+
// - Selects pods with app=service-ca-operator
69+
// - Allows ingress on TCP 8443 (metrics)
70+
// - Applies both Ingress and Egress policyTypes
71+
func testOperatorNetworkPolicySpec(t testing.TB) {
72+
client, err := getKubeClient()
73+
if err != nil {
74+
t.Fatalf("error getting kube client: %v", err)
75+
}
76+
77+
np, err := client.NetworkingV1().NetworkPolicies(serviceCAOperatorNamespace).Get(
78+
context.TODO(), "service-ca-operator", metav1.GetOptions{},
79+
)
80+
if err != nil {
81+
t.Fatalf("failed to get NetworkPolicy service-ca-operator in %s: %v", serviceCAOperatorNamespace, err)
82+
}
83+
84+
checkServiceCANetworkPolicySpec(t, np, "app", "service-ca-operator")
85+
}
86+
87+
// testControllerNetworkPolicySpec verifies the spec of the service-ca NetworkPolicy:
88+
// - Selects pods with app=service-ca
89+
// - Allows ingress on TCP 8443 (metrics)
90+
// - Applies both Ingress and Egress policyTypes
91+
func testControllerNetworkPolicySpec(t testing.TB) {
92+
client, err := getKubeClient()
93+
if err != nil {
94+
t.Fatalf("error getting kube client: %v", err)
95+
}
96+
97+
np, err := client.NetworkingV1().NetworkPolicies(serviceCAControllerNamespace).Get(
98+
context.TODO(), "service-ca", metav1.GetOptions{},
99+
)
100+
if err != nil {
101+
t.Fatalf("failed to get NetworkPolicy service-ca in %s: %v", serviceCAControllerNamespace, err)
102+
}
103+
104+
checkServiceCANetworkPolicySpec(t, np, "app", "service-ca")
105+
}
106+
107+
// checkNetworkPoliciesExist asserts that all named NetworkPolicies exist in the given namespace.
108+
func checkNetworkPoliciesExist(t testing.TB, client *kubernetes.Clientset, namespace string, names []string) {
109+
t.Helper()
110+
existing, err := client.NetworkingV1().NetworkPolicies(namespace).List(context.TODO(), metav1.ListOptions{})
111+
if err != nil {
112+
t.Fatalf("failed to list NetworkPolicies in %s: %v", namespace, err)
113+
}
114+
115+
nameSet := make(map[string]bool, len(existing.Items))
116+
for _, np := range existing.Items {
117+
nameSet[np.Name] = true
118+
}
119+
120+
for _, name := range names {
121+
if !nameSet[name] {
122+
t.Errorf("expected NetworkPolicy %q to exist in namespace %s, but it was not found (found: %v)",
123+
name, namespace, existingNetworkPolicyNames(existing.Items))
124+
}
125+
}
126+
}
127+
128+
// checkServiceCANetworkPolicySpec validates common spec requirements for service-ca allow policies:
129+
// - podSelector targets the expected label
130+
// - ingress allows port 8443/TCP (metrics scraping)
131+
// - egress allows port 5353 (DNS)
132+
// - both Ingress and Egress policyTypes are set
133+
func checkServiceCANetworkPolicySpec(t testing.TB, np *networkingv1.NetworkPolicy, labelKey, labelValue string) {
134+
t.Helper()
135+
136+
if v, ok := np.Spec.PodSelector.MatchLabels[labelKey]; !ok || v != labelValue {
137+
t.Errorf("NetworkPolicy %q podSelector: expected matchLabel %s=%s, got %v",
138+
np.Name, labelKey, labelValue, np.Spec.PodSelector.MatchLabels)
139+
}
140+
141+
hasIngress, hasEgress := false, false
142+
for _, pt := range np.Spec.PolicyTypes {
143+
switch pt {
144+
case networkingv1.PolicyTypeIngress:
145+
hasIngress = true
146+
case networkingv1.PolicyTypeEgress:
147+
hasEgress = true
148+
}
149+
}
150+
if !hasIngress {
151+
t.Errorf("NetworkPolicy %q: expected policyTypes to include Ingress", np.Name)
152+
}
153+
if !hasEgress {
154+
t.Errorf("NetworkPolicy %q: expected policyTypes to include Egress", np.Name)
155+
}
156+
157+
if !hasIngressPort(np, 8443) {
158+
t.Errorf("NetworkPolicy %q: expected an ingress rule allowing TCP port 8443 for metrics scraping", np.Name)
159+
}
160+
161+
if !hasEgressPort(np, 5353) {
162+
t.Errorf("NetworkPolicy %q: expected an egress rule allowing port 5353 for DNS resolution", np.Name)
163+
}
164+
}
165+
166+
// hasIngressPort returns true if the NetworkPolicy has an ingress rule that opens the given port.
167+
func hasIngressPort(np *networkingv1.NetworkPolicy, port int) bool {
168+
for _, rule := range np.Spec.Ingress {
169+
for _, p := range rule.Ports {
170+
if p.Port != nil && int(p.Port.IntVal) == port {
171+
return true
172+
}
173+
}
174+
}
175+
return false
176+
}
177+
178+
// hasEgressPort returns true if the NetworkPolicy has an egress rule that allows the given port.
179+
func hasEgressPort(np *networkingv1.NetworkPolicy, port int) bool {
180+
for _, rule := range np.Spec.Egress {
181+
for _, p := range rule.Ports {
182+
if p.Port != nil && int(p.Port.IntVal) == port {
183+
return true
184+
}
185+
}
186+
}
187+
return false
188+
}
189+
190+
// existingNetworkPolicyNames returns the names of the given NetworkPolicies for error messages.
191+
func existingNetworkPolicyNames(policies []networkingv1.NetworkPolicy) []string {
192+
names := make([]string, 0, len(policies))
193+
for _, np := range policies {
194+
names = append(names, np.Name)
195+
}
196+
return names
197+
}

0 commit comments

Comments
 (0)