npm/pkg/controlplane/controllers/v1/translatePolicy.go (1,541 lines of code) (raw):

// Copyright 2018 Microsoft. All rights reserved. // MIT License package controllers import ( "sort" "strconv" "strings" "github.com/Azure/azure-container-networking/log" "github.com/Azure/azure-container-networking/npm/iptm" "github.com/Azure/azure-container-networking/npm/util" networkingv1 "k8s.io/api/networking/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) func craftPartialIptEntrySpecFromPort(portRule networkingv1.NetworkPolicyPort, sPortOrDPortFlag string) []string { partialSpec := []string{} if portRule.Protocol != nil { partialSpec = append( partialSpec, util.IptablesProtFlag, string(*portRule.Protocol), ) } if portRule.Port != nil { partialSpec = append( partialSpec, sPortOrDPortFlag, portRule.Port.String(), ) } return partialSpec } func getPortType(portRule networkingv1.NetworkPolicyPort) string { if portRule.Port == nil || portRule.Port.IntValue() != 0 { return "validport" } else if portRule.Port.IntValue() == 0 && portRule.Port.String() != "" { return "namedport" } return "invalid" } func craftPartialIptablesCommentFromPort(portRule networkingv1.NetworkPolicyPort, sPortOrDPortFlag string) string { partialComment := "" if portRule.Protocol != nil { partialComment += string(*portRule.Protocol) if portRule.Port != nil { partialComment += "-" } } if portRule.Port != nil { partialComment += "PORT-" partialComment += portRule.Port.String() } return partialComment } func craftPartialIptEntrySpecFromOpAndLabel(op, label, srcOrDstFlag string, isNamespaceSelector bool) []string { if isNamespaceSelector { label = "ns-" + label } partialSpec := []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, op, util.IptablesMatchSetFlag, util.GetHashedName(label), srcOrDstFlag, } 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 if ns != "" { spec = []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName("ns-" + ns), srcOrDstFlag, } } if len(ops) == 1 && len(labels) == 1 { if ops[0] == "" && labels[0] == "" { if isNamespaceSelector { // This is an empty namespaceSelector, // selecting all namespaces. spec = []string{ util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(util.KubeAllNamespacesFlag), srcOrDstFlag, } } return spec } } 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)...) } return spec } // craftPartialIptEntrySpecFromSelector :- ns must be "" for namespace selectors // 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) ops, labels := GetOperatorsAndLabels(labelsWithOps) valueLabels := []string{} listLabelsWithMembers := make(map[string][]string) labelsForSpec := labels // 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 labelsForSpec = append(labelsForSpec, labelKVIpsetName) } for _, labelValue := range labelValueList { ipsetName := util.GetIpSetFromLabelKV(labelKey, labelValue) valueLabels = append(valueLabels, ipsetName) listLabelsWithMembers[labelKVIpsetName] = append(listLabelsWithMembers[labelKVIpsetName], ipsetName) } } iptEntrySpecs := craftPartialIptEntrySpecFromOpsAndLabels(ns, ops, labelsForSpec, srcOrDstFlag, isNamespaceSelector) // 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 } // craftPartialIptablesCommentFromSelector :- ns must be "" for namespace selectors func craftPartialIptablesCommentFromSelector(ns string, selector *metav1.LabelSelector, isNamespaceSelector bool) string { if selector == nil { return "none" } if len(selector.MatchExpressions) == 0 && len(selector.MatchLabels) == 0 { if isNamespaceSelector { return util.KubeAllNamespacesFlag } return "ns-" + ns } // TODO check if we are missing any crucial comment labelsWithOps, labelKVs := parseSelector(selector) ops, labelsWithoutOps := GetOperatorsAndLabels(labelsWithOps) for labelKeyWithOps, labelValueList := range labelKVs { op, labelKey := GetOperatorAndLabel(labelKeyWithOps) labelKVIpsetName := getSetNameForMultiValueSelector(labelKey, labelValueList) labelsWithoutOps = append(labelsWithoutOps, labelKVIpsetName) ops = append(ops, op) } var prefix, postfix string if isNamespaceSelector { prefix = "ns-" } else { if ns != "" { postfix = "-IN-ns-" + ns } } comments := []string{} for i := range labelsWithoutOps { comments = append(comments, prefix+ops[i]+labelsWithoutOps[i]) } sort.Strings(comments) return strings.Join(comments, "-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 ( netHashIPsets []string // ipsets with type: net:hash namedPorts []string // ipsets with type: hash:ip,port listIPsets map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry fromRuleEntries []*iptm.IptEntry addedCidrEntry bool // all cidr entry will be added in one set per from/to rule addedPortEntry bool // add drop entries at the end of the chain when there are non ALLOW-ALL* rules ) log.Logf("started parsing ingress rule") netHashIPsets = append(netHashIPsets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) listIPsets = make(map[string][]string) targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) netHashIPsets = append(netHashIPsets, labels...) for parsedListName, parsedListMembers := range listLabelsWithMembers { listIPsets[parsedListName] = append(listIPsets[parsedListName], parsedListMembers...) } targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false portRuleExists := rule.Ports != nil && len(rule.Ports) > 0 fromRuleExists := false addedPortEntry = addedPortEntry || portRuleExists ipCidrs[i] = make([]string, len(rule.From)) if rule.From != nil { if len(rule.From) == 0 { fromRuleExists = true allowExternal = true } for _, fromRule := range rule.From { if fromRule.PodSelector != nil || fromRule.NamespaceSelector != nil || fromRule.IPBlock != nil { fromRuleExists = true break } } } else if !portRuleExists { allowExternal = true } if !portRuleExists && !fromRuleExists && !allowExternal { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(util.KubeAllNamespacesFlag), util.IptablesSrcFlag, ) 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-ALL-TO-"+targetSelectorComment+ "-FROM-"+util.KubeAllNamespacesFlag, ) entries = append(entries, entry) listIPsets[util.KubeAllNamespacesFlag] = []string{} continue } // Only Ports rules exist if portRuleExists && !fromRuleExists && !allowExternal { 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...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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-ALL-"+ craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) entries = append(entries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, Specs: craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag), } 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-ALL-"+ craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) entries = append(entries, entry) default: log.Logf("Invalid NetworkPolicyPort.") } } continue } // fromRuleExists for j, fromRule := range rule.From { // Handle IPBlock field of NetworkPolicyPeer if fromRule.IPBlock != nil { if len(fromRule.IPBlock.CIDR) > 0 { ipCidrs[i] = append(ipCidrs[i], fromRule.IPBlock.CIDR) cidrIpsetName := policyName + "-in-ns-" + ns + "-" + strconv.Itoa(i) + "in" if len(fromRule.IPBlock.Except) > 0 { for _, except := range fromRule.IPBlock.Except { // TODO move IP cidrs rule to allow based only ipCidrs[i] = append(ipCidrs[i], except+util.IpsetNomatch) } } if j != 0 && addedCidrEntry { continue } 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...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesSrcFlag, ) 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-"+cidrIpsetName+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) fromRuleEntries = append(fromRuleEntries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesSrcFlag, ) 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-"+cidrIpsetName+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-TO-"+targetSelectorComment, ) fromRuleEntries = append(fromRuleEntries, entry) default: log.Logf("Invalid NetworkPolicyPort.") } } } else { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressFromChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesSrcFlag, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureIngressMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+cidrIpsetName+ "-TO-"+targetSelectorComment, ) fromRuleEntries = append(fromRuleEntries, entry) } addedCidrEntry = true } continue } // Handle podSelector and namespaceSelector. // For PodSelector, use hash:net in ipset. // For NamespaceSelector, use set:list in ipset. if fromRule.PodSelector == nil && fromRule.NamespaceSelector == nil { continue } if fromRule.PodSelector == nil && fromRule.NamespaceSelector != 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 := 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 := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil } } appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) } 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) } } 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) } } netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) // TODO check this if ns- is needed here. appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, 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), targetSelectorIptEntrySpec...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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.IptablesAzureIngressMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+iptPartialPodComment+ "-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, iptPartialPodSpec..., ) 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-"+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), iptPartialPodSpec...), } 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-"+iptPartialPodComment+ "-TO-"+targetSelectorComment, ) entries = append(entries, entry) } 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 := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil } } appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", fromRule.PodSelector, util.IptablesSrcFlag, false) netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, 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...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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) } } } if allowExternal { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressPortChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureIngressMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-ALL-TO-"+ targetSelectorComment, ) entries = append(entries, entry) continue } } // prepending fromRuleEntries (which is in reverse order) so that they will retain correct ordering // of drop->allow... when the rules are beind prepended to their corresponding chain if len(fromRuleEntries) > 0 { entries = append(fromRuleEntries, entries...) } log.Logf("finished parsing ingress rule") 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 ( netHashIPsets []string // ipsets with type: net:hash namedPorts []string // ipsets with type: hash:ip,port listIPsets map[string][]string // ipsets with type: list:set ipCidrs [][]string entries []*iptm.IptEntry toRuleEntries []*iptm.IptEntry addedCidrEntry bool // all cidr entry will be added in one set per from/to rule addedPortEntry bool // add drop entry when there are non ALLOW-ALL* rules ) log.Logf("started parsing egress rule") netHashIPsets = append(netHashIPsets, "ns-"+ns) ipCidrs = make([][]string, len(rules)) listIPsets = make(map[string][]string) targetSelectorIptEntrySpec, labels, listLabelsWithMembers := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) netHashIPsets = append(netHashIPsets, labels...) appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) for i, rule := range rules { allowExternal := false portRuleExists := rule.Ports != nil && len(rule.Ports) > 0 toRuleExists := false addedPortEntry = addedPortEntry || portRuleExists ipCidrs[i] = make([]string, len(rule.To)) if rule.To != nil { if len(rule.To) == 0 { toRuleExists = true allowExternal = true } for _, toRule := range rule.To { if toRule.PodSelector != nil || toRule.NamespaceSelector != nil || toRule.IPBlock != nil { toRuleExists = true break } } } else if !portRuleExists { allowExternal = true } if !portRuleExists && !toRuleExists && !allowExternal { entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(util.KubeAllNamespacesFlag), util.IptablesDstFlag, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureEgressXMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-ALL-FROM-"+targetSelectorComment+ "-TO-"+util.KubeAllNamespacesFlag, ) entries = append(entries, entry) if _, ok := listIPsets[util.KubeAllNamespacesFlag]; !ok { listIPsets[util.KubeAllNamespacesFlag] = nil } continue } // Only Ports rules exist if portRuleExists && !toRuleExists && !allowExternal { 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...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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-ALL-TO-"+ craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) entries = append(entries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, 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-ALL-TO-"+ craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) entries = append(entries, entry) default: log.Logf("Invalid NetworkPolicyPort.") } } continue } // toRuleExists for j, toRule := range rule.To { // Handle IPBlock field of NetworkPolicyPeer if toRule.IPBlock != nil { if len(toRule.IPBlock.CIDR) > 0 { ipCidrs[i] = append(ipCidrs[i], toRule.IPBlock.CIDR) cidrIpsetName := policyName + "-in-ns-" + ns + "-" + strconv.Itoa(i) + "out" if len(toRule.IPBlock.Except) > 0 { for _, except := range toRule.IPBlock.Except { // TODO move IP cidrs rule to allow based only ipCidrs[i] = append(ipCidrs[i], except+util.IpsetNomatch) } } if j != 0 && addedCidrEntry { continue } 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...), } if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesDstFlag, ) 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-"+cidrIpsetName+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) toRuleEntries = append(toRuleEntries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, Specs: craftPartialIptEntrySpecFromPort(portRule, util.IptablesDstPortFlag), } entry.Specs = append( entry.Specs, targetSelectorIptEntrySpec..., ) entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesDstFlag, ) entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureEgressXMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+cidrIpsetName+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) toRuleEntries = append(toRuleEntries, entry) default: log.Logf("Invalid NetworkPolicyPort.") } } } else { entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressToChain, } entry.Specs = append( entry.Specs, targetSelectorIptEntrySpec..., ) entry.Specs = append( entry.Specs, util.IptablesModuleFlag, util.IptablesSetModuleFlag, util.IptablesMatchSetFlag, util.GetHashedName(cidrIpsetName), util.IptablesDstFlag, ) entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureEgressXMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+cidrIpsetName+ "-FROM-"+targetSelectorComment, ) toRuleEntries = append(toRuleEntries, entry) } addedCidrEntry = true } continue } // Handle podSelector and namespaceSelector. // For PodSelector, use hash:net in ipset. // For NamespaceSelector, use set:list in ipset. if toRule.PodSelector == nil && toRule.NamespaceSelector == nil { continue } if toRule.PodSelector == nil && toRule.NamespaceSelector != 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 := 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 := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil } } appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) } 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) } } 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) } } netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) // TODO check if the ns- is needed here ? appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialPodComment := craftPartialIptablesCommentFromSelector(ns, 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), iptPartialPodSpec...), } entry.Specs = append( entry.Specs, targetSelectorIptEntrySpec..., ) if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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-"+iptPartialPodComment+ "-AND-"+craftPartialIptablesCommentFromPort(portRule, util.IptablesDstPortFlag)+ "-FROM-"+targetSelectorComment, ) entries = append(entries, entry) case "validport": entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, Specs: append([]string(nil), iptPartialPodSpec...), } 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-"+iptPartialPodComment+ "-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, iptPartialPodSpec..., ) entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureEgressXMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-"+targetSelectorComment+ "-TO-"+iptPartialPodComment, ) entries = append(entries, entry) } 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 := listIPsets[nsLabelsWithoutOps[i]]; !ok { listIPsets[nsLabelsWithoutOps[i]] = nil } } appendSelectorLabelsToLists(listIPsets, listLabelsWithMembers, true) iptPartialPodSpec, podLabelsWithoutOps, listPodLabelsWithMembers := craftPartialIptEntrySpecFromSelector("", toRule.PodSelector, util.IptablesDstFlag, false) netHashIPsets = append(netHashIPsets, podLabelsWithoutOps...) appendSelectorLabelsToLists(listIPsets, listPodLabelsWithMembers, false) iptPartialNsComment := craftPartialIptablesCommentFromSelector("", &nsSelector, 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..., ) if portRule.Protocol != nil { entry.Specs = append( entry.Specs, util.IptablesProtFlag, string(*portRule.Protocol), ) } 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) } } } if allowExternal { entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressPortChain, Specs: append([]string(nil), targetSelectorIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesMark, util.IptablesSetMarkFlag, util.IptablesAzureEgressXMarkHex, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "ALLOW-ALL-FROM-"+ targetSelectorComment, ) entries = append(entries, entry) // borrowing this var to add jump entry from port chain only addedPortEntry = true } } // prepending toRuleEntries (which is in reverse order) so that they will retain correct ordering // of drop->allow... when the rules are beind prepended to their corresponding chain if len(toRuleEntries) > 0 { entries = append(toRuleEntries, entries...) } log.Logf("finished parsing egress rule") return util.DropEmptyFields(netHashIPsets), util.DropEmptyFields(namedPorts), listIPsets, ipCidrs, entries } // Drop all non-whitelisted packets. func getDefaultDropEntries(ns string, targetSelector metav1.LabelSelector, hasIngress, hasEgress bool) []*iptm.IptEntry { var entries []*iptm.IptEntry targetSelectorIngressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesDstFlag, false) targetSelectorEgressIptEntrySpec, _, _ := craftPartialIptEntrySpecFromSelector(ns, &targetSelector, util.IptablesSrcFlag, false) targetSelectorComment := craftPartialIptablesCommentFromSelector(ns, &targetSelector, false) if hasIngress { entry := &iptm.IptEntry{ Chain: util.IptablesAzureIngressDropsChain, Specs: append([]string(nil), targetSelectorIngressIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesDrop, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "DROP-ALL-TO-"+targetSelectorComment, ) entries = append(entries, entry) } if hasEgress { entry := &iptm.IptEntry{ Chain: util.IptablesAzureEgressDropsChain, Specs: append([]string(nil), targetSelectorEgressIptEntrySpec...), } entry.Specs = append( entry.Specs, util.IptablesJumpFlag, util.IptablesDrop, util.IptablesModuleFlag, util.IptablesCommentModuleFlag, util.IptablesCommentFlag, "DROP-ALL-FROM-"+targetSelectorComment, ) entries = append(entries, entry) } return entries } // translatePolicy translates network policy object into a set of iptables rules. // input: // kubernetes network policy project // output: // 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, map[string][]string, [][]string, [][]string, []*iptm.IptEntry) { var ( resultSets []string resultNamedPorts []string resultListMap map[string][]string resultIngressIPCidrs [][]string resultEgressIPCidrs [][]string entries []*iptm.IptEntry hasIngress, hasEgress bool ) defer func() { log.Logf("Finished translatePolicy") log.Logf("sets: %v", resultSets) log.Logf("lists: %v", resultListMap) log.Logf("entries: ") for _, entry := range entries { log.Logf("entry: %+v", entry) } }() npNs := npObj.ObjectMeta.Namespace 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...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) 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...) 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), resultListMap, ingressIPCidrs, egressIPCidrs, entries } for _, ptype := range npObj.Spec.PolicyTypes { if ptype == networkingv1.PolicyTypeIngress { ingressSets, ingressNamedPorts, ingressLists, ingressIPCidrs, ingressEntries := translateIngress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Ingress) resultSets = append(resultSets, ingressSets...) resultNamedPorts = append(resultNamedPorts, ingressNamedPorts...) for resultListKey, resultLists := range ingressLists { resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) } resultIngressIPCidrs = ingressIPCidrs entries = append(entries, ingressEntries...) if npObj.Spec.Ingress != nil && len(npObj.Spec.Ingress) == 1 && len(npObj.Spec.Ingress[0].Ports) == 0 && len(npObj.Spec.Ingress[0].From) == 0 { hasIngress = false } else { hasIngress = true } } if ptype == networkingv1.PolicyTypeEgress { egressSets, egressNamedPorts, egressLists, egressIPCidrs, egressEntries := translateEgress(npNs, policyName, npObj.Spec.PodSelector, npObj.Spec.Egress) resultSets = append(resultSets, egressSets...) resultNamedPorts = append(resultNamedPorts, egressNamedPorts...) for resultListKey, resultLists := range egressLists { resultListMap[resultListKey] = append(resultListMap[resultListKey], resultLists...) } resultEgressIPCidrs = egressIPCidrs entries = append(entries, egressEntries...) if npObj.Spec.Egress != nil && len(npObj.Spec.Egress) == 1 && len(npObj.Spec.Egress[0].Ports) == 0 && len(npObj.Spec.Egress[0].To) == 0 { hasEgress = false } else { hasEgress = true } } } 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), resultListMap, resultIngressIPCidrs, resultEgressIPCidrs, entries }