2021-02-01 19:20:24 +00:00
// Apache License v2.0 (copyright Cloud Native Labs & Rancher Labs)
// - modified from https://github.com/cloudnativelabs/kube-router/blob/ee9f6d890d10609284098229fa1e283ab5d83b93/pkg/controllers/netpol/network_policy_controller.go
// +build !windows
2019-10-17 21:46:15 +00:00
package netpol
import (
"crypto/sha256"
"encoding/base32"
"fmt"
"net"
"strconv"
"strings"
"sync"
"time"
"github.com/coreos/go-iptables/iptables"
2021-02-01 19:20:24 +00:00
"github.com/rancher/k3s/pkg/agent/netpol/utils"
"github.com/rancher/k3s/pkg/daemons/config"
2021-02-01 19:03:43 +00:00
2019-10-17 21:46:15 +00:00
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
2021-02-01 19:20:24 +00:00
glog "k8s.io/klog"
2019-10-17 21:46:15 +00:00
)
const (
kubePodFirewallChainPrefix = "KUBE-POD-FW-"
kubeNetworkPolicyChainPrefix = "KUBE-NWPLCY-"
kubeSourceIPSetPrefix = "KUBE-SRC-"
kubeDestinationIPSetPrefix = "KUBE-DST-"
2021-02-01 19:03:43 +00:00
kubeInputChainName = "KUBE-ROUTER-INPUT"
kubeForwardChainName = "KUBE-ROUTER-FORWARD"
kubeOutputChainName = "KUBE-ROUTER-OUTPUT"
2021-02-01 19:20:24 +00:00
defaultSyncPeriod = 5 * time . Minute
2019-10-17 21:46:15 +00:00
)
// Network policy controller provides both ingress and egress filtering for the pods as per the defined network
// policies. Two different types of iptables chains are used. Each pod running on the node which either
// requires ingress or egress filtering gets a pod specific chains. Each network policy has a iptables chain, which
// has rules expressed through ipsets matching source and destination pod ip's. In the FORWARD chain of the
// filter table a rule is added to jump the traffic originating (in case of egress network policy) from the pod
// or destined (in case of ingress network policy) to the pod specific iptables chain. Each
// pod specific iptables chain has rules to jump to the network polices chains, that pod matches. So packet
2021-01-28 01:26:48 +00:00
// originating/destined from/to pod goes through filter table's, FORWARD chain, followed by pod specific chain,
2019-10-17 21:46:15 +00:00
// followed by one or more network policy chains, till there is a match which will accept the packet, or gets
// dropped by the rule in the pod chain, if there is no match.
2021-02-01 19:03:43 +00:00
// NetworkPolicyController strcut to hold information required by NetworkPolicyController
2019-10-17 21:46:15 +00:00
type NetworkPolicyController struct {
2021-02-01 19:03:43 +00:00
nodeIP net . IP
nodeHostName string
serviceClusterIPRange net . IPNet
serviceExternalIPRanges [ ] net . IPNet
serviceNodePortRange string
mu sync . Mutex
syncPeriod time . Duration
fullSyncRequestChan chan struct { }
ipSetHandler * utils . IPSet
2019-10-17 21:46:15 +00:00
podLister cache . Indexer
npLister cache . Indexer
nsLister cache . Indexer
PodEventHandler cache . ResourceEventHandler
NamespaceEventHandler cache . ResourceEventHandler
NetworkPolicyEventHandler cache . ResourceEventHandler
}
// internal structure to represent a network policy
type networkPolicyInfo struct {
2021-02-01 19:03:43 +00:00
name string
namespace string
podSelector labels . Selector
2019-10-17 21:46:15 +00:00
// set of pods matching network policy spec podselector label selector
targetPods map [ string ] podInfo
// whitelist ingress rules from the network policy spec
ingressRules [ ] ingressRule
// whitelist egress rules from the network policy spec
egressRules [ ] egressRule
// policy type "ingress" or "egress" or "both" as defined by PolicyType in the spec
policyType string
}
// internal structure to represent Pod
type podInfo struct {
ip string
name string
namespace string
labels map [ string ] string
}
// internal structure to represent NetworkPolicyIngressRule in the spec
type ingressRule struct {
matchAllPorts bool
ports [ ] protocolAndPort
namedPorts [ ] endPoints
matchAllSource bool
srcPods [ ] podInfo
srcIPBlocks [ ] [ ] string
}
// internal structure to represent NetworkPolicyEgressRule in the spec
type egressRule struct {
matchAllPorts bool
ports [ ] protocolAndPort
namedPorts [ ] endPoints
matchAllDestinations bool
dstPods [ ] podInfo
dstIPBlocks [ ] [ ] string
}
type protocolAndPort struct {
protocol string
port string
}
type endPoints struct {
ips [ ] string
protocolAndPort
}
type numericPort2eps map [ string ] * endPoints
type protocol2eps map [ string ] numericPort2eps
type namedPort2eps map [ string ] protocol2eps
2021-01-28 01:26:48 +00:00
// Run runs forever till we receive notification on stopCh
2021-02-01 19:20:24 +00:00
func ( npc * NetworkPolicyController ) Run ( stopCh <- chan struct { } ) {
2019-10-17 21:46:15 +00:00
t := time . NewTicker ( npc . syncPeriod )
defer t . Stop ( )
2021-02-01 19:03:43 +00:00
glog . Info ( "Starting network policy controller" )
// setup kube-router specific top level cutoms chains
npc . ensureTopLevelChains ( )
// Full syncs of the network policy controller take a lot of time and can only be processed one at a time,
// therefore, we start it in it's own goroutine and request a sync through a single item channel
glog . Info ( "Starting network policy controller full sync goroutine" )
2021-02-01 19:20:24 +00:00
go func ( fullSyncRequest <- chan struct { } , stopCh <- chan struct { } ) {
2021-02-01 19:03:43 +00:00
for {
// Add an additional non-blocking select to ensure that if the stopCh channel is closed it is handled first
select {
case <- stopCh :
glog . Info ( "Shutting down network policies full sync goroutine" )
return
default :
}
select {
case <- stopCh :
glog . Info ( "Shutting down network policies full sync goroutine" )
return
case <- fullSyncRequest :
glog . V ( 3 ) . Info ( "Received request for a full sync, processing" )
npc . fullPolicySync ( ) // fullPolicySync() is a blocking request here
}
}
2021-02-01 19:20:24 +00:00
} ( npc . fullSyncRequestChan , stopCh )
2019-10-17 21:46:15 +00:00
// loop forever till notified to stop on stopCh
for {
2021-02-01 19:03:43 +00:00
glog . V ( 1 ) . Info ( "Requesting periodic sync of iptables to reflect network policies" )
npc . RequestFullSync ( )
2019-10-17 21:46:15 +00:00
select {
case <- stopCh :
2021-02-01 19:03:43 +00:00
glog . Infof ( "Shutting down network policies controller" )
2019-10-17 21:46:15 +00:00
return
case <- t . C :
}
}
}
2021-02-01 19:03:43 +00:00
// RequestFullSync allows the request of a full network policy sync without blocking the callee
func ( npc * NetworkPolicyController ) RequestFullSync ( ) {
select {
case npc . fullSyncRequestChan <- struct { } { } :
glog . V ( 3 ) . Info ( "Full sync request queue was empty so a full sync request was successfully sent" )
default : // Don't block if the buffered channel is full, return quickly so that we don't block callee execution
glog . V ( 1 ) . Info ( "Full sync request queue was full, skipping..." )
2019-10-17 21:46:15 +00:00
}
}
// Sync synchronizes iptables to desired state of network policies
2021-02-01 19:03:43 +00:00
func ( npc * NetworkPolicyController ) fullPolicySync ( ) {
2019-10-17 21:46:15 +00:00
var err error
2021-02-01 19:03:43 +00:00
var networkPoliciesInfo [ ] networkPolicyInfo
2019-10-17 21:46:15 +00:00
npc . mu . Lock ( )
defer npc . mu . Unlock ( )
start := time . Now ( )
syncVersion := strconv . FormatInt ( start . UnixNano ( ) , 10 )
defer func ( ) {
endTime := time . Since ( start )
2021-02-01 19:03:43 +00:00
glog . V ( 1 ) . Infof ( "sync iptables took %v" , endTime )
2019-10-17 21:46:15 +00:00
} ( )
2021-02-01 19:03:43 +00:00
glog . V ( 1 ) . Infof ( "Starting sync of iptables with version: %s" , syncVersion )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
// ensure kube-router specific top level chains and corresponding rules exist
npc . ensureTopLevelChains ( )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
networkPoliciesInfo , err = npc . buildNetworkPoliciesInfo ( )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Aborting sync. Failed to build network policies: %v" , err . Error ( ) )
return
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
activePolicyChains , activePolicyIPSets , err := npc . syncNetworkPolicyChains ( networkPoliciesInfo , syncVersion )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Aborting sync. Failed to sync network policy chains: %v" + err . Error ( ) )
return
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
activePodFwChains , err := npc . syncPodFirewallChains ( networkPoliciesInfo , syncVersion )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Aborting sync. Failed to sync pod firewalls: %v" , err . Error ( ) )
return
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
err = cleanupStaleRules ( activePolicyChains , activePodFwChains , activePolicyIPSets )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Aborting sync. Failed to cleanup stale iptables rules: %v" , err . Error ( ) )
return
2019-10-17 21:46:15 +00:00
}
}
2021-02-01 19:03:43 +00:00
// Creates custom chains KUBE-ROUTER-INPUT, KUBE-ROUTER-FORWARD, KUBE-ROUTER-OUTPUT
// and following rules in the filter table to jump from builtin chain to custom chain
// -A INPUT -m comment --comment "kube-router netpol" -j KUBE-ROUTER-INPUT
// -A FORWARD -m comment --comment "kube-router netpol" -j KUBE-ROUTER-FORWARD
// -A OUTPUT -m comment --comment "kube-router netpol" -j KUBE-ROUTER-OUTPUT
func ( npc * NetworkPolicyController ) ensureTopLevelChains ( ) {
2019-10-17 21:46:15 +00:00
iptablesCmdHandler , err := iptables . New ( )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to initialize iptables executor due to %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
addUUIDForRuleSpec := func ( chain string , ruleSpec * [ ] string ) ( string , error ) {
hash := sha256 . Sum256 ( [ ] byte ( chain + strings . Join ( * ruleSpec , "" ) ) )
encoded := base32 . StdEncoding . EncodeToString ( hash [ : ] ) [ : 16 ]
for idx , part := range * ruleSpec {
if "--comment" == part {
( * ruleSpec ) [ idx + 1 ] = ( * ruleSpec ) [ idx + 1 ] + " - " + encoded
return encoded , nil
2019-10-17 21:46:15 +00:00
}
}
2021-02-01 19:03:43 +00:00
return "" , fmt . Errorf ( "could not find a comment in the ruleSpec string given: %s" , strings . Join ( * ruleSpec , " " ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
ensureRuleAtPosition := func ( chain string , ruleSpec [ ] string , uuid string , position int ) {
exists , err := iptablesCmdHandler . Exists ( "filter" , chain , ruleSpec ... )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to verify rule exists in %s chain due to %s" , chain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
if ! exists {
2021-02-01 19:03:43 +00:00
err := iptablesCmdHandler . Insert ( "filter" , chain , position , ruleSpec ... )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to run iptables command to insert in %s chain %s" , chain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
return
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
rules , err := iptablesCmdHandler . List ( "filter" , chain )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "failed to list rules in filter table %s chain due to %s" , chain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
var ruleNo , ruleIndexOffset int
for i , rule := range rules {
rule = strings . Replace ( rule , "\"" , "" , 2 ) //removes quote from comment string
if strings . HasPrefix ( rule , "-P" ) || strings . HasPrefix ( rule , "-N" ) {
// if this chain has a default policy, then it will show as rule #1 from iptablesCmdHandler.List so we
// need to account for this offset
ruleIndexOffset ++
continue
}
if strings . Contains ( rule , uuid ) {
// range uses a 0 index, but iptables uses a 1 index so we need to increase ruleNo by 1
ruleNo = i + 1 - ruleIndexOffset
break
2019-10-17 21:46:15 +00:00
}
}
2021-02-01 19:03:43 +00:00
if ruleNo != position {
err = iptablesCmdHandler . Insert ( "filter" , chain , position , ruleSpec ... )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to run iptables command to insert in %s chain %s" , chain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
err = iptablesCmdHandler . Delete ( "filter" , chain , strconv . Itoa ( ruleNo + 1 ) )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to delete incorrect rule in %s chain due to %s" , chain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
}
}
2021-02-01 19:03:43 +00:00
chains := map [ string ] string { "INPUT" : kubeInputChainName , "FORWARD" : kubeForwardChainName , "OUTPUT" : kubeOutputChainName }
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
for builtinChain , customChain := range chains {
err = iptablesCmdHandler . NewChain ( "filter" , customChain )
2019-10-17 21:46:15 +00:00
if err != nil && err . ( * iptables . Error ) . ExitStatus ( ) != 1 {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to run iptables command to create %s chain due to %s" , customChain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
args := [ ] string { "-m" , "comment" , "--comment" , "kube-router netpol" , "-j" , customChain }
uuid , err := addUUIDForRuleSpec ( builtinChain , & args )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to get uuid for rule: %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
ensureRuleAtPosition ( builtinChain , args , uuid , 1 )
}
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
whitelistServiceVips := [ ] string { "-m" , "comment" , "--comment" , "allow traffic to cluster IP" , "-d" , npc . serviceClusterIPRange . String ( ) , "-j" , "RETURN" }
uuid , err := addUUIDForRuleSpec ( kubeInputChainName , & whitelistServiceVips )
if err != nil {
glog . Fatalf ( "Failed to get uuid for rule: %s" , err . Error ( ) )
}
ensureRuleAtPosition ( kubeInputChainName , whitelistServiceVips , uuid , 1 )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
whitelistTCPNodeports := [ ] string { "-p" , "tcp" , "-m" , "comment" , "--comment" , "allow LOCAL TCP traffic to node ports" , "-m" , "addrtype" , "--dst-type" , "LOCAL" ,
"-m" , "multiport" , "--dports" , npc . serviceNodePortRange , "-j" , "RETURN" }
uuid , err = addUUIDForRuleSpec ( kubeInputChainName , & whitelistTCPNodeports )
if err != nil {
glog . Fatalf ( "Failed to get uuid for rule: %s" , err . Error ( ) )
}
ensureRuleAtPosition ( kubeInputChainName , whitelistTCPNodeports , uuid , 2 )
whitelistUDPNodeports := [ ] string { "-p" , "udp" , "-m" , "comment" , "--comment" , "allow LOCAL UDP traffic to node ports" , "-m" , "addrtype" , "--dst-type" , "LOCAL" ,
"-m" , "multiport" , "--dports" , npc . serviceNodePortRange , "-j" , "RETURN" }
uuid , err = addUUIDForRuleSpec ( kubeInputChainName , & whitelistUDPNodeports )
if err != nil {
glog . Fatalf ( "Failed to get uuid for rule: %s" , err . Error ( ) )
}
ensureRuleAtPosition ( kubeInputChainName , whitelistUDPNodeports , uuid , 3 )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
for externalIPIndex , externalIPRange := range npc . serviceExternalIPRanges {
whitelistServiceVips := [ ] string { "-m" , "comment" , "--comment" , "allow traffic to external IP range: " + externalIPRange . String ( ) , "-d" , externalIPRange . String ( ) , "-j" , "RETURN" }
uuid , err = addUUIDForRuleSpec ( kubeInputChainName , & whitelistServiceVips )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "Failed to get uuid for rule: %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
ensureRuleAtPosition ( kubeInputChainName , whitelistServiceVips , uuid , externalIPIndex + 4 )
2019-10-17 21:46:15 +00:00
}
}
func cleanupStaleRules ( activePolicyChains , activePodFwChains , activePolicyIPSets map [ string ] bool ) error {
cleanupPodFwChains := make ( [ ] string , 0 )
cleanupPolicyChains := make ( [ ] string , 0 )
2021-02-01 19:03:43 +00:00
cleanupPolicyIPSets := make ( [ ] * utils . Set , 0 )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
// initialize tool sets for working with iptables and ipset
2019-10-17 21:46:15 +00:00
iptablesCmdHandler , err := iptables . New ( )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "failed to initialize iptables command executor due to %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
ipsets , err := utils . NewIPSet ( false )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Fatalf ( "failed to create ipsets command executor due to %s" , err . Error ( ) )
}
err = ipsets . Save ( )
if err != nil {
glog . Fatalf ( "failed to initialize ipsets command executor due to %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
// find iptables chains and ipsets that are no longer used by comparing current to the active maps we were passed
2019-10-17 21:46:15 +00:00
chains , err := iptablesCmdHandler . ListChains ( "filter" )
2021-02-01 19:03:43 +00:00
if err != nil {
return fmt . Errorf ( "Unable to list chains: %s" , err )
}
2019-10-17 21:46:15 +00:00
for _ , chain := range chains {
if strings . HasPrefix ( chain , kubeNetworkPolicyChainPrefix ) {
if _ , ok := activePolicyChains [ chain ] ; ! ok {
cleanupPolicyChains = append ( cleanupPolicyChains , chain )
}
}
if strings . HasPrefix ( chain , kubePodFirewallChainPrefix ) {
if _ , ok := activePodFwChains [ chain ] ; ! ok {
cleanupPodFwChains = append ( cleanupPodFwChains , chain )
}
}
}
2021-02-01 19:03:43 +00:00
for _ , set := range ipsets . Sets {
2019-10-17 21:46:15 +00:00
if strings . HasPrefix ( set . Name , kubeSourceIPSetPrefix ) ||
strings . HasPrefix ( set . Name , kubeDestinationIPSetPrefix ) {
if _ , ok := activePolicyIPSets [ set . Name ] ; ! ok {
cleanupPolicyIPSets = append ( cleanupPolicyIPSets , set )
}
}
}
2021-02-01 19:03:43 +00:00
// remove stale iptables podFwChain references from the filter table chains
for _ , podFwChain := range cleanupPodFwChains {
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
primaryChains := [ ] string { kubeInputChainName , kubeForwardChainName , kubeOutputChainName }
for _ , egressChain := range primaryChains {
forwardChainRules , err := iptablesCmdHandler . List ( "filter" , egressChain )
if err != nil {
return fmt . Errorf ( "failed to list rules in filter table, %s podFwChain due to %s" , egressChain , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
// TODO delete rule by spec, than rule number to avoid extra loop
var realRuleNo int
for i , rule := range forwardChainRules {
if strings . Contains ( rule , podFwChain ) {
err = iptablesCmdHandler . Delete ( "filter" , egressChain , strconv . Itoa ( i - realRuleNo ) )
if err != nil {
return fmt . Errorf ( "failed to delete rule: %s from the %s podFwChain of filter table due to %s" , rule , egressChain , err . Error ( ) )
}
realRuleNo ++
2019-10-17 21:46:15 +00:00
}
}
}
}
// cleanup pod firewall chain
for _ , chain := range cleanupPodFwChains {
2021-02-01 19:03:43 +00:00
glog . V ( 2 ) . Infof ( "Found pod fw chain to cleanup: %s" , chain )
2019-10-17 21:46:15 +00:00
err = iptablesCmdHandler . ClearChain ( "filter" , chain )
if err != nil {
return fmt . Errorf ( "Failed to flush the rules in chain %s due to %s" , chain , err . Error ( ) )
}
err = iptablesCmdHandler . DeleteChain ( "filter" , chain )
if err != nil {
return fmt . Errorf ( "Failed to delete the chain %s due to %s" , chain , err . Error ( ) )
}
2021-02-01 19:03:43 +00:00
glog . V ( 2 ) . Infof ( "Deleted pod specific firewall chain: %s from the filter table" , chain )
2019-10-17 21:46:15 +00:00
}
// cleanup network policy chains
for _ , policyChain := range cleanupPolicyChains {
2021-02-01 19:03:43 +00:00
glog . V ( 2 ) . Infof ( "Found policy chain to cleanup %s" , policyChain )
2019-10-17 21:46:15 +00:00
2021-02-01 19:03:43 +00:00
// first clean up any references from active pod firewall chains
2019-10-17 21:46:15 +00:00
for podFwChain := range activePodFwChains {
podFwChainRules , err := iptablesCmdHandler . List ( "filter" , podFwChain )
if err != nil {
2021-02-01 19:03:43 +00:00
return fmt . Errorf ( "Unable to list rules from the chain %s: %s" , podFwChain , err )
2019-10-17 21:46:15 +00:00
}
for i , rule := range podFwChainRules {
if strings . Contains ( rule , policyChain ) {
err = iptablesCmdHandler . Delete ( "filter" , podFwChain , strconv . Itoa ( i ) )
if err != nil {
return fmt . Errorf ( "Failed to delete rule %s from the chain %s" , rule , podFwChain )
}
break
}
}
}
2021-02-01 19:03:43 +00:00
// now that all stale and active references to the network policy chain have been removed, delete the chain
2019-10-17 21:46:15 +00:00
err = iptablesCmdHandler . ClearChain ( "filter" , policyChain )
if err != nil {
return fmt . Errorf ( "Failed to flush the rules in chain %s due to %s" , policyChain , err )
}
err = iptablesCmdHandler . DeleteChain ( "filter" , policyChain )
if err != nil {
return fmt . Errorf ( "Failed to flush the rules in chain %s due to %s" , policyChain , err )
}
2021-02-01 19:03:43 +00:00
glog . V ( 2 ) . Infof ( "Deleted network policy chain: %s from the filter table" , policyChain )
2019-10-17 21:46:15 +00:00
}
// cleanup network policy ipsets
for _ , set := range cleanupPolicyIPSets {
err = set . Destroy ( )
if err != nil {
return fmt . Errorf ( "Failed to delete ipset %s due to %s" , set . Name , err )
}
}
return nil
}
// Cleanup cleanup configurations done
func ( npc * NetworkPolicyController ) Cleanup ( ) {
2021-02-01 19:03:43 +00:00
glog . Info ( "Cleaning up iptables configuration permanently done by kube-router" )
2019-10-17 21:46:15 +00:00
iptablesCmdHandler , err := iptables . New ( )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to initialize iptables executor: %s" , err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
// delete jump rules in FORWARD chain to pod specific firewall chain
2021-02-01 19:03:43 +00:00
forwardChainRules , err := iptablesCmdHandler . List ( "filter" , kubeForwardChainName )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to delete iptables rules as part of cleanup" )
2019-10-17 21:46:15 +00:00
return
}
2021-01-28 01:26:48 +00:00
// TODO: need a better way to delete rule with out using number
2019-10-17 21:46:15 +00:00
var realRuleNo int
for i , rule := range forwardChainRules {
if strings . Contains ( rule , kubePodFirewallChainPrefix ) {
2021-02-01 19:03:43 +00:00
err = iptablesCmdHandler . Delete ( "filter" , kubeForwardChainName , strconv . Itoa ( i - realRuleNo ) )
if err != nil {
glog . Errorf ( "Failed to delete iptables rule as part of cleanup: %s" , err )
}
2019-10-17 21:46:15 +00:00
realRuleNo ++
}
}
// delete jump rules in OUTPUT chain to pod specific firewall chain
2021-02-01 19:03:43 +00:00
forwardChainRules , err = iptablesCmdHandler . List ( "filter" , kubeOutputChainName )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to delete iptables rules as part of cleanup" )
2019-10-17 21:46:15 +00:00
return
}
2021-01-28 01:26:48 +00:00
// TODO: need a better way to delete rule with out using number
2019-10-17 21:46:15 +00:00
realRuleNo = 0
for i , rule := range forwardChainRules {
if strings . Contains ( rule , kubePodFirewallChainPrefix ) {
2021-02-01 19:03:43 +00:00
err = iptablesCmdHandler . Delete ( "filter" , kubeOutputChainName , strconv . Itoa ( i - realRuleNo ) )
if err != nil {
glog . Errorf ( "Failed to delete iptables rule as part of cleanup: %s" , err )
}
2019-10-17 21:46:15 +00:00
realRuleNo ++
}
}
// flush and delete pod specific firewall chain
chains , err := iptablesCmdHandler . ListChains ( "filter" )
2021-02-01 19:03:43 +00:00
if err != nil {
glog . Errorf ( "Unable to list chains: %s" , err )
return
}
2019-10-17 21:46:15 +00:00
for _ , chain := range chains {
if strings . HasPrefix ( chain , kubePodFirewallChainPrefix ) {
err = iptablesCmdHandler . ClearChain ( "filter" , chain )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to cleanup iptables rules: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
return
}
err = iptablesCmdHandler . DeleteChain ( "filter" , chain )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to cleanup iptables rules: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
return
}
}
}
// flush and delete per network policy specific chain
chains , err = iptablesCmdHandler . ListChains ( "filter" )
2021-02-01 19:03:43 +00:00
if err != nil {
glog . Errorf ( "Unable to list chains: %s" , err )
return
}
2019-10-17 21:46:15 +00:00
for _ , chain := range chains {
if strings . HasPrefix ( chain , kubeNetworkPolicyChainPrefix ) {
err = iptablesCmdHandler . ClearChain ( "filter" , chain )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to cleanup iptables rules: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
return
}
err = iptablesCmdHandler . DeleteChain ( "filter" , chain )
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to cleanup iptables rules: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
return
}
}
}
// delete all ipsets
2021-02-01 19:03:43 +00:00
ipset , err := utils . NewIPSet ( false )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to clean up ipsets: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
err = ipset . Save ( )
2019-10-17 21:46:15 +00:00
if err != nil {
2021-02-01 19:03:43 +00:00
glog . Errorf ( "Failed to clean up ipsets: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
err = ipset . DestroyAllWithin ( )
if err != nil {
glog . Errorf ( "Failed to clean up ipsets: " + err . Error ( ) )
2019-10-17 21:46:15 +00:00
}
2021-02-01 19:03:43 +00:00
glog . Infof ( "Successfully cleaned the iptables configuration done by kube-router" )
2019-10-17 21:46:15 +00:00
}
// NewNetworkPolicyController returns new NetworkPolicyController object
2021-02-01 19:03:43 +00:00
func NewNetworkPolicyController ( clientset kubernetes . Interface ,
2021-02-01 19:20:24 +00:00
config * config . Node , podInformer cache . SharedIndexInformer ,
2021-02-01 19:03:43 +00:00
npInformer cache . SharedIndexInformer , nsInformer cache . SharedIndexInformer ) ( * NetworkPolicyController , error ) {
2019-10-17 21:46:15 +00:00
npc := NetworkPolicyController { }
2021-02-01 19:03:43 +00:00
// Creating a single-item buffered channel to ensure that we only keep a single full sync request at a time,
// additional requests would be pointless to queue since after the first one was processed the system would already
// be up to date with all of the policy changes from any enqueued request after that
npc . fullSyncRequestChan = make ( chan struct { } , 1 )
2019-10-17 21:46:15 +00:00
2021-04-21 22:56:20 +00:00
npc . serviceClusterIPRange = * config . AgentConfig . ServiceCIDR
2021-02-01 19:20:24 +00:00
npc . serviceNodePortRange = strings . ReplaceAll ( config . AgentConfig . ServiceNodePortRange . String ( ) , "-" , ":" )
npc . syncPeriod = defaultSyncPeriod
2021-02-01 19:03:43 +00:00
2021-02-01 19:20:24 +00:00
node , err := utils . GetNodeObject ( clientset , config . AgentConfig . NodeName )
2019-10-17 21:46:15 +00:00
if err != nil {
return nil , err
}
npc . nodeHostName = node . Name
2021-02-01 19:03:43 +00:00
nodeIP , err := utils . GetNodeIP ( node )
2019-10-17 21:46:15 +00:00
if err != nil {
return nil , err
}
npc . nodeIP = nodeIP
2021-02-01 19:03:43 +00:00
ipset , err := utils . NewIPSet ( false )
if err != nil {
return nil , err
}
err = ipset . Save ( )
2019-10-17 21:46:15 +00:00
if err != nil {
return nil , err
}
npc . ipSetHandler = ipset
npc . podLister = podInformer . GetIndexer ( )
npc . PodEventHandler = npc . newPodEventHandler ( )
npc . nsLister = nsInformer . GetIndexer ( )
npc . NamespaceEventHandler = npc . newNamespaceEventHandler ( )
npc . npLister = npInformer . GetIndexer ( )
npc . NetworkPolicyEventHandler = npc . newNetworkPolicyEventHandler ( )
return & npc , nil
}