Skip to content

Commit bffdc72

Browse files
authored
fix(npc): ordering of firewall / service rules (cloudnativelabs#1144)
1 parent 35d334c commit bffdc72

File tree

3 files changed

+52
-17
lines changed

3 files changed

+52
-17
lines changed

pkg/controllers/netpol/network_policy_controller.go

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ const (
3535
kubeDefaultNetpolChain = "KUBE-NWPLCY-DEFAULT"
3636
)
3737

38+
var (
39+
defaultChains = map[string]string{"INPUT": kubeInputChainName, "FORWARD": kubeForwardChainName, "OUTPUT": kubeOutputChainName}
40+
)
41+
3842
// Network policy controller provides both ingress and egress filtering for the pods as per the defined network
3943
// policies. Two different types of iptables chains are used. Each pod running on the node which either
4044
// requires ingress or egress filtering gets a pod specific chains. Each network policy has a iptables chain, which
@@ -251,6 +255,10 @@ func (npc *NetworkPolicyController) fullPolicySync() {
251255
return
252256
}
253257

258+
// Makes sure that the ACCEPT rules for packets marked with "0x20000" are added to the end of each of kube-router's
259+
// top level chains
260+
npc.ensureExplicitAccept()
261+
254262
err = npc.cleanupStaleRules(activePolicyChains, activePodFwChains, false)
255263
if err != nil {
256264
klog.Errorf("Aborting sync. Failed to cleanup stale iptables rules: %v", err.Error())
@@ -337,9 +345,7 @@ func (npc *NetworkPolicyController) ensureTopLevelChains() {
337345
}
338346
}
339347

340-
chains := map[string]string{"INPUT": kubeInputChainName, "FORWARD": kubeForwardChainName, "OUTPUT": kubeOutputChainName}
341-
342-
for builtinChain, customChain := range chains {
348+
for builtinChain, customChain := range defaultChains {
343349
err = iptablesCmdHandler.NewChain("filter", customChain)
344350
if err != nil && err.(*iptables.Error).ExitStatus() != 1 {
345351
klog.Fatalf("Failed to run iptables command to create %s chain due to %s", customChain, err.Error())
@@ -383,16 +389,15 @@ func (npc *NetworkPolicyController) ensureTopLevelChains() {
383389
}
384390
ensureRuleAtPosition(kubeInputChainName, whitelistServiceVips, uuid, externalIPIndex+4)
385391
}
392+
}
386393

394+
func (npc *NetworkPolicyController) ensureExplicitAccept() {
387395
// for the traffic to/from the local pod's let network policy controller be
388396
// authoritative entity to ACCEPT the traffic if it complies to network policies
389-
for _, chain := range chains {
390-
comment := "rule to explicitly ACCEPT traffic that comply to network policies"
397+
for _, chain := range defaultChains {
398+
comment := "\"rule to explicitly ACCEPT traffic that comply to network policies\""
391399
args := []string{"-m", "comment", "--comment", comment, "-m", "mark", "--mark", "0x20000/0x20000", "-j", "ACCEPT"}
392-
err = iptablesCmdHandler.AppendUnique("filter", chain, args...)
393-
if err != nil {
394-
klog.Fatalf("Failed to run iptables command: %s", err.Error())
395-
}
400+
npc.filterTableRules = utils.AppendUnique(npc.filterTableRules, chain, args)
396401
}
397402
}
398403

pkg/controllers/netpol/pod.go

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -196,19 +196,19 @@ func (npc *NetworkPolicyController) interceptPodInboundTraffic(pod *podInfo, pod
196196
// this rule applies to the traffic getting routed (coming for other node pods)
197197
comment := "\"rule to jump traffic destined to POD name:" + pod.name + " namespace: " + pod.namespace +
198198
" to chain " + podFwChainName + "\""
199-
args := []string{"-I", kubeForwardChainName, "1", "-m", "comment", "--comment", comment, "-d", pod.ip, "-j", podFwChainName + "\n"}
199+
args := []string{"-A", kubeForwardChainName, "-m", "comment", "--comment", comment, "-d", pod.ip, "-j", podFwChainName + "\n"}
200200
npc.filterTableRules.WriteString(strings.Join(args, " "))
201201

202202
// ensure there is rule in filter table and OUTPUT chain to jump to pod specific firewall chain
203203
// this rule applies to the traffic from a pod getting routed back to another pod on same node by service proxy
204-
args = []string{"-I", kubeOutputChainName, "1", "-m", "comment", "--comment", comment, "-d", pod.ip, "-j", podFwChainName + "\n"}
204+
args = []string{"-A", kubeOutputChainName, "-m", "comment", "--comment", comment, "-d", pod.ip, "-j", podFwChainName + "\n"}
205205
npc.filterTableRules.WriteString(strings.Join(args, " "))
206206

207207
// ensure there is rule in filter table and forward chain to jump to pod specific firewall chain
208208
// this rule applies to the traffic getting switched (coming for same node pods)
209209
comment = "\"rule to jump traffic destined to POD name:" + pod.name + " namespace: " + pod.namespace +
210210
" to chain " + podFwChainName + "\""
211-
args = []string{"-I", kubeForwardChainName, "1", "-m", "physdev", "--physdev-is-bridged",
211+
args = []string{"-A", kubeForwardChainName, "-m", "physdev", "--physdev-is-bridged",
212212
"-m", "comment", "--comment", comment,
213213
"-d", pod.ip,
214214
"-j", podFwChainName, "\n"}
@@ -218,22 +218,21 @@ func (npc *NetworkPolicyController) interceptPodInboundTraffic(pod *podInfo, pod
218218
// setup iptable rules to intercept outbound traffic from pods and run it across the
219219
// firewall chain corresponding to the pod so that egress network policies are enforced
220220
func (npc *NetworkPolicyController) interceptPodOutboundTraffic(pod *podInfo, podFwChainName string) {
221-
egressFilterChains := []string{kubeInputChainName, kubeForwardChainName, kubeOutputChainName}
222-
for _, chain := range egressFilterChains {
221+
for _, chain := range defaultChains {
223222
// ensure there is rule in filter table and FORWARD chain to jump to pod specific firewall chain
224-
// this rule applies to the traffic getting forwarded/routed (traffic from the pod destinted
223+
// this rule applies to the traffic getting forwarded/routed (traffic from the pod destined
225224
// to pod on a different node)
226225
comment := "\"rule to jump traffic from POD name:" + pod.name + " namespace: " + pod.namespace +
227226
" to chain " + podFwChainName + "\""
228-
args := []string{"-I", chain, "1", "-m", "comment", "--comment", comment, "-s", pod.ip, "-j", podFwChainName, "\n"}
227+
args := []string{"-A", chain, "-m", "comment", "--comment", comment, "-s", pod.ip, "-j", podFwChainName, "\n"}
229228
npc.filterTableRules.WriteString(strings.Join(args, " "))
230229
}
231230

232231
// ensure there is rule in filter table and forward chain to jump to pod specific firewall chain
233232
// this rule applies to the traffic getting switched (coming for same node pods)
234233
comment := "\"rule to jump traffic from POD name:" + pod.name + " namespace: " + pod.namespace +
235234
" to chain " + podFwChainName + "\""
236-
args := []string{"-I", kubeForwardChainName, "1", "-m", "physdev", "--physdev-is-bridged",
235+
args := []string{"-A", kubeForwardChainName, "-m", "physdev", "--physdev-is-bridged",
237236
"-m", "comment", "--comment", comment,
238237
"-s", pod.ip,
239238
"-j", podFwChainName, "\n"}

pkg/utils/iptables.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,34 @@ func Restore(table string, data []byte) error {
7070

7171
return nil
7272
}
73+
74+
// AppendUnique ensures that rule is in chain only once in the buffer and that the occurrence is at the end of the buffer
75+
func AppendUnique(buffer bytes.Buffer, chain string, rule []string) bytes.Buffer {
76+
var desiredBuffer bytes.Buffer
77+
78+
// First we need to remove any previous instances of the rule that exist, so that we can be sure that our version
79+
// is unique and appended to the very end of the buffer
80+
rules := strings.Split(buffer.String(), "\n")
81+
if len(rules) > 0 && rules[len(rules)-1] == "" {
82+
rules = rules[:len(rules)-1]
83+
}
84+
for _, foundRule := range rules {
85+
if strings.Contains(foundRule, chain) {
86+
if strings.Contains(foundRule, strings.Join(rule, " ")) {
87+
continue
88+
}
89+
}
90+
desiredBuffer.WriteString(foundRule + "\n")
91+
}
92+
93+
// Now append the rule that we wanted to be unique
94+
desiredBuffer = Append(desiredBuffer, chain, rule)
95+
return desiredBuffer
96+
}
97+
98+
// Append appends rule to chain at the end of buffer
99+
func Append(buffer bytes.Buffer, chain string, rule []string) bytes.Buffer {
100+
ruleStr := strings.Join(append(append([]string{"-A", chain}, rule...), "\n"), " ")
101+
buffer.WriteString(ruleStr)
102+
return buffer
103+
}

0 commit comments

Comments
 (0)