Skip to content

Commit 8e53810

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 de11f78 commit 8e53810

File tree

1 file changed

+156
-0
lines changed

1 file changed

+156
-0
lines changed

test/e2e/network_policy.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
package e2e
2+
3+
import (
4+
"context"
5+
"fmt"
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+
client, err := getKubeClient()
17+
if err != nil {
18+
g.Fail(fmt.Sprintf("error getting kube client: %v", err))
19+
}
20+
checkNetworkPoliciesExist(client, serviceCAOperatorNamespace, []string{
21+
"service-ca-operator",
22+
"default-deny-all",
23+
})
24+
})
25+
})
26+
27+
g.Context("controller-namespace-network-policies", func() {
28+
g.It("[Operator][Serial] should have network policies deployed in the controller namespace", func() {
29+
client, err := getKubeClient()
30+
if err != nil {
31+
g.Fail(fmt.Sprintf("error getting kube client: %v", err))
32+
}
33+
checkNetworkPoliciesExist(client, serviceCAControllerNamespace, []string{
34+
"service-ca",
35+
"default-deny-all",
36+
})
37+
})
38+
})
39+
40+
g.Context("operator-network-policy-spec", func() {
41+
g.It("[Operator][Serial] should allow metrics scraping on port 8443 and restrict other ingress in the operator namespace", func() {
42+
client, err := getKubeClient()
43+
if err != nil {
44+
g.Fail(fmt.Sprintf("error getting kube client: %v", err))
45+
}
46+
np, err := client.NetworkingV1().NetworkPolicies(serviceCAOperatorNamespace).Get(
47+
context.TODO(), "service-ca-operator", metav1.GetOptions{},
48+
)
49+
if err != nil {
50+
g.Fail(fmt.Sprintf("failed to get NetworkPolicy service-ca-operator in %s: %v", serviceCAOperatorNamespace, err))
51+
}
52+
checkServiceCANetworkPolicySpec(np, "app", "service-ca-operator")
53+
})
54+
})
55+
56+
g.Context("controller-network-policy-spec", func() {
57+
g.It("[Operator][Serial] should allow metrics scraping on port 8443 and restrict other ingress in the controller namespace", func() {
58+
client, err := getKubeClient()
59+
if err != nil {
60+
g.Fail(fmt.Sprintf("error getting kube client: %v", err))
61+
}
62+
np, err := client.NetworkingV1().NetworkPolicies(serviceCAControllerNamespace).Get(
63+
context.TODO(), "service-ca", metav1.GetOptions{},
64+
)
65+
if err != nil {
66+
g.Fail(fmt.Sprintf("failed to get NetworkPolicy service-ca in %s: %v", serviceCAControllerNamespace, err))
67+
}
68+
checkServiceCANetworkPolicySpec(np, "app", "service-ca")
69+
})
70+
})
71+
})
72+
73+
// checkNetworkPoliciesExist asserts that all named NetworkPolicies exist in the given namespace.
74+
func checkNetworkPoliciesExist(client *kubernetes.Clientset, namespace string, names []string) {
75+
existing, err := client.NetworkingV1().NetworkPolicies(namespace).List(context.TODO(), metav1.ListOptions{})
76+
if err != nil {
77+
g.Fail(fmt.Sprintf("failed to list NetworkPolicies in %s: %v", namespace, err))
78+
}
79+
80+
nameSet := make(map[string]bool, len(existing.Items))
81+
for _, np := range existing.Items {
82+
nameSet[np.Name] = true
83+
}
84+
85+
for _, name := range names {
86+
if !nameSet[name] {
87+
g.Fail(fmt.Sprintf("expected NetworkPolicy %q to exist in namespace %s, but it was not found (found: %v)",
88+
name, namespace, existingNetworkPolicyNames(existing.Items)))
89+
}
90+
}
91+
}
92+
93+
// checkServiceCANetworkPolicySpec validates that a service-ca allow policy:
94+
// - selects pods by the expected label
95+
// - allows ingress on TCP 8443 (metrics scraping)
96+
// - allows egress on port 5353 (DNS)
97+
// - declares both Ingress and Egress policyTypes
98+
func checkServiceCANetworkPolicySpec(np *networkingv1.NetworkPolicy, labelKey, labelValue string) {
99+
if v, ok := np.Spec.PodSelector.MatchLabels[labelKey]; !ok || v != labelValue {
100+
g.Fail(fmt.Sprintf("NetworkPolicy %q podSelector: expected matchLabel %s=%s, got %v",
101+
np.Name, labelKey, labelValue, np.Spec.PodSelector.MatchLabels))
102+
}
103+
104+
hasIngress, hasEgress := false, false
105+
for _, pt := range np.Spec.PolicyTypes {
106+
switch pt {
107+
case networkingv1.PolicyTypeIngress:
108+
hasIngress = true
109+
case networkingv1.PolicyTypeEgress:
110+
hasEgress = true
111+
}
112+
}
113+
if !hasIngress {
114+
g.Fail(fmt.Sprintf("NetworkPolicy %q: expected policyTypes to include Ingress", np.Name))
115+
}
116+
if !hasEgress {
117+
g.Fail(fmt.Sprintf("NetworkPolicy %q: expected policyTypes to include Egress", np.Name))
118+
}
119+
120+
if !hasIngressPort(np, 8443) {
121+
g.Fail(fmt.Sprintf("NetworkPolicy %q: expected an ingress rule allowing TCP port 8443 for metrics scraping", np.Name))
122+
}
123+
if !hasEgressPort(np, 5353) {
124+
g.Fail(fmt.Sprintf("NetworkPolicy %q: expected an egress rule allowing port 5353 for DNS resolution", np.Name))
125+
}
126+
}
127+
128+
func hasIngressPort(np *networkingv1.NetworkPolicy, port int) bool {
129+
for _, rule := range np.Spec.Ingress {
130+
for _, p := range rule.Ports {
131+
if p.Port != nil && int(p.Port.IntVal) == port {
132+
return true
133+
}
134+
}
135+
}
136+
return false
137+
}
138+
139+
func hasEgressPort(np *networkingv1.NetworkPolicy, port int) bool {
140+
for _, rule := range np.Spec.Egress {
141+
for _, p := range rule.Ports {
142+
if p.Port != nil && int(p.Port.IntVal) == port {
143+
return true
144+
}
145+
}
146+
}
147+
return false
148+
}
149+
150+
func existingNetworkPolicyNames(policies []networkingv1.NetworkPolicy) []string {
151+
names := make([]string, 0, len(policies))
152+
for _, np := range policies {
153+
names = append(names, np.Name)
154+
}
155+
return names
156+
}

0 commit comments

Comments
 (0)