mirror of
https://github.com/cloudnativelabs/kube-router.git
synced 2025-09-27 11:01:11 +02:00
Use ipSetName utility method to ensure that ipset names are generated correctly when they are formulated. This feeds into the activeIPSets map later on, so it is important that we get the name right from the start.
972 lines
38 KiB
Go
972 lines
38 KiB
Go
package netpol
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/base32"
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/cloudnativelabs/kube-router/v2/pkg/metrics"
|
|
"github.com/cloudnativelabs/kube-router/v2/pkg/utils"
|
|
api "k8s.io/api/core/v1"
|
|
networking "k8s.io/api/networking/v1"
|
|
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/util/intstr"
|
|
listers "k8s.io/client-go/listers/core/v1"
|
|
"k8s.io/client-go/tools/cache"
|
|
"k8s.io/klog/v2"
|
|
netutils "k8s.io/utils/net"
|
|
)
|
|
|
|
func (npc *NetworkPolicyController) newNetworkPolicyEventHandler() cache.ResourceEventHandler {
|
|
return cache.ResourceEventHandlerFuncs{
|
|
AddFunc: func(obj interface{}) {
|
|
npc.OnNetworkPolicyUpdate(obj)
|
|
|
|
},
|
|
UpdateFunc: func(oldObj, newObj interface{}) {
|
|
npc.OnNetworkPolicyUpdate(newObj)
|
|
},
|
|
DeleteFunc: func(obj interface{}) {
|
|
npc.handleNetworkPolicyDelete(obj)
|
|
|
|
},
|
|
}
|
|
}
|
|
|
|
// OnNetworkPolicyUpdate handles updates to network policy from the kubernetes api server
|
|
func (npc *NetworkPolicyController) OnNetworkPolicyUpdate(obj interface{}) {
|
|
netpol := obj.(*networking.NetworkPolicy)
|
|
klog.V(2).Infof("Received update for network policy: %s/%s", netpol.Namespace, netpol.Name)
|
|
|
|
npc.RequestFullSync()
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) handleNetworkPolicyDelete(obj interface{}) {
|
|
netpol, ok := obj.(*networking.NetworkPolicy)
|
|
if !ok {
|
|
tombstone, ok := obj.(cache.DeletedFinalStateUnknown)
|
|
if !ok {
|
|
klog.Errorf("unexpected object type: %v", obj)
|
|
return
|
|
}
|
|
if netpol, ok = tombstone.Obj.(*networking.NetworkPolicy); !ok {
|
|
klog.Errorf("unexpected object type: %v", obj)
|
|
return
|
|
}
|
|
}
|
|
klog.V(2).Infof("Received network policy: %s/%s delete event", netpol.Namespace, netpol.Name)
|
|
|
|
npc.RequestFullSync()
|
|
}
|
|
|
|
// Configure iptables rules representing each network policy. All pod's matched by
|
|
// network policy spec podselector labels are grouped together in one ipset which
|
|
// is used for matching destination ip address. Each ingress rule in the network
|
|
// policyspec is evaluated to set of matching pods, which are grouped in to a
|
|
// ipset used for source ip addr matching.
|
|
func (npc *NetworkPolicyController) syncNetworkPolicyChains(networkPoliciesInfo []networkPolicyInfo,
|
|
version string) (map[string]bool, map[string]bool, error) {
|
|
start := time.Now()
|
|
defer func() {
|
|
endTime := time.Since(start)
|
|
if npc.MetricsEnabled {
|
|
metrics.ControllerPolicyChainsSyncTime.Observe(endTime.Seconds())
|
|
}
|
|
klog.V(2).Infof("Syncing network policy chains took %v", endTime)
|
|
}()
|
|
|
|
klog.V(1).Infof("Attempting to attain ipset mutex lock")
|
|
npc.ipsetMutex.Lock()
|
|
klog.V(1).Infof("Attained ipset mutex lock, continuing...")
|
|
defer func() {
|
|
npc.ipsetMutex.Unlock()
|
|
klog.V(1).Infof("Returned ipset mutex lock")
|
|
}()
|
|
|
|
activePolicyChains := make(map[string]bool)
|
|
activePolicyIPSets := make(map[string]bool)
|
|
|
|
defer func() {
|
|
if npc.MetricsEnabled {
|
|
metrics.ControllerPolicyChains.Set(float64(len(activePolicyChains)))
|
|
metrics.ControllerPolicyIpsets.Set(float64(len(activePolicyIPSets)))
|
|
}
|
|
}()
|
|
|
|
// run through all network policies
|
|
for _, policy := range networkPoliciesInfo {
|
|
currentPodIPs := make(map[api.IPFamily][]string)
|
|
for _, pod := range policy.targetPods {
|
|
for _, ip := range pod.ips {
|
|
if netutils.IsIPv4String(ip.IP) {
|
|
currentPodIPs[api.IPv4Protocol] = append(currentPodIPs[api.IPv4Protocol], ip.IP)
|
|
}
|
|
if netutils.IsIPv6String(ip.IP) {
|
|
currentPodIPs[api.IPv6Protocol] = append(currentPodIPs[api.IPv6Protocol], ip.IP)
|
|
}
|
|
}
|
|
}
|
|
|
|
for ipFamily := range npc.ipSetHandlers {
|
|
// ensure there is a unique chain per network policy in filter table
|
|
policyChainName := networkPolicyChainName(policy.namespace, policy.name, version, ipFamily)
|
|
|
|
npc.filterTableRules[ipFamily].WriteString(":" + policyChainName + "\n")
|
|
|
|
activePolicyChains[policyChainName] = true
|
|
|
|
if policy.policyType == kubeBothPolicyType || policy.policyType == kubeIngressPolicyType {
|
|
// create a ipset for all destination pod ip's matched by the policy spec PodSelector
|
|
targetDestPodIPSetName := policyDestinationPodIPSetName(policy.namespace, policy.name, ipFamily)
|
|
npc.createGenericHashIPSet(targetDestPodIPSetName, utils.TypeHashIP, currentPodIPs[ipFamily], ipFamily)
|
|
|
|
if err := npc.processIngressRules(policy,
|
|
targetDestPodIPSetName, activePolicyIPSets, version, ipFamily); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
activePolicyIPSets[targetDestPodIPSetName] = true
|
|
}
|
|
if policy.policyType == kubeBothPolicyType || policy.policyType == kubeEgressPolicyType {
|
|
// create a ipset for all source pod ip's matched by the policy spec PodSelector
|
|
targetSourcePodIPSetName := policySourcePodIPSetName(policy.namespace, policy.name, ipFamily)
|
|
npc.createGenericHashIPSet(targetSourcePodIPSetName, utils.TypeHashIP, currentPodIPs[ipFamily], ipFamily)
|
|
|
|
if err := npc.processEgressRules(policy,
|
|
targetSourcePodIPSetName, activePolicyIPSets, version, ipFamily); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
activePolicyIPSets[targetSourcePodIPSetName] = true
|
|
}
|
|
}
|
|
}
|
|
|
|
for ipFamily, ipset := range npc.ipSetHandlers {
|
|
ipFamily := ipFamily
|
|
restoreStart := time.Now()
|
|
err := ipset.Restore()
|
|
restoreEndTime := time.Since(restoreStart)
|
|
|
|
if npc.MetricsEnabled {
|
|
//nolint:exhaustive // we don't need exhaustive searching for IP Families
|
|
switch ipFamily {
|
|
case api.IPv4Protocol:
|
|
metrics.ControllerPolicyIpsetV4RestoreTime.Observe(restoreEndTime.Seconds())
|
|
case api.IPv6Protocol:
|
|
metrics.ControllerPolicyIpsetV6RestoreTime.Observe(restoreEndTime.Seconds())
|
|
}
|
|
}
|
|
klog.V(1).Infof("Restoring %v ipset took %v", ipFamily, restoreEndTime)
|
|
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("failed to perform ipset restore: %w", err)
|
|
}
|
|
}
|
|
|
|
klog.V(2).Infof("Iptables chains in the filter table are synchronized with the network policies.")
|
|
|
|
return activePolicyChains, activePolicyIPSets, nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) processIngressRules(policy networkPolicyInfo,
|
|
targetDestPodIPSetName string, activePolicyIPSets map[string]bool, version string,
|
|
ipFamily api.IPFamily) error {
|
|
|
|
// From network policy spec: "If field 'Ingress' is empty then this NetworkPolicy does not allow any traffic "
|
|
// so no whitelist rules to be added to the network policy
|
|
if policy.ingressRules == nil {
|
|
return nil
|
|
}
|
|
|
|
policyChainName := networkPolicyChainName(policy.namespace, policy.name, version, ipFamily)
|
|
|
|
// run through all the ingress rules in the spec and create iptables rules
|
|
// in the chain for the network policy
|
|
for ruleIdx, ingressRule := range policy.ingressRules {
|
|
|
|
if len(ingressRule.srcPods) != 0 {
|
|
srcPodIPSetName := policyIndexedSourcePodIPSetName(policy.namespace, policy.name, ruleIdx, ipFamily)
|
|
activePolicyIPSets[srcPodIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
ips := getIPsFromPods(ingressRule.srcPods, ipFamily)
|
|
for _, ip := range ips {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(srcPodIPSetName, setEntries, utils.TypeHashIP)
|
|
|
|
// Create policy based ipset with source pod IPs
|
|
npc.createPolicyIndexedIPSet(activePolicyIPSets, srcPodIPSetName, utils.TypeHashIP,
|
|
getIPsFromPods(ingressRule.srcPods, ipFamily), ipFamily)
|
|
|
|
// If the ingress policy contains port declarations, we need to make sure that we match on pod IP and port
|
|
if len(ingressRule.ports) != 0 {
|
|
if err := npc.createPodWithPortPolicyRule(ingressRule.ports, policy, policyChainName,
|
|
srcPodIPSetName, targetDestPodIPSetName, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// If the ingress policy contains named port declarations, we need to make sure that we match on pod IP and
|
|
// the resolved port number
|
|
if len(ingressRule.namedPorts) != 0 {
|
|
for epIdx, endPoints := range ingressRule.namedPorts {
|
|
namedPortIPSetName := policyIndexedIngressNamedPortIPSetName(policy.namespace,
|
|
policy.name, ruleIdx, epIdx, ipFamily)
|
|
activePolicyIPSets[namedPortIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
for _, ip := range endPoints.ips[ipFamily] {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(namedPortIPSetName, setEntries, utils.TypeHashIP)
|
|
|
|
//nolint:goconst // don't need to make error messages a constant
|
|
comment := "rule to ACCEPT traffic from source pods to dest pods selected by policy name " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, srcPodIPSetName, namedPortIPSetName,
|
|
endPoints.protocol, endPoints.port, endPoints.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the ingress policy contains no ports at all create the policy based only on IP
|
|
if len(ingressRule.ports) == 0 && len(ingressRule.namedPorts) == 0 {
|
|
// case where no 'ports' details specified in the ingress rule but 'from' details specified
|
|
// so match on specified source and destination ip with all port and protocol
|
|
comment := "rule to ACCEPT traffic from source pods to dest pods selected by policy name " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName,
|
|
comment, srcPodIPSetName, targetDestPodIPSetName, "", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// case where only 'ports' details specified but no 'from' details in the ingress rule so match on all sources,
|
|
// with specified port (if any) and protocol
|
|
if ingressRule.matchAllSource && !ingressRule.matchAllPorts {
|
|
for _, portProtocol := range ingressRule.ports {
|
|
//nolint:goconst // don't need to make error messages a constant
|
|
comment := "rule to ACCEPT traffic from all sources to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, "", targetDestPodIPSetName,
|
|
portProtocol.protocol, portProtocol.port, portProtocol.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for epIdx, endPoints := range ingressRule.namedPorts {
|
|
namedPortIPSetName := policyIndexedIngressNamedPortIPSetName(policy.namespace,
|
|
policy.name, ruleIdx, epIdx, ipFamily)
|
|
activePolicyIPSets[namedPortIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
for _, ip := range endPoints.ips[ipFamily] {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(namedPortIPSetName, setEntries, utils.TypeHashIP)
|
|
|
|
comment := "rule to ACCEPT traffic from all sources to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName,
|
|
comment, "", namedPortIPSetName, endPoints.protocol, endPoints.port, endPoints.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// case where neither ports nor from details are specified in the ingress rule so match on all ports, protocol,
|
|
// source IP's
|
|
if ingressRule.matchAllSource && ingressRule.matchAllPorts {
|
|
comment := "rule to ACCEPT traffic from all sources to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, "", targetDestPodIPSetName,
|
|
"", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if len(ingressRule.srcIPBlocks[ipFamily]) != 0 {
|
|
srcIPBlockIPSetName := policyIndexedSourceIPBlockIPSetName(policy.namespace, policy.name, ruleIdx, ipFamily)
|
|
activePolicyIPSets[srcIPBlockIPSetName] = true
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(srcIPBlockIPSetName, ingressRule.srcIPBlocks[ipFamily], utils.TypeHashNet)
|
|
|
|
if !ingressRule.matchAllPorts {
|
|
for _, portProtocol := range ingressRule.ports {
|
|
//nolint:goconst // don't need to make error messages a constant
|
|
comment := "rule to ACCEPT traffic from specified ipBlocks to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, srcIPBlockIPSetName,
|
|
targetDestPodIPSetName, portProtocol.protocol, portProtocol.port,
|
|
portProtocol.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for epIdx, endPoints := range ingressRule.namedPorts {
|
|
namedPortIPSetName := policyIndexedIngressNamedPortIPSetName(policy.namespace,
|
|
policy.name, ruleIdx, epIdx, ipFamily)
|
|
activePolicyIPSets[namedPortIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
for _, ip := range endPoints.ips[ipFamily] {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(namedPortIPSetName, setEntries, utils.TypeHashNet)
|
|
comment := "rule to ACCEPT traffic from specified ipBlocks to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, srcIPBlockIPSetName, namedPortIPSetName,
|
|
endPoints.protocol, endPoints.port, endPoints.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if ingressRule.matchAllPorts {
|
|
comment := "rule to ACCEPT traffic from specified ipBlocks to dest pods selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, srcIPBlockIPSetName,
|
|
targetDestPodIPSetName, "", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) processEgressRules(policy networkPolicyInfo,
|
|
targetSourcePodIPSetName string, activePolicyIPSets map[string]bool, version string,
|
|
ipFamily api.IPFamily) error {
|
|
|
|
// From network policy spec: "If field 'Ingress' is empty then this NetworkPolicy does not allow any traffic "
|
|
// so no whitelist rules to be added to the network policy
|
|
if policy.egressRules == nil {
|
|
return nil
|
|
}
|
|
|
|
policyChainName := networkPolicyChainName(policy.namespace, policy.name, version, ipFamily)
|
|
|
|
// run through all the egress rules in the spec and create iptables rules
|
|
// in the chain for the network policy
|
|
for ruleIdx, egressRule := range policy.egressRules {
|
|
|
|
if len(egressRule.dstPods) != 0 {
|
|
dstPodIPSetName := policyIndexedDestinationPodIPSetName(policy.namespace, policy.name, ruleIdx, ipFamily)
|
|
activePolicyIPSets[dstPodIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
ips := getIPsFromPods(egressRule.dstPods, ipFamily)
|
|
for _, ip := range ips {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(dstPodIPSetName, setEntries, utils.TypeHashIP)
|
|
if len(egressRule.ports) != 0 {
|
|
if err := npc.createPodWithPortPolicyRule(egressRule.ports, policy, policyChainName,
|
|
targetSourcePodIPSetName, dstPodIPSetName, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// If the egress policy contains named port declarations, we need to make sure that we match on pod IP and
|
|
// the resolved port number
|
|
if len(egressRule.namedPorts) != 0 {
|
|
for epIdx, endPoints := range egressRule.namedPorts {
|
|
namedPortIPSetName := policyIndexedEgressNamedPortIPSetName(policy.namespace,
|
|
policy.name, ruleIdx, epIdx, ipFamily)
|
|
activePolicyIPSets[namedPortIPSetName] = true
|
|
setEntries := make([][]string, 0)
|
|
for _, ip := range endPoints.ips[ipFamily] {
|
|
setEntries = append(setEntries, []string{ip, utils.OptionTimeout, "0"})
|
|
}
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(namedPortIPSetName, setEntries, utils.TypeHashIP)
|
|
comment := "rule to ACCEPT traffic from source pods to dest pods selected by policy name " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
namedPortIPSetName, endPoints.protocol, endPoints.port, endPoints.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the egress policy contains no ports at all create the policy based only on IP
|
|
if len(egressRule.ports) == 0 && len(egressRule.namedPorts) == 0 {
|
|
// case where no 'ports' details specified in the ingress rule but 'from' details specified
|
|
// so match on specified source and destination ip with all port and protocol
|
|
comment := "rule to ACCEPT traffic from source pods to dest pods selected by policy name " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
dstPodIPSetName, "", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// case where only 'ports' details specified but no 'to' details in the egress rule so match on all sources,
|
|
// with specified port (if any) and protocol
|
|
if egressRule.matchAllDestinations && !egressRule.matchAllPorts {
|
|
for _, portProtocol := range egressRule.ports {
|
|
//nolint:goconst // don't need to make error messages a constant
|
|
comment := "rule to ACCEPT traffic from source pods to all destinations selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
"", portProtocol.protocol, portProtocol.port, portProtocol.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
for _, portProtocol := range egressRule.namedPorts {
|
|
comment := "rule to ACCEPT traffic from source pods to all destinations selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
"", portProtocol.protocol, portProtocol.port, portProtocol.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
|
|
// case where neither ports nor from details are specified in the egress rule so match on all ports, protocol,
|
|
// source IP's
|
|
if egressRule.matchAllDestinations && egressRule.matchAllPorts {
|
|
comment := "rule to ACCEPT traffic from source pods to all destinations selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
"", "", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
if len(egressRule.dstIPBlocks[ipFamily]) != 0 {
|
|
dstIPBlockIPSetName := policyIndexedDestinationIPBlockIPSetName(policy.namespace, policy.name, ruleIdx, ipFamily)
|
|
activePolicyIPSets[dstIPBlockIPSetName] = true
|
|
npc.ipSetHandlers[ipFamily].RefreshSet(dstIPBlockIPSetName, egressRule.dstIPBlocks[ipFamily], utils.TypeHashNet)
|
|
if !egressRule.matchAllPorts {
|
|
for _, portProtocol := range egressRule.ports {
|
|
comment := "rule to ACCEPT traffic from source pods to specified ipBlocks selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
dstIPBlockIPSetName, portProtocol.protocol, portProtocol.port,
|
|
portProtocol.endport, ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
if egressRule.matchAllPorts {
|
|
comment := "rule to ACCEPT traffic from source pods to specified ipBlocks selected by policy name: " +
|
|
policy.name + " namespace " + policy.namespace
|
|
if err := npc.appendRuleToPolicyChain(policyChainName, comment, targetSourcePodIPSetName,
|
|
dstIPBlockIPSetName, "", "", "", ipFamily); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) appendRuleToPolicyChain(policyChainName, comment, srcIPSetName, dstIPSetName,
|
|
protocol, dPort, endDport string, ipFamily api.IPFamily) error {
|
|
|
|
args := make([]string, 0)
|
|
args = append(args, "-A", policyChainName)
|
|
|
|
if comment != "" {
|
|
args = append(args, "-m", "comment", "--comment", "\""+comment+"\"")
|
|
}
|
|
if srcIPSetName != "" {
|
|
args = append(args, "-m", "set", "--match-set", ipSetName(srcIPSetName, ipFamily), "src")
|
|
}
|
|
if dstIPSetName != "" {
|
|
args = append(args, "-m", "set", "--match-set", ipSetName(dstIPSetName, ipFamily), "dst")
|
|
}
|
|
if protocol != "" {
|
|
args = append(args, "-p", protocol)
|
|
}
|
|
if dPort != "" {
|
|
if endDport != "" {
|
|
multiport := fmt.Sprintf("%s:%s", dPort, endDport)
|
|
args = append(args, "--dport", multiport)
|
|
} else {
|
|
args = append(args, "--dport", dPort)
|
|
}
|
|
}
|
|
|
|
//nolint:gocritic // we want to append to a separate array here so that we can re-use args below
|
|
markArgs := append(args, "-j", "MARK", "--set-xmark", "0x10000/0x10000", "\n")
|
|
npc.filterTableRules[ipFamily].WriteString(strings.Join(markArgs, " "))
|
|
|
|
args = append(args, "-m", "mark", "--mark", "0x10000/0x10000", "-j", "RETURN", "\n")
|
|
npc.filterTableRules[ipFamily].WriteString(strings.Join(args, " "))
|
|
|
|
return nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) buildNetworkPoliciesInfo() ([]networkPolicyInfo, error) {
|
|
|
|
NetworkPolicies := make([]networkPolicyInfo, 0)
|
|
_, isIPv4Enabled := npc.ipSetHandlers[api.IPv4Protocol]
|
|
_, isIPv6Enabled := npc.ipSetHandlers[api.IPv6Protocol]
|
|
|
|
for _, policyObj := range npc.npLister.List() {
|
|
|
|
policy, ok := policyObj.(*networking.NetworkPolicy)
|
|
podSelector, _ := v1.LabelSelectorAsSelector(&policy.Spec.PodSelector)
|
|
if !ok {
|
|
return nil, fmt.Errorf("failed to convert")
|
|
}
|
|
newPolicy := networkPolicyInfo{
|
|
name: policy.Name,
|
|
namespace: policy.Namespace,
|
|
podSelector: podSelector,
|
|
policyType: kubeIngressPolicyType,
|
|
}
|
|
|
|
ingressType, egressType := false, false
|
|
for _, policyType := range policy.Spec.PolicyTypes {
|
|
if policyType == networking.PolicyTypeIngress {
|
|
ingressType = true
|
|
}
|
|
if policyType == networking.PolicyTypeEgress {
|
|
egressType = true
|
|
}
|
|
}
|
|
switch {
|
|
case ingressType && egressType:
|
|
newPolicy.policyType = kubeBothPolicyType
|
|
case egressType:
|
|
newPolicy.policyType = kubeEgressPolicyType
|
|
case ingressType:
|
|
newPolicy.policyType = kubeIngressPolicyType
|
|
}
|
|
|
|
matchingPods, err := npc.ListPodsByNamespaceAndLabels(policy.Namespace, podSelector)
|
|
newPolicy.targetPods = make(map[string]podInfo)
|
|
namedPort2IngressEps := make(namedPort2eps)
|
|
if err == nil {
|
|
for _, matchingPod := range matchingPods {
|
|
if !isNetPolActionable(matchingPod) {
|
|
continue
|
|
}
|
|
newPolicy.targetPods[matchingPod.Status.PodIP] = podInfo{ips: matchingPod.Status.PodIPs,
|
|
name: matchingPod.ObjectMeta.Name,
|
|
namespace: matchingPod.ObjectMeta.Namespace,
|
|
labels: matchingPod.ObjectMeta.Labels}
|
|
npc.grabNamedPortFromPod(matchingPod, &namedPort2IngressEps)
|
|
}
|
|
}
|
|
|
|
if policy.Spec.Ingress == nil {
|
|
newPolicy.ingressRules = nil
|
|
} else {
|
|
newPolicy.ingressRules = make([]ingressRule, 0)
|
|
}
|
|
|
|
if policy.Spec.Egress == nil {
|
|
newPolicy.egressRules = nil
|
|
} else {
|
|
newPolicy.egressRules = make([]egressRule, 0)
|
|
}
|
|
|
|
for _, specIngressRule := range policy.Spec.Ingress {
|
|
ingressRule := ingressRule{}
|
|
ingressRule.srcPods = make([]podInfo, 0)
|
|
ingressRule.srcIPBlocks = make(map[api.IPFamily][][]string, 0)
|
|
|
|
// If this field is empty or missing in the spec, this rule matches all sources
|
|
if len(specIngressRule.From) == 0 {
|
|
ingressRule.matchAllSource = true
|
|
} else {
|
|
ingressRule.matchAllSource = false
|
|
for _, peer := range specIngressRule.From {
|
|
if peerPods, err := npc.evalPodPeer(policy, peer); err == nil {
|
|
for _, peerPod := range peerPods {
|
|
if !isNetPolActionable(peerPod) {
|
|
continue
|
|
}
|
|
ingressRule.srcPods = append(ingressRule.srcPods,
|
|
podInfo{ips: peerPod.Status.PodIPs,
|
|
name: peerPod.ObjectMeta.Name,
|
|
namespace: peerPod.ObjectMeta.Namespace,
|
|
labels: peerPod.ObjectMeta.Labels})
|
|
}
|
|
}
|
|
peerIPBlock := npc.evalIPBlockPeer(peer)
|
|
|
|
_, foundIPv4Addresses := peerIPBlock[api.IPv4Protocol]
|
|
_, foundIPv6Addresses := peerIPBlock[api.IPv6Protocol]
|
|
if foundIPv4Addresses && !isIPv4Enabled {
|
|
klog.Warningf("Ignoring IPv4 source IP blocks %s from policy %s because we are not IPv4 "+
|
|
"Enabled!", peerIPBlock[api.IPv4Protocol], policy.Name)
|
|
}
|
|
if foundIPv6Addresses && !isIPv6Enabled {
|
|
klog.Warningf("Ignoring IPv6 source IP blocks %s from policy %s because we are not IPv6 "+
|
|
"Enabled!", peerIPBlock[api.IPv6Protocol], policy.Name)
|
|
}
|
|
|
|
ingressRule.srcIPBlocks[api.IPv4Protocol] = append(
|
|
ingressRule.srcIPBlocks[api.IPv4Protocol],
|
|
peerIPBlock[api.IPv4Protocol]...,
|
|
)
|
|
ingressRule.srcIPBlocks[api.IPv6Protocol] = append(
|
|
ingressRule.srcIPBlocks[api.IPv6Protocol],
|
|
peerIPBlock[api.IPv6Protocol]...,
|
|
)
|
|
}
|
|
}
|
|
|
|
ingressRule.ports = make([]protocolAndPort, 0)
|
|
ingressRule.namedPorts = make([]endPoints, 0)
|
|
// If this field is empty or missing in the spec, this rule matches all ports
|
|
if len(specIngressRule.Ports) == 0 {
|
|
ingressRule.matchAllPorts = true
|
|
} else {
|
|
ingressRule.matchAllPorts = false
|
|
ingressRule.ports, ingressRule.namedPorts = npc.processNetworkPolicyPorts(
|
|
specIngressRule.Ports, namedPort2IngressEps)
|
|
}
|
|
|
|
newPolicy.ingressRules = append(newPolicy.ingressRules, ingressRule)
|
|
}
|
|
|
|
for _, specEgressRule := range policy.Spec.Egress {
|
|
egressRule := egressRule{}
|
|
egressRule.dstPods = make([]podInfo, 0)
|
|
egressRule.dstIPBlocks = make(map[api.IPFamily][][]string, 0)
|
|
namedPort2EgressEps := make(namedPort2eps)
|
|
|
|
// If this field is empty or missing in the spec, this rule matches all sources
|
|
if len(specEgressRule.To) == 0 {
|
|
egressRule.matchAllDestinations = true
|
|
// if rule.To is empty but rule.Ports not, we must try to grab NamedPort from pods that in same
|
|
// namespace, so that we can design iptables rule to describe "match all dst but match some named
|
|
// dst-port" egress rule
|
|
if policyRulePortsHasNamedPort(specEgressRule.Ports) {
|
|
matchingPeerPods, _ := npc.ListPodsByNamespaceAndLabels(policy.Namespace, labels.Everything())
|
|
for _, peerPod := range matchingPeerPods {
|
|
if !isNetPolActionable(peerPod) {
|
|
continue
|
|
}
|
|
npc.grabNamedPortFromPod(peerPod, &namedPort2EgressEps)
|
|
}
|
|
}
|
|
} else {
|
|
egressRule.matchAllDestinations = false
|
|
for _, peer := range specEgressRule.To {
|
|
if peerPods, err := npc.evalPodPeer(policy, peer); err == nil {
|
|
for _, peerPod := range peerPods {
|
|
if !isNetPolActionable(peerPod) {
|
|
continue
|
|
}
|
|
egressRule.dstPods = append(egressRule.dstPods,
|
|
podInfo{ips: peerPod.Status.PodIPs,
|
|
name: peerPod.ObjectMeta.Name,
|
|
namespace: peerPod.ObjectMeta.Namespace,
|
|
labels: peerPod.ObjectMeta.Labels})
|
|
npc.grabNamedPortFromPod(peerPod, &namedPort2EgressEps)
|
|
}
|
|
|
|
}
|
|
peerIPBlock := npc.evalIPBlockPeer(peer)
|
|
|
|
_, foundIPv4Addresses := peerIPBlock[api.IPv4Protocol]
|
|
_, foundIPv6Addresses := peerIPBlock[api.IPv6Protocol]
|
|
if foundIPv4Addresses && !isIPv4Enabled {
|
|
klog.Warningf("Ignoring IPv4 dest IP blocks %s from policy %s because we are not IPv4 "+
|
|
"Enabled!", peerIPBlock[api.IPv4Protocol], policy.Name)
|
|
}
|
|
if foundIPv6Addresses && !isIPv6Enabled {
|
|
klog.Warningf("Ignoring IPv6 dest IP blocks %s from policy %s because we are not IPv6 "+
|
|
"Enabled!", peerIPBlock[api.IPv6Protocol], policy.Name)
|
|
}
|
|
|
|
egressRule.dstIPBlocks[api.IPv4Protocol] = append(
|
|
egressRule.dstIPBlocks[api.IPv4Protocol],
|
|
peerIPBlock[api.IPv4Protocol]...,
|
|
)
|
|
egressRule.dstIPBlocks[api.IPv6Protocol] = append(
|
|
egressRule.dstIPBlocks[api.IPv6Protocol],
|
|
peerIPBlock[api.IPv6Protocol]...,
|
|
)
|
|
}
|
|
}
|
|
|
|
egressRule.ports = make([]protocolAndPort, 0)
|
|
egressRule.namedPorts = make([]endPoints, 0)
|
|
// If this field is empty or missing in the spec, this rule matches all ports
|
|
if len(specEgressRule.Ports) == 0 {
|
|
egressRule.matchAllPorts = true
|
|
} else {
|
|
egressRule.matchAllPorts = false
|
|
egressRule.ports, egressRule.namedPorts = npc.processNetworkPolicyPorts(
|
|
specEgressRule.Ports, namedPort2EgressEps)
|
|
}
|
|
|
|
newPolicy.egressRules = append(newPolicy.egressRules, egressRule)
|
|
}
|
|
NetworkPolicies = append(NetworkPolicies, newPolicy)
|
|
}
|
|
|
|
return NetworkPolicies, nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) evalPodPeer(policy *networking.NetworkPolicy,
|
|
peer networking.NetworkPolicyPeer) ([]*api.Pod, error) {
|
|
|
|
var matchingPods []*api.Pod
|
|
matchingPods = make([]*api.Pod, 0)
|
|
var err error
|
|
// spec can have both PodSelector AND NamespaceSelector
|
|
if peer.NamespaceSelector != nil {
|
|
namespaceSelector, _ := v1.LabelSelectorAsSelector(peer.NamespaceSelector)
|
|
namespaces, err := npc.ListNamespaceByLabels(namespaceSelector)
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build network policies info due to " + err.Error())
|
|
}
|
|
|
|
podSelector := labels.Everything()
|
|
if peer.PodSelector != nil {
|
|
podSelector, _ = v1.LabelSelectorAsSelector(peer.PodSelector)
|
|
}
|
|
for _, namespace := range namespaces {
|
|
namespacePods, err := npc.ListPodsByNamespaceAndLabels(namespace.Name, podSelector)
|
|
if err != nil {
|
|
return nil, errors.New("Failed to build network policies info due to " + err.Error())
|
|
}
|
|
matchingPods = append(matchingPods, namespacePods...)
|
|
}
|
|
} else if peer.PodSelector != nil {
|
|
podSelector, _ := v1.LabelSelectorAsSelector(peer.PodSelector)
|
|
matchingPods, err = npc.ListPodsByNamespaceAndLabels(policy.Namespace, podSelector)
|
|
}
|
|
|
|
return matchingPods, err
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) processNetworkPolicyPorts(npPorts []networking.NetworkPolicyPort,
|
|
namedPort2eps namedPort2eps) (numericPorts []protocolAndPort, namedPorts []endPoints) {
|
|
numericPorts, namedPorts = make([]protocolAndPort, 0), make([]endPoints, 0)
|
|
for _, npPort := range npPorts {
|
|
var protocol string
|
|
if npPort.Protocol != nil {
|
|
protocol = string(*npPort.Protocol)
|
|
}
|
|
if npPort.Port == nil {
|
|
numericPorts = append(numericPorts, protocolAndPort{port: "", protocol: protocol})
|
|
} else if npPort.Port.Type == intstr.Int {
|
|
var portProto protocolAndPort
|
|
if npPort.EndPort != nil {
|
|
if *npPort.EndPort >= npPort.Port.IntVal {
|
|
portProto.endport = strconv.Itoa(int(*npPort.EndPort))
|
|
}
|
|
}
|
|
portProto.protocol, portProto.port = protocol, npPort.Port.String()
|
|
numericPorts = append(numericPorts, portProto)
|
|
} else if protocol2eps, ok := namedPort2eps[npPort.Port.String()]; ok {
|
|
if numericPort2eps, ok := protocol2eps[protocol]; ok {
|
|
for _, eps := range numericPort2eps {
|
|
namedPorts = append(namedPorts, *eps)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) ListPodsByNamespaceAndLabels(namespace string,
|
|
podSelector labels.Selector) (ret []*api.Pod, err error) {
|
|
podLister := listers.NewPodLister(npc.podLister)
|
|
allMatchedNameSpacePods, err := podLister.Pods(namespace).List(podSelector)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return allMatchedNameSpacePods, nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) ListNamespaceByLabels(namespaceSelector labels.Selector) ([]*api.Namespace, error) {
|
|
namespaceLister := listers.NewNamespaceLister(npc.nsLister)
|
|
matchedNamespaces, err := namespaceLister.List(namespaceSelector)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return matchedNamespaces, nil
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) evalIPBlockPeer(peer networking.NetworkPolicyPeer) map[api.IPFamily][][]string {
|
|
ipBlock := make(map[api.IPFamily][][]string, 0)
|
|
if peer.PodSelector == nil && peer.NamespaceSelector == nil && peer.IPBlock != nil {
|
|
cidr := peer.IPBlock.CIDR
|
|
|
|
if netutils.IsIPv4CIDRString(cidr) {
|
|
if strings.HasSuffix(cidr, "/0") {
|
|
ipBlock[api.IPv4Protocol] = append(
|
|
ipBlock[api.IPv4Protocol],
|
|
[]string{"0.0.0.0/1", utils.OptionTimeout, "0"},
|
|
[]string{"128.0.0.0/1", utils.OptionTimeout, "0"},
|
|
)
|
|
} else {
|
|
ipBlock[api.IPv4Protocol] = append(
|
|
ipBlock[api.IPv4Protocol],
|
|
[]string{cidr, utils.OptionTimeout, "0"},
|
|
)
|
|
}
|
|
|
|
for _, except := range peer.IPBlock.Except {
|
|
if strings.HasSuffix(except, "/0") {
|
|
ipBlock[api.IPv4Protocol] = append(
|
|
ipBlock[api.IPv4Protocol],
|
|
[]string{"0.0.0.0/1", utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
[]string{"128.0.0.0/1", utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
)
|
|
} else {
|
|
ipBlock[api.IPv4Protocol] = append(
|
|
ipBlock[api.IPv4Protocol],
|
|
[]string{except, utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
if netutils.IsIPv6CIDRString(cidr) {
|
|
if strings.HasSuffix(cidr, "/0") {
|
|
ipBlock[api.IPv6Protocol] = append(
|
|
ipBlock[api.IPv6Protocol],
|
|
[]string{"2000::/3", utils.OptionTimeout, "0"},
|
|
[]string{"fd00::/8", utils.OptionTimeout, "0"},
|
|
)
|
|
} else {
|
|
ipBlock[api.IPv6Protocol] = append(ipBlock[api.IPv6Protocol], []string{cidr, utils.OptionTimeout, "0"})
|
|
}
|
|
|
|
for _, except := range peer.IPBlock.Except {
|
|
if strings.HasSuffix(except, "/0") {
|
|
ipBlock[api.IPv6Protocol] = append(
|
|
ipBlock[api.IPv6Protocol],
|
|
[]string{"2000::/3", utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
[]string{"fd00::/8", utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
)
|
|
} else {
|
|
ipBlock[api.IPv6Protocol] = append(
|
|
ipBlock[api.IPv6Protocol],
|
|
[]string{except, utils.OptionTimeout, "0", utils.OptionNoMatch},
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ipBlock
|
|
}
|
|
|
|
func (npc *NetworkPolicyController) grabNamedPortFromPod(pod *api.Pod, namedPort2eps *namedPort2eps) {
|
|
if pod == nil || namedPort2eps == nil {
|
|
return
|
|
}
|
|
|
|
ips := make(map[api.IPFamily][]string)
|
|
for _, ip := range pod.Status.PodIPs {
|
|
if netutils.IsIPv4String(ip.IP) {
|
|
ips[api.IPv4Protocol] = append(ips[api.IPv4Protocol], ip.IP)
|
|
} else if netutils.IsIPv6String(ip.IP) {
|
|
ips[api.IPv6Protocol] = append(ips[api.IPv6Protocol], ip.IP)
|
|
}
|
|
}
|
|
|
|
for k := range pod.Spec.Containers {
|
|
for _, port := range pod.Spec.Containers[k].Ports {
|
|
name := port.Name
|
|
protocol := string(port.Protocol)
|
|
containerPort := strconv.Itoa(int(port.ContainerPort))
|
|
|
|
if (*namedPort2eps)[name] == nil {
|
|
(*namedPort2eps)[name] = make(protocol2eps)
|
|
}
|
|
if (*namedPort2eps)[name][protocol] == nil {
|
|
(*namedPort2eps)[name][protocol] = make(numericPort2eps)
|
|
}
|
|
if eps, ok := (*namedPort2eps)[name][protocol][containerPort]; !ok {
|
|
(*namedPort2eps)[name][protocol][containerPort] = &endPoints{
|
|
ips: ips,
|
|
protocolAndPort: protocolAndPort{port: containerPort, protocol: protocol},
|
|
}
|
|
} else {
|
|
eps.ips[api.IPv4Protocol] = append(eps.ips[api.IPv4Protocol], ips[api.IPv4Protocol]...)
|
|
eps.ips[api.IPv6Protocol] = append(eps.ips[api.IPv6Protocol], ips[api.IPv6Protocol]...)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func networkPolicyChainName(namespace, policyName string, version string, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + version + string(ipFamily)))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return kubeNetworkPolicyChainPrefix + encoded[:16]
|
|
}
|
|
|
|
func policySourcePodIPSetName(namespace, policyName string, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + string(ipFamily)))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeSourceIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyDestinationPodIPSetName(namespace, policyName string, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + string(ipFamily)))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeDestinationIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedSourcePodIPSetName(
|
|
namespace, policyName string, ingressRuleNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "ingressrule" + strconv.Itoa(ingressRuleNo) +
|
|
string(ipFamily) + "pod"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeSourceIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedDestinationPodIPSetName(
|
|
namespace, policyName string, egressRuleNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "egressrule" + strconv.Itoa(egressRuleNo) +
|
|
string(ipFamily) + "pod"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeDestinationIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedSourceIPBlockIPSetName(
|
|
namespace, policyName string, ingressRuleNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "ingressrule" + strconv.Itoa(ingressRuleNo) +
|
|
string(ipFamily) + "ipblock"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeSourceIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedDestinationIPBlockIPSetName(
|
|
namespace, policyName string, egressRuleNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "egressrule" + strconv.Itoa(egressRuleNo) +
|
|
string(ipFamily) + "ipblock"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeDestinationIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedIngressNamedPortIPSetName(
|
|
namespace, policyName string, ingressRuleNo, namedPortNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "ingressrule" + strconv.Itoa(ingressRuleNo) +
|
|
strconv.Itoa(namedPortNo) + string(ipFamily) + "namedport"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeDestinationIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyIndexedEgressNamedPortIPSetName(
|
|
namespace, policyName string, egressRuleNo, namedPortNo int, ipFamily api.IPFamily) string {
|
|
hash := sha256.Sum256([]byte(namespace + policyName + "egressrule" + strconv.Itoa(egressRuleNo) +
|
|
strconv.Itoa(namedPortNo) + string(ipFamily) + "namedport"))
|
|
encoded := base32.StdEncoding.EncodeToString(hash[:])
|
|
return ipSetName(kubeDestinationIPSetPrefix+encoded[:16], ipFamily)
|
|
}
|
|
|
|
func policyRulePortsHasNamedPort(npPorts []networking.NetworkPolicyPort) bool {
|
|
for _, npPort := range npPorts {
|
|
if npPort.Port != nil && npPort.Port.Type == intstr.String {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|