Skip to content

Commit 0c3d9c5

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 0c3d9c5

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed

test/e2e/network_policy.go

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

0 commit comments

Comments
 (0)