From 5e3dc65eb432b5fea7fc91aaea48758a64ccbd76 Mon Sep 17 00:00:00 2001 From: Nadia Pinaeva Date: Thu, 29 Jun 2023 09:47:46 +0200 Subject: [PATCH] Allow hostNetwork ingress for network policies with empty namespace selector. The previous version used shared address sets for empty namespace selector to reuse the address set, but it didn't include a special config.Kubernetes.HostNetworkNamespace that only has an address set, but no pods. This difference may break existing network policies for hostNetwork pods, therefore we explicitly add this address sets for an empty namespace selector. Signed-off-by: Nadia Pinaeva --- .../pkg/ovn/base_network_controller_policy.go | 7 +++ go-controller/pkg/ovn/policy_test.go | 58 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/go-controller/pkg/ovn/base_network_controller_policy.go b/go-controller/pkg/ovn/base_network_controller_policy.go index 57ef06c5786..0459dbab2a7 100644 --- a/go-controller/pkg/ovn/base_network_controller_policy.go +++ b/go-controller/pkg/ovn/base_network_controller_policy.go @@ -1085,6 +1085,13 @@ func (bnc *BaseNetworkController) setupGressPolicy(np *networkPolicy, gp *gressP } gp.addPeerAddressSets(ipv4as, ipv6as) } + if podSel.Empty() && nsSel.Empty() && config.Kubernetes.HostNetworkNamespace != "" { + // all namespaces selector, add hostnetwork address set + _, err := gp.addNamespaceAddressSet(config.Kubernetes.HostNetworkNamespace, bnc.addressSetFactory) + if err != nil { + return nil, fmt.Errorf("failed to add namespace address set for gress policy: %w", err) + } + } return nil, nil } diff --git a/go-controller/pkg/ovn/policy_test.go b/go-controller/pkg/ovn/policy_test.go index 6fdb754942b..467df8e6621 100644 --- a/go-controller/pkg/ovn/policy_test.go +++ b/go-controller/pkg/ovn/policy_test.go @@ -292,10 +292,15 @@ func getGressACLs(gressIdx int, namespace, policyName string, peerNamespaces []s ipBlocks := []string{} for _, peer := range peers { // follow the algorithm from setupGressPolicy + podSelector := peer.PodSelector + if podSelector == nil { + // nil pod selector is equivalent to empty pod selector, which selects all + podSelector = &metav1.LabelSelector{} + } podSel, _ := metav1.LabelSelectorAsSelector(peer.PodSelector) nsSel, _ := metav1.LabelSelectorAsSelector(peer.NamespaceSelector) if !((peer.PodSelector == nil || podSel.Empty()) && (peer.NamespaceSelector == nil || !nsSel.Empty())) { - peerIndex := getPodSelectorAddrSetDbIDs(getPodSelectorKey(peer.PodSelector, peer.NamespaceSelector, namespace), controllerName) + peerIndex := getPodSelectorAddrSetDbIDs(getPodSelectorKey(podSelector, peer.NamespaceSelector, namespace), controllerName) asv4, _ := addressset.GetHashNamesForAS(peerIndex) hashedASNames = append(hashedASNames, asv4) } @@ -1797,6 +1802,57 @@ var _ = ginkgo.Describe("OVN NetworkPolicy Operations", func() { } gomega.Expect(app.Run([]string{app.Name})).To(gomega.Succeed()) }) + + ginkgo.It("references all namespace address sets for empty namespace selector, even if they don't have pods (HostNetworkNamespace)", func() { + app.Action = func(ctx *cli.Context) error { + hostNamespaceName := "host-network" + config.Kubernetes.HostNetworkNamespace = hostNamespaceName + hostNamespace := *newNamespace(hostNamespaceName) + + namespace1 := *newNamespace(namespaceName1) + nPodTest := getTestPod(namespace1.Name, nodeName) + networkPolicy := newNetworkPolicy(netPolicyName1, namespaceName1, metav1.LabelSelector{}, []knet.NetworkPolicyIngressRule{ + { + From: []knet.NetworkPolicyPeer{{ + NamespaceSelector: &metav1.LabelSelector{}, + }}, + }, + }, nil) + startOvn(initialDB, []v1.Namespace{namespace1, hostNamespace}, []knet.NetworkPolicy{*networkPolicy}, + []testPod{nPodTest}, nil) + + // emulate namespace handler adding management IPs for this address set + // we could let controller do that, but that would require adding nodes with their annotations + dbIDs := libovsdbops.NewDbObjectIDs(libovsdbops.AddressSetNamespace, fakeOvn.controller.controllerName, + map[libovsdbops.ExternalIDKey]string{ + libovsdbops.ObjectNameKey: hostNamespaceName, + }) + // random set of IPs + hostNamespaceAddrSet, err := fakeOvn.asf.GetAddressSet(dbIDs) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + // emulate management IP being added to the hostNetwork address set, but no pods in that namespace + err = hostNamespaceAddrSet.SetIPs([]net.IP{net.ParseIP("10.244.0.2")}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + + // create networkPolicy, check db + _, err = fakeOvn.fakeClient.KubeClient.NetworkingV1().NetworkPolicies(networkPolicy.Namespace). + Get(context.TODO(), networkPolicy.Name, metav1.GetOptions{}) + gomega.Expect(err).NotTo(gomega.HaveOccurred()) + fakeOvn.asf.ExpectAddressSetWithIPs(namespaceName1, []string{nPodTest.podIP}) + fakeOvn.asf.ExpectAddressSetWithIPs(hostNamespaceName, []string{"10.244.0.2"}) + + gressPolicyExpectedData := getPolicyData(networkPolicy, []string{nPodTest.portUUID}, + []string{hostNamespace.Name}, nil) + defaultDenyExpectedData := getDefaultDenyData(networkPolicy, []string{nPodTest.portUUID}) + expectedData := getUpdatedInitialDB([]testPod{nPodTest}) + expectedData = append(expectedData, gressPolicyExpectedData...) + expectedData = append(expectedData, defaultDenyExpectedData...) + gomega.Eventually(fakeOvn.nbClient).Should(libovsdb.HaveData(expectedData...)) + + return nil + } + gomega.Expect(app.Run([]string{app.Name})).To(gomega.Succeed()) + }) }) ginkgo.Context("ACL logging for network policies", func() {