From 08dc8442bbe9ab11d0275f4330d94457770dab51 Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 3 Mar 2021 11:46:52 -0800 Subject: [PATCH 01/34] basic scenario and investigation --- npm/testpolicies/allow-ns-y-z-pod-b-c.yaml | 26 +++++++ npm/translatePolicy.go | 1 + npm/translatePolicy_test.go | 88 ++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 npm/testpolicies/allow-ns-y-z-pod-b-c.yaml diff --git a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml new file mode 100644 index 0000000000..5c5df632f0 --- /dev/null +++ b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ns-y-z-pod-b-c + namespace: netpol-4537-x +spec: + ingress: + - from: + - namespaceSelector: + matchExpressions: + - key: ns + operator: NotIn + values: + - netpol-4537-x + podSelector: + matchExpressions: + - key: pod + operator: In + values: + - b + - c + podSelector: + matchLabels: + pod: a + policyTypes: + - Ingress diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 288d309b35..0ff4cec055 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -113,6 +113,7 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } for i, _ := range ops { + // TODO need to change this logic, create a list of lsts here and have a single match against it spec = append(spec, craftPartialIptEntrySpecFromOpAndLabel(ops[i], labels[i], srcOrDstFlag, isNamespaceSelector)...) } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index f1e28c9f64..344e383ac9 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2852,6 +2852,94 @@ func TestAllowAllFromAppBackend(t *testing.T) { } } +func TestAllowMultiplePodSelectors(t *testing.T) { + allowAllEgress, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") + if err != nil { + t.Fatal(err) + } + + util.IsNewNwPolicyVerFlag = true + + sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) + + expectedSets := []string{ + "app:backend", + "ns-testnamespace", + } + if !reflect.DeepEqual(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") + t.Errorf("sets: %v", sets) + t.Errorf("expectedSets: %v", expectedSets) + } + + expectedLists := []string{} + if !reflect.DeepEqual(lists, expectedLists) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") + t.Errorf("lists: %v", lists) + t.Errorf("expectedLists: %v", expectedLists) + } + + expectedIptEntries := []*iptm.IptEntry{} + nonKubeSystemEntries := []*iptm.IptEntry{ + &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-testnamespace"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:backend"), + util.IptablesSrcFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureEgressXMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace", + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + IsJumpEntry: true, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-testnamespace"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:backend"), + util.IptablesSrcFlag, + util.IptablesJumpFlag, + util.IptablesAzureEgressDropsChain, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + fmt.Sprintf("ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace-TO-JUMP-TO-%s", + util.IptablesAzureEgressDropsChain), + }, + }, + } + expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) + // has egress, but empty map means allow all + expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllEgress.Spec.PodSelector, false, false)...) + if !reflect.DeepEqual(iptEntries, expectedIptEntries) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy policy comparison") + marshalledIptEntries, _ := json.Marshal(iptEntries) + marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) + t.Errorf("iptEntries: %s", marshalledIptEntries) + t.Errorf("expectedIptEntries: %s", marshalledExpectedIptEntries) + } +} + func TestDenyAllFromNsUnsafe(t *testing.T) { denyAllFromNsUnsafePolicy, err := readPolicyYaml("testpolicies/deny-all-from-ns-unsafe.yaml") if err != nil { From ad6a2ddf2ed9e713756dd297fa3fef2259aef216 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:01:26 -0700 Subject: [PATCH 02/34] adding some basic imcrements to yaml --- npm/npm.go | 2 +- npm/parseSelector.go | 55 +++++++++++++++------- npm/testpolicies/allow-ns-y-z-pod-b-c.yaml | 14 +++++- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/npm/npm.go b/npm/npm.go index 2f6429308a..15add9cd84 100644 --- a/npm/npm.go +++ b/npm/npm.go @@ -161,7 +161,7 @@ func (npMgr *NetworkPolicyManager) backup() { time.Sleep(backupWaitTimeInSeconds * time.Second) if err = iptMgr.Save(util.IptablesConfigFile); err != nil { - metrics.SendErrorLogAndMetric(util.NpmID, "Error: failed to back up Azure-NPM states") + metrics.SendErrorLogAndMetric(util.NpmID, "Error: failed to back up Azure-NPM states %s", err.Error()) } } } diff --git a/npm/parseSelector.go b/npm/parseSelector.go index f762aef3b1..cd6859b82d 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -1,9 +1,9 @@ package npm import ( + "container/heap" "fmt" "sort" - "container/heap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -14,18 +14,18 @@ import ( // An ReqHeap is a min-heap of labelSelectorRequirements. type ReqHeap []metav1.LabelSelectorRequirement -func (h ReqHeap) Len() int { +func (h ReqHeap) Len() int { return len(h) } func (h ReqHeap) Less(i, j int) bool { sort.Strings(h[i].Values) sort.Strings(h[j].Values) - + if int(h[i].Key[0]) < int(h[j].Key[0]) { return true } - + if int(h[i].Key[0]) > int(h[j].Key[0]) { return false } @@ -37,7 +37,7 @@ func (h ReqHeap) Less(i, j int) bool { if len(h[j].Values) == 0 { return false } - + if len(h[i].Values[0]) == 0 { return true } @@ -61,8 +61,8 @@ func (h *ReqHeap) Push(x interface{}) { func (h *ReqHeap) Pop() interface{} { old := *h n := len(old) - x := old[n -1] - *h = old[0 : n - 1] + x := old[n-1] + *h = old[0 : n-1] return x } @@ -121,6 +121,16 @@ func sortSelector(selector *metav1.LabelSelector) { selector.MatchExpressions = sortedReqs } +// getSetNameForMultiValueSelector takes in label with multiple values without operator +// and returns a new 2nd level ipset name +func getSetNameForMultiValueSelector(key string, vals []string) string { + rtStr := key + for _, val := range vals { + rtStr = util.GetIpSetFromLabelKV(rtStr, val) + } + return rtStr +} + // HashSelector returns the hash value of the selector. func HashSelector(selector *metav1.LabelSelector) string { sortSelector(selector) @@ -128,13 +138,14 @@ func HashSelector(selector *metav1.LabelSelector) string { } // parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. -func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string) { +func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[string][]string) { var ( labels []string keys []string - vals []string + vals map[string][]string ) + vals = make(map[string][]string) if selector == nil { return labels, keys, vals } @@ -142,7 +153,7 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { labels = append(labels, "") keys = append(keys, "") - vals = append(vals, "") + vals[""] = append(vals[""], "") return labels, keys, vals } @@ -151,38 +162,48 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string for i := range sortedKeys { labels = append(labels, sortedKeys[i]+":"+sortedVals[i]) + vals[sortedKeys[i]] = append(vals[sortedKeys[i]], sortedVals[i]) } keys = append(keys, sortedKeys...) - vals = append(vals, sortedVals...) for _, req := range selector.MatchExpressions { var k string switch op := req.Operator; op { + // TODO remove this + // - key: pod + // operator: NotIn + // values: + // - b + // - c + // !pod b !pod:b + // !pod a !pod:a + // case metav1.LabelSelectorOpIn: for _, v := range req.Values { k = req.Key keys = append(keys, k) - vals = append(vals, v) - labels = append(labels, k+":"+v) + vals[k] = append(vals[k], v) + // TODO make sure this removed labels are covered in all cases + //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: for _, v := range req.Values { k = util.IptablesNotFlag + req.Key keys = append(keys, k) - vals = append(vals, v) - labels = append(labels, k+":"+v) + vals[k] = append(vals[k], v) + //labels = append(labels, k+":"+v) } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key keys = append(keys, req.Key) - vals = append(vals, "") + vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key keys = append(keys, k) - vals = append(vals, "") + vals[k] = append(vals[k], "") labels = append(labels, k) default: log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector) diff --git a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml index 5c5df632f0..71cb960a9b 100644 --- a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml +++ b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml @@ -12,6 +12,7 @@ spec: operator: NotIn values: - netpol-4537-x + - netpol-4537-y podSelector: matchExpressions: - key: pod @@ -19,8 +20,17 @@ spec: values: - b - c + - key: app + operator: In + values: + - test + - int podSelector: - matchLabels: - pod: a + matchExpressions: + - key: pod + operator: In + values: + - a + - x policyTypes: - Ingress From 6668117dcebffcc9a828aa5065d6241c704db94f Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:02:50 -0700 Subject: [PATCH 03/34] First pass at adding 2nd level ipsets for multi value selector expressions --- npm/ipsm/ipsm.go | 68 ++++++----- npm/ipsm/ipsm_test.go | 21 ---- npm/networkPolicyController.go | 23 +++- npm/translatePolicy.go | 213 +++++++++++++++++++++------------ npm/translatePolicy_test.go | 3 +- 5 files changed, 199 insertions(+), 129 deletions(-) diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index da7412fee5..b3f9aa28f2 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -16,6 +16,14 @@ import ( "github.com/Azure/azure-container-networking/npm/util" ) +// ReferCountOperation is used to indicate whether ipset refer count should be increased or decreased. +type ReferCountOperation bool + +const ( + IncrementOp ReferCountOperation = true + DecrmentOp ReferCountOperation = false +) + type ipsEntry struct { operationFlag string name string @@ -36,11 +44,20 @@ type Ipset struct { referCount int } +func (ipset *Ipset) IncReferCount() { + ipset.referCount++ +} + +func (ipset *Ipset) DecReferCount() { + ipset.referCount-- +} + // NewIpset creates a new instance for Ipset object. func NewIpset(setName string) *Ipset { return &Ipset{ - name: setName, - elements: make(map[string]string), + name: setName, + elements: make(map[string]string), + referCount: 0, } } @@ -70,6 +87,21 @@ func (ipsMgr *IpsetManager) Exists(listName string, setName string, kind string) return true } +// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases tis refer count. +func (ipsMgr *IpsetManager) IpSetReferIncOrDec(ipsetName string, kind string, countOperation ReferCountOperation) { + m := ipsMgr.SetMap + if kind == util.IpsetSetListFlag { + m = ipsMgr.ListMap + } + + switch countOperation { + case IncrementOp: + m[ipsetName].IncReferCount() + case DecrmentOp: + m[ipsetName].DecReferCount() + } +} + // SetExists checks if an ipset exists, and returns the type func (ipsMgr *IpsetManager) SetExists(setName string) (bool, string) { _, exists := ipsMgr.SetMap[setName] @@ -119,6 +151,11 @@ func (ipsMgr *IpsetManager) DeleteList(listName string) error { set: util.GetHashedName(listName), } + if ipsMgr.ListMap[listName].referCount > 0 { + ipsMgr.IpSetReferIncOrDec(listName, util.IpsetSetListFlag, DecrmentOp) + return nil + } + if errCode, err := ipsMgr.Run(entry); err != nil { if errCode == 1 { return nil @@ -422,33 +459,6 @@ func (ipsMgr *IpsetManager) DeleteFromSet(setName, ip, podKey string) error { return nil } -// Clean removes all the empty sets & lists under the namespace. -func (ipsMgr *IpsetManager) Clean() error { - for setName, set := range ipsMgr.SetMap { - if len(set.elements) > 0 { - continue - } - - if err := ipsMgr.DeleteSet(setName); err != nil { - metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset") - return err - } - } - - for listName, list := range ipsMgr.ListMap { - if len(list.elements) > 0 { - continue - } - - if err := ipsMgr.DeleteList(listName); err != nil { - metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset list") - return err - } - } - - return nil -} - // Destroy completely cleans ipset. func (ipsMgr *IpsetManager) Destroy() error { entry := &ipsEntry{ diff --git a/npm/ipsm/ipsm_test.go b/npm/ipsm/ipsm_test.go index 5f98876d9f..9f6a70c8fd 100644 --- a/npm/ipsm/ipsm_test.go +++ b/npm/ipsm/ipsm_test.go @@ -465,27 +465,6 @@ func TestDeleteFromSetWithPodCache(t *testing.T) { } } -func TestClean(t *testing.T) { - ipsMgr := NewIpsetManager() - if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Save") - } - - defer func() { - if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Restore") - } - }() - - if err := ipsMgr.CreateSet("test-set", append([]string{util.IpsetNetHashFlag})); err != nil { - t.Errorf("TestClean failed @ ipsMgr.CreateSet with err %+v", err) - } - - if err := ipsMgr.Clean(); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Clean") - } -} - func TestDestroy(t *testing.T) { ipsMgr := NewIpsetManager() if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 5134f9ceec..51436a5511 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -351,10 +351,18 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset named port %s with err: %v", set, err) } } - for _, list := range lists { - if err = ipsMgr.CreateList(list); err != nil { - return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", list, err) + // (TODO) now add the []string value of the lists into a new obj + // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + for listKey, listLabelsMembers := range lists { + if err = ipsMgr.CreateList(listKey); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } + for _, listMember := range listLabelsMembers { + if err = ipsMgr.AddToList(listKey, listMember); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipst member %s to ipset list %s with err: %v", listMember, listKey, err) + } + } + ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp) } if err = c.createCidrsRule("in", netPolObj.ObjectMeta.Name, netPolObj.ObjectMeta.Namespace, ingressIPCidrs, ipsMgr); err != nil { @@ -385,7 +393,7 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC ipsMgr := c.npMgr.NsMap[util.KubeAllNamespacesFlag].IpsMgr iptMgr := c.npMgr.NsMap[util.KubeAllNamespacesFlag].iptMgr // translate policy from "cachedNetPolObj" - _, _, _, ingressIPCidrs, egressIPCidrs, iptEntries := translatePolicy(cachedNetPolObj) + _, _, lists, ingressIPCidrs, egressIPCidrs, iptEntries := translatePolicy(cachedNetPolObj) var err error // delete iptables entries @@ -394,6 +402,13 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC return fmt.Errorf("[cleanUpNetworkPolicy] Error: failed to apply iptables rule. Rule: %+v with err: %v", iptEntry, err) } } + // (TODO) now add the []string value of the lists into a new obj + // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + for listKey, _ := range lists { + if err = ipsMgr.DeleteList(listKey); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) + } + } // delete ipset list related to ingress CIDRs if err = c.removeCidrsRule("in", cachedNetPolObj.Name, cachedNetPolObj.Namespace, ingressIPCidrs, ipsMgr); err != nil { diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 0ff4cec055..e6a1730ef7 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -80,6 +80,7 @@ func craftPartialIptEntrySpecFromOpAndLabel(op, label, srcOrDstFlag string, isNa return util.DropEmptyFields(partialSpec) } +// TODO check this func references and change the label and op logic // craftPartialIptablesCommentFromSelector :- ns must be "" for namespace selectors func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, srcOrDstFlag string, isNamespaceSelector bool) []string { var spec []string @@ -121,10 +122,29 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors -func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) []string { - labelsWithOps, _, _ := parseSelector(selector) +func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { + labelsWithOps, _, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) - return craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + valueLabels := []string{} + listLabelsWithMembers := make(map[string][]string) + // TODO add comments very confusing for sure + for labelKeyWithOps, labelValueList := range nsLabelListKVs { + op, labelKey := GetOperatorAndLabel(labelKeyWithOps) + labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) + ops = append(ops, op) + // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists + //labels = append(labels, labelKVIpsetName) + for _, labelValue := range labelValueList { + ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) + valueLabels = append(valueLabels, ipsetName) + listLabelsWithMembers[labelKVIpsetName] = append(listLabelsWithMembers[labelKVIpsetName], ipsetName) + } + } + iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + // only append valueLabels to labels after creating the Ipt Spec as valueLabels + // are included in labelKVIpsetName + labels = append(labels, valueLabels...) + return iptEntrySpecs, labels, listLabelsWithMembers } // craftPartialIptablesCommentFromSelector :- ns must be "" for namespace selectors @@ -161,11 +181,11 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe return comment[:len(comment)-len("-AND-")] + postfix } -func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, []string, [][]string, []*iptm.IptEntry) { +func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash - namedPorts []string // ipsets with type: hash:ip,port - lists []string // ipsets with type: list:set + sets []string // ipsets with type: net:hash + namedPorts []string // ipsets with type: hash:ip,port + lists map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry fromRuleEntries []*iptm.IptEntry @@ -174,14 +194,15 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) log.Logf("started parsing ingress rule") - - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - sets = append(sets, labels...) sets = append(sets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) + lists = make(map[string][]string) - targetSelectorIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesDstFlag, false) + targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) + sets = append(sets, labels...) + for parsedKey, parsedValue := range listLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { @@ -236,7 +257,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) entries = append(entries, entry) - lists = append(lists, util.KubeAllNamespacesFlag) + lists[util.KubeAllNamespacesFlag] = []string{} continue } @@ -424,20 +445,26 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } if fromRule.PodSelector == nil && fromRule.NamespaceSelector != nil { - nsLabelsWithOps, _, _ := parseSelector(fromRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) } } - lists = append(lists, nsLabelsWithoutOps...) - - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) if portRuleExists { for _, portRule := range rule.Ports { @@ -531,16 +558,18 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } if fromRule.PodSelector != nil && fromRule.NamespaceSelector == nil { - podLabelsWithOps, _, _ := parseSelector(fromRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + // TODO check old code if we need any ns- prefix for pod selectors + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) if len(podLabelsWithoutOps) == 1 { if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = "ns-" + ns + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } sets = append(sets, podLabelsWithoutOps...) - - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -641,21 +670,23 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS continue } - nsLabelsWithOps, _, _ := parseSelector(fromRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) - // Add namespaces prefix to distinguish namespace ipsets and pod ipsets + // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } } - lists = append(lists, nsLabelsWithoutOps...) - - podLabelsWithOps, _, _ := parseSelector(fromRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - - // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) if portRuleExists { @@ -846,15 +877,19 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS entries = append(entries, entry) } + for parsedKey, parsedValue := range lists { + lists[parsedKey] = util.DropEmptyFields(parsedValue) + } + log.Logf("finished parsing ingress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), util.DropEmptyFields(lists), ipCidrs, entries + return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries } -func translateEgress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyEgressRule) ([]string, []string, []string, [][]string, []*iptm.IptEntry) { +func translateEgress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyEgressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash - namedPorts []string // ipsets with type: hash:ip,port - lists []string // ipsets with type: list:set + sets []string // ipsets with type: net:hash + namedPorts []string // ipsets with type: hash:ip,port + lists map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry toRuleEntries []*iptm.IptEntry @@ -921,7 +956,9 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) entries = append(entries, entry) - lists = append(lists, util.KubeAllNamespacesFlag) + if _, ok := lists[util.KubeAllNamespacesFlag]; !ok { + lists[util.KubeAllNamespacesFlag] = nil + } continue } @@ -1115,20 +1152,26 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } if toRule.PodSelector == nil && toRule.NamespaceSelector != nil { - nsLabelsWithOps, _, _ := parseSelector(toRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) } } - lists = append(lists, nsLabelsWithoutOps...) - - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) if portRuleExists { for _, portRule := range rule.Ports { @@ -1222,16 +1265,17 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } if toRule.PodSelector != nil && toRule.NamespaceSelector == nil { - podLabelsWithOps, _, _ := parseSelector(toRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) if len(podLabelsWithoutOps) == 1 { if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = "ns-" + ns + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } + for parsedKey, parsedValue := range listPodLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } sets = append(sets, podLabelsWithoutOps...) - - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1332,21 +1376,24 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe continue } - nsLabelsWithOps, _, _ := parseSelector(toRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } } - lists = append(lists, nsLabelsWithoutOps...) - - podLabelsWithOps, _, _ := parseSelector(toRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - - // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) if portRuleExists { @@ -1538,8 +1585,12 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe entries = append(entries, entry) } + for parsedKey, parsedValue := range lists { + lists[parsedKey] = util.DropEmptyFields(parsedValue) + } + log.Logf("finished parsing egress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), util.DropEmptyFields(lists), ipCidrs, entries + return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries } // Drop all non-whitelisted packets. @@ -1597,11 +1648,11 @@ func getDefaultDropEntries(ns string, targetSelector metav1.LabelSelector, hasIn // 1. ipset set names generated from all podSelectors // 2. ipset list names generated from all namespaceSelectors // 3. iptables entries generated from the input network policy object. -func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []string, [][]string, [][]string, []*iptm.IptEntry) { +func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, map[string][]string, [][]string, [][]string, []*iptm.IptEntry) { var ( resultSets []string resultNamedPorts []string - resultLists []string + resultListMap map[string][]string resultIngressIPCidrs [][]string resultEgressIPCidrs [][]string entries []*iptm.IptEntry @@ -1611,7 +1662,7 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s defer func() { log.Logf("Finished translatePolicy") log.Logf("sets: %v", resultSets) - log.Logf("lists: %v", resultLists) + log.Logf("lists: %v", resultListMap) log.Logf("entries: ") for _, entry := range entries { log.Logf("entry: %+v", entry) @@ -1625,20 +1676,27 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) - resultLists = append(resultLists, ingressLists...) + for resultListKey, resultLists := range ingressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } entries = append(entries, ingressEntries...) egressSets, egressNamedPorts, egressLists, egressIPCidrs, egressEntries := translateEgress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Egress) resultSets = append(resultSets, egressSets...) resultNamedPorts = append(resultNamedPorts, egressNamedPorts...) - resultLists = append(resultLists, egressLists...) + for resultListKey, resultLists := range egressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } entries = append(entries, egressEntries...) hasIngress = len(ingressSets) > 0 hasEgress = len(egressSets) > 0 entries = append(entries, getDefaultDropEntries(npNs, npObj.Spec.PodSelector, hasIngress, hasEgress)...) + for resultListKey, resultLists := range resultListMap { + resultListMap[resultListKey] = util.UniqueStrSlice(resultLists) + } - return util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultNamedPorts), util.UniqueStrSlice(resultLists), ingressIPCidrs, egressIPCidrs, entries + return util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultNamedPorts), resultListMap, ingressIPCidrs, egressIPCidrs, entries } for _, ptype := range npObj.Spec.PolicyTypes { @@ -1646,7 +1704,9 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) - resultLists = append(resultLists, ingressLists...) + for resultListKey, resultLists := range ingressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } resultIngressIPCidrs = ingressIPCidrs entries = append(entries, ingressEntries...) @@ -1664,7 +1724,9 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s egressSets, egressNamedPorts, egressLists, egressIPCidrs, egressEntries := translateEgress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Egress) resultSets = append(resultSets, egressSets...) resultNamedPorts = append(resultNamedPorts, egressNamedPorts...) - resultLists = append(resultLists, egressLists...) + for resultListKey, resultLists := range egressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } resultEgressIPCidrs = egressIPCidrs entries = append(entries, egressEntries...) @@ -1680,7 +1742,10 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s } entries = append(entries, getDefaultDropEntries(npNs, npObj.Spec.PodSelector, hasIngress, hasEgress)...) - resultSets, resultLists = util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultLists) + resultSets = util.UniqueStrSlice(resultSets) + for resultListKey, resultLists := range resultListMap { + resultListMap[resultListKey] = util.UniqueStrSlice(resultLists) + } - return resultSets, resultNamedPorts, resultLists, resultIngressIPCidrs, resultEgressIPCidrs, entries + return resultSets, resultNamedPorts, resultListMap, resultIngressIPCidrs, resultEgressIPCidrs, entries } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 344e383ac9..2b055ed628 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -267,7 +267,8 @@ func TestCraftPartialIptEntryFromSelector(t *testing.T) { }, } - iptEntrySpec := craftPartialIptEntrySpecFromSelector("testnamespace", srcSelector, util.IptablesSrcFlag, false) + // TODO add more test cases here form multi value + iptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector("testnamespace", srcSelector, util.IptablesSrcFlag, false) expectedIptEntrySpec := []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, From ac135bfdbed6f3732ae13e3d2b99e7f371661e25 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:12:51 -0700 Subject: [PATCH 04/34] resolving some references for drop match fields --- npm/translatePolicy.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index e6a1730ef7..cb2c9f2fe9 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -898,14 +898,15 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) log.Logf("started parsing egress rule") - - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - sets = append(sets, labels...) sets = append(sets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) + lists = make(map[string][]string) - targetSelectorIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesSrcFlag, false) + targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) + sets = append(sets, labels...) + for parsedKey, parsedValue := range listLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false @@ -1597,11 +1598,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe func getDefaultDropEntries(ns string, targetSelector metav1.LabelSelector, hasIngress, hasEgress bool) []*iptm.IptEntry { var entries []*iptm.IptEntry - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - - targetSelectorIngressIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesDstFlag, false) - targetSelectorEgressIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesSrcFlag, false) + targetSelectorIngressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) + targetSelectorEgressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) if hasIngress { From 08916ba4252096749f74164837d821a3d21846d1 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 15:19:14 -0700 Subject: [PATCH 05/34] Adding some fixes around nil checks --- npm/parseSelector.go | 3 +++ npm/translatePolicy.go | 11 ++++++++--- npm/translatePolicy_test.go | 2 +- npm/util/util.go | 10 ++++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index cd6859b82d..78230e081e 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -184,6 +184,9 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri keys = append(keys, k) vals[k] = append(vals[k], v) // TODO make sure this removed labels are covered in all cases + // We are not adding the k:v to labels, because, labels are used to contruct + // partial IptEntries and if these below labels are added then we are inducing + // AND condition on value of a match expression //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index cb2c9f2fe9..125965d4ca 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -131,9 +131,12 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec for labelKeyWithOps, labelValueList := range nsLabelListKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) - ops = append(ops, op) - // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists - //labels = append(labels, labelKVIpsetName) + if !util.StrExistsInSlice(labels, labelKVIpsetName) { + ops = append(ops, op) + // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists + // check if the 2nd level is already part of labels + labels = append(labels, labelKVIpsetName) + } for _, labelValue := range labelValueList { ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) valueLabels = append(valueLabels, ipsetName) @@ -161,6 +164,7 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe return "ns-" + ns } + // TODO check if we are missing any crucial comment labelsWithOps, _, _ := parseSelector(selector) ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) @@ -1669,6 +1673,7 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, map npNs := npObj.ObjectMeta.Namespace policyName := npObj.ObjectMeta.Name + resultListMap = make(map[string][]string) if len(npObj.Spec.PolicyTypes) == 0 { ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 2b055ed628..d7d925bd8e 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2776,8 +2776,8 @@ func TestAllowAllFromAppBackend(t *testing.T) { sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) expectedSets := []string{ - "app:backend", "ns-testnamespace", + "app:backend", } if !reflect.DeepEqual(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") diff --git a/npm/util/util.go b/npm/util/util.go index bb73365eea..60f958cdbf 100644 --- a/npm/util/util.go +++ b/npm/util/util.go @@ -322,3 +322,13 @@ func GetLabelKVFromSet(ipsetName string) (string, string) { } return strSplit[0], "" } + +// StrExistsInSlice check if a string already exists in a given slice +func StrExistsInSlice(items []string, val string) bool { + for _, item := range items { + if item == val { + return true + } + } + return false +} From e031817c8faa061dacda0c316b101dfe5a8dbec4 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 17:44:29 -0700 Subject: [PATCH 06/34] ignoring 1 value expr to be added to list mems --- npm/parseSelector.go | 35 +++++++--------- npm/parseSelector_test.go | 87 +++++++-------------------------------- npm/translatePolicy.go | 13 +++++- 3 files changed, 43 insertions(+), 92 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 78230e081e..0dcd8cdede 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -138,33 +138,27 @@ func HashSelector(selector *metav1.LabelSelector) string { } // parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. -func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[string][]string) { +func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]string) { var ( labels []string - keys []string vals map[string][]string ) vals = make(map[string][]string) if selector == nil { - return labels, keys, vals + return labels, vals } if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { labels = append(labels, "") - keys = append(keys, "") - vals[""] = append(vals[""], "") - - return labels, keys, vals + return labels, vals } sortedKeys, sortedVals := util.SortMap(&selector.MatchLabels) for i := range sortedKeys { labels = append(labels, sortedKeys[i]+":"+sortedVals[i]) - vals[sortedKeys[i]] = append(vals[sortedKeys[i]], sortedVals[i]) } - keys = append(keys, sortedKeys...) for _, req := range selector.MatchExpressions { var k string @@ -179,33 +173,36 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri // !pod a !pod:a // case metav1.LabelSelectorOpIn: + k = req.Key + if len(req.Values) == 1 { + labels = append(labels, k+":"+req.Values[0]) + continue + } for _, v := range req.Values { - k = req.Key - keys = append(keys, k) vals[k] = append(vals[k], v) // TODO make sure this removed labels are covered in all cases - // We are not adding the k:v to labels, because, labels are used to contruct - // partial IptEntries and if these below labels are added then we are inducing + // We are not adding the k:v to labels for multiple values, because, labels are used + // to contruct partial IptEntries and if these below labels are added then we are inducing // AND condition on value of a match expression //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: + k = util.IptablesNotFlag + req.Key + if len(req.Values) == 1 { + labels = append(labels, k+":"+req.Values[0]) + continue + } for _, v := range req.Values { - k = util.IptablesNotFlag + req.Key - keys = append(keys, k) vals[k] = append(vals[k], v) - //labels = append(labels, k+":"+v) } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key - keys = append(keys, req.Key) vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key - keys = append(keys, k) vals[k] = append(vals[k], "") labels = append(labels, k) default: @@ -213,5 +210,5 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri } } - return labels, keys, vals + return labels, vals } diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 877530fa9b..6478144661 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -1,9 +1,9 @@ package npm import ( + "container/heap" "reflect" "testing" - "container/heap" "github.com/Azure/azure-container-networking/npm/util" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -89,7 +89,6 @@ func TestGetOperatorAndLabel(t *testing.T) { t.Errorf("TestGetOperatorAndLabel failed @ operator comparison") } - if !reflect.DeepEqual(resultLabels, expectedLabels) { t.Errorf("TestGetOperatorAndLabel failed @ label comparison") } @@ -136,7 +135,7 @@ func TestReqHeap(t *testing.T) { metav1.LabelSelectorRequirement{ Key: "a", Operator: metav1.LabelSelectorOpIn, - Values: []string{}, + Values: []string{}, }, metav1.LabelSelectorRequirement{ Key: "testIn", @@ -164,7 +163,7 @@ func TestReqHeap(t *testing.T) { metav1.LabelSelectorRequirement{ Key: "a", Operator: metav1.LabelSelectorOpIn, - Values: []string{}, + Values: []string{}, }, metav1.LabelSelectorRequirement{ Key: "testIn", @@ -272,7 +271,7 @@ func TestHashSelector(t *testing.T) { "c": "d", }, } - + secondSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ metav1.LabelSelectorRequirement{ @@ -302,17 +301,13 @@ func TestHashSelector(t *testing.T) { func TestParseSelector(t *testing.T) { var selector, expectedSelector *metav1.LabelSelector selector, expectedSelector = nil, nil - labels, keys, vals := parseSelector(selector) - expectedLabels, expectedKeys, expectedVals := []string{}, []string{}, []string{} + labels, vals := parseSelector(selector) + expectedLabels, expectedVals := []string{}, []string{} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -322,16 +317,12 @@ func TestParseSelector(t *testing.T) { } selector = &metav1.LabelSelector{} - labels, keys, vals = parseSelector(selector) - expectedLabels, expectedKeys, expectedVals = []string{""}, []string{""}, []string{""} + labels, vals = parseSelector(selector) + expectedLabels, expectedVals = []string{""}, []string{""} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -349,15 +340,11 @@ func TestParseSelector(t *testing.T) { }, } - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) expectedLabels = []string{ "testIn:frontend", "testIn:backend", } - expectedKeys = []string{ - "testIn", - "testIn", - } expectedVals = []string{ "frontend", "backend", @@ -367,20 +354,13 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -397,41 +377,29 @@ func TestParseSelector(t *testing.T) { me := &selector.MatchExpressions *me = append(*me, notIn) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels := []string{ "!testNotIn:frontend", "!testNotIn:backend", } - addedKeys := []string{ - "!testNotIn", - "!testNotIn", - } addedVals := []string{ "frontend", "backend", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -444,38 +412,27 @@ func TestParseSelector(t *testing.T) { *me = append(*me, exists) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels = []string{ "testExists", } - addedKeys = []string{ - "testExists", - } addedVals = []string{ "", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -488,29 +445,21 @@ func TestParseSelector(t *testing.T) { *me = append(*me, doesNotExist) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels = []string{ "!testDoesNotExist", } - addedKeys = []string{ - "!testDoesNotExist", - } addedVals = []string{ "", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -518,10 +467,6 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } - if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 125965d4ca..6defb56c4a 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -122,8 +122,9 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors +// TODO check all references of this func func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { - labelsWithOps, _, nsLabelListKVs := parseSelector(selector) + labelsWithOps, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) valueLabels := []string{} listLabelsWithMembers := make(map[string][]string) @@ -165,8 +166,16 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe } // TODO check if we are missing any crucial comment - labelsWithOps, _, _ := parseSelector(selector) + labelsWithOps, labelKVs := parseSelector(selector) ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) + for labelKeyWithOps, labelValueList := range labelKVs { + op, labelKey := GetOperatorAndLabel(labelKeyWithOps) + for _, labelValue := range labelValueList { + ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) + labelsWithoutOps = append(labelsWithoutOps, ipsetName) + ops = append(ops, op) + } + } var comment, prefix, postfix string if isNamespaceSelector { From 8180aae06cbe7a9e4b53e13bef1c2853b72fbe82 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 22:05:41 -0700 Subject: [PATCH 07/34] not adding lists to the setMap --- npm/networkPolicyController.go | 2 +- npm/translatePolicy.go | 59 +++++++++++++++++----------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 51436a5511..24c2fe333e 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -359,7 +359,7 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 } for _, listMember := range listLabelsMembers { if err = ipsMgr.AddToList(listKey, listMember); err != nil { - return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipst member %s to ipset list %s with err: %v", listMember, listKey, err) + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipset member %s to ipset list %s with err: %v", listMember, listKey, err) } } ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 6defb56c4a..de0e7bb2eb 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -127,6 +127,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec labelsWithOps, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) valueLabels := []string{} + labelsForSpec := labels listLabelsWithMembers := make(map[string][]string) // TODO add comments very confusing for sure for labelKeyWithOps, labelValueList := range nsLabelListKVs { @@ -136,7 +137,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec ops = append(ops, op) // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists // check if the 2nd level is already part of labels - labels = append(labels, labelKVIpsetName) + labelsForSpec = append(labelsForSpec, labelKVIpsetName) } for _, labelValue := range labelValueList { ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) @@ -144,7 +145,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec listLabelsWithMembers[labelKVIpsetName] = append(listLabelsWithMembers[labelKVIpsetName], ipsetName) } } - iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labelsForSpec, srcOrDstFlag, isNamespaceSelector) // only append valueLabels to labels after creating the Ipt Spec as valueLabels // are included in labelKVIpsetName labels = append(labels, valueLabels...) @@ -213,8 +214,8 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) sets = append(sets, labels...) - for parsedKey, parsedValue := range listLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) @@ -473,9 +474,9 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) @@ -579,9 +580,9 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } } sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { @@ -691,14 +692,14 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) @@ -917,8 +918,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) sets = append(sets, labels...) - for parsedKey, parsedValue := range listLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { @@ -1181,9 +1182,9 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) @@ -1285,11 +1286,11 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } - for parsedKey, parsedValue := range listPodLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) - } sets = append(sets, podLabelsWithoutOps...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) + } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1399,14 +1400,14 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) From 6c7ae92ad259f50713ee57af66659ed5923496a0 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 11:54:53 -0700 Subject: [PATCH 08/34] correcting some UTs --- npm/parseSelector.go | 2 -- npm/parseSelector_test.go | 55 ++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 0dcd8cdede..8bb4439052 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -198,12 +198,10 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key - vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key - vals[k] = append(vals[k], "") labels = append(labels, k) default: log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector) diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 6478144661..c9b181c1d1 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -302,7 +302,7 @@ func TestParseSelector(t *testing.T) { var selector, expectedSelector *metav1.LabelSelector selector, expectedSelector = nil, nil labels, vals := parseSelector(selector) - expectedLabels, expectedVals := []string{}, []string{} + expectedLabels, expectedVals := []string{}, make(map[string][]string) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -318,7 +318,7 @@ func TestParseSelector(t *testing.T) { selector = &metav1.LabelSelector{} labels, vals = parseSelector(selector) - expectedLabels, expectedVals = []string{""}, []string{""} + expectedLabels = []string{""} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } @@ -341,13 +341,12 @@ func TestParseSelector(t *testing.T) { } labels, vals = parseSelector(selector) - expectedLabels = []string{ - "testIn:frontend", - "testIn:backend", - } - expectedVals = []string{ - "frontend", - "backend", + expectedLabels = []string{} + expectedVals = map[string][]string{ + "testIn": { + "frontend", + "backend", + }, } if len(labels) != len(expectedLabels) { @@ -358,7 +357,7 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ vals length comparison") } - if !reflect.DeepEqual(labels, expectedLabels) { + if labels != nil { t.Errorf("TestparseSelector failed @ label comparison") } if !reflect.DeepEqual(vals, expectedVals) { @@ -378,16 +377,18 @@ func TestParseSelector(t *testing.T) { *me = append(*me, notIn) labels, vals = parseSelector(selector) - addedLabels := []string{ - "!testNotIn:frontend", - "!testNotIn:backend", - } - addedVals := []string{ - "frontend", - "backend", + addedLabels := []string{} + addedVals := map[string][]string{ + "!testNotIn": { + "frontend", + "backend", + }, } + expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -397,7 +398,7 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ vals length comparison") } - if !reflect.DeepEqual(labels, expectedLabels) { + if labels != nil { t.Errorf("TestparseSelector failed @ label comparison") } if !reflect.DeepEqual(vals, expectedVals) { @@ -416,11 +417,11 @@ func TestParseSelector(t *testing.T) { addedLabels = []string{ "testExists", } - addedVals = []string{ - "", - } + addedVals = map[string][]string{} expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -449,11 +450,11 @@ func TestParseSelector(t *testing.T) { addedLabels = []string{ "!testDoesNotExist", } - addedVals = []string{ - "", - } + addedVals = map[string][]string{} expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") From 5299dc5fbf591d75d3022e79c080b9c5a23cdcd3 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 14:46:28 -0700 Subject: [PATCH 09/34] Correcting UTs. --- npm/translatePolicy.go | 8 +++----- npm/translatePolicy_test.go | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index de0e7bb2eb..b61282b224 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -171,11 +171,9 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) for labelKeyWithOps, labelValueList := range labelKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) - for _, labelValue := range labelValueList { - ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) - labelsWithoutOps = append(labelsWithoutOps, ipsetName) - ops = append(ops, op) - } + labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) + labelsWithoutOps = append(labelsWithoutOps, labelKVIpsetName) + ops = append(ops, op) } var comment, prefix, postfix string diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index d7d925bd8e..4bbba0862f 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -344,7 +344,7 @@ func TestCraftPartialIptablesCommentFromSelector(t *testing.T) { }, } comment = craftPartialIptablesCommentFromSelector("testnamespace", selector, false) - expectedComment = "k0:v0-AND-k1:v10-AND-k1:v11-AND-!k2-IN-ns-testnamespace" + expectedComment = "k0:v0-AND-!k2-AND-k1:v10:v11-IN-ns-testnamespace" if comment != expectedComment { t.Errorf("TestCraftPartialIptablesCommentFromSelector failed @ normal selector comparison") t.Errorf("comment:\n%v", comment) @@ -372,7 +372,7 @@ func TestCraftPartialIptablesCommentFromSelector(t *testing.T) { }, } comment = craftPartialIptablesCommentFromSelector("", nsSelector, true) - expectedComment = "ns-k0:v0-AND-ns-k1:v10-AND-ns-k1:v11-AND-ns-!k2" + expectedComment = "ns-k0:v0-AND-ns-!k2-AND-ns-k1:v10:v11" if comment != expectedComment { t.Errorf("TestCraftPartialIptablesCommentFromSelector failed @ namespace selector comparison") t.Errorf("comment:\n%v", comment) From bf83fd4683be3710dd6963f60e77d712ecdbfdfb Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 18:55:18 -0700 Subject: [PATCH 10/34] fixing all UTs --- npm/translatePolicy_test.go | 299 +++++++++++++++++++++--------------- npm/util/util.go | 9 ++ npm/util/util_test.go | 56 +++++++ 3 files changed, 238 insertions(+), 126 deletions(-) diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 4bbba0862f..1d68f20da1 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -653,17 +653,17 @@ func TestTranslateIngress(t *testing.T) { "k", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedIngress failed @ sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", - "ns-testIn:frontendns", - "ns-planet:earth", - "ns-keyExists", + expectedLists := map[string][]string{ + "ns-ns:dev": nil, + "ns-testIn:frontendns": nil, + "ns-planet:earth": nil, + "ns-keyExists": nil, } if !reflect.DeepEqual(lists, expectedLists) { @@ -965,17 +965,17 @@ func TestTranslateEgress(t *testing.T) { "k", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedEgress failed @ sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", - "ns-testIn:frontendns", - "ns-planet:earth", - "ns-keyExists", + expectedLists := map[string][]string{ + "ns-ns:dev": nil, + "ns-testIn:frontendns": nil, + "ns-planet:earth": nil, + "ns-keyExists": nil, } if !reflect.DeepEqual(lists, expectedLists) { @@ -1192,13 +1192,13 @@ func TestDenyAllPolicy(t *testing.T) { sets, _, lists, _, _, iptEntries := translatePolicy(denyAllPolicy) expectedSets := []string{"ns-testnamespace"} - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ deny-all-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ deny-all-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1228,13 +1228,13 @@ func TestAllowBackendToFrontend(t *testing.T) { "ns-testnamespace", "app:frontend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1367,13 +1367,13 @@ func TestAllowAllToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1430,13 +1430,13 @@ func TestDenyAllToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1466,13 +1466,13 @@ func TestNamespaceToFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ns-testnamespace-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ns-testnamespace-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1599,14 +1599,14 @@ func TestAllowAllNamespacesToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-namespaces-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - util.KubeAllNamespacesFlag, + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-namespaces-TO-app:frontend-policy lists comparison") @@ -1735,19 +1735,23 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy sets comparison") + if !util.CompareSlices(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-namespace:dev", - "ns-namespace:test0", - "ns-namespace:test1", + expectedLists := map[string][]string{ + "ns-namespace:dev": {}, + "ns-namespace:test0": {}, + "ns-namespace:test1": {}, + "ns-namespace:test0:test1": { + "namespace:test0", + "namespace:test1", + }, } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy lists comparison") + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -1766,13 +1770,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesSetModuleFlag, util.IptablesNotFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-namespace:test0"), - util.IptablesSrcFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesNotFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("ns-namespace:test1"), + util.GetHashedName("ns-namespace:test0:test1"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, @@ -1791,7 +1789,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0-AND-ns-!namespace:test1-TO-app:frontend-IN-ns-testnamespace", + "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0:test1-TO-app:frontend-IN-ns-testnamespace", }, }, &iptm.IptEntry{ @@ -1866,7 +1864,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowNsDevToFrontendPolicy.Spec.PodSelector, false, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy policy comparison") + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -1889,15 +1887,21 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { "k1:v1", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{util.KubeAllNamespacesFlag} + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, + "k1:v0:v1": { + "k1:v0", + "k1:v1", + }, + } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy lists comparison") + t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0:v1-AND-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -1931,12 +1935,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesMark, @@ -1945,7 +1944,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-all-namespaces-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace", + "ALLOW-all-namespaces-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace", }, }, &iptm.IptEntry{ @@ -1971,19 +1970,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesAzureIngressFromChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace-TO-JUMP-TO-" + + "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace-TO-JUMP-TO-" + util.IptablesAzureIngressFromChain, }, }, @@ -2010,19 +2004,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesAzureIngressDropsChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace-TO-JUMP-TO-" + + "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace-TO-JUMP-TO-" + util.IptablesAzureIngressDropsChain, }, }, @@ -2048,19 +2037,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesDrop, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "DROP-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace", + "DROP-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace", }, }, } @@ -2068,7 +2052,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllToFrontendPolicy.Spec.PodSelector, false, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ AllOW-all-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy policy comparison") + t.Errorf("translatedPolicy failed @ AllOW-all-TO-k0-AND-k1:v0:v1-AND-app:frontend-policy policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -2090,14 +2074,14 @@ func TestAllowNsDevAndAppBackendToAppFrontend(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ns-ns:dev-AND-app:backend-TO-app:frontend sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", + expectedLists := map[string][]string{ + "ns-ns:dev": {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ns-ns:dev-AND-app:backend-TO-app:frontend lists comparison") @@ -2232,13 +2216,13 @@ func TestAllowInternalAndExternal(t *testing.T) { "app:backdoor", "ns-dangerous", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TO-app:backdoor-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TO-app:backdoor-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2296,13 +2280,13 @@ func TestAllowBackendToFrontendPort8000(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2415,13 +2399,13 @@ func TestAllowBackendToFrontendWithMissingPort(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2536,13 +2520,13 @@ func TestAllowMultipleLabelsToMultipleLabels(t *testing.T) { "binary:cns", "group:container", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-program:cni-AND-team:acn-OR-binary:cns-AND-group:container-TO-app:k8s-AND-team:aks-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-program:cni-AND-team:acn-OR-binary:cns-AND-group:container-TO-app:k8s-AND-team:aks-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2743,13 +2727,13 @@ func TestDenyAllFromAppBackend(t *testing.T) { "app:backend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2779,13 +2763,13 @@ func TestAllowAllFromAppBackend(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2854,28 +2838,52 @@ func TestAllowAllFromAppBackend(t *testing.T) { } func TestAllowMultiplePodSelectors(t *testing.T) { - allowAllEgress, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") + multiPodSlector, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") if err != nil { t.Fatal(err) } util.IsNewNwPolicyVerFlag = true - sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) + sets, _, lists, _, _, iptEntries := translatePolicy(multiPodSlector) expectedSets := []string{ - "app:backend", - "ns-testnamespace", + "ns-netpol-4537-x", + "pod:a", + "pod:x", + "pod:b", + "pod:c", + "app:test", + "app:int", } - if !reflect.DeepEqual(sets, expectedSets) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") + if !util.CompareSlices(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := map[string][]string{ + "app:test:int": { + "app:test", + "app:int", + }, + "ns-ns:netpol-4537-x": {}, + "ns-ns:netpol-4537-x:netpol-4537-y": { + "ns:netpol-4537-x", + "ns:netpol-4537-y", + }, + "ns-ns:netpol-4537-y": {}, + "pod:a:x": { + "pod:a", + "pod:x", + }, + "pod:b:c": { + "pod:b", + "pod:c", + }, + } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -2883,57 +2891,96 @@ func TestAllowMultiplePodSelectors(t *testing.T) { expectedIptEntries := []*iptm.IptEntry{} nonKubeSystemEntries := []*iptm.IptEntry{ &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, + Chain: util.IptablesAzureIngressFromChain, Specs: []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-testnamespace"), + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesNotFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-ns:netpol-4537-x:netpol-4537-y"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("app:backend"), + util.GetHashedName("pod:b:c"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:test:int"), util.IptablesSrcFlag, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, - util.IptablesAzureEgressXMarkHex, + util.IptablesAzureIngressMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace", + "ALLOW-ns-!ns:netpol-4537-x:netpol-4537-y-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", }, }, &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, + Chain: util.IptablesAzureIngressPortChain, IsJumpEntry: true, Specs: []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-testnamespace"), - util.IptablesSrcFlag, + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("app:backend"), - util.IptablesSrcFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, util.IptablesJumpFlag, - util.IptablesAzureEgressDropsChain, + util.IptablesAzureIngressFromChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - fmt.Sprintf("ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace-TO-JUMP-TO-%s", - util.IptablesAzureEgressDropsChain), + fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", + util.IptablesAzureIngressFromChain), + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureIngressFromChain, + IsJumpEntry: true, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, + util.IptablesJumpFlag, + util.IptablesAzureIngressDropsChain, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", + util.IptablesAzureIngressDropsChain), }, }, } expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) // has egress, but empty map means allow all - expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllEgress.Spec.PodSelector, false, false)...) + expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("netpol-4537-x", multiPodSlector.Spec.PodSelector, true, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy policy comparison") + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -2951,12 +2998,12 @@ func TestDenyAllFromNsUnsafe(t *testing.T) { expectedSets := []string{ "ns-unsafe", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-ns-unsafe-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2986,14 +3033,14 @@ func TestAllowAppFrontendToTCPPort53UDPPort53Policy(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-FROM-app:frontend-TCP-PORT-53-OR-UDP-PORT-53-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - util.KubeAllNamespacesFlag, + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-FROM-app:frontend-TCP-PORT-53-OR-UDP-PORT-53-policy lists comparison") @@ -3179,14 +3226,14 @@ func TestComplexPolicy(t *testing.T) { "ns-default", "role:frontend", } - if !reflect.DeepEqual(sets, expectedSets) || !reflect.DeepEqual(setsDiffOrder, expectedSets) { + if !util.CompareSlices(sets, expectedSets) || !util.CompareSlices(setsDiffOrder, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-project:myproject", + expectedLists := map[string][]string{ + "ns-project:myproject": {}, } if !reflect.DeepEqual(lists, expectedLists) || !reflect.DeepEqual(listsDiffOrder, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") @@ -3588,13 +3635,13 @@ func TestDropPrecedenceOverAllow(t *testing.T) { expectedSets := []string{ "ns-default", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") t.Errorf("lists: %v", lists) @@ -3609,14 +3656,14 @@ func TestDropPrecedenceOverAllow(t *testing.T) { "testIn:pod-B", "testIn:pod-C", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists = []string{ - "all-namespaces", + expectedLists = map[string][]string{ + "all-namespaces": {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") @@ -3953,7 +4000,7 @@ func TestNamedPorts(t *testing.T) { "app:server", "ns-test", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TCP-PORT-serve-80-TO-app:server-IN-ns-test-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) @@ -3968,7 +4015,7 @@ func TestNamedPorts(t *testing.T) { t.Errorf("expectedSets: %v", expectedNamedPorts) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TCP-PORT-serve-80-TO-app:server-IN-ns-test-policy lists comparison") t.Errorf("lists: %v", lists) diff --git a/npm/util/util.go b/npm/util/util.go index 60f958cdbf..09d7b7d0d1 100644 --- a/npm/util/util.go +++ b/npm/util/util.go @@ -332,3 +332,12 @@ func StrExistsInSlice(items []string, val string) bool { } return false } + +func CompareSlices(list1, list2 []string) bool { + for _, item := range list1 { + if !StrExistsInSlice(list2, item) { + return false + } + } + return true +} diff --git a/npm/util/util_test.go b/npm/util/util_test.go index 0452d2b976..d1b5b51bfb 100644 --- a/npm/util/util_test.go +++ b/npm/util/util_test.go @@ -270,3 +270,59 @@ func TestParseResourceVersion(t *testing.T) { t.Errorf("TestParseResourceVersion failed @ inavlid RV gave no error") } } + +func TestCompareSlices(t *testing.T) { + list1 := []string{ + "a", + "b", + "c", + "d", + } + list2 := []string{ + "c", + "d", + "a", + "b", + } + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 1") + } + + list2 = []string{ + "c", + "a", + "b", + } + + if CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 2") + } + list1 = []string{ + "a", + "b", + "c", + "d", + "123", + "44", + } + list2 = []string{ + "c", + "44", + "d", + "a", + "b", + "123", + } + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 3") + } + + list1 = []string{} + list2 = []string{} + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 4") + } +} From 928d281853c3da3580ed2ecc7494683d26eb004f Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 5 May 2021 10:55:54 -0700 Subject: [PATCH 11/34] Adding and cleaning some comments --- npm/networkPolicyController.go | 13 +++++++++---- npm/parseSelector.go | 23 ++++++++--------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 24c2fe333e..85eec3c0cf 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -351,8 +351,9 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset named port %s with err: %v", set, err) } } - // (TODO) now add the []string value of the lists into a new obj - // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + + // lists is a map with list name and members as value + // NPM will create the list first, add members to it and increments the refer count for listKey, listLabelsMembers := range lists { if err = ipsMgr.CreateList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) @@ -402,9 +403,13 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC return fmt.Errorf("[cleanUpNetworkPolicy] Error: failed to apply iptables rule. Rule: %+v with err: %v", iptEntry, err) } } - // (TODO) now add the []string value of the lists into a new obj - // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + + // lists is a map with list name and members as value for listKey, _ := range lists { + // We do not have delete the members before deleting set as, + // 1. ipset allows deleting a ipset list with members + // 2. if the refer count is more than one we should not remove members + // 3. for reduced datapath operations if err = ipsMgr.DeleteList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 8bb4439052..207cd737de 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -137,7 +137,11 @@ func HashSelector(selector *metav1.LabelSelector) string { return util.Hash(fmt.Sprintf("%v", selector)) } -// parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. +// parseSelector takes a LabelSelector and returns a slice of processed labels, Lists with members as values. +// this function returns +// +// +// func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]string) { var ( labels []string @@ -163,28 +167,17 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin for _, req := range selector.MatchExpressions { var k string switch op := req.Operator; op { - // TODO remove this - // - key: pod - // operator: NotIn - // values: - // - b - // - c - // !pod b !pod:b - // !pod a !pod:a - // case metav1.LabelSelectorOpIn: k = req.Key if len(req.Values) == 1 { labels = append(labels, k+":"+req.Values[0]) continue } + // We are not adding the k:v to labels for multiple values, because, labels are used + // to contruct partial IptEntries and if these below labels are added then we are inducing + // AND condition on values of a match expression instead of OR for _, v := range req.Values { vals[k] = append(vals[k], v) - // TODO make sure this removed labels are covered in all cases - // We are not adding the k:v to labels for multiple values, because, labels are used - // to contruct partial IptEntries and if these below labels are added then we are inducing - // AND condition on value of a match expression - //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: k = util.IptablesNotFlag + req.Key From 0553248b1103b04bbf36a68599a68dcb9cfdbed5 Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 3 Mar 2021 11:46:52 -0800 Subject: [PATCH 12/34] basic scenario and investigation --- npm/testpolicies/allow-ns-y-z-pod-b-c.yaml | 26 +++++++ npm/translatePolicy.go | 1 + npm/translatePolicy_test.go | 88 ++++++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 npm/testpolicies/allow-ns-y-z-pod-b-c.yaml diff --git a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml new file mode 100644 index 0000000000..5c5df632f0 --- /dev/null +++ b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml @@ -0,0 +1,26 @@ +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: allow-ns-y-z-pod-b-c + namespace: netpol-4537-x +spec: + ingress: + - from: + - namespaceSelector: + matchExpressions: + - key: ns + operator: NotIn + values: + - netpol-4537-x + podSelector: + matchExpressions: + - key: pod + operator: In + values: + - b + - c + podSelector: + matchLabels: + pod: a + policyTypes: + - Ingress diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 288d309b35..0ff4cec055 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -113,6 +113,7 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } for i, _ := range ops { + // TODO need to change this logic, create a list of lsts here and have a single match against it spec = append(spec, craftPartialIptEntrySpecFromOpAndLabel(ops[i], labels[i], srcOrDstFlag, isNamespaceSelector)...) } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index f1e28c9f64..344e383ac9 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2852,6 +2852,94 @@ func TestAllowAllFromAppBackend(t *testing.T) { } } +func TestAllowMultiplePodSelectors(t *testing.T) { + allowAllEgress, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") + if err != nil { + t.Fatal(err) + } + + util.IsNewNwPolicyVerFlag = true + + sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) + + expectedSets := []string{ + "app:backend", + "ns-testnamespace", + } + if !reflect.DeepEqual(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") + t.Errorf("sets: %v", sets) + t.Errorf("expectedSets: %v", expectedSets) + } + + expectedLists := []string{} + if !reflect.DeepEqual(lists, expectedLists) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") + t.Errorf("lists: %v", lists) + t.Errorf("expectedLists: %v", expectedLists) + } + + expectedIptEntries := []*iptm.IptEntry{} + nonKubeSystemEntries := []*iptm.IptEntry{ + &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-testnamespace"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:backend"), + util.IptablesSrcFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureEgressXMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace", + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + IsJumpEntry: true, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-testnamespace"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:backend"), + util.IptablesSrcFlag, + util.IptablesJumpFlag, + util.IptablesAzureEgressDropsChain, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + fmt.Sprintf("ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace-TO-JUMP-TO-%s", + util.IptablesAzureEgressDropsChain), + }, + }, + } + expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) + // has egress, but empty map means allow all + expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllEgress.Spec.PodSelector, false, false)...) + if !reflect.DeepEqual(iptEntries, expectedIptEntries) { + t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy policy comparison") + marshalledIptEntries, _ := json.Marshal(iptEntries) + marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) + t.Errorf("iptEntries: %s", marshalledIptEntries) + t.Errorf("expectedIptEntries: %s", marshalledExpectedIptEntries) + } +} + func TestDenyAllFromNsUnsafe(t *testing.T) { denyAllFromNsUnsafePolicy, err := readPolicyYaml("testpolicies/deny-all-from-ns-unsafe.yaml") if err != nil { From 661bbb412714ded1b78082cdf95631be48217dd7 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:01:26 -0700 Subject: [PATCH 13/34] adding some basic imcrements to yaml --- npm/npm.go | 2 +- npm/parseSelector.go | 55 +++++++++++++++------- npm/testpolicies/allow-ns-y-z-pod-b-c.yaml | 14 +++++- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/npm/npm.go b/npm/npm.go index 2f6429308a..15add9cd84 100644 --- a/npm/npm.go +++ b/npm/npm.go @@ -161,7 +161,7 @@ func (npMgr *NetworkPolicyManager) backup() { time.Sleep(backupWaitTimeInSeconds * time.Second) if err = iptMgr.Save(util.IptablesConfigFile); err != nil { - metrics.SendErrorLogAndMetric(util.NpmID, "Error: failed to back up Azure-NPM states") + metrics.SendErrorLogAndMetric(util.NpmID, "Error: failed to back up Azure-NPM states %s", err.Error()) } } } diff --git a/npm/parseSelector.go b/npm/parseSelector.go index f762aef3b1..cd6859b82d 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -1,9 +1,9 @@ package npm import ( + "container/heap" "fmt" "sort" - "container/heap" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -14,18 +14,18 @@ import ( // An ReqHeap is a min-heap of labelSelectorRequirements. type ReqHeap []metav1.LabelSelectorRequirement -func (h ReqHeap) Len() int { +func (h ReqHeap) Len() int { return len(h) } func (h ReqHeap) Less(i, j int) bool { sort.Strings(h[i].Values) sort.Strings(h[j].Values) - + if int(h[i].Key[0]) < int(h[j].Key[0]) { return true } - + if int(h[i].Key[0]) > int(h[j].Key[0]) { return false } @@ -37,7 +37,7 @@ func (h ReqHeap) Less(i, j int) bool { if len(h[j].Values) == 0 { return false } - + if len(h[i].Values[0]) == 0 { return true } @@ -61,8 +61,8 @@ func (h *ReqHeap) Push(x interface{}) { func (h *ReqHeap) Pop() interface{} { old := *h n := len(old) - x := old[n -1] - *h = old[0 : n - 1] + x := old[n-1] + *h = old[0 : n-1] return x } @@ -121,6 +121,16 @@ func sortSelector(selector *metav1.LabelSelector) { selector.MatchExpressions = sortedReqs } +// getSetNameForMultiValueSelector takes in label with multiple values without operator +// and returns a new 2nd level ipset name +func getSetNameForMultiValueSelector(key string, vals []string) string { + rtStr := key + for _, val := range vals { + rtStr = util.GetIpSetFromLabelKV(rtStr, val) + } + return rtStr +} + // HashSelector returns the hash value of the selector. func HashSelector(selector *metav1.LabelSelector) string { sortSelector(selector) @@ -128,13 +138,14 @@ func HashSelector(selector *metav1.LabelSelector) string { } // parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. -func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string) { +func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[string][]string) { var ( labels []string keys []string - vals []string + vals map[string][]string ) + vals = make(map[string][]string) if selector == nil { return labels, keys, vals } @@ -142,7 +153,7 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { labels = append(labels, "") keys = append(keys, "") - vals = append(vals, "") + vals[""] = append(vals[""], "") return labels, keys, vals } @@ -151,38 +162,48 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, []string for i := range sortedKeys { labels = append(labels, sortedKeys[i]+":"+sortedVals[i]) + vals[sortedKeys[i]] = append(vals[sortedKeys[i]], sortedVals[i]) } keys = append(keys, sortedKeys...) - vals = append(vals, sortedVals...) for _, req := range selector.MatchExpressions { var k string switch op := req.Operator; op { + // TODO remove this + // - key: pod + // operator: NotIn + // values: + // - b + // - c + // !pod b !pod:b + // !pod a !pod:a + // case metav1.LabelSelectorOpIn: for _, v := range req.Values { k = req.Key keys = append(keys, k) - vals = append(vals, v) - labels = append(labels, k+":"+v) + vals[k] = append(vals[k], v) + // TODO make sure this removed labels are covered in all cases + //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: for _, v := range req.Values { k = util.IptablesNotFlag + req.Key keys = append(keys, k) - vals = append(vals, v) - labels = append(labels, k+":"+v) + vals[k] = append(vals[k], v) + //labels = append(labels, k+":"+v) } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key keys = append(keys, req.Key) - vals = append(vals, "") + vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key keys = append(keys, k) - vals = append(vals, "") + vals[k] = append(vals[k], "") labels = append(labels, k) default: log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector) diff --git a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml index 5c5df632f0..71cb960a9b 100644 --- a/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml +++ b/npm/testpolicies/allow-ns-y-z-pod-b-c.yaml @@ -12,6 +12,7 @@ spec: operator: NotIn values: - netpol-4537-x + - netpol-4537-y podSelector: matchExpressions: - key: pod @@ -19,8 +20,17 @@ spec: values: - b - c + - key: app + operator: In + values: + - test + - int podSelector: - matchLabels: - pod: a + matchExpressions: + - key: pod + operator: In + values: + - a + - x policyTypes: - Ingress From 7fc64196534f770a3fad82f15865a6df7a9b5f25 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:02:50 -0700 Subject: [PATCH 14/34] First pass at adding 2nd level ipsets for multi value selector expressions --- npm/ipsm/ipsm.go | 68 ++++++----- npm/ipsm/ipsm_test.go | 21 ---- npm/networkPolicyController.go | 23 +++- npm/translatePolicy.go | 213 +++++++++++++++++++++------------ npm/translatePolicy_test.go | 3 +- 5 files changed, 199 insertions(+), 129 deletions(-) diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index f2aeba6032..d61b8cfb29 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -16,6 +16,14 @@ import ( "github.com/Azure/azure-container-networking/npm/util" ) +// ReferCountOperation is used to indicate whether ipset refer count should be increased or decreased. +type ReferCountOperation bool + +const ( + IncrementOp ReferCountOperation = true + DecrmentOp ReferCountOperation = false +) + type ipsEntry struct { operationFlag string name string @@ -36,11 +44,20 @@ type Ipset struct { referCount int } +func (ipset *Ipset) IncReferCount() { + ipset.referCount++ +} + +func (ipset *Ipset) DecReferCount() { + ipset.referCount-- +} + // NewIpset creates a new instance for Ipset object. func NewIpset(setName string) *Ipset { return &Ipset{ - name: setName, - elements: make(map[string]string), + name: setName, + elements: make(map[string]string), + referCount: 0, } } @@ -70,6 +87,21 @@ func (ipsMgr *IpsetManager) Exists(listName string, setName string, kind string) return true } +// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases tis refer count. +func (ipsMgr *IpsetManager) IpSetReferIncOrDec(ipsetName string, kind string, countOperation ReferCountOperation) { + m := ipsMgr.SetMap + if kind == util.IpsetSetListFlag { + m = ipsMgr.ListMap + } + + switch countOperation { + case IncrementOp: + m[ipsetName].IncReferCount() + case DecrmentOp: + m[ipsetName].DecReferCount() + } +} + // SetExists checks if an ipset exists, and returns the type func (ipsMgr *IpsetManager) SetExists(setName string) (bool, string) { _, exists := ipsMgr.SetMap[setName] @@ -119,6 +151,11 @@ func (ipsMgr *IpsetManager) DeleteList(listName string) error { set: util.GetHashedName(listName), } + if ipsMgr.ListMap[listName].referCount > 0 { + ipsMgr.IpSetReferIncOrDec(listName, util.IpsetSetListFlag, DecrmentOp) + return nil + } + if errCode, err := ipsMgr.Run(entry); err != nil { if errCode == 1 { return nil @@ -425,33 +462,6 @@ func (ipsMgr *IpsetManager) DeleteFromSet(setName, ip, podKey string) error { return nil } -// Clean removes all the empty sets & lists under the namespace. -func (ipsMgr *IpsetManager) Clean() error { - for setName, set := range ipsMgr.SetMap { - if len(set.elements) > 0 { - continue - } - - if err := ipsMgr.DeleteSet(setName); err != nil { - metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset") - return err - } - } - - for listName, list := range ipsMgr.ListMap { - if len(list.elements) > 0 { - continue - } - - if err := ipsMgr.DeleteList(listName); err != nil { - metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset list") - return err - } - } - - return nil -} - // Destroy completely cleans ipset. func (ipsMgr *IpsetManager) Destroy() error { entry := &ipsEntry{ diff --git a/npm/ipsm/ipsm_test.go b/npm/ipsm/ipsm_test.go index 5f98876d9f..9f6a70c8fd 100644 --- a/npm/ipsm/ipsm_test.go +++ b/npm/ipsm/ipsm_test.go @@ -465,27 +465,6 @@ func TestDeleteFromSetWithPodCache(t *testing.T) { } } -func TestClean(t *testing.T) { - ipsMgr := NewIpsetManager() - if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Save") - } - - defer func() { - if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Restore") - } - }() - - if err := ipsMgr.CreateSet("test-set", append([]string{util.IpsetNetHashFlag})); err != nil { - t.Errorf("TestClean failed @ ipsMgr.CreateSet with err %+v", err) - } - - if err := ipsMgr.Clean(); err != nil { - t.Errorf("TestClean failed @ ipsMgr.Clean") - } -} - func TestDestroy(t *testing.T) { ipsMgr := NewIpsetManager() if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 5134f9ceec..51436a5511 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -351,10 +351,18 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset named port %s with err: %v", set, err) } } - for _, list := range lists { - if err = ipsMgr.CreateList(list); err != nil { - return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", list, err) + // (TODO) now add the []string value of the lists into a new obj + // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + for listKey, listLabelsMembers := range lists { + if err = ipsMgr.CreateList(listKey); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } + for _, listMember := range listLabelsMembers { + if err = ipsMgr.AddToList(listKey, listMember); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipst member %s to ipset list %s with err: %v", listMember, listKey, err) + } + } + ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp) } if err = c.createCidrsRule("in", netPolObj.ObjectMeta.Name, netPolObj.ObjectMeta.Namespace, ingressIPCidrs, ipsMgr); err != nil { @@ -385,7 +393,7 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC ipsMgr := c.npMgr.NsMap[util.KubeAllNamespacesFlag].IpsMgr iptMgr := c.npMgr.NsMap[util.KubeAllNamespacesFlag].iptMgr // translate policy from "cachedNetPolObj" - _, _, _, ingressIPCidrs, egressIPCidrs, iptEntries := translatePolicy(cachedNetPolObj) + _, _, lists, ingressIPCidrs, egressIPCidrs, iptEntries := translatePolicy(cachedNetPolObj) var err error // delete iptables entries @@ -394,6 +402,13 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC return fmt.Errorf("[cleanUpNetworkPolicy] Error: failed to apply iptables rule. Rule: %+v with err: %v", iptEntry, err) } } + // (TODO) now add the []string value of the lists into a new obj + // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + for listKey, _ := range lists { + if err = ipsMgr.DeleteList(listKey); err != nil { + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) + } + } // delete ipset list related to ingress CIDRs if err = c.removeCidrsRule("in", cachedNetPolObj.Name, cachedNetPolObj.Namespace, ingressIPCidrs, ipsMgr); err != nil { diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 0ff4cec055..e6a1730ef7 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -80,6 +80,7 @@ func craftPartialIptEntrySpecFromOpAndLabel(op, label, srcOrDstFlag string, isNa return util.DropEmptyFields(partialSpec) } +// TODO check this func references and change the label and op logic // craftPartialIptablesCommentFromSelector :- ns must be "" for namespace selectors func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, srcOrDstFlag string, isNamespaceSelector bool) []string { var spec []string @@ -121,10 +122,29 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors -func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) []string { - labelsWithOps, _, _ := parseSelector(selector) +func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { + labelsWithOps, _, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) - return craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + valueLabels := []string{} + listLabelsWithMembers := make(map[string][]string) + // TODO add comments very confusing for sure + for labelKeyWithOps, labelValueList := range nsLabelListKVs { + op, labelKey := GetOperatorAndLabel(labelKeyWithOps) + labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) + ops = append(ops, op) + // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists + //labels = append(labels, labelKVIpsetName) + for _, labelValue := range labelValueList { + ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) + valueLabels = append(valueLabels, ipsetName) + listLabelsWithMembers[labelKVIpsetName] = append(listLabelsWithMembers[labelKVIpsetName], ipsetName) + } + } + iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + // only append valueLabels to labels after creating the Ipt Spec as valueLabels + // are included in labelKVIpsetName + labels = append(labels, valueLabels...) + return iptEntrySpecs, labels, listLabelsWithMembers } // craftPartialIptablesCommentFromSelector :- ns must be "" for namespace selectors @@ -161,11 +181,11 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe return comment[:len(comment)-len("-AND-")] + postfix } -func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, []string, [][]string, []*iptm.IptEntry) { +func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash - namedPorts []string // ipsets with type: hash:ip,port - lists []string // ipsets with type: list:set + sets []string // ipsets with type: net:hash + namedPorts []string // ipsets with type: hash:ip,port + lists map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry fromRuleEntries []*iptm.IptEntry @@ -174,14 +194,15 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) log.Logf("started parsing ingress rule") - - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - sets = append(sets, labels...) sets = append(sets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) + lists = make(map[string][]string) - targetSelectorIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesDstFlag, false) + targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) + sets = append(sets, labels...) + for parsedKey, parsedValue := range listLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { @@ -236,7 +257,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) entries = append(entries, entry) - lists = append(lists, util.KubeAllNamespacesFlag) + lists[util.KubeAllNamespacesFlag] = []string{} continue } @@ -424,20 +445,26 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } if fromRule.PodSelector == nil && fromRule.NamespaceSelector != nil { - nsLabelsWithOps, _, _ := parseSelector(fromRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) } } - lists = append(lists, nsLabelsWithoutOps...) - - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) if portRuleExists { for _, portRule := range rule.Ports { @@ -531,16 +558,18 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } if fromRule.PodSelector != nil && fromRule.NamespaceSelector == nil { - podLabelsWithOps, _, _ := parseSelector(fromRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + // TODO check old code if we need any ns- prefix for pod selectors + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) if len(podLabelsWithoutOps) == 1 { if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = "ns-" + ns + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } sets = append(sets, podLabelsWithoutOps...) - - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -641,21 +670,23 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS continue } - nsLabelsWithOps, _, _ := parseSelector(fromRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) - // Add namespaces prefix to distinguish namespace ipsets and pod ipsets + // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } } - lists = append(lists, nsLabelsWithoutOps...) - - podLabelsWithOps, _, _ := parseSelector(fromRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - - // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) if portRuleExists { @@ -846,15 +877,19 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS entries = append(entries, entry) } + for parsedKey, parsedValue := range lists { + lists[parsedKey] = util.DropEmptyFields(parsedValue) + } + log.Logf("finished parsing ingress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), util.DropEmptyFields(lists), ipCidrs, entries + return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries } -func translateEgress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyEgressRule) ([]string, []string, []string, [][]string, []*iptm.IptEntry) { +func translateEgress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyEgressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash - namedPorts []string // ipsets with type: hash:ip,port - lists []string // ipsets with type: list:set + sets []string // ipsets with type: net:hash + namedPorts []string // ipsets with type: hash:ip,port + lists map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry toRuleEntries []*iptm.IptEntry @@ -921,7 +956,9 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) entries = append(entries, entry) - lists = append(lists, util.KubeAllNamespacesFlag) + if _, ok := lists[util.KubeAllNamespacesFlag]; !ok { + lists[util.KubeAllNamespacesFlag] = nil + } continue } @@ -1115,20 +1152,26 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } if toRule.PodSelector == nil && toRule.NamespaceSelector != nil { - nsLabelsWithOps, _, _ := parseSelector(toRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) } } - lists = append(lists, nsLabelsWithoutOps...) - - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) if portRuleExists { for _, portRule := range rule.Ports { @@ -1222,16 +1265,17 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } if toRule.PodSelector != nil && toRule.NamespaceSelector == nil { - podLabelsWithOps, _, _ := parseSelector(toRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) if len(podLabelsWithoutOps) == 1 { if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = "ns-" + ns + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } + for parsedKey, parsedValue := range listPodLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } sets = append(sets, podLabelsWithoutOps...) - - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1332,21 +1376,24 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe continue } - nsLabelsWithOps, _, _ := parseSelector(toRule.NamespaceSelector) - _, nsLabelsWithoutOps := GetOperatorsAndLabels(nsLabelsWithOps) + // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } } - lists = append(lists, nsLabelsWithoutOps...) - - podLabelsWithOps, _, _ := parseSelector(toRule.PodSelector) - _, podLabelsWithoutOps := GetOperatorsAndLabels(podLabelsWithOps) + for parsedKey, parsedValue := range listLabelsWithMembers { + parsedKey = util.GetNSNameWithPrefix(parsedKey) + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - - // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) - iptPartialPodSpec := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) + for parsedKey, parsedValue := range listPodLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) if portRuleExists { @@ -1538,8 +1585,12 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe entries = append(entries, entry) } + for parsedKey, parsedValue := range lists { + lists[parsedKey] = util.DropEmptyFields(parsedValue) + } + log.Logf("finished parsing egress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), util.DropEmptyFields(lists), ipCidrs, entries + return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries } // Drop all non-whitelisted packets. @@ -1597,11 +1648,11 @@ func getDefaultDropEntries(ns string, targetSelector metav1.LabelSelector, hasIn // 1. ipset set names generated from all podSelectors // 2. ipset list names generated from all namespaceSelectors // 3. iptables entries generated from the input network policy object. -func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []string, [][]string, [][]string, []*iptm.IptEntry) { +func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, map[string][]string, [][]string, [][]string, []*iptm.IptEntry) { var ( resultSets []string resultNamedPorts []string - resultLists []string + resultListMap map[string][]string resultIngressIPCidrs [][]string resultEgressIPCidrs [][]string entries []*iptm.IptEntry @@ -1611,7 +1662,7 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s defer func() { log.Logf("Finished translatePolicy") log.Logf("sets: %v", resultSets) - log.Logf("lists: %v", resultLists) + log.Logf("lists: %v", resultListMap) log.Logf("entries: ") for _, entry := range entries { log.Logf("entry: %+v", entry) @@ -1625,20 +1676,27 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) - resultLists = append(resultLists, ingressLists...) + for resultListKey, resultLists := range ingressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } entries = append(entries, ingressEntries...) egressSets, egressNamedPorts, egressLists, egressIPCidrs, egressEntries := translateEgress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Egress) resultSets = append(resultSets, egressSets...) resultNamedPorts = append(resultNamedPorts, egressNamedPorts...) - resultLists = append(resultLists, egressLists...) + for resultListKey, resultLists := range egressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } entries = append(entries, egressEntries...) hasIngress = len(ingressSets) > 0 hasEgress = len(egressSets) > 0 entries = append(entries, getDefaultDropEntries(npNs, npObj.Spec.PodSelector, hasIngress, hasEgress)...) + for resultListKey, resultLists := range resultListMap { + resultListMap[resultListKey] = util.UniqueStrSlice(resultLists) + } - return util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultNamedPorts), util.UniqueStrSlice(resultLists), ingressIPCidrs, egressIPCidrs, entries + return util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultNamedPorts), resultListMap, ingressIPCidrs, egressIPCidrs, entries } for _, ptype := range npObj.Spec.PolicyTypes { @@ -1646,7 +1704,9 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) - resultLists = append(resultLists, ingressLists...) + for resultListKey, resultLists := range ingressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } resultIngressIPCidrs = ingressIPCidrs entries = append(entries, ingressEntries...) @@ -1664,7 +1724,9 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s egressSets, egressNamedPorts, egressLists, egressIPCidrs, egressEntries := translateEgress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Egress) resultSets = append(resultSets, egressSets...) resultNamedPorts = append(resultNamedPorts, egressNamedPorts...) - resultLists = append(resultLists, egressLists...) + for resultListKey, resultLists := range egressLists { + resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) + } resultEgressIPCidrs = egressIPCidrs entries = append(entries, egressEntries...) @@ -1680,7 +1742,10 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, []s } entries = append(entries, getDefaultDropEntries(npNs, npObj.Spec.PodSelector, hasIngress, hasEgress)...) - resultSets, resultLists = util.UniqueStrSlice(resultSets), util.UniqueStrSlice(resultLists) + resultSets = util.UniqueStrSlice(resultSets) + for resultListKey, resultLists := range resultListMap { + resultListMap[resultListKey] = util.UniqueStrSlice(resultLists) + } - return resultSets, resultNamedPorts, resultLists, resultIngressIPCidrs, resultEgressIPCidrs, entries + return resultSets, resultNamedPorts, resultListMap, resultIngressIPCidrs, resultEgressIPCidrs, entries } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 344e383ac9..2b055ed628 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -267,7 +267,8 @@ func TestCraftPartialIptEntryFromSelector(t *testing.T) { }, } - iptEntrySpec := craftPartialIptEntrySpecFromSelector("testnamespace", srcSelector, util.IptablesSrcFlag, false) + // TODO add more test cases here form multi value + iptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector("testnamespace", srcSelector, util.IptablesSrcFlag, false) expectedIptEntrySpec := []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, From b8cd4b175ef829e095acda87582ff6cdbabc3c6a Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 30 Apr 2021 16:12:51 -0700 Subject: [PATCH 15/34] resolving some references for drop match fields --- npm/translatePolicy.go | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index e6a1730ef7..cb2c9f2fe9 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -898,14 +898,15 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) log.Logf("started parsing egress rule") - - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - sets = append(sets, labels...) sets = append(sets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) + lists = make(map[string][]string) - targetSelectorIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesSrcFlag, false) + targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) + sets = append(sets, labels...) + for parsedKey, parsedValue := range listLabelsWithMembers { + lists[parsedKey] = append(lists[parsedKey], parsedValue...) + } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false @@ -1597,11 +1598,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe func getDefaultDropEntries(ns string, targetSelector metav1.LabelSelector, hasIngress, hasEgress bool) []*iptm.IptEntry { var entries []*iptm.IptEntry - labelsWithOps, _, _ := parseSelector(&targetSelector) - ops, labels := GetOperatorsAndLabels(labelsWithOps) - - targetSelectorIngressIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesDstFlag, false) - targetSelectorEgressIptEntrySpec := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, util.IptablesSrcFlag, false) + targetSelectorIngressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) + targetSelectorEgressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) if hasIngress { From 4f7a8aa428e7346a4eb34b4ae8069d18c3071217 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 15:19:14 -0700 Subject: [PATCH 16/34] Adding some fixes around nil checks --- npm/parseSelector.go | 3 +++ npm/translatePolicy.go | 11 ++++++++--- npm/translatePolicy_test.go | 2 +- npm/util/util.go | 10 ++++++++++ 4 files changed, 22 insertions(+), 4 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index cd6859b82d..78230e081e 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -184,6 +184,9 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri keys = append(keys, k) vals[k] = append(vals[k], v) // TODO make sure this removed labels are covered in all cases + // We are not adding the k:v to labels, because, labels are used to contruct + // partial IptEntries and if these below labels are added then we are inducing + // AND condition on value of a match expression //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index cb2c9f2fe9..125965d4ca 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -131,9 +131,12 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec for labelKeyWithOps, labelValueList := range nsLabelListKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) - ops = append(ops, op) - // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists - //labels = append(labels, labelKVIpsetName) + if !util.StrExistsInSlice(labels, labelKVIpsetName) { + ops = append(ops, op) + // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists + // check if the 2nd level is already part of labels + labels = append(labels, labelKVIpsetName) + } for _, labelValue := range labelValueList { ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) valueLabels = append(valueLabels, ipsetName) @@ -161,6 +164,7 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe return "ns-" + ns } + // TODO check if we are missing any crucial comment labelsWithOps, _, _ := parseSelector(selector) ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) @@ -1669,6 +1673,7 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, map npNs := npObj.ObjectMeta.Namespace policyName := npObj.ObjectMeta.Name + resultListMap = make(map[string][]string) if len(npObj.Spec.PolicyTypes) == 0 { ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 2b055ed628..d7d925bd8e 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2776,8 +2776,8 @@ func TestAllowAllFromAppBackend(t *testing.T) { sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) expectedSets := []string{ - "app:backend", "ns-testnamespace", + "app:backend", } if !reflect.DeepEqual(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") diff --git a/npm/util/util.go b/npm/util/util.go index bb73365eea..60f958cdbf 100644 --- a/npm/util/util.go +++ b/npm/util/util.go @@ -322,3 +322,13 @@ func GetLabelKVFromSet(ipsetName string) (string, string) { } return strSplit[0], "" } + +// StrExistsInSlice check if a string already exists in a given slice +func StrExistsInSlice(items []string, val string) bool { + for _, item := range items { + if item == val { + return true + } + } + return false +} From d5cd6c3a2634d670244b89b2285352de4dc43bc8 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 17:44:29 -0700 Subject: [PATCH 17/34] ignoring 1 value expr to be added to list mems --- npm/parseSelector.go | 35 +++++++--------- npm/parseSelector_test.go | 87 +++++++-------------------------------- npm/translatePolicy.go | 13 +++++- 3 files changed, 43 insertions(+), 92 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 78230e081e..0dcd8cdede 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -138,33 +138,27 @@ func HashSelector(selector *metav1.LabelSelector) string { } // parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. -func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[string][]string) { +func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]string) { var ( labels []string - keys []string vals map[string][]string ) vals = make(map[string][]string) if selector == nil { - return labels, keys, vals + return labels, vals } if len(selector.MatchLabels) == 0 && len(selector.MatchExpressions) == 0 { labels = append(labels, "") - keys = append(keys, "") - vals[""] = append(vals[""], "") - - return labels, keys, vals + return labels, vals } sortedKeys, sortedVals := util.SortMap(&selector.MatchLabels) for i := range sortedKeys { labels = append(labels, sortedKeys[i]+":"+sortedVals[i]) - vals[sortedKeys[i]] = append(vals[sortedKeys[i]], sortedVals[i]) } - keys = append(keys, sortedKeys...) for _, req := range selector.MatchExpressions { var k string @@ -179,33 +173,36 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri // !pod a !pod:a // case metav1.LabelSelectorOpIn: + k = req.Key + if len(req.Values) == 1 { + labels = append(labels, k+":"+req.Values[0]) + continue + } for _, v := range req.Values { - k = req.Key - keys = append(keys, k) vals[k] = append(vals[k], v) // TODO make sure this removed labels are covered in all cases - // We are not adding the k:v to labels, because, labels are used to contruct - // partial IptEntries and if these below labels are added then we are inducing + // We are not adding the k:v to labels for multiple values, because, labels are used + // to contruct partial IptEntries and if these below labels are added then we are inducing // AND condition on value of a match expression //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: + k = util.IptablesNotFlag + req.Key + if len(req.Values) == 1 { + labels = append(labels, k+":"+req.Values[0]) + continue + } for _, v := range req.Values { - k = util.IptablesNotFlag + req.Key - keys = append(keys, k) vals[k] = append(vals[k], v) - //labels = append(labels, k+":"+v) } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key - keys = append(keys, req.Key) vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key - keys = append(keys, k) vals[k] = append(vals[k], "") labels = append(labels, k) default: @@ -213,5 +210,5 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, []string, map[stri } } - return labels, keys, vals + return labels, vals } diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 877530fa9b..6478144661 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -1,9 +1,9 @@ package npm import ( + "container/heap" "reflect" "testing" - "container/heap" "github.com/Azure/azure-container-networking/npm/util" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -89,7 +89,6 @@ func TestGetOperatorAndLabel(t *testing.T) { t.Errorf("TestGetOperatorAndLabel failed @ operator comparison") } - if !reflect.DeepEqual(resultLabels, expectedLabels) { t.Errorf("TestGetOperatorAndLabel failed @ label comparison") } @@ -136,7 +135,7 @@ func TestReqHeap(t *testing.T) { metav1.LabelSelectorRequirement{ Key: "a", Operator: metav1.LabelSelectorOpIn, - Values: []string{}, + Values: []string{}, }, metav1.LabelSelectorRequirement{ Key: "testIn", @@ -164,7 +163,7 @@ func TestReqHeap(t *testing.T) { metav1.LabelSelectorRequirement{ Key: "a", Operator: metav1.LabelSelectorOpIn, - Values: []string{}, + Values: []string{}, }, metav1.LabelSelectorRequirement{ Key: "testIn", @@ -272,7 +271,7 @@ func TestHashSelector(t *testing.T) { "c": "d", }, } - + secondSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ metav1.LabelSelectorRequirement{ @@ -302,17 +301,13 @@ func TestHashSelector(t *testing.T) { func TestParseSelector(t *testing.T) { var selector, expectedSelector *metav1.LabelSelector selector, expectedSelector = nil, nil - labels, keys, vals := parseSelector(selector) - expectedLabels, expectedKeys, expectedVals := []string{}, []string{}, []string{} + labels, vals := parseSelector(selector) + expectedLabels, expectedVals := []string{}, []string{} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -322,16 +317,12 @@ func TestParseSelector(t *testing.T) { } selector = &metav1.LabelSelector{} - labels, keys, vals = parseSelector(selector) - expectedLabels, expectedKeys, expectedVals = []string{""}, []string{""}, []string{""} + labels, vals = parseSelector(selector) + expectedLabels, expectedVals = []string{""}, []string{""} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -349,15 +340,11 @@ func TestParseSelector(t *testing.T) { }, } - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) expectedLabels = []string{ "testIn:frontend", "testIn:backend", } - expectedKeys = []string{ - "testIn", - "testIn", - } expectedVals = []string{ "frontend", "backend", @@ -367,20 +354,13 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -397,41 +377,29 @@ func TestParseSelector(t *testing.T) { me := &selector.MatchExpressions *me = append(*me, notIn) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels := []string{ "!testNotIn:frontend", "!testNotIn:backend", } - addedKeys := []string{ - "!testNotIn", - "!testNotIn", - } addedVals := []string{ "frontend", "backend", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -444,38 +412,27 @@ func TestParseSelector(t *testing.T) { *me = append(*me, exists) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels = []string{ "testExists", } - addedKeys = []string{ - "testExists", - } addedVals = []string{ "", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } if !reflect.DeepEqual(labels, expectedLabels) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } @@ -488,29 +445,21 @@ func TestParseSelector(t *testing.T) { *me = append(*me, doesNotExist) - labels, keys, vals = parseSelector(selector) + labels, vals = parseSelector(selector) addedLabels = []string{ "!testDoesNotExist", } - addedKeys = []string{ - "!testDoesNotExist", - } addedVals = []string{ "", } expectedLabels = append(expectedLabels, addedLabels...) - expectedKeys = append(expectedKeys, addedKeys...) expectedVals = append(expectedVals, addedVals...) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } - if len(keys) != len(expectedKeys) { - t.Errorf("TestparseSelector failed @ keys length comparison") - } - - if len(vals) != len(vals) { + if len(vals) != len(expectedVals) { t.Errorf("TestparseSelector failed @ vals length comparison") } @@ -518,10 +467,6 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ label comparison") } - if !reflect.DeepEqual(keys, expectedKeys) { - t.Errorf("TestparseSelector failed @ key comparison") - } - if !reflect.DeepEqual(vals, expectedVals) { t.Errorf("TestparseSelector failed @ value comparison") } diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 125965d4ca..6defb56c4a 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -122,8 +122,9 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors +// TODO check all references of this func func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { - labelsWithOps, _, nsLabelListKVs := parseSelector(selector) + labelsWithOps, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) valueLabels := []string{} listLabelsWithMembers := make(map[string][]string) @@ -165,8 +166,16 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe } // TODO check if we are missing any crucial comment - labelsWithOps, _, _ := parseSelector(selector) + labelsWithOps, labelKVs := parseSelector(selector) ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) + for labelKeyWithOps, labelValueList := range labelKVs { + op, labelKey := GetOperatorAndLabel(labelKeyWithOps) + for _, labelValue := range labelValueList { + ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) + labelsWithoutOps = append(labelsWithoutOps, ipsetName) + ops = append(ops, op) + } + } var comment, prefix, postfix string if isNamespaceSelector { From 96bc1b7482f767f9dd0e59457b1481387958c1b4 Mon Sep 17 00:00:00 2001 From: vakr Date: Mon, 3 May 2021 22:05:41 -0700 Subject: [PATCH 18/34] not adding lists to the setMap --- npm/networkPolicyController.go | 2 +- npm/translatePolicy.go | 59 +++++++++++++++++----------------- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 51436a5511..24c2fe333e 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -359,7 +359,7 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 } for _, listMember := range listLabelsMembers { if err = ipsMgr.AddToList(listKey, listMember); err != nil { - return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipst member %s to ipset list %s with err: %v", listMember, listKey, err) + return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipset member %s to ipset list %s with err: %v", listMember, listKey, err) } } ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 6defb56c4a..de0e7bb2eb 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -127,6 +127,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec labelsWithOps, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) valueLabels := []string{} + labelsForSpec := labels listLabelsWithMembers := make(map[string][]string) // TODO add comments very confusing for sure for labelKeyWithOps, labelValueList := range nsLabelListKVs { @@ -136,7 +137,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec ops = append(ops, op) // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists // check if the 2nd level is already part of labels - labels = append(labels, labelKVIpsetName) + labelsForSpec = append(labelsForSpec, labelKVIpsetName) } for _, labelValue := range labelValueList { ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) @@ -144,7 +145,7 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec listLabelsWithMembers[labelKVIpsetName] = append(listLabelsWithMembers[labelKVIpsetName], ipsetName) } } - iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labels, srcOrDstFlag, isNamespaceSelector) + iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labelsForSpec, srcOrDstFlag, isNamespaceSelector) // only append valueLabels to labels after creating the Ipt Spec as valueLabels // are included in labelKVIpsetName labels = append(labels, valueLabels...) @@ -213,8 +214,8 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) sets = append(sets, labels...) - for parsedKey, parsedValue := range listLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) @@ -473,9 +474,9 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) @@ -579,9 +580,9 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } } sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { @@ -691,14 +692,14 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) @@ -917,8 +918,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) sets = append(sets, labels...) - for parsedKey, parsedValue := range listLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { @@ -1181,9 +1182,9 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) @@ -1285,11 +1286,11 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } - for parsedKey, parsedValue := range listPodLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) - } sets = append(sets, podLabelsWithoutOps...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) + } iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1399,14 +1400,14 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedKey, parsedValue := range listLabelsWithMembers { - parsedKey = util.GetNSNameWithPrefix(parsedKey) - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listLabelsWithMembers { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedKey, parsedValue := range listPodLabelsWithMembers { - lists[parsedKey] = append(lists[parsedKey], parsedValue...) + for parsedListName, parsedListMembers := range listPodLabelsWithMembers { + lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) From e0664293e56761876e9c66756ec336236e658d04 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 11:54:53 -0700 Subject: [PATCH 19/34] correcting some UTs --- npm/parseSelector.go | 2 -- npm/parseSelector_test.go | 55 ++++++++++++++++++++------------------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 0dcd8cdede..8bb4439052 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -198,12 +198,10 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: k = req.Key - vals[k] = append(vals[k], "") labels = append(labels, k) // DoesNotExist matches pods without req.Key as key case metav1.LabelSelectorOpDoesNotExist: k = util.IptablesNotFlag + req.Key - vals[k] = append(vals[k], "") labels = append(labels, k) default: log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *selector) diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 6478144661..c9b181c1d1 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -302,7 +302,7 @@ func TestParseSelector(t *testing.T) { var selector, expectedSelector *metav1.LabelSelector selector, expectedSelector = nil, nil labels, vals := parseSelector(selector) - expectedLabels, expectedVals := []string{}, []string{} + expectedLabels, expectedVals := []string{}, make(map[string][]string) if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -318,7 +318,7 @@ func TestParseSelector(t *testing.T) { selector = &metav1.LabelSelector{} labels, vals = parseSelector(selector) - expectedLabels, expectedVals = []string{""}, []string{""} + expectedLabels = []string{""} if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") } @@ -341,13 +341,12 @@ func TestParseSelector(t *testing.T) { } labels, vals = parseSelector(selector) - expectedLabels = []string{ - "testIn:frontend", - "testIn:backend", - } - expectedVals = []string{ - "frontend", - "backend", + expectedLabels = []string{} + expectedVals = map[string][]string{ + "testIn": { + "frontend", + "backend", + }, } if len(labels) != len(expectedLabels) { @@ -358,7 +357,7 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ vals length comparison") } - if !reflect.DeepEqual(labels, expectedLabels) { + if labels != nil { t.Errorf("TestparseSelector failed @ label comparison") } if !reflect.DeepEqual(vals, expectedVals) { @@ -378,16 +377,18 @@ func TestParseSelector(t *testing.T) { *me = append(*me, notIn) labels, vals = parseSelector(selector) - addedLabels := []string{ - "!testNotIn:frontend", - "!testNotIn:backend", - } - addedVals := []string{ - "frontend", - "backend", + addedLabels := []string{} + addedVals := map[string][]string{ + "!testNotIn": { + "frontend", + "backend", + }, } + expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -397,7 +398,7 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ vals length comparison") } - if !reflect.DeepEqual(labels, expectedLabels) { + if labels != nil { t.Errorf("TestparseSelector failed @ label comparison") } if !reflect.DeepEqual(vals, expectedVals) { @@ -416,11 +417,11 @@ func TestParseSelector(t *testing.T) { addedLabels = []string{ "testExists", } - addedVals = []string{ - "", - } + addedVals = map[string][]string{} expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") @@ -449,11 +450,11 @@ func TestParseSelector(t *testing.T) { addedLabels = []string{ "!testDoesNotExist", } - addedVals = []string{ - "", - } + addedVals = map[string][]string{} expectedLabels = append(expectedLabels, addedLabels...) - expectedVals = append(expectedVals, addedVals...) + for k, v := range addedVals { + expectedVals[k] = append(expectedVals[k], v...) + } if len(labels) != len(expectedLabels) { t.Errorf("TestparseSelector failed @ labels length comparison") From 9c8af4c79d637c8c98246c4a70962d3f887d5edb Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 14:46:28 -0700 Subject: [PATCH 20/34] Correcting UTs. --- npm/translatePolicy.go | 8 +++----- npm/translatePolicy_test.go | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index de0e7bb2eb..b61282b224 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -171,11 +171,9 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) for labelKeyWithOps, labelValueList := range labelKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) - for _, labelValue := range labelValueList { - ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) - labelsWithoutOps = append(labelsWithoutOps, ipsetName) - ops = append(ops, op) - } + labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) + labelsWithoutOps = append(labelsWithoutOps, labelKVIpsetName) + ops = append(ops, op) } var comment, prefix, postfix string diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index d7d925bd8e..4bbba0862f 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -344,7 +344,7 @@ func TestCraftPartialIptablesCommentFromSelector(t *testing.T) { }, } comment = craftPartialIptablesCommentFromSelector("testnamespace", selector, false) - expectedComment = "k0:v0-AND-k1:v10-AND-k1:v11-AND-!k2-IN-ns-testnamespace" + expectedComment = "k0:v0-AND-!k2-AND-k1:v10:v11-IN-ns-testnamespace" if comment != expectedComment { t.Errorf("TestCraftPartialIptablesCommentFromSelector failed @ normal selector comparison") t.Errorf("comment:\n%v", comment) @@ -372,7 +372,7 @@ func TestCraftPartialIptablesCommentFromSelector(t *testing.T) { }, } comment = craftPartialIptablesCommentFromSelector("", nsSelector, true) - expectedComment = "ns-k0:v0-AND-ns-k1:v10-AND-ns-k1:v11-AND-ns-!k2" + expectedComment = "ns-k0:v0-AND-ns-!k2-AND-ns-k1:v10:v11" if comment != expectedComment { t.Errorf("TestCraftPartialIptablesCommentFromSelector failed @ namespace selector comparison") t.Errorf("comment:\n%v", comment) From 12277431bece5d84aca73e7d923c7f6774bf3e56 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 4 May 2021 18:55:18 -0700 Subject: [PATCH 21/34] fixing all UTs --- npm/translatePolicy_test.go | 299 +++++++++++++++++++++--------------- npm/util/util.go | 9 ++ npm/util/util_test.go | 56 +++++++ 3 files changed, 238 insertions(+), 126 deletions(-) diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 4bbba0862f..1d68f20da1 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -653,17 +653,17 @@ func TestTranslateIngress(t *testing.T) { "k", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedIngress failed @ sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", - "ns-testIn:frontendns", - "ns-planet:earth", - "ns-keyExists", + expectedLists := map[string][]string{ + "ns-ns:dev": nil, + "ns-testIn:frontendns": nil, + "ns-planet:earth": nil, + "ns-keyExists": nil, } if !reflect.DeepEqual(lists, expectedLists) { @@ -965,17 +965,17 @@ func TestTranslateEgress(t *testing.T) { "k", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedEgress failed @ sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", - "ns-testIn:frontendns", - "ns-planet:earth", - "ns-keyExists", + expectedLists := map[string][]string{ + "ns-ns:dev": nil, + "ns-testIn:frontendns": nil, + "ns-planet:earth": nil, + "ns-keyExists": nil, } if !reflect.DeepEqual(lists, expectedLists) { @@ -1192,13 +1192,13 @@ func TestDenyAllPolicy(t *testing.T) { sets, _, lists, _, _, iptEntries := translatePolicy(denyAllPolicy) expectedSets := []string{"ns-testnamespace"} - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ deny-all-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ deny-all-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1228,13 +1228,13 @@ func TestAllowBackendToFrontend(t *testing.T) { "ns-testnamespace", "app:frontend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1367,13 +1367,13 @@ func TestAllowAllToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1430,13 +1430,13 @@ func TestDenyAllToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1466,13 +1466,13 @@ func TestNamespaceToFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ns-testnamespace-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ns-testnamespace-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -1599,14 +1599,14 @@ func TestAllowAllNamespacesToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-namespaces-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - util.KubeAllNamespacesFlag, + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-namespaces-TO-app:frontend-policy lists comparison") @@ -1735,19 +1735,23 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy sets comparison") + if !util.CompareSlices(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-namespace:dev", - "ns-namespace:test0", - "ns-namespace:test1", + expectedLists := map[string][]string{ + "ns-namespace:dev": {}, + "ns-namespace:test0": {}, + "ns-namespace:test1": {}, + "ns-namespace:test0:test1": { + "namespace:test0", + "namespace:test1", + }, } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy lists comparison") + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -1766,13 +1770,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesSetModuleFlag, util.IptablesNotFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-namespace:test0"), - util.IptablesSrcFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesNotFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("ns-namespace:test1"), + util.GetHashedName("ns-namespace:test0:test1"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, @@ -1791,7 +1789,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0-AND-ns-!namespace:test1-TO-app:frontend-IN-ns-testnamespace", + "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0:test1-TO-app:frontend-IN-ns-testnamespace", }, }, &iptm.IptEntry{ @@ -1866,7 +1864,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowNsDevToFrontendPolicy.Spec.PodSelector, false, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0-AND-!ns-namespace:test1-TO-app:frontend-policy policy comparison") + t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -1889,15 +1887,21 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { "k1:v1", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{util.KubeAllNamespacesFlag} + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, + "k1:v0:v1": { + "k1:v0", + "k1:v1", + }, + } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy lists comparison") + t.Errorf("translatedPolicy failed @ AllOW-ALL-TO-k0-AND-k1:v0:v1-AND-app:frontend-policy lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -1931,12 +1935,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesMark, @@ -1945,7 +1944,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-all-namespaces-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace", + "ALLOW-all-namespaces-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace", }, }, &iptm.IptEntry{ @@ -1971,19 +1970,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesAzureIngressFromChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace-TO-JUMP-TO-" + + "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace-TO-JUMP-TO-" + util.IptablesAzureIngressFromChain, }, }, @@ -2010,19 +2004,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesAzureIngressDropsChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace-TO-JUMP-TO-" + + "ALLOW-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace-TO-JUMP-TO-" + util.IptablesAzureIngressDropsChain, }, }, @@ -2048,19 +2037,14 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("k1:v0"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("k1:v1"), + util.GetHashedName("k1:v0:v1"), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesDrop, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "DROP-ALL-TO-app:frontend-AND-!k0-AND-k1:v0-AND-k1:v1-IN-ns-testnamespace", + "DROP-ALL-TO-app:frontend-AND-!k0-AND-k1:v0:v1-IN-ns-testnamespace", }, }, } @@ -2068,7 +2052,7 @@ func TestAllowAllToK0AndK1AndAppFrontend(t *testing.T) { expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllToFrontendPolicy.Spec.PodSelector, false, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ AllOW-all-TO-k0-AND-k1:v0-AND-k1:v1-AND-app:frontend-policy policy comparison") + t.Errorf("translatedPolicy failed @ AllOW-all-TO-k0-AND-k1:v0:v1-AND-app:frontend-policy policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -2090,14 +2074,14 @@ func TestAllowNsDevAndAppBackendToAppFrontend(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ns-ns:dev-AND-app:backend-TO-app:frontend sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-ns:dev", + expectedLists := map[string][]string{ + "ns-ns:dev": {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ns-ns:dev-AND-app:backend-TO-app:frontend lists comparison") @@ -2232,13 +2216,13 @@ func TestAllowInternalAndExternal(t *testing.T) { "app:backdoor", "ns-dangerous", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TO-app:backdoor-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TO-app:backdoor-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2296,13 +2280,13 @@ func TestAllowBackendToFrontendPort8000(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2415,13 +2399,13 @@ func TestAllowBackendToFrontendWithMissingPort(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-app:backend-TO-app:frontend-port-8000-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2536,13 +2520,13 @@ func TestAllowMultipleLabelsToMultipleLabels(t *testing.T) { "binary:cns", "group:container", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-program:cni-AND-team:acn-OR-binary:cns-AND-group:container-TO-app:k8s-AND-team:aks-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-program:cni-AND-team:acn-OR-binary:cns-AND-group:container-TO-app:k8s-AND-team:aks-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2743,13 +2727,13 @@ func TestDenyAllFromAppBackend(t *testing.T) { "app:backend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2779,13 +2763,13 @@ func TestAllowAllFromAppBackend(t *testing.T) { "ns-testnamespace", "app:backend", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2854,28 +2838,52 @@ func TestAllowAllFromAppBackend(t *testing.T) { } func TestAllowMultiplePodSelectors(t *testing.T) { - allowAllEgress, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") + multiPodSlector, err := readPolicyYaml("testpolicies/allow-ns-y-z-pod-b-c.yaml") if err != nil { t.Fatal(err) } util.IsNewNwPolicyVerFlag = true - sets, _, lists, _, _, iptEntries := translatePolicy(allowAllEgress) + sets, _, lists, _, _, iptEntries := translatePolicy(multiPodSlector) expectedSets := []string{ - "app:backend", - "ns-testnamespace", + "ns-netpol-4537-x", + "pod:a", + "pod:x", + "pod:b", + "pod:c", + "app:test", + "app:int", } - if !reflect.DeepEqual(sets, expectedSets) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy sets comparison") + if !util.CompareSlices(sets, expectedSets) { + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := map[string][]string{ + "app:test:int": { + "app:test", + "app:int", + }, + "ns-ns:netpol-4537-x": {}, + "ns-ns:netpol-4537-x:netpol-4537-y": { + "ns:netpol-4537-x", + "ns:netpol-4537-y", + }, + "ns-ns:netpol-4537-y": {}, + "pod:a:x": { + "pod:a", + "pod:x", + }, + "pod:b:c": { + "pod:b", + "pod:c", + }, + } if !reflect.DeepEqual(lists, expectedLists) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy lists comparison") + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c lists comparison") t.Errorf("lists: %v", lists) t.Errorf("expectedLists: %v", expectedLists) } @@ -2883,57 +2891,96 @@ func TestAllowMultiplePodSelectors(t *testing.T) { expectedIptEntries := []*iptm.IptEntry{} nonKubeSystemEntries := []*iptm.IptEntry{ &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, + Chain: util.IptablesAzureIngressFromChain, Specs: []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-testnamespace"), + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesNotFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-ns:netpol-4537-x:netpol-4537-y"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("app:backend"), + util.GetHashedName("pod:b:c"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:test:int"), util.IptablesSrcFlag, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, - util.IptablesAzureEgressXMarkHex, + util.IptablesAzureIngressMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace", + "ALLOW-ns-!ns:netpol-4537-x:netpol-4537-y-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", }, }, &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, + Chain: util.IptablesAzureIngressPortChain, IsJumpEntry: true, Specs: []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-testnamespace"), - util.IptablesSrcFlag, + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, - util.GetHashedName("app:backend"), - util.IptablesSrcFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, util.IptablesJumpFlag, - util.IptablesAzureEgressDropsChain, + util.IptablesAzureIngressFromChain, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - fmt.Sprintf("ALLOW-ALL-FROM-app:backend-IN-ns-testnamespace-TO-JUMP-TO-%s", - util.IptablesAzureEgressDropsChain), + fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", + util.IptablesAzureIngressFromChain), + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureIngressFromChain, + IsJumpEntry: true, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, + util.IptablesJumpFlag, + util.IptablesAzureIngressDropsChain, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", + util.IptablesAzureIngressDropsChain), }, }, } expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) // has egress, but empty map means allow all - expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("testnamespace", allowAllEgress.Spec.PodSelector, false, false)...) + expectedIptEntries = append(expectedIptEntries, getDefaultDropEntries("netpol-4537-x", multiPodSlector.Spec.PodSelector, true, false)...) if !reflect.DeepEqual(iptEntries, expectedIptEntries) { - t.Errorf("translatedPolicy failed @ ALLOW-all-FROM-app:backend-policy policy comparison") + t.Errorf("translatedPolicy failed @ allow-ns-y-z-pod-b-c policy comparison") marshalledIptEntries, _ := json.Marshal(iptEntries) marshalledExpectedIptEntries, _ := json.Marshal(expectedIptEntries) t.Errorf("iptEntries: %s", marshalledIptEntries) @@ -2951,12 +2998,12 @@ func TestDenyAllFromNsUnsafe(t *testing.T) { expectedSets := []string{ "ns-unsafe", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-ns-unsafe-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-none-FROM-app:backend-policy lists comparison") t.Errorf("lists: %v", lists) @@ -2986,14 +3033,14 @@ func TestAllowAppFrontendToTCPPort53UDPPort53Policy(t *testing.T) { "app:frontend", "ns-testnamespace", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-FROM-app:frontend-TCP-PORT-53-OR-UDP-PORT-53-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - util.KubeAllNamespacesFlag, + expectedLists := map[string][]string{ + util.KubeAllNamespacesFlag: {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-FROM-app:frontend-TCP-PORT-53-OR-UDP-PORT-53-policy lists comparison") @@ -3179,14 +3226,14 @@ func TestComplexPolicy(t *testing.T) { "ns-default", "role:frontend", } - if !reflect.DeepEqual(sets, expectedSets) || !reflect.DeepEqual(setsDiffOrder, expectedSets) { + if !util.CompareSlices(sets, expectedSets) || !util.CompareSlices(setsDiffOrder, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{ - "ns-project:myproject", + expectedLists := map[string][]string{ + "ns-project:myproject": {}, } if !reflect.DeepEqual(lists, expectedLists) || !reflect.DeepEqual(listsDiffOrder, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") @@ -3588,13 +3635,13 @@ func TestDropPrecedenceOverAllow(t *testing.T) { expectedSets := []string{ "ns-default", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") t.Errorf("lists: %v", lists) @@ -3609,14 +3656,14 @@ func TestDropPrecedenceOverAllow(t *testing.T) { "testIn:pod-B", "testIn:pod-C", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ k8s-example-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) } - expectedLists = []string{ - "all-namespaces", + expectedLists = map[string][]string{ + "all-namespaces": {}, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ k8s-example-policy lists comparison") @@ -3953,7 +4000,7 @@ func TestNamedPorts(t *testing.T) { "app:server", "ns-test", } - if !reflect.DeepEqual(sets, expectedSets) { + if !util.CompareSlices(sets, expectedSets) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TCP-PORT-serve-80-TO-app:server-IN-ns-test-policy sets comparison") t.Errorf("sets: %v", sets) t.Errorf("expectedSets: %v", expectedSets) @@ -3968,7 +4015,7 @@ func TestNamedPorts(t *testing.T) { t.Errorf("expectedSets: %v", expectedNamedPorts) } - expectedLists := []string{} + expectedLists := make(map[string][]string) if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ALL-TCP-PORT-serve-80-TO-app:server-IN-ns-test-policy lists comparison") t.Errorf("lists: %v", lists) diff --git a/npm/util/util.go b/npm/util/util.go index 60f958cdbf..09d7b7d0d1 100644 --- a/npm/util/util.go +++ b/npm/util/util.go @@ -332,3 +332,12 @@ func StrExistsInSlice(items []string, val string) bool { } return false } + +func CompareSlices(list1, list2 []string) bool { + for _, item := range list1 { + if !StrExistsInSlice(list2, item) { + return false + } + } + return true +} diff --git a/npm/util/util_test.go b/npm/util/util_test.go index 0452d2b976..d1b5b51bfb 100644 --- a/npm/util/util_test.go +++ b/npm/util/util_test.go @@ -270,3 +270,59 @@ func TestParseResourceVersion(t *testing.T) { t.Errorf("TestParseResourceVersion failed @ inavlid RV gave no error") } } + +func TestCompareSlices(t *testing.T) { + list1 := []string{ + "a", + "b", + "c", + "d", + } + list2 := []string{ + "c", + "d", + "a", + "b", + } + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 1") + } + + list2 = []string{ + "c", + "a", + "b", + } + + if CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 2") + } + list1 = []string{ + "a", + "b", + "c", + "d", + "123", + "44", + } + list2 = []string{ + "c", + "44", + "d", + "a", + "b", + "123", + } + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 3") + } + + list1 = []string{} + list2 = []string{} + + if !CompareSlices(list1, list2) { + t.Errorf("TestCompareSlices failed @ slice comparison 4") + } +} From fbb0bedb6fcda83b030141439e7ddbd12c0c57ef Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 5 May 2021 10:55:54 -0700 Subject: [PATCH 22/34] Adding and cleaning some comments --- npm/networkPolicyController.go | 13 +++++++++---- npm/parseSelector.go | 23 ++++++++--------------- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 24c2fe333e..85eec3c0cf 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -351,8 +351,9 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset named port %s with err: %v", set, err) } } - // (TODO) now add the []string value of the lists into a new obj - // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + + // lists is a map with list name and members as value + // NPM will create the list first, add members to it and increments the refer count for listKey, listLabelsMembers := range lists { if err = ipsMgr.CreateList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) @@ -402,9 +403,13 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC return fmt.Errorf("[cleanUpNetworkPolicy] Error: failed to apply iptables rule. Rule: %+v with err: %v", iptEntry, err) } } - // (TODO) now add the []string value of the lists into a new obj - // and this below createList needs to be checked, we have to create all the lists, but also need to create new ones based on the list values + + // lists is a map with list name and members as value for listKey, _ := range lists { + // We do not have delete the members before deleting set as, + // 1. ipset allows deleting a ipset list with members + // 2. if the refer count is more than one we should not remove members + // 3. for reduced datapath operations if err = ipsMgr.DeleteList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 8bb4439052..207cd737de 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -137,7 +137,11 @@ func HashSelector(selector *metav1.LabelSelector) string { return util.Hash(fmt.Sprintf("%v", selector)) } -// parseSelector takes a LabelSelector and returns a slice of processed labels, keys and values. +// parseSelector takes a LabelSelector and returns a slice of processed labels, Lists with members as values. +// this function returns +// +// +// func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]string) { var ( labels []string @@ -163,28 +167,17 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin for _, req := range selector.MatchExpressions { var k string switch op := req.Operator; op { - // TODO remove this - // - key: pod - // operator: NotIn - // values: - // - b - // - c - // !pod b !pod:b - // !pod a !pod:a - // case metav1.LabelSelectorOpIn: k = req.Key if len(req.Values) == 1 { labels = append(labels, k+":"+req.Values[0]) continue } + // We are not adding the k:v to labels for multiple values, because, labels are used + // to contruct partial IptEntries and if these below labels are added then we are inducing + // AND condition on values of a match expression instead of OR for _, v := range req.Values { vals[k] = append(vals[k], v) - // TODO make sure this removed labels are covered in all cases - // We are not adding the k:v to labels for multiple values, because, labels are used - // to contruct partial IptEntries and if these below labels are added then we are inducing - // AND condition on value of a match expression - //labels = append(labels, k+":"+v) } case metav1.LabelSelectorOpNotIn: k = util.IptablesNotFlag + req.Key From 6c6543ba9d0545d27a6fc7feb9c582e20ae31f8b Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 5 May 2021 15:36:07 -0700 Subject: [PATCH 23/34] fixing ns- prefixes for some lists and adding sort for comment --- npm/networkPolicyController.go | 9 +++-- npm/parseSelector.go | 8 ++--- npm/translatePolicy.go | 65 ++++++++++++++++------------------ npm/translatePolicy_test.go | 6 ++-- 4 files changed, 45 insertions(+), 43 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 85eec3c0cf..81bfae4184 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -353,11 +353,16 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 } // lists is a map with list name and members as value - // NPM will create the list first, add members to it and increments the refer count - for listKey, listLabelsMembers := range lists { + // NPM will create the list first and increments the refer count + for listKey, _ := range lists { if err = ipsMgr.CreateList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } + ipsMgr.IpSetReferIncOrDec(listKey, util.IpsetSetListFlag, ipsm.IncrementOp) + } + // Then NPM will add members to the above list, this is to avoid members being added + // to lists before they are created. + for listKey, listLabelsMembers := range lists { for _, listMember := range listLabelsMembers { if err = ipsMgr.AddToList(listKey, listMember); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: Adding ipset member %s to ipset list %s with err: %v", listMember, listKey, err) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 207cd737de..e0479803e3 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -138,10 +138,10 @@ func HashSelector(selector *metav1.LabelSelector) string { } // parseSelector takes a LabelSelector and returns a slice of processed labels, Lists with members as values. -// this function returns -// -// -// +// this function returns a slice of all the label ipsets excluding multivalue matchExprs +// and a map of labelKeys and labelIpsetname for multivalue match exprs +// higher level functions will need to compute what sets or ipsets should be +// used from this map func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]string) { var ( labels []string diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index b61282b224..e795b0aafd 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -3,6 +3,7 @@ package npm import ( + "sort" "strconv" "github.com/Azure/azure-container-networking/log" @@ -124,11 +125,13 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors // TODO check all references of this func func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { + // parse the sector into labels and maps of multiVal match Exprs labelsWithOps, nsLabelListKVs := parseSelector(selector) ops, labels := GetOperatorsAndLabels(labelsWithOps) + valueLabels := []string{} - labelsForSpec := labels listLabelsWithMembers := make(map[string][]string) + labelsForSpec := labels // TODO add comments very confusing for sure for labelKeyWithOps, labelValueList := range nsLabelListKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) @@ -185,6 +188,8 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe } } + // sort the slices to remove ambuigivity on ordering of labels for comments + sort.Sort(sort.StringSlice(labelsWithoutOps)) for i, _ := range labelsWithoutOps { comment += prefix + ops[i] + labelsWithoutOps[i] comment += "-AND-" @@ -193,6 +198,20 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe return comment[:len(comment)-len("-AND-")] + postfix } +func appendSelectorLabelsToLists(lists, listLabelsWithMembers map[string][]string, isNamespaceSelector bool) { + for parsedListName, parsedListMembers := range listLabelsWithMembers { + if isNamespaceSelector { + parsedListName = util.GetNSNameWithPrefix(parsedListName) + } + for _, member := range parsedListMembers { + if isNamespaceSelector { + member = util.GetNSNameWithPrefix(member) + } + lists[parsedListName] = append(lists[parsedListName], member) + } + } +} + func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( sets []string // ipsets with type: net:hash @@ -472,10 +491,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedListName, parsedListMembers := range listLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) if portRuleExists { @@ -578,10 +594,8 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } } sets = append(sets, podLabelsWithoutOps...) - for parsedListName, parsedListMembers := range listPodLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + // TODO check this if ns- is needed here. + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -690,15 +704,10 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS lists[nsLabelsWithoutOps[i]] = nil } } - for parsedListName, parsedListMembers := range listLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedListName, parsedListMembers := range listPodLabelsWithMembers { - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) if portRuleExists { @@ -916,9 +925,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) sets = append(sets, labels...) - for parsedListName, parsedListMembers := range listLabelsWithMembers { - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false @@ -1180,10 +1187,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedListName, parsedListMembers := range listLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) if portRuleExists { @@ -1285,10 +1289,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } } sets = append(sets, podLabelsWithoutOps...) - for parsedListName, parsedListMembers := range listPodLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + // TODO check if the ns- is needed here ? + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1398,15 +1400,10 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe lists[nsLabelsWithoutOps[i]] = nil } } - for parsedListName, parsedListMembers := range listLabelsWithMembers { - parsedListName = util.GetNSNameWithPrefix(parsedListName) - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - for parsedListName, parsedListMembers := range listPodLabelsWithMembers { - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) - } + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) if portRuleExists { diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 1d68f20da1..3146524ff4 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2869,8 +2869,8 @@ func TestAllowMultiplePodSelectors(t *testing.T) { }, "ns-ns:netpol-4537-x": {}, "ns-ns:netpol-4537-x:netpol-4537-y": { - "ns:netpol-4537-x", - "ns:netpol-4537-y", + "ns-ns:netpol-4537-x", + "ns-ns:netpol-4537-y", }, "ns-ns:netpol-4537-y": {}, "pod:a:x": { @@ -2926,7 +2926,7 @@ func TestAllowMultiplePodSelectors(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ns-!ns:netpol-4537-x:netpol-4537-y-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", + "ALLOW-ns-!ns:netpol-4537-x:netpol-4537-y-AND-app:test:int-AND-pod:b:c-TO-pod:a:x-IN-ns-netpol-4537-x", }, }, &iptm.IptEntry{ From 9aabfe66297692be9238410dd6a90dc9478172d2 Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 5 May 2021 23:34:25 -0700 Subject: [PATCH 24/34] fixing nsSlectors, flattening nsSelectors, since list of lists is not allowed in ipset --- npm/parseSelector.go | 85 +++++ npm/parseSelector_test.go | 45 +++ npm/translatePolicy.go | 667 +++++++++++++++++++------------------- 3 files changed, 468 insertions(+), 329 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index e0479803e3..af9355b8a1 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -137,6 +137,91 @@ func HashSelector(selector *metav1.LabelSelector) string { return util.Hash(fmt.Sprintf("%v", selector)) } +// flattenNameSpaceSelector will help flatten multiple NameSpace selector match Expressions values +// into multiple label selectors helping with the OR condition. +func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSelector { + //egress section + // for _, egressRule := range nsSelector { + // log.Logf("%+v", egressRule) + // } + if nsSelector == nil { + return []metav1.LabelSelector{*nsSelector} + } + + if len(nsSelector.MatchExpressions) == 0 { + return []metav1.LabelSelector{*nsSelector} + } + + baseSelector := &metav1.LabelSelector{ + MatchLabels: nsSelector.MatchLabels, + MatchExpressions: []metav1.LabelSelectorRequirement{}, + } + + multiValuePresent := false + multiValueMatchExprs := []metav1.LabelSelectorRequirement{} + for _, req := range nsSelector.MatchExpressions { + switch op := req.Operator; op { + case metav1.LabelSelectorOpIn: + if len(req.Values) == 1 { + baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) + continue + } + multiValuePresent = true + multiValueMatchExprs = append(multiValueMatchExprs, req) + case metav1.LabelSelectorOpNotIn: + if len(req.Values) == 1 { + baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) + continue + } + multiValuePresent = true + multiValueMatchExprs = append(multiValueMatchExprs, req) + case metav1.LabelSelectorOpExists: + baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) + case metav1.LabelSelectorOpDoesNotExist: + baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) + default: + log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *nsSelector) + } + } + + // If there are no multiValue NS selector match expressions + // return the original NsSelector + if !multiValuePresent { + return []metav1.LabelSelector{*nsSelector} + } + + // Now use the baseSelector and loop over multiValueMatchExprs to create all + // combinations of values + flatNsSelectors := []metav1.LabelSelector{ + *baseSelector.DeepCopy(), + } + for _, req := range multiValueMatchExprs { + flatNsSelectors = zipMatchExprs(flatNsSelectors, req) + } + + return flatNsSelectors +} + +func zipMatchExprs(baseSelectors []metav1.LabelSelector, matchExpr metav1.LabelSelectorRequirement) []metav1.LabelSelector { + zippedLabelSelectors := []metav1.LabelSelector{} + for _, selector := range baseSelectors { + for _, value := range matchExpr.Values { + tempBaseSelector := selector.DeepCopy() + tempBaseSelector.MatchExpressions = append( + tempBaseSelector.MatchExpressions, + metav1.LabelSelectorRequirement{ + Key: matchExpr.Key, + Operator: matchExpr.Operator, + Values: []string{value}, + }, + ) + zippedLabelSelectors = append(zippedLabelSelectors, *tempBaseSelector) + + } + } + return zippedLabelSelectors +} + // parseSelector takes a LabelSelector and returns a slice of processed labels, Lists with members as values. // this function returns a slice of all the label ipsets excluding multivalue matchExprs // and a map of labelKeys and labelIpsetname for multivalue match exprs diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index c9b181c1d1..8523f05e6e 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -472,3 +472,48 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ value comparison") } } +func TestFlattenNameSpaceSelector(t *testing.T) { + secondSelector := &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + "frontend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + "b", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + "y", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + } + + testSelectors := FlattenNameSpaceSelector(secondSelector) + + if len(testSelectors) != 4 { + t.Error(testSelectors) + } +} diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index e795b0aafd..faf6f7973e 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -476,24 +476,129 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } if fromRule.PodSelector == nil && fromRule.NamespaceSelector != nil { - iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) - if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { - // Empty namespaceSelector. This selects all namespaces - nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag - if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { - lists[nsLabelsWithoutOps[0]] = nil + for _, nsSelector := range FlattenNameSpaceSelector(fromRule.NamespaceSelector) { + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesSrcFlag, true) + if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { + // Empty namespaceSelector. This selects all namespaces + nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } + } else { + for i, _ := range nsLabelsWithoutOps { + // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } - } else { - for i, _ := range nsLabelsWithoutOps { - // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) + if portRuleExists { + for _, portRule := range rule.Ports { + switch portCheck := getPortType(portRule); portCheck { + case "namedport": + portName := util.NamedPortIPSetPrefix + portRule.Port.String() + namedPorts = append(namedPorts, portName) + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureIngressPortChain, + Specs: append([]string(nil), targetSelectorIptEntrySpec...), + } + entry.Specs = append( + entry.Specs, + iptPartialNsSpec..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName(portName), + util.IptablesDstFlag+","+util.IptablesDstFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureIngressMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+iptPartialNsComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ + "-TO-"+targetSelectorComment, + ) + entries = append(entries, entry) + case "validport": + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureIngressPortChain, + Specs: append([]string(nil), targetSelectorIptEntrySpec...), + } + entry.Specs = append( + entry.Specs, + iptPartialNsSpec..., + ) + entry.Specs = append( + entry.Specs, + craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureIngressMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+iptPartialNsComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ + "-TO-"+targetSelectorComment, + ) + entries = append(entries, entry) + default: + log.Logf("Invalid NetworkPolicyPort.") + } + } + } else { + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureIngressFromChain, + Specs: append([]string(nil), iptPartialNsSpec...), } + entry.Specs = append( + entry.Specs, + targetSelectorIptEntrySpec..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureIngressMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+iptPartialNsComment+ + "-TO-"+targetSelectorComment, + ) + entries = append(entries, entry) + addedIngressFromEntry = true + } + } + continue + } + + if fromRule.PodSelector != nil && fromRule.NamespaceSelector == nil { + // TODO check old code if we need any ns- prefix for pod selectors + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) + if len(podLabelsWithoutOps) == 1 { + if podLabelsWithoutOps[0] == "" { + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } - iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) + sets = append(sets, podLabelsWithoutOps...) + // TODO check this if ns- is needed here. + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { switch portCheck := getPortType(portRule); portCheck { @@ -506,7 +611,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } entry.Specs = append( entry.Specs, - iptPartialNsSpec..., + iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, @@ -522,7 +627,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ + "ALLOW-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) @@ -534,7 +639,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } entry.Specs = append( entry.Specs, - iptPartialNsSpec..., + iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, @@ -549,7 +654,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ + "ALLOW-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) @@ -561,7 +666,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } else { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressFromChain, - Specs: append([]string(nil), iptPartialNsSpec...), + Specs: append([]string(nil), iptPartialPodSpec...), } entry.Specs = append( entry.Specs, @@ -576,7 +681,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ + "ALLOW-"+iptPartialPodComment+ "-TO-"+targetSelectorComment, ) entries = append(entries, entry) @@ -585,18 +690,28 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS continue } - if fromRule.PodSelector != nil && fromRule.NamespaceSelector == nil { - // TODO check old code if we need any ns- prefix for pod selectors - iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, fromRule.PodSelector, util.IptablesSrcFlag, false) - if len(podLabelsWithoutOps) == 1 { - if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) + // fromRule has both namespaceSelector and podSelector set. + // We should match the selected pods in the selected namespaces. + // This allows traffic from podSelector intersects namespaceSelector + // This is only supported in kubernetes version >= 1.11 + if !util.IsNewNwPolicyVerFlag { + continue + } + for _, nsSelector := range FlattenNameSpaceSelector(fromRule.NamespaceSelector) { + // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets + for i, _ := range nsLabelsWithoutOps { + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil } } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) sets = append(sets, podLabelsWithoutOps...) - // TODO check this if ns- is needed here. appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) - iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) + iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) + iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { switch portCheck := getPortType(portRule); portCheck { @@ -605,12 +720,16 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS namedPorts = append(namedPorts, portName) entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), + Specs: append([]string(nil), iptPartialNsSpec...), } entry.Specs = append( entry.Specs, iptPartialPodSpec..., ) + entry.Specs = append( + entry.Specs, + targetSelectorIptEntrySpec..., + ) entry.Specs = append( entry.Specs, util.IptablesModuleFlag, @@ -625,7 +744,8 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialPodComment+ + "ALLOW-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) @@ -633,12 +753,16 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), + Specs: append([]string(nil), iptPartialNsSpec...), } entry.Specs = append( entry.Specs, iptPartialPodSpec..., ) + entry.Specs = append( + entry.Specs, + targetSelectorIptEntrySpec..., + ) entry.Specs = append( entry.Specs, craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., @@ -652,7 +776,8 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialPodComment+ + "ALLOW-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) @@ -664,11 +789,15 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS } else { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressFromChain, - Specs: append([]string(nil), iptPartialPodSpec...), + Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, - targetSelectorIptEntrySpec..., + iptPartialNsSpec..., + ) + entry.Specs = append( + entry.Specs, + iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, @@ -679,139 +808,13 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialPodComment+ + "ALLOW-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment+ "-TO-"+targetSelectorComment, ) entries = append(entries, entry) addedIngressFromEntry = true } - continue - } - - // fromRule has both namespaceSelector and podSelector set. - // We should match the selected pods in the selected namespaces. - // This allows traffic from podSelector intersects namespaceSelector - // This is only supported in kubernetes version >= 1.11 - if !util.IsNewNwPolicyVerFlag { - continue - } - - // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.NamespaceSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets - for i, _ := range nsLabelsWithoutOps { - nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil - } - } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) - iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) - sets = append(sets, podLabelsWithoutOps...) - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) - iptPartialNsComment := craftPartialIptablesCommentFromSelector("", fromRule.NamespaceSelector, true) - iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) - if portRuleExists { - for _, portRule := range rule.Ports { - switch portCheck := getPortType(portRule); portCheck { - case "namedport": - portName := util.NamedPortIPSetPrefix + portRule.Port.String() - namedPorts = append(namedPorts, portName) - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureIngressPortChain, - Specs: append([]string(nil), iptPartialNsSpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - targetSelectorIptEntrySpec..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName(portName), - util.IptablesDstFlag+","+util.IptablesDstFlag, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureIngressMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ - "-TO-"+targetSelectorComment, - ) - entries = append(entries, entry) - case "validport": - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureIngressPortChain, - Specs: append([]string(nil), iptPartialNsSpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - targetSelectorIptEntrySpec..., - ) - entry.Specs = append( - entry.Specs, - craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureIngressMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ - "-TO-"+targetSelectorComment, - ) - entries = append(entries, entry) - default: - log.Logf("Invalid NetworkPolicyPort.") - } - } - } else { - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureIngressFromChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialNsSpec..., - ) - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureIngressMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment+ - "-TO-"+targetSelectorComment, - ) - entries = append(entries, entry) - addedIngressFromEntry = true } } @@ -1172,24 +1175,128 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } if toRule.PodSelector == nil && toRule.NamespaceSelector != nil { - iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) - if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { - // Empty namespaceSelector. This selects all namespaces - nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag - if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { - lists[nsLabelsWithoutOps[0]] = nil + for _, nsSelector := range FlattenNameSpaceSelector(toRule.NamespaceSelector) { + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesDstFlag, true) + if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { + // Empty namespaceSelector. This selects all namespaces + nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag + if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { + lists[nsLabelsWithoutOps[0]] = nil + } + } else { + for i, _ := range nsLabelsWithoutOps { + // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets + nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil + } + } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } - } else { - for i, _ := range nsLabelsWithoutOps { - // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets - nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) + if portRuleExists { + for _, portRule := range rule.Ports { + switch portCheck := getPortType(portRule); portCheck { + case "namedport": + portName := util.NamedPortIPSetPrefix + portRule.Port.String() + namedPorts = append(namedPorts, portName) + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + Specs: append([]string(nil), iptPartialNsSpec...), + } + entry.Specs = append( + entry.Specs, + targetSelectorIptEntrySpec..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName(portName), + util.IptablesDstFlag+","+util.IptablesDstFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureEgressXMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+iptPartialNsComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ + "-FROM-"+targetSelectorComment, + ) + entries = append(entries, entry) + case "validport": + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureEgressPortChain, + Specs: append([]string(nil), iptPartialNsSpec...), + } + entry.Specs = append( + entry.Specs, + craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., + ) + entry.Specs = append( + entry.Specs, + targetSelectorIptEntrySpec..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureEgressXMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+iptPartialNsComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ + "-FROM-"+targetSelectorComment, + ) + entries = append(entries, entry) + default: + log.Logf("Invalid NetworkPolicyPort.") + } } + } else { + entry := &iptm.IptEntry{ + Chain: util.IptablesAzureEgressToChain, + Specs: append([]string(nil), targetSelectorIptEntrySpec...), + } + entry.Specs = append( + entry.Specs, + iptPartialNsSpec..., + ) + entry.Specs = append( + entry.Specs, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureEgressXMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-"+targetSelectorComment+ + "-TO-"+iptPartialNsComment, + ) + entries = append(entries, entry) + addedEgressToEntry = true + } + } + continue + } + + if toRule.PodSelector != nil && toRule.NamespaceSelector == nil { + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) + if len(podLabelsWithoutOps) == 1 { + if podLabelsWithoutOps[0] == "" { + podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) } - iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) + sets = append(sets, podLabelsWithoutOps...) + // TODO check if the ns- is needed here ? + appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { switch portCheck := getPortType(portRule); portCheck { @@ -1198,7 +1305,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe namedPorts = append(namedPorts, portName) entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), iptPartialNsSpec...), + Specs: append([]string(nil), iptPartialPodSpec...), } entry.Specs = append( entry.Specs, @@ -1218,7 +1325,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ + "ALLOW-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) @@ -1226,7 +1333,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), iptPartialNsSpec...), + Specs: append([]string(nil), iptPartialPodSpec...), } entry.Specs = append( entry.Specs, @@ -1245,7 +1352,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialNsComment+ + "ALLOW-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) @@ -1261,7 +1368,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe } entry.Specs = append( entry.Specs, - iptPartialNsSpec..., + iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, @@ -1273,7 +1380,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+targetSelectorComment+ - "-TO-"+iptPartialNsComment, + "-TO-"+iptPartialPodComment, ) entries = append(entries, entry) addedEgressToEntry = true @@ -1281,17 +1388,29 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe continue } - if toRule.PodSelector != nil && toRule.NamespaceSelector == nil { - iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, toRule.PodSelector, util.IptablesDstFlag, false) - if len(podLabelsWithoutOps) == 1 { - if podLabelsWithoutOps[0] == "" { - podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) + // toRule has both namespaceSelector and podSelector set. + // We should match the selected pods in the selected namespaces. + // This allows traffic from podSelector intersects namespaceSelector + // This is only supported in kubernetes version >= 1.11 + if !util.IsNewNwPolicyVerFlag { + continue + } + for _, nsSelector := range FlattenNameSpaceSelector(toRule.NamespaceSelector) { + // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace + iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesDstFlag, true) + // Add namespaces prefix to distinguish namespace ipsets and pod ipsets + for i, _ := range nsLabelsWithoutOps { + nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] + if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { + lists[nsLabelsWithoutOps[i]] = nil } } + appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) sets = append(sets, podLabelsWithoutOps...) - // TODO check if the ns- is needed here ? appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) - iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) + iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) + iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { switch portCheck := getPortType(portRule); portCheck { @@ -1300,11 +1419,15 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe namedPorts = append(namedPorts, portName) entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), iptPartialPodSpec...), + Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, - targetSelectorIptEntrySpec..., + iptPartialNsSpec..., + ) + entry.Specs = append( + entry.Specs, + iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, @@ -1320,23 +1443,28 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ - "-FROM-"+targetSelectorComment, + "ALLOW-"+targetSelectorComment+ + "-TO-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag), ) entries = append(entries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), iptPartialPodSpec...), + Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, - craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., + iptPartialNsSpec..., ) entry.Specs = append( entry.Specs, - targetSelectorIptEntrySpec..., + iptPartialPodSpec..., + ) + entry.Specs = append( + entry.Specs, + craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., ) entry.Specs = append( entry.Specs, @@ -1347,9 +1475,10 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ - "-FROM-"+targetSelectorComment, + "ALLOW-"+targetSelectorComment+ + "-TO-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment+ + "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag), ) entries = append(entries, entry) default: @@ -1361,6 +1490,10 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe Chain: util.IptablesAzureEgressToChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } + entry.Specs = append( + entry.Specs, + iptPartialNsSpec..., + ) entry.Specs = append( entry.Specs, iptPartialPodSpec..., @@ -1375,139 +1508,12 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+targetSelectorComment+ - "-TO-"+iptPartialPodComment, + "-TO-"+iptPartialNsComment+ + "-AND-"+iptPartialPodComment, ) entries = append(entries, entry) addedEgressToEntry = true } - continue - } - - // toRule has both namespaceSelector and podSelector set. - // We should match the selected pods in the selected namespaces. - // This allows traffic from podSelector intersects namespaceSelector - // This is only supported in kubernetes version >= 1.11 - if !util.IsNewNwPolicyVerFlag { - continue - } - - // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace - iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.NamespaceSelector, util.IptablesDstFlag, true) - // Add namespaces prefix to distinguish namespace ipsets and pod ipsets - for i, _ := range nsLabelsWithoutOps { - nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil - } - } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) - iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) - sets = append(sets, podLabelsWithoutOps...) - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) - iptPartialNsComment := craftPartialIptablesCommentFromSelector("", toRule.NamespaceSelector, true) - iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) - if portRuleExists { - for _, portRule := range rule.Ports { - switch portCheck := getPortType(portRule); portCheck { - case "namedport": - portName := util.NamedPortIPSetPrefix + portRule.Port.String() - namedPorts = append(namedPorts, portName) - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialNsSpec..., - ) - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName(portName), - util.IptablesDstFlag+","+util.IptablesDstFlag, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureEgressXMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+targetSelectorComment+ - "-TO-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag), - ) - entries = append(entries, entry) - case "validport": - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureEgressPortChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialNsSpec..., - ) - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag)..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureEgressXMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+targetSelectorComment+ - "-TO-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment+ - "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag), - ) - entries = append(entries, entry) - default: - log.Logf("Invalid NetworkPolicyPort.") - } - } - } else { - entry := &iptm.IptEntry{ - Chain: util.IptablesAzureEgressToChain, - Specs: append([]string(nil), targetSelectorIptEntrySpec...), - } - entry.Specs = append( - entry.Specs, - iptPartialNsSpec..., - ) - entry.Specs = append( - entry.Specs, - iptPartialPodSpec..., - ) - entry.Specs = append( - entry.Specs, - util.IptablesJumpFlag, - util.IptablesMark, - util.IptablesSetMarkFlag, - util.IptablesAzureEgressXMarkHex, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - "ALLOW-"+targetSelectorComment+ - "-TO-"+iptPartialNsComment+ - "-AND-"+iptPartialPodComment, - ) - entries = append(entries, entry) - addedEgressToEntry = true } } @@ -1680,6 +1686,9 @@ func translatePolicy(npObj *networkingv1.NetworkPolicy) ([]string, []string, map policyName := npObj.ObjectMeta.Name resultListMap = make(map[string][]string) + // Since nested ipset list:sets are not allowed. We cannot use 2nd level Ipsets + // for NameSpaceSelectors with multiple values + // NPM will need to duplicate rules for each value in NSSelector if len(npObj.Spec.PolicyTypes) == 0 { ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) From 51c0a62ae3eb4aa26e2125df0c74c8e947928e6c Mon Sep 17 00:00:00 2001 From: vakr Date: Thu, 6 May 2021 15:06:15 -0700 Subject: [PATCH 25/34] correcting some UTs for nsselectors --- npm/parseSelector_test.go | 47 ++++++++++++++++++-- npm/translatePolicy.go | 3 -- npm/translatePolicy_test.go | 89 ++++++++++++++++++++++++++++++++----- 3 files changed, 120 insertions(+), 19 deletions(-) diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 8523f05e6e..0b5733c39c 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -473,6 +473,46 @@ func TestParseSelector(t *testing.T) { } } func TestFlattenNameSpaceSelector(t *testing.T) { + firstSelector := &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + } + + testSelectors := FlattenNameSpaceSelector(firstSelector) + if len(testSelectors) != 1 { + t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors) + } + secondSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ metav1.LabelSelectorRequirement{ @@ -511,9 +551,8 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, } - testSelectors := FlattenNameSpaceSelector(secondSelector) - - if len(testSelectors) != 4 { - t.Error(testSelectors) + testSelectors = FlattenNameSpaceSelector(secondSelector) + if len(testSelectors) != 8 { + t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector length check %+v", testSelectors) } } diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index faf6f7973e..8e05c0a3a3 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -3,7 +3,6 @@ package npm import ( - "sort" "strconv" "github.com/Azure/azure-container-networking/log" @@ -188,8 +187,6 @@ func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSe } } - // sort the slices to remove ambuigivity on ordering of labels for comments - sort.Sort(sort.StringSlice(labelsWithoutOps)) for i, _ := range labelsWithoutOps { comment += prefix + ops[i] + labelsWithoutOps[i] comment += "-AND-" diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 3146524ff4..64c2d46266 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -1745,10 +1745,6 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { "ns-namespace:dev": {}, "ns-namespace:test0": {}, "ns-namespace:test1": {}, - "ns-namespace:test0:test1": { - "namespace:test0", - "namespace:test1", - }, } if !reflect.DeepEqual(lists, expectedLists) { t.Errorf("translatedPolicy failed @ ALLOW-ns-namespace:dev-AND-!ns-namespace:test0:test1-TO-app:frontend-policy lists comparison") @@ -1770,7 +1766,41 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesSetModuleFlag, util.IptablesNotFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-namespace:test0:test1"), + util.GetHashedName("ns-namespace:test0"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-testnamespace"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:frontend"), + util.IptablesDstFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureIngressMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0-TO-app:frontend-IN-ns-testnamespace", + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureIngressFromChain, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-namespace:dev"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesNotFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-namespace:test1"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, @@ -1789,7 +1819,7 @@ func TestAllowNamespaceDevToAppFrontend(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ns-namespace:dev-AND-ns-!namespace:test0:test1-TO-app:frontend-IN-ns-testnamespace", + "ALLOW-ns-namespace:dev-AND-ns-!namespace:test1-TO-app:frontend-IN-ns-testnamespace", }, }, &iptm.IptEntry{ @@ -2868,10 +2898,6 @@ func TestAllowMultiplePodSelectors(t *testing.T) { "app:int", }, "ns-ns:netpol-4537-x": {}, - "ns-ns:netpol-4537-x:netpol-4537-y": { - "ns-ns:netpol-4537-x", - "ns-ns:netpol-4537-y", - }, "ns-ns:netpol-4537-y": {}, "pod:a:x": { "pod:a", @@ -2907,7 +2933,46 @@ func TestAllowMultiplePodSelectors(t *testing.T) { util.IptablesSetModuleFlag, util.IptablesNotFlag, util.IptablesMatchSetFlag, - util.GetHashedName("ns-ns:netpol-4537-x:netpol-4537-y"), + util.GetHashedName("ns-ns:netpol-4537-x"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:b:c"), + util.IptablesSrcFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("app:test:int"), + util.IptablesSrcFlag, + util.IptablesJumpFlag, + util.IptablesMark, + util.IptablesSetMarkFlag, + util.IptablesAzureIngressMarkHex, + util.IptablesModuleFlag, + util.IptablesCommentModuleFlag, + util.IptablesCommentFlag, + "ALLOW-ns-!ns:netpol-4537-x-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", + }, + }, + &iptm.IptEntry{ + Chain: util.IptablesAzureIngressFromChain, + Specs: []string{ + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-netpol-4537-x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("pod:a:x"), + util.IptablesDstFlag, + util.IptablesModuleFlag, + util.IptablesSetModuleFlag, + util.IptablesNotFlag, + util.IptablesMatchSetFlag, + util.GetHashedName("ns-ns:netpol-4537-y"), util.IptablesSrcFlag, util.IptablesModuleFlag, util.IptablesSetModuleFlag, @@ -2926,7 +2991,7 @@ func TestAllowMultiplePodSelectors(t *testing.T) { util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, - "ALLOW-ns-!ns:netpol-4537-x:netpol-4537-y-AND-app:test:int-AND-pod:b:c-TO-pod:a:x-IN-ns-netpol-4537-x", + "ALLOW-ns-!ns:netpol-4537-y-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", }, }, &iptm.IptEntry{ From 8a0b4a5eeaa6bc25549de5945a784f182b441505 Mon Sep 17 00:00:00 2001 From: vakr Date: Thu, 6 May 2021 15:36:42 -0700 Subject: [PATCH 26/34] putting back removed testcase to resolve conflicts --- npm/ipsm/ipsm.go | 27 +++++++++++++++++++++++++++ npm/ipsm/ipsm_test.go | 21 +++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index d61b8cfb29..46affd7914 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -462,6 +462,33 @@ func (ipsMgr *IpsetManager) DeleteFromSet(setName, ip, podKey string) error { return nil } +// Clean removes all the empty sets & lists under the namespace. +func (ipsMgr *IpsetManager) Clean() error { + for setName, set := range ipsMgr.SetMap { + if len(set.elements) > 0 { + continue + } + + if err := ipsMgr.DeleteSet(setName); err != nil { + metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset") + return err + } + } + + for listName, list := range ipsMgr.ListMap { + if len(list.elements) > 0 { + continue + } + + if err := ipsMgr.DeleteList(listName); err != nil { + metrics.SendErrorLogAndMetric(util.IpsmID, "Error: failed to clean ipset list") + return err + } + } + + return nil +} + // Destroy completely cleans ipset. func (ipsMgr *IpsetManager) Destroy() error { entry := &ipsEntry{ diff --git a/npm/ipsm/ipsm_test.go b/npm/ipsm/ipsm_test.go index 9f6a70c8fd..5f98876d9f 100644 --- a/npm/ipsm/ipsm_test.go +++ b/npm/ipsm/ipsm_test.go @@ -465,6 +465,27 @@ func TestDeleteFromSetWithPodCache(t *testing.T) { } } +func TestClean(t *testing.T) { + ipsMgr := NewIpsetManager() + if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { + t.Errorf("TestClean failed @ ipsMgr.Save") + } + + defer func() { + if err := ipsMgr.Restore(util.IpsetTestConfigFile); err != nil { + t.Errorf("TestClean failed @ ipsMgr.Restore") + } + }() + + if err := ipsMgr.CreateSet("test-set", append([]string{util.IpsetNetHashFlag})); err != nil { + t.Errorf("TestClean failed @ ipsMgr.CreateSet with err %+v", err) + } + + if err := ipsMgr.Clean(); err != nil { + t.Errorf("TestClean failed @ ipsMgr.Clean") + } +} + func TestDestroy(t *testing.T) { ipsMgr := NewIpsetManager() if err := ipsMgr.Save(util.IpsetTestConfigFile); err != nil { From 8b383d69e5720066d05d04000f23fcf3770c6406 Mon Sep 17 00:00:00 2001 From: vakr Date: Wed, 19 May 2021 13:52:13 -0700 Subject: [PATCH 27/34] addressing some comments --- npm/ipsm/ipsm.go | 16 ++++++++-------- npm/parseSelector.go | 26 +++++++++----------------- 2 files changed, 17 insertions(+), 25 deletions(-) diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index 46affd7914..7df23d1bd1 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -21,7 +21,7 @@ type ReferCountOperation bool const ( IncrementOp ReferCountOperation = true - DecrmentOp ReferCountOperation = false + DecrementOp ReferCountOperation = false ) type ipsEntry struct { @@ -44,11 +44,11 @@ type Ipset struct { referCount int } -func (ipset *Ipset) IncReferCount() { +func (ipset *Ipset) incReferCount() { ipset.referCount++ } -func (ipset *Ipset) DecReferCount() { +func (ipset *Ipset) decReferCount() { ipset.referCount-- } @@ -87,7 +87,7 @@ func (ipsMgr *IpsetManager) Exists(listName string, setName string, kind string) return true } -// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases tis refer count. +// IpSetReferIncOrDec checks if an element exists in setMap/listMap and then increases or decreases this referCount. func (ipsMgr *IpsetManager) IpSetReferIncOrDec(ipsetName string, kind string, countOperation ReferCountOperation) { m := ipsMgr.SetMap if kind == util.IpsetSetListFlag { @@ -96,9 +96,9 @@ func (ipsMgr *IpsetManager) IpSetReferIncOrDec(ipsetName string, kind string, co switch countOperation { case IncrementOp: - m[ipsetName].IncReferCount() - case DecrmentOp: - m[ipsetName].DecReferCount() + m[ipsetName].incReferCount() + case DecrementOp: + m[ipsetName].decReferCount() } } @@ -152,7 +152,7 @@ func (ipsMgr *IpsetManager) DeleteList(listName string) error { } if ipsMgr.ListMap[listName].referCount > 0 { - ipsMgr.IpSetReferIncOrDec(listName, util.IpsetSetListFlag, DecrmentOp) + ipsMgr.IpSetReferIncOrDec(listName, util.IpsetSetListFlag, DecrementOp) return nil } diff --git a/npm/parseSelector.go b/npm/parseSelector.go index af9355b8a1..d3d61d192e 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -124,11 +124,11 @@ func sortSelector(selector *metav1.LabelSelector) { // getSetNameForMultiValueSelector takes in label with multiple values without operator // and returns a new 2nd level ipset name func getSetNameForMultiValueSelector(key string, vals []string) string { - rtStr := key + returnString := key for _, val := range vals { - rtStr = util.GetIpSetFromLabelKV(rtStr, val) + returnString = util.GetIpSetFromLabelKV(returnString, val) } - return rtStr + return returnString } // HashSelector returns the hash value of the selector. @@ -160,27 +160,19 @@ func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSe multiValuePresent := false multiValueMatchExprs := []metav1.LabelSelectorRequirement{} for _, req := range nsSelector.MatchExpressions { - switch op := req.Operator; op { - case metav1.LabelSelectorOpIn: - if len(req.Values) == 1 { - baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) - continue - } - multiValuePresent = true - multiValueMatchExprs = append(multiValueMatchExprs, req) - case metav1.LabelSelectorOpNotIn: + + if (req.Operator == metav1.LabelSelectorOpIn) || (req.Operator == metav1.LabelSelectorOpNotIn) { if len(req.Values) == 1 { baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) continue } multiValuePresent = true multiValueMatchExprs = append(multiValueMatchExprs, req) - case metav1.LabelSelectorOpExists: - baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) - case metav1.LabelSelectorOpDoesNotExist: + + } else if (req.Operator == metav1.LabelSelectorOpExists) || (req.Operator == metav1.LabelSelectorOpDoesNotExist) { baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) - default: - log.Errorf("Invalid operator [%s] for selector [%v] requirement", op, *nsSelector) + } else { + log.Errorf("Invalid operator [%s] for selector [%v] requirement", req.Operator, *nsSelector) } } From a6e7867d8eaae27c12fd0c2341103265733a6021 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 25 May 2021 12:10:42 -0700 Subject: [PATCH 28/34] Addressing some comments regarding policy translation --- npm/parseSelector.go | 87 ++++++--- npm/parseSelector_test.go | 389 ++++++++++++++++++++++++++++++++++++++ npm/translatePolicy.go | 111 ++++++----- 3 files changed, 516 insertions(+), 71 deletions(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index d3d61d192e..07cde64c26 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -124,11 +124,11 @@ func sortSelector(selector *metav1.LabelSelector) { // getSetNameForMultiValueSelector takes in label with multiple values without operator // and returns a new 2nd level ipset name func getSetNameForMultiValueSelector(key string, vals []string) string { - returnString := key + newIpSet := key for _, val := range vals { - returnString = util.GetIpSetFromLabelKV(returnString, val) + newIpSet = util.GetIpSetFromLabelKV(newIpSet, val) } - return returnString + return newIpSet } // HashSelector returns the hash value of the selector. @@ -140,10 +140,41 @@ func HashSelector(selector *metav1.LabelSelector) string { // flattenNameSpaceSelector will help flatten multiple NameSpace selector match Expressions values // into multiple label selectors helping with the OR condition. func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSelector { - //egress section - // for _, egressRule := range nsSelector { - // log.Logf("%+v", egressRule) - // } + /* + This function helps to create multiple labelSelectors when given a single multivalue nsSelector + Take below exmaple: this nsSelector has 2 values in a matchSelector. + - namespaceSelector: + matchExpressions: + - key: ns + operator: NotIn + values: + - netpol-x + - netpol-y + + goal is to convert this single nsSelector into multiple nsSelectors to preserve OR condition + between multiple values of the matchExpr i.e. this function will return + + - namespaceSelector: + matchExpressions: + - key: ns + operator: NotIn + values: + - netpol-x + - namespaceSelector: + matchExpressions: + - key: ns + operator: NotIn + values: + - netpol-y + + then, translate policy will replicate each of these nsSelectors to add two different rules in iptables, + resulting in OR condition between the values. + + Check TestFlattenNameSpaceSelector 2nd subcase for complex scenario + */ + + // To avoid any additional length checks, just return a slice of labelSelectors + // with original nsSelector if nsSelector == nil { return []metav1.LabelSelector{*nsSelector} } @@ -152,6 +183,8 @@ func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSe return []metav1.LabelSelector{*nsSelector} } + // create a baseSelector which needs to be same across all + // new labelSelectors baseSelector := &metav1.LabelSelector{ MatchLabels: nsSelector.MatchLabels, MatchExpressions: []metav1.LabelSelectorRequirement{}, @@ -161,15 +194,20 @@ func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSe multiValueMatchExprs := []metav1.LabelSelectorRequirement{} for _, req := range nsSelector.MatchExpressions { + // Only In and NotIn operators of matchExprs have multiple values + // NPM will ignore single value matchExprs of these operators. + // for multiple values, it will create a slice of them to be used for Zipping with baseSelector + // to create multiple nsSelectors to preserve OR condition across all labels and expressions if (req.Operator == metav1.LabelSelectorOpIn) || (req.Operator == metav1.LabelSelectorOpNotIn) { if len(req.Values) == 1 { + // for length 1, add the matchExpr to baseSelector baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) - continue + } else { + multiValuePresent = true + multiValueMatchExprs = append(multiValueMatchExprs, req) } - multiValuePresent = true - multiValueMatchExprs = append(multiValueMatchExprs, req) - } else if (req.Operator == metav1.LabelSelectorOpExists) || (req.Operator == metav1.LabelSelectorOpDoesNotExist) { + // since Exists and NotExists do not contain any values, NPM can safely add them to the baseSelector baseSelector.MatchExpressions = append(baseSelector.MatchExpressions, req) } else { log.Errorf("Invalid operator [%s] for selector [%v] requirement", req.Operator, *nsSelector) @@ -194,6 +232,11 @@ func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSe return flatNsSelectors } +// zipMatchExprs helps with zipping a given matchExpr with given baseLabelSelectors +// this func will loop over each baseSelector in the slice, +// deepCopies each baseSelector, combines with given matchExpr by looping over each value +// and creating a new LabelSelector with given baseSelector and value matchExpr +// then returns a new slice of these zipped LabelSelectors func zipMatchExprs(baseSelectors []metav1.LabelSelector, matchExpr metav1.LabelSelectorRequirement) []metav1.LabelSelector { zippedLabelSelectors := []metav1.LabelSelector{} for _, selector := range baseSelectors { @@ -248,22 +291,22 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin k = req.Key if len(req.Values) == 1 { labels = append(labels, k+":"+req.Values[0]) - continue - } - // We are not adding the k:v to labels for multiple values, because, labels are used - // to contruct partial IptEntries and if these below labels are added then we are inducing - // AND condition on values of a match expression instead of OR - for _, v := range req.Values { - vals[k] = append(vals[k], v) + } else { + // We are not adding the k:v to labels for multiple values, because, labels are used + // to contruct partial IptEntries and if these below labels are added then we are inducing + // AND condition on values of a match expression instead of OR + for _, v := range req.Values { + vals[k] = append(vals[k], v) + } } case metav1.LabelSelectorOpNotIn: k = util.IptablesNotFlag + req.Key if len(req.Values) == 1 { labels = append(labels, k+":"+req.Values[0]) - continue - } - for _, v := range req.Values { - vals[k] = append(vals[k], v) + } else { + for _, v := range req.Values { + vals[k] = append(vals[k], v) + } } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 0b5733c39c..b8edf04eca 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -513,6 +513,10 @@ func TestFlattenNameSpaceSelector(t *testing.T) { t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors) } + if !reflect.DeepEqual(testSelectors[0], *firstSelector) { + t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector deepEqual check.\n Expected: %+v \n Actual: %+v", *firstSelector, testSelectors[0]) + } + secondSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ metav1.LabelSelectorRequirement{ @@ -555,4 +559,389 @@ func TestFlattenNameSpaceSelector(t *testing.T) { if len(testSelectors) != 8 { t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector length check %+v", testSelectors) } + + expectedSelectors := []metav1.LabelSelector{ + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "y", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "b", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "b", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "y", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "frontend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "frontend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "y", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "frontend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "b", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "frontend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "b", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "y", + }, + }, + }, + MatchLabels: map[string]string{ + "c": "d", + "a": "b", + }, + }, + } + + if !reflect.DeepEqual(expectedSelectors, testSelectors) { + t.Errorf("TestFlattenNameSpaceSelector failed @ 2nd selector deepEqual check.\n Expected: %+v \n Actual: %+v", expectedSelectors, testSelectors) + } +} + +func TestFlattenNameSpaceSelectorWoMatchLabels(t *testing.T) { + firstSelector := &metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + "y", + }, + }, + }, + } + + testSelectors := FlattenNameSpaceSelector(firstSelector) + if len(testSelectors) != 2 { + t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector length check %+v", testSelectors) + } + + expectedSelectors := []metav1.LabelSelector{ + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "t", + }, + }, + }, + }, + metav1.LabelSelector{ + MatchExpressions: []metav1.LabelSelectorRequirement{ + metav1.LabelSelectorRequirement{ + Key: "testIn", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "backend", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "pod", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "a", + }, + }, + metav1.LabelSelectorRequirement{ + Key: "testExists", + Operator: metav1.LabelSelectorOpExists, + Values: []string{}, + }, + metav1.LabelSelectorRequirement{ + Key: "ns", + Operator: metav1.LabelSelectorOpIn, + Values: []string{ + "y", + }, + }, + }, + }, + } + + if !reflect.DeepEqual(testSelectors, expectedSelectors) { + t.Errorf("TestFlattenNameSpaceSelector failed @ 1st selector deepEqual check.\n Expected: %+v \n Actual: %+v", expectedSelectors, testSelectors) + } } diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index 8e05c0a3a3..169e17b734 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -122,7 +122,13 @@ func craftPartialIptEntrySpecFromOpsAndLabels(ns string, ops, labels []string, s } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors -// TODO check all references of this func +// func helps in taking a labelSelector and converts it into corresponding matchSets +// to be a used in full iptable rules +// selector *metav1.LabelSelector: is used to create matchSets +// ns string: helps with adding a namespace name in case of empty (or all) selector +// srcOrDstFlag string: helps with determining if the src flag is to used in matchsets or dst flag, +// depending on ingress or egress translate policy +// isNamespaceSelector bool: helps in adding prefix for nameSpace ipsets func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelector, srcOrDstFlag string, isNamespaceSelector bool) ([]string, []string, map[string][]string) { // parse the sector into labels and maps of multiVal match Exprs labelsWithOps, nsLabelListKVs := parseSelector(selector) @@ -131,11 +137,18 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec valueLabels := []string{} listLabelsWithMembers := make(map[string][]string) labelsForSpec := labels - // TODO add comments very confusing for sure + // parseSelector returns a slice of processed label and a map of lists with members. + // now we need to compute the 2nd-level ipset names from lists and its members + // add use those 2nd level ipsets to be used to create the partial match set for labelKeyWithOps, labelValueList := range nsLabelListKVs { + // look at each list and its members op, labelKey := GetOperatorAndLabel(labelKeyWithOps) + // get the new 2nd level IpSet name labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) if !util.StrExistsInSlice(labels, labelKVIpsetName) { + // Important: make sure length andordering of ops and labelsForSpec are same + // because craftPartialEntry loops over both of them at once and assumes + // a given position ops is to be applied on the same position label in labelsForSpec ops = append(ops, op) // TODO doubt check if this 2nd level needs to be added to the labels when labels are added to lists // check if the 2nd level is already part of labels @@ -148,8 +161,8 @@ func craftPartialIptEntrySpecFromSelector(ns string, selector *metav1.LabelSelec } } iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labelsForSpec, srcOrDstFlag, isNamespaceSelector) - // only append valueLabels to labels after creating the Ipt Spec as valueLabels - // are included in labelKVIpsetName + // only append valueLabels to labels after creating the Ipt Spec with valueLabels + // as 1D valueLabels are included in 2nd level labelKVIpsetName labels = append(labels, valueLabels...) return iptEntrySpecs, labels, listLabelsWithMembers } @@ -211,9 +224,9 @@ func appendSelectorLabelsToLists(lists, listLabelsWithMembers map[string][]strin func translateIngress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyIngressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash + netHashIPsets []string // ipsets with type: net:hash namedPorts []string // ipsets with type: hash:ip,port - lists map[string][]string // ipsets with type: list:set + listIPsets map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry fromRuleEntries []*iptm.IptEntry @@ -222,14 +235,14 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) log.Logf("started parsing ingress rule") - sets = append(sets, "ns-"+ns) + netHashIPsets = append(netHashIPsets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) - lists = make(map[string][]string) + listIPsets = make(map[string][]string) targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) - sets = append(sets, labels...) + netHashIPsets = append(netHashIPsets, labels...) for parsedListName, parsedListMembers := range listLabelsWithMembers { - lists[parsedListName] = append(lists[parsedListName], parsedListMembers...) + listIPsets[parsedListName] = append(listIPsets[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) @@ -285,7 +298,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS ) entries = append(entries, entry) - lists[util.KubeAllNamespacesFlag] = []string{} + listIPsets[util.KubeAllNamespacesFlag] = []string{} continue } @@ -478,18 +491,18 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag - if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { - lists[nsLabelsWithoutOps[0]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[0]]; !ok { + listIPsets[nsLabelsWithoutOps[0]] = nil } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { + listIPsets[nsLabelsWithoutOps[i]] = nil } } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) if portRuleExists { @@ -592,9 +605,9 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } - sets = append(sets, podLabelsWithoutOps...) + netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) // TODO check this if ns- is needed here. - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, fromRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -699,14 +712,14 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { + listIPsets[nsLabelsWithoutOps[i]] = nil } } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) - sets = append(sets, podLabelsWithoutOps...) - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) + appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", fromRule.PodSelector, false) if portRuleExists { @@ -898,19 +911,19 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS entries = append(entries, entry) } - for parsedKey, parsedValue := range lists { - lists[parsedKey] = util.DropEmptyFields(parsedValue) + for parsedKey, parsedValue := range listIPsets { + listIPsets[parsedKey] = util.DropEmptyFields(parsedValue) } log.Logf("finished parsing ingress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries + return util.DropEmptyFields(netHashIPsets), util.DropEmptyFields(namedPorts), listIPsets, ipCidrs, entries } func translateEgress(ns string, policyName string, targetSelector metav1.LabelSelector, rules []networkingv1.NetworkPolicyEgressRule) ([]string, []string, map[string][]string, [][]string, []*iptm.IptEntry) { var ( - sets []string // ipsets with type: net:hash + netHashIPsets []string // ipsets with type: net:hash namedPorts []string // ipsets with type: hash:ip,port - lists map[string][]string // ipsets with type: list:set + listIPsets map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry toRuleEntries []*iptm.IptEntry @@ -919,13 +932,13 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) log.Logf("started parsing egress rule") - sets = append(sets, "ns-"+ns) + netHashIPsets = append(netHashIPsets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) - lists = make(map[string][]string) + listIPsets = make(map[string][]string) targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) - sets = append(sets, labels...) - appendSelectorLabelsToLists(lists, listLabelsWithMembers, false) + netHashIPsets = append(netHashIPsets, labels...) + appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false @@ -976,8 +989,8 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe ) entries = append(entries, entry) - if _, ok := lists[util.KubeAllNamespacesFlag]; !ok { - lists[util.KubeAllNamespacesFlag] = nil + if _, ok := listIPsets[util.KubeAllNamespacesFlag]; !ok { + listIPsets[util.KubeAllNamespacesFlag] = nil } continue } @@ -1177,18 +1190,18 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe if len(nsLabelsWithoutOps) == 1 && nsLabelsWithoutOps[0] == "" { // Empty namespaceSelector. This selects all namespaces nsLabelsWithoutOps[0] = util.KubeAllNamespacesFlag - if _, ok := lists[nsLabelsWithoutOps[0]]; !ok { - lists[nsLabelsWithoutOps[0]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[0]]; !ok { + listIPsets[nsLabelsWithoutOps[0]] = nil } } else { for i, _ := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { + listIPsets[nsLabelsWithoutOps[i]] = nil } } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) } iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) if portRuleExists { @@ -1290,9 +1303,9 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe podLabelsWithoutOps[0] = util.GetNSNameWithPrefix(ns) } } - sets = append(sets, podLabelsWithoutOps...) + netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) // TODO check if the ns- is needed here ? - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, toRule.PodSelector, false) if portRuleExists { for _, portRule := range rule.Ports { @@ -1398,14 +1411,14 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe // Add namespaces prefix to distinguish namespace ipsets and pod ipsets for i, _ := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] - if _, ok := lists[nsLabelsWithoutOps[i]]; !ok { - lists[nsLabelsWithoutOps[i]] = nil + if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { + listIPsets[nsLabelsWithoutOps[i]] = nil } } - appendSelectorLabelsToLists(lists, listLabelsWithMembers, true) + appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) - sets = append(sets, podLabelsWithoutOps...) - appendSelectorLabelsToLists(lists, listPodLabelsWithMembers, false) + netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) + appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, true) iptPartialPodComment := craftPartialIptablesCommentFromSelector("", toRule.PodSelector, false) if portRuleExists { @@ -1598,12 +1611,12 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe entries = append(entries, entry) } - for parsedKey, parsedValue := range lists { - lists[parsedKey] = util.DropEmptyFields(parsedValue) + for parsedKey, parsedValue := range listIPsets { + listIPsets[parsedKey] = util.DropEmptyFields(parsedValue) } log.Logf("finished parsing egress rule") - return util.DropEmptyFields(sets), util.DropEmptyFields(namedPorts), lists, ipCidrs, entries + return util.DropEmptyFields(netHashIPsets), util.DropEmptyFields(namedPorts), listIPsets, ipCidrs, entries } // Drop all non-whitelisted packets. From cca6c89492c30c29dd794239108df2ea97233332 Mon Sep 17 00:00:00 2001 From: vakr Date: Thu, 1 Jul 2021 16:18:31 -0700 Subject: [PATCH 29/34] fixing some test after the merge --- npm/parseSelector_test.go | 56 +++++++++++-------------------------- npm/translatePolicy_test.go | 45 ----------------------------- 2 files changed, 16 insertions(+), 85 deletions(-) diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index b8edf04eca..8cff9def59 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -473,6 +473,12 @@ func TestParseSelector(t *testing.T) { } } func TestFlattenNameSpaceSelector(t *testing.T) { + + commonMatchLabel := map[string]string{ + "c": "d", + "a": "b", + } + firstSelector := &metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ metav1.LabelSelectorRequirement{ @@ -502,10 +508,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, } testSelectors := FlattenNameSpaceSelector(firstSelector) @@ -549,10 +552,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, } testSelectors = FlattenNameSpaceSelector(secondSelector) @@ -590,10 +590,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -624,10 +621,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -658,10 +652,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -692,10 +683,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -726,10 +714,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -760,10 +745,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -794,10 +776,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, metav1.LabelSelector{ MatchExpressions: []metav1.LabelSelectorRequirement{ @@ -828,10 +807,7 @@ func TestFlattenNameSpaceSelector(t *testing.T) { }, }, }, - MatchLabels: map[string]string{ - "c": "d", - "a": "b", - }, + MatchLabels: commonMatchLabel, }, } diff --git a/npm/translatePolicy_test.go b/npm/translatePolicy_test.go index 5c722a1133..27d16018a4 100644 --- a/npm/translatePolicy_test.go +++ b/npm/translatePolicy_test.go @@ -2,7 +2,6 @@ package npm import ( "encoding/json" - "fmt" "io/ioutil" "reflect" "testing" @@ -2516,50 +2515,6 @@ func TestAllowMultiplePodSelectors(t *testing.T) { "ALLOW-ns-!ns:netpol-4537-y-AND-pod:b:c-AND-app:test:int-TO-pod:a:x-IN-ns-netpol-4537-x", }, }, - &iptm.IptEntry{ - Chain: util.IptablesAzureIngressPortChain, - Specs: []string{ - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("ns-netpol-4537-x"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("pod:a:x"), - util.IptablesDstFlag, - util.IptablesJumpFlag, - util.IptablesAzureIngressFromChain, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", - util.IptablesAzureIngressFromChain), - }, - }, - &iptm.IptEntry{ - Chain: util.IptablesAzureIngressFromChain, - Specs: []string{ - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("ns-netpol-4537-x"), - util.IptablesDstFlag, - util.IptablesModuleFlag, - util.IptablesSetModuleFlag, - util.IptablesMatchSetFlag, - util.GetHashedName("pod:a:x"), - util.IptablesDstFlag, - util.IptablesJumpFlag, - util.IptablesAzureIngressDropsChain, - util.IptablesModuleFlag, - util.IptablesCommentModuleFlag, - util.IptablesCommentFlag, - fmt.Sprintf("ALLOW-ALL-TO-pod:a:x-IN-ns-netpol-4537-x-TO-JUMP-TO-%s", - util.IptablesAzureIngressDropsChain), - }, - }, } expectedIptEntries = append(expectedIptEntries, nonKubeSystemEntries...) // has egress, but empty map means allow all From 1d5164dd79958f5610e806e69a277c25d77106d0 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 2 Jul 2021 09:46:19 -0700 Subject: [PATCH 30/34] addressing a potential nil deference issue --- npm/parseSelector.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 07cde64c26..3ccc4ffe84 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -176,7 +176,7 @@ func FlattenNameSpaceSelector(nsSelector *metav1.LabelSelector) []metav1.LabelSe // To avoid any additional length checks, just return a slice of labelSelectors // with original nsSelector if nsSelector == nil { - return []metav1.LabelSelector{*nsSelector} + return []metav1.LabelSelector{} } if len(nsSelector.MatchExpressions) == 0 { From 9dbbace583af91c30ebc5e8cbe7e2dd97388e31c Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 2 Jul 2021 11:52:27 -0700 Subject: [PATCH 31/34] adding a test case for some corner cases in flattenNS --- npm/parseSelector_test.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/npm/parseSelector_test.go b/npm/parseSelector_test.go index 8cff9def59..cdfd6d2f77 100644 --- a/npm/parseSelector_test.go +++ b/npm/parseSelector_test.go @@ -472,6 +472,24 @@ func TestParseSelector(t *testing.T) { t.Errorf("TestparseSelector failed @ value comparison") } } + +func TestFlattenNameSpaceSelectorCases(t *testing.T) { + firstSelector := &metav1.LabelSelector{} + + testSelectors := FlattenNameSpaceSelector(firstSelector) + if len(testSelectors) != 1 { + t.Errorf("TestFlattenNameSpaceSelectorCases failed @ 1st selector length check %+v", testSelectors) + } + + var secondSelector *metav1.LabelSelector + + testSelectors = FlattenNameSpaceSelector(secondSelector) + if len(testSelectors) > 0 { + t.Errorf("TestFlattenNameSpaceSelectorCases failed @ 1st selector length check %+v", testSelectors) + } + +} + func TestFlattenNameSpaceSelector(t *testing.T) { commonMatchLabel := map[string]string{ From dfd4b49f0f38df61a030178c7bac3808b98655b8 Mon Sep 17 00:00:00 2001 From: vakr Date: Fri, 2 Jul 2021 11:56:31 -0700 Subject: [PATCH 32/34] adding a TODO to clean up stale code if not used in next iteration --- npm/ipsm/ipsm.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/npm/ipsm/ipsm.go b/npm/ipsm/ipsm.go index 8c596b6093..0dd57e64ca 100644 --- a/npm/ipsm/ipsm.go +++ b/npm/ipsm/ipsm.go @@ -465,6 +465,8 @@ func (ipsMgr *IpsetManager) DeleteFromSet(setName, ip, podKey string) error { return nil } +// TODO this below function is to be extended while improving ipset refer count +// support, if not used, please remove this stale function. // Clean removes all the empty sets & lists under the namespace. func (ipsMgr *IpsetManager) Clean() error { for setName, set := range ipsMgr.SetMap { From 16fc03acae401cdb04fb78385278969622ec9aaa Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 6 Jul 2021 16:58:35 -0700 Subject: [PATCH 33/34] Fixing some golint --- npm/networkPolicyController.go | 4 ++-- npm/parseSelector.go | 8 ++------ npm/translatePolicy.go | 8 ++++---- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/npm/networkPolicyController.go b/npm/networkPolicyController.go index 81bfae4184..ea6c7cbfa0 100644 --- a/npm/networkPolicyController.go +++ b/npm/networkPolicyController.go @@ -354,7 +354,7 @@ func (c *networkPolicyController) syncAddAndUpdateNetPol(netPolObj *networkingv1 // lists is a map with list name and members as value // NPM will create the list first and increments the refer count - for listKey, _ := range lists { + for listKey := range lists { if err = ipsMgr.CreateList(listKey); err != nil { return fmt.Errorf("[syncAddAndUpdateNetPol] Error: creating ipset list %s with err: %v", listKey, err) } @@ -410,7 +410,7 @@ func (c *networkPolicyController) cleanUpNetworkPolicy(netPolKey string, isSafeC } // lists is a map with list name and members as value - for listKey, _ := range lists { + for listKey := range lists { // We do not have delete the members before deleting set as, // 1. ipset allows deleting a ipset list with members // 2. if the refer count is more than one we should not remove members diff --git a/npm/parseSelector.go b/npm/parseSelector.go index 3ccc4ffe84..594b60e5c9 100644 --- a/npm/parseSelector.go +++ b/npm/parseSelector.go @@ -295,18 +295,14 @@ func parseSelector(selector *metav1.LabelSelector) ([]string, map[string][]strin // We are not adding the k:v to labels for multiple values, because, labels are used // to contruct partial IptEntries and if these below labels are added then we are inducing // AND condition on values of a match expression instead of OR - for _, v := range req.Values { - vals[k] = append(vals[k], v) - } + vals[k] = append(vals[k], req.Values...) } case metav1.LabelSelectorOpNotIn: k = util.IptablesNotFlag + req.Key if len(req.Values) == 1 { labels = append(labels, k+":"+req.Values[0]) } else { - for _, v := range req.Values { - vals[k] = append(vals[k], v) - } + vals[k] = append(vals[k], req.Values...) } // Exists matches pods with req.Key as key case metav1.LabelSelectorOpExists: diff --git a/npm/translatePolicy.go b/npm/translatePolicy.go index d2bbbb6363..d63538b449 100644 --- a/npm/translatePolicy.go +++ b/npm/translatePolicy.go @@ -493,7 +493,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS listIPsets[nsLabelsWithoutOps[0]] = nil } } else { - for i, _ := range nsLabelsWithoutOps { + for i := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { @@ -706,7 +706,7 @@ func translateIngress(ns string, policyName string, targetSelector metav1.LabelS for _, nsSelector := range FlattenNameSpaceSelector(fromRule.NamespaceSelector) { // we pass empty ns for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesSrcFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets - for i, _ := range nsLabelsWithoutOps { + for i := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil @@ -1128,7 +1128,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe listIPsets[nsLabelsWithoutOps[0]] = nil } } else { - for i, _ := range nsLabelsWithoutOps { + for i := range nsLabelsWithoutOps { // Add namespaces prefix to distinguish namespace ipset lists and pod ipsets nsLabelsWithoutOps[i] = util.GetNSNameWithPrefix(nsLabelsWithoutOps[i]) if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { @@ -1341,7 +1341,7 @@ func translateEgress(ns string, policyName string, targetSelector metav1.LabelSe // we pass true for the podspec and comment here because it's a combo of both selectors and not limited to network policy namespace iptPartialNsSpec, nsLabelsWithoutOps, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", &nsSelector, util.IptablesDstFlag, true) // Add namespaces prefix to distinguish namespace ipsets and pod ipsets - for i, _ := range nsLabelsWithoutOps { + for i := range nsLabelsWithoutOps { nsLabelsWithoutOps[i] = "ns-" + nsLabelsWithoutOps[i] if _, ok := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil From 8dda7ae95bcb110f5e2c492db7e7a99511c2fbe9 Mon Sep 17 00:00:00 2001 From: vakr Date: Tue, 6 Jul 2021 17:08:48 -0700 Subject: [PATCH 34/34] Fixing a sed in github actions --- .github/workflows/cyclonus-netpol-test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cyclonus-netpol-test.yaml b/.github/workflows/cyclonus-netpol-test.yaml index 5fce38aa16..a3a2ab88a7 100644 --- a/.github/workflows/cyclonus-netpol-test.yaml +++ b/.github/workflows/cyclonus-netpol-test.yaml @@ -40,7 +40,7 @@ jobs: - name: Install Azure NPM run: | - sed -i 's/mcr.microsoft.com\/containernetworking\/azure-npm:v1.3.1/acnpublic.azurecr.io\/azure-npm:cyclonus/' ./npm/azure-npm.yaml + sed -i 's/mcr.microsoft.com\/containernetworking\/azure-npm:v1.4.1/acnpublic.azurecr.io\/azure-npm:cyclonus/' ./npm/azure-npm.yaml kind load docker-image acnpublic.azurecr.io/azure-npm:cyclonus --name npm-kind kubectl apply -f ./npm/azure-npm.yaml