Skip to content

Commit 4d6b0b8

Browse files
authored
whitelist traffic to cluster IP and node ports in INPUT chain to bypass netwrok policy enforcement (#914)
* whitelist traffic to cluster IP and node ports in INPUT chain to bypass netwrok policy enforcement Fixes #905 * fix unit test failure * ensure netpol firewall rules are configured after service proxy firewall rules
1 parent 210dc3d commit 4d6b0b8

File tree

5 files changed

+98
-55
lines changed

5 files changed

+98
-55
lines changed

docs/user-guide.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ Usage of kube-router:
8282
--run-firewall Enables Network Policy -- sets up iptables to provide ingress firewall for pods. (default true)
8383
--run-router Enables Pod Networking -- Advertises and learns the routes to Pods via iBGP. (default true)
8484
--run-service-proxy Enables Service Proxy -- sets up IPVS for Kubernetes Services. (default true)
85+
--service-cluster-ip-range string CIDR value from which service cluster IPs are assigned. Default: 10.96.0.0/12 (default "10.96.0.0/12")
86+
--service-node-port-range string NodePort range. Default: 30000-32767 (default "30000:32767")
8587
-v, --v string log level for V logs (default "0")
8688
-V, --version Print version information.
8789
```

pkg/cmd/kube-router.go

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,21 +127,6 @@ func (kr *KubeRouter) Run() error {
127127
kr.Config.MetricsEnabled = false
128128
}
129129

130-
if kr.Config.RunFirewall {
131-
npc, err := netpol.NewNetworkPolicyController(kr.Client,
132-
kr.Config, podInformer, npInformer, nsInformer)
133-
if err != nil {
134-
return errors.New("Failed to create network policy controller: " + err.Error())
135-
}
136-
137-
podInformer.AddEventHandler(npc.PodEventHandler)
138-
nsInformer.AddEventHandler(npc.NamespaceEventHandler)
139-
npInformer.AddEventHandler(npc.NetworkPolicyEventHandler)
140-
141-
wg.Add(1)
142-
go npc.Run(healthChan, stopCh, &wg)
143-
}
144-
145130
if kr.Config.BGPGracefulRestart {
146131
if kr.Config.BGPGracefulRestartDeferralTime > time.Hour*18 {
147132
return errors.New("BGPGracefuleRestartDeferralTime should be less than 18 hours")
@@ -177,6 +162,28 @@ func (kr *KubeRouter) Run() error {
177162

178163
wg.Add(1)
179164
go nsc.Run(healthChan, stopCh, &wg)
165+
166+
// wait for the proxy firewall rules to be setup before network policies
167+
if kr.Config.RunFirewall {
168+
nsc.ProxyFirewallSetup.L.Lock()
169+
nsc.ProxyFirewallSetup.Wait()
170+
nsc.ProxyFirewallSetup.L.Unlock()
171+
}
172+
}
173+
174+
if kr.Config.RunFirewall {
175+
npc, err := netpol.NewNetworkPolicyController(kr.Client,
176+
kr.Config, podInformer, npInformer, nsInformer)
177+
if err != nil {
178+
return errors.New("Failed to create network policy controller: " + err.Error())
179+
}
180+
181+
podInformer.AddEventHandler(npc.PodEventHandler)
182+
nsInformer.AddEventHandler(npc.NamespaceEventHandler)
183+
npInformer.AddEventHandler(npc.NetworkPolicyEventHandler)
184+
185+
wg.Add(1)
186+
go npc.Run(healthChan, stopCh, &wg)
180187
}
181188

182189
// Handle SIGINT and SIGTERM

pkg/controllers/netpol/network_policy_controller.go

Lines changed: 62 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,16 @@ const (
5454

5555
// NetworkPolicyController strcut to hold information required by NetworkPolicyController
5656
type NetworkPolicyController struct {
57-
nodeIP net.IP
58-
nodeHostName string
59-
mu sync.Mutex
60-
syncPeriod time.Duration
61-
MetricsEnabled bool
62-
v1NetworkPolicy bool
63-
healthChan chan<- *healthcheck.ControllerHeartbeat
64-
fullSyncRequestChan chan struct{}
57+
nodeIP net.IP
58+
nodeHostName string
59+
serviceClusterIPRange string
60+
serviceNodePortRange string
61+
mu sync.Mutex
62+
syncPeriod time.Duration
63+
MetricsEnabled bool
64+
v1NetworkPolicy bool
65+
healthChan chan<- *healthcheck.ControllerHeartbeat
66+
fullSyncRequestChan chan struct{}
6567

6668
ipSetHandler *utils.IPSet
6769

@@ -197,48 +199,65 @@ func (npc *NetworkPolicyController) ensureTopLevelChains() {
197199
glog.Fatalf("Failed to initialize iptables executor due to %s", err.Error())
198200
}
199201

200-
chains := map[string]string{"INPUT": kubeInputChainName, "FORWARD": kubeForwardChainName, "OUTPUT": kubeOutputChainName}
201-
202-
for builtinChain, customChain := range chains {
203-
err = iptablesCmdHandler.NewChain("filter", customChain)
204-
if err != nil && err.(*iptables.Error).ExitStatus() != 1 {
205-
glog.Fatalf("Failed to run iptables command to create %s chain due to %s", customChain, err.Error())
202+
ensureRuleAtposition := func(chain string, ruleSpec []string, position int) {
203+
rules, err := iptablesCmdHandler.List("filter", chain)
204+
if err != nil {
205+
glog.Fatalf("failed to list rules in filter table %s chain due to %s", chain, err.Error())
206206
}
207-
args := []string{"-m", "comment", "--comment", "kube-router netpol", "-j", customChain}
208-
exists, err := iptablesCmdHandler.Exists("filter", builtinChain, args...)
207+
208+
exists, err := iptablesCmdHandler.Exists("filter", chain, ruleSpec...)
209209
if err != nil {
210-
glog.Fatalf("Failed to verify rule exists to jump to chain %s in %s chain due to %s", customChain, builtinChain, err.Error())
210+
glog.Fatalf("Failed to verify rule exists in %s chain due to %s", chain, err.Error())
211211
}
212212
if !exists {
213-
err := iptablesCmdHandler.Insert("filter", builtinChain, 1, args...)
213+
err := iptablesCmdHandler.Insert("filter", chain, position, ruleSpec...)
214214
if err != nil {
215-
glog.Fatalf("Failed to run iptables command to insert in %s chain %s", builtinChain, err.Error())
215+
glog.Fatalf("Failed to run iptables command to insert in %s chain %s", chain, err.Error())
216216
}
217-
} else {
218-
rules, err := iptablesCmdHandler.List("filter", builtinChain)
219-
if err != nil {
220-
glog.Fatalf("failed to list rules in filter table %s chain due to %s", builtinChain, err.Error())
217+
return
218+
}
219+
var ruleNo int
220+
for i, rule := range rules {
221+
rule = strings.Replace(rule, "\"", "", 2) //removes quote from comment string
222+
if strings.Contains(rule, strings.Join(ruleSpec, " ")) {
223+
ruleNo = i
224+
break
221225
}
222-
223-
var ruleNo int
224-
for i, rule := range rules {
225-
if strings.Contains(rule, customChain) {
226-
ruleNo = i
227-
break
228-
}
226+
}
227+
if ruleNo != position {
228+
err = iptablesCmdHandler.Insert("filter", chain, position, ruleSpec...)
229+
if err != nil {
230+
glog.Fatalf("Failed to run iptables command to insert in %s chain %s", chain, err.Error())
229231
}
230-
if ruleNo != 1 {
231-
err = iptablesCmdHandler.Insert("filter", builtinChain, 1, args...)
232-
if err != nil {
233-
glog.Fatalf("Failed to run iptables command to insert in %s chain %s", builtinChain, err.Error())
234-
}
235-
err = iptablesCmdHandler.Delete("filter", builtinChain, strconv.Itoa(ruleNo+1))
236-
if err != nil {
237-
glog.Fatalf("Failed to delete wrong rule to jump to chain %s in %s chain due to %s", customChain, builtinChain, err.Error())
238-
}
232+
err = iptablesCmdHandler.Delete("filter", chain, strconv.Itoa(ruleNo+1))
233+
if err != nil {
234+
glog.Fatalf("Failed to delete incorrect rule in %s chain due to %s", chain, err.Error())
239235
}
240236
}
241237
}
238+
239+
chains := map[string]string{"INPUT": kubeInputChainName, "FORWARD": kubeForwardChainName, "OUTPUT": kubeOutputChainName}
240+
241+
for builtinChain, customChain := range chains {
242+
err = iptablesCmdHandler.NewChain("filter", customChain)
243+
if err != nil && err.(*iptables.Error).ExitStatus() != 1 {
244+
glog.Fatalf("Failed to run iptables command to create %s chain due to %s", customChain, err.Error())
245+
}
246+
args := []string{"-m", "comment", "--comment", "kube-router netpol", "-j", customChain}
247+
ensureRuleAtposition(builtinChain, args, 1)
248+
}
249+
250+
whitelistServiceVips := []string{"-m", "comment", "--comment", "allow traffic to cluster IP", "-d", npc.serviceClusterIPRange, "-j", "RETURN"}
251+
ensureRuleAtposition(kubeInputChainName, whitelistServiceVips, 1)
252+
253+
whitelistTCPNodeports := []string{"-p", "tcp", "-m", "comment", "--comment", "allow LOCAL traffic to node ports", "-m", "addrtype", "--dst-type", "LOCAL",
254+
"-m", "multiport", "--dports", npc.serviceNodePortRange, "-j", "RETURN"}
255+
ensureRuleAtposition(kubeInputChainName, whitelistTCPNodeports, 2)
256+
257+
whitelistUDPNodeports := []string{"-p", "udp", "-m", "comment", "--comment", "allow LOCAL traffic to node ports", "-m", "addrtype", "--dst-type", "LOCAL",
258+
"-m", "multiport", "--dports", npc.serviceNodePortRange, "-j", "RETURN"}
259+
ensureRuleAtposition(kubeInputChainName, whitelistUDPNodeports, 3)
260+
242261
}
243262

244263
// OnPodUpdate handles updates to pods from the Kubernetes api server
@@ -953,7 +972,7 @@ func (npc *NetworkPolicyController) syncPodFirewallChains(networkPoliciesInfo []
953972
return nil, fmt.Errorf("Failed to run iptables command: %s", err.Error())
954973
}
955974
if !exists {
956-
err := iptablesCmdHandler.Insert("filter", chain, 1, args...)
975+
err := iptablesCmdHandler.AppendUnique("filter", chain, args...)
957976
if err != nil {
958977
return nil, fmt.Errorf("Failed to run iptables command: %s", err.Error())
959978
}
@@ -1780,6 +1799,9 @@ func NewNetworkPolicyController(clientset kubernetes.Interface,
17801799
// be up to date with all of the policy changes from any enqueued request after that
17811800
npc.fullSyncRequestChan = make(chan struct{}, 1)
17821801

1802+
npc.serviceClusterIPRange = config.ClusterIPCIDR
1803+
npc.serviceNodePortRange = config.NodePortRange
1804+
17831805
if config.MetricsEnabled {
17841806
//Register the metrics for this controller
17851807
prometheus.MustRegister(metrics.ControllerIptablesSyncTime)

pkg/controllers/proxy/network_services_controller.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ type NetworkServicesController struct {
217217
MetricsEnabled bool
218218
ln LinuxNetworking
219219
readyForUpdates bool
220+
ProxyFirewallSetup *sync.Cond
220221

221222
// Map of ipsets that we use.
222223
ipsetMap map[string]*utils.Set
@@ -344,6 +345,7 @@ func (nsc *NetworkServicesController) Run(healthChan chan<- *healthcheck.Control
344345
if err != nil {
345346
glog.Error("Error setting up ipvs firewall: " + err.Error())
346347
}
348+
nsc.ProxyFirewallSetup.Broadcast()
347349

348350
gracefulTicker := time.NewTicker(5 * time.Second)
349351
defer gracefulTicker.Stop()
@@ -2222,6 +2224,8 @@ func NewNetworkServicesController(clientset kubernetes.Interface,
22222224
nsc.endpointsMap = make(endpointsInfoMap)
22232225
nsc.client = clientset
22242226

2227+
nsc.ProxyFirewallSetup = sync.NewCond(&sync.Mutex{})
2228+
22252229
nsc.masqueradeAll = false
22262230
if config.MasqueradeAll {
22272231
nsc.masqueradeAll = true

pkg/options/options.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ type KubeRouterConfig struct {
2323
CleanupConfig bool
2424
ClusterAsn uint
2525
ClusterCIDR string
26+
ClusterIPCIDR string
27+
NodePortRange string
2628
DisableSrcDstCheck bool
2729
EnableCNI bool
2830
EnableiBGP bool
@@ -74,6 +76,8 @@ func NewKubeRouterConfig() *KubeRouterConfig {
7476
BGPGracefulRestartDeferralTime: 360 * time.Second,
7577
EnableOverlay: true,
7678
OverlayType: "subnet",
79+
ClusterIPCIDR: "10.96.0.0/12",
80+
NodePortRange: "30000:32767",
7781
}
7882
}
7983

@@ -102,6 +106,10 @@ func (s *KubeRouterConfig) AddFlags(fs *pflag.FlagSet) {
102106
"CIDR range of pods in the cluster. It is used to identify traffic originating from and destinated to pods.")
103107
fs.StringSliceVar(&s.ExcludedCidrs, "excluded-cidrs", s.ExcludedCidrs,
104108
"Excluded CIDRs are used to exclude IPVS rules from deletion.")
109+
fs.StringVar(&s.ClusterIPCIDR, "service-cluster-ip-range", s.ClusterIPCIDR,
110+
"CIDR value from which service cluster IPs are assigned. Default: 10.96.0.0/12")
111+
fs.StringVar(&s.NodePortRange, "service-node-port-range", s.NodePortRange,
112+
"NodePort range. Default: 30000-32767")
105113
fs.BoolVar(&s.EnablePodEgress, "enable-pod-egress", true,
106114
"SNAT traffic from Pods to destinations outside the cluster.")
107115
fs.DurationVar(&s.IPTablesSyncPeriod, "iptables-sync-period", s.IPTablesSyncPeriod,

0 commit comments

Comments
 (0)