mirror of
https://github.com/cloudnativelabs/kube-router.git
synced 2025-09-26 02:21:03 +02:00
974 lines
37 KiB
Go
974 lines
37 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)))
|
|
}
|
|
}()
|
|
|
|
for _, ipset := range npc.ipSetHandlers {
|
|
err := ipset.Save()
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
}
|
|
|
|
// 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 {
|
|
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)
|
|
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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.Name,
|
|
namespace: matchingPod.Namespace,
|
|
labels: matchingPod.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.Name,
|
|
namespace: peerPod.Namespace,
|
|
labels: peerPod.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.Name,
|
|
namespace: peerPod.Namespace,
|
|
labels: peerPod.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
|
|
}
|