diff --git a/iptables/iptables.go b/iptables/iptables.go index 8fdf3048..4b4e0b42 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -35,7 +35,7 @@ const ( var ( // ExecutionTraceID provides a unique identifier for this script's execution. - ExecutionTraceID = strconv.Itoa(int(time.Now().Unix())) + executionTraceID = strconv.Itoa(int(time.Now().Unix())) preroutingRuleRegex = regexp.MustCompile(`(?m)^-A PREROUTING (.+ )?-j PROXY_INIT_REDIRECT`) outputRuleRegex = regexp.MustCompile(`(?m)^-A OUTPUT (.+ )?-j PROXY_INIT_OUTPUT`) @@ -43,7 +43,7 @@ var ( outputChainRegex = regexp.MustCompile(`(?m)^:PROXY_INIT_OUTPUT `) ) -// FirewallConfiguration specifies how to configure a pod's iptables. +// FirewallConfiguration specifies how to configure iptables. type FirewallConfiguration struct { Mode string PortsToRedirectInbound []int @@ -58,13 +58,14 @@ type FirewallConfiguration struct { UseWaitFlag bool BinPath string SaveBinPath string + ContinueOnError bool } -// ConfigureFirewall configures a pod's internal iptables to redirect all desired traffic through the proxy, allowing for -// the pod to join the service mesh. A lot of this logic was based on +// ConfigureFirewall configures iptables to redirect all desired traffic through the proxy, allowing for +// the workload to join the service mesh. A lot of this logic was based on // https://github.com/istio/istio/blob/e83411e/pilot/docker/prepare_proxy.sh func ConfigureFirewall(firewallConfiguration FirewallConfiguration) error { - log.Debugf("tracing script execution as [%s]", ExecutionTraceID) + log.Debugf("tracing script execution as [%s]", executionTraceID) log.Debugf("using '%s' to set-up firewall rules", firewallConfiguration.BinPath) log.Debugf("using '%s' to list all available rules", firewallConfiguration.SaveBinPath) @@ -90,7 +91,44 @@ func ConfigureFirewall(firewallConfiguration FirewallConfiguration) error { } if _, err := executeCommand(firewallConfiguration, cmd); err != nil { - return err + if !firewallConfiguration.ContinueOnError { + return err + } + + log.Debugf("continuing despite error: %s", err) + } + } + + _, _ = executeCommand(firewallConfiguration, firewallConfiguration.makeShowAllRules()) + + return nil +} + +// CleanupFirewallConfig removed the iptables rules that have been added as a result of +// calling ConfigureFirewall. +func CleanupFirewallConfig(firewallConfiguration FirewallConfiguration) error { + log.Debugf("tracing script execution as [%s]", executionTraceID) + log.Debugf("using '%s' to clean-up firewall rules", firewallConfiguration.BinPath) + log.Debugf("using '%s' to list all available rules", firewallConfiguration.SaveBinPath) + + commands := make([]*exec.Cmd, 0) + commands = firewallConfiguration.cleanupRules(commands) + + if firewallConfiguration.UseWaitFlag { + log.Debug("'useWaitFlag' set: iptables will wait for xtables to become available") + } + + for _, cmd := range commands { + if firewallConfiguration.UseWaitFlag { + cmd.Args = append(cmd.Args, "-w") + } + + if _, err := executeCommand(firewallConfiguration, cmd); err != nil { + if !firewallConfiguration.ContinueOnError { + return err + } + + log.Debugf("continuing despite error: %s", err) } } @@ -99,10 +137,40 @@ func ConfigureFirewall(firewallConfiguration FirewallConfiguration) error { return nil } +func (fc FirewallConfiguration) cleanupRules(commands []*exec.Cmd) []*exec.Cmd { + // delete ref from prerouting + commands = append( + commands, + fc.makeJumpFromChainToAnotherForAllProtocols( + IptablesPreroutingChainName, + redirectChainName, + "install-proxy-init-prerouting", + true)) + + // delete ref from output + commands = append( + commands, + fc.makeJumpFromChainToAnotherForAllProtocols( + IptablesOutputChainName, + outputChainName, + "install-proxy-init-output", + true)) + + // flush chains + commands = append(commands, fc.makeFlushChain(outputChainName)) + commands = append(commands, fc.makeFlushChain(redirectChainName)) + + // delete chains + commands = append(commands, fc.makeDeleteChain(outputChainName)) + commands = append(commands, fc.makeDeleteChain(redirectChainName)) + + return commands +} + // formatComment is used to format iptables comments in such way that it is possible to identify when the rules were added. // This helps debug when iptables has some stale rules from previous runs, something that can happen frequently on minikube. func formatComment(text string) string { - return fmt.Sprintf("proxy-init/%s/%s", text, ExecutionTraceID) + return fmt.Sprintf("proxy-init/%s", text) } func (fc FirewallConfiguration) addOutgoingTrafficRules(existingRules []byte, commands []*exec.Cmd) []*exec.Cmd { @@ -270,6 +338,12 @@ func (fc FirewallConfiguration) makeFlushChain(name string) *exec.Cmd { "-F", name) } +func (fc FirewallConfiguration) makeDeleteChain(name string) *exec.Cmd { + return exec.Command(fc.BinPath, + "-t", "nat", + "-X", name) +} + func (fc FirewallConfiguration) makeCreateNewChain(name string) *exec.Cmd { return exec.Command(fc.BinPath, "-t", "nat", diff --git a/iptables/iptables_cleaner.go b/iptables/iptables_cleaner.go deleted file mode 100644 index d9360c67..00000000 --- a/iptables/iptables_cleaner.go +++ /dev/null @@ -1 +0,0 @@ -package iptables diff --git a/iptables/iptables_test.go b/iptables/iptables_test.go index c6f2f0bb..8e1f7bd8 100644 --- a/iptables/iptables_test.go +++ b/iptables/iptables_test.go @@ -32,18 +32,16 @@ var existingRules = []byte(`# iptables-save :POSTROUTING ACCEPT [0:0] :PROXY_INIT_OUTPUT - [0:0] :PROXY_INIT_REDIRECT - [0:0] --A PREROUTING -m comment --comment "proxy-init/install-proxy-init-prerouting/testExecutionTraceID" -j PROXY_INIT_REDIRECT --A OUTPUT -m comment --comment "proxy-init/install-proxy-init-output/testExecutionTraceID" -j PROXY_INIT_OUTPUT --A PROXY_INIT_OUTPUT -o lo -m comment --comment "proxy-init/ignore-loopback/testExecutionTraceID" -j RETURN --A PROXY_INIT_OUTPUT -p tcp -m comment --comment "proxy-init/redirect-all-outgoing-to-proxy-port/testExecutionTraceID" -j REDIRECT --to-ports 1234 --A PROXY_INIT_REDIRECT -p tcp -m multiport --dports 1234 -m comment --comment "proxy-init/ignore-port-1234/testExecutionTraceID" -j RETURN +-A PREROUTING -m comment --comment "proxy-init/install-proxy-init-prerouting" -j PROXY_INIT_REDIRECT +-A OUTPUT -m comment --comment "proxy-init/install-proxy-init-output" -j PROXY_INIT_OUTPUT +-A PROXY_INIT_OUTPUT -o lo -m comment --comment "proxy-init/ignore-loopback" -j RETURN +-A PROXY_INIT_OUTPUT -p tcp -m comment --comment "proxy-init/redirect-all-outgoing-to-proxy-port" -j REDIRECT --to-ports 1234 +-A PROXY_INIT_REDIRECT -p tcp -m multiport --dports 1234 -m comment --comment "proxy-init/ignore-port-1234" -j RETURN COMMIT # Completed on Fri Jan 6 23:00:00 2023 `) func TestAddIncomingTrafficRules(t *testing.T) { - ExecutionTraceID = "testExecutionTraceID" - for _, tt := range []struct { name string existingRules []byte @@ -53,8 +51,8 @@ func TestAddIncomingTrafficRules(t *testing.T) { name: "no existing rules, create new chain and PREROUTING rule", wantCommands: []*exec.Cmd{ exec.Command("", "-t", "nat", "-N", "PROXY_INIT_REDIRECT"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234/testExecutionTraceID"), - exec.Command("", "-t", "nat", "-A", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting/testExecutionTraceID"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234"), + exec.Command("", "-t", "nat", "-A", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting"), }, }, { @@ -62,7 +60,7 @@ func TestAddIncomingTrafficRules(t *testing.T) { existingRules: existingRules, wantCommands: []*exec.Cmd{ exec.Command("", "-t", "nat", "-F", "PROXY_INIT_REDIRECT"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234/testExecutionTraceID"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234"), }, }, } { @@ -78,8 +76,6 @@ func TestAddIncomingTrafficRules(t *testing.T) { } func TestAddOutgoingTrafficRules(t *testing.T) { - ExecutionTraceID = "testExecutionTraceID" - for _, tt := range []struct { name string existingRules []byte @@ -89,9 +85,9 @@ func TestAddOutgoingTrafficRules(t *testing.T) { name: "no existing rules, create new chain and OUTPUT rule", wantCommands: []*exec.Cmd{ exec.Command("", "-t", "nat", "-N", "PROXY_INIT_OUTPUT"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback/testExecutionTraceID"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-port", "1234", "-m", "comment", "--comment", "proxy-init/redirect-all-outgoing-to-proxy-port/testExecutionTraceID"), - exec.Command("", "-t", "nat", "-A", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output/testExecutionTraceID"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-port", "1234", "-m", "comment", "--comment", "proxy-init/redirect-all-outgoing-to-proxy-port"), + exec.Command("", "-t", "nat", "-A", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output"), }, }, { @@ -99,8 +95,8 @@ func TestAddOutgoingTrafficRules(t *testing.T) { existingRules: existingRules, wantCommands: []*exec.Cmd{ exec.Command("", "-t", "nat", "-F", "PROXY_INIT_OUTPUT"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback/testExecutionTraceID"), - exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-port", "1234", "-m", "comment", "--comment", "proxy-init/redirect-all-outgoing-to-proxy-port/testExecutionTraceID"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback"), + exec.Command("", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-port", "1234", "-m", "comment", "--comment", "proxy-init/redirect-all-outgoing-to-proxy-port"), }, }, } { @@ -113,6 +109,26 @@ func TestAddOutgoingTrafficRules(t *testing.T) { assertEqual(t, cmds, tt.wantCommands) }) } + +} + +func TestCleanupFirewallConfig(t *testing.T) { + wantCommands := []*exec.Cmd{ + exec.Command("", "-t", "nat", "-D", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting"), + exec.Command("", "-t", "nat", "-D", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output"), + exec.Command("", "-t", "nat", "-F", "PROXY_INIT_OUTPUT"), + exec.Command("", "-t", "nat", "-F", "PROXY_INIT_REDIRECT"), + exec.Command("", "-t", "nat", "-X", "PROXY_INIT_OUTPUT"), + exec.Command("", "-t", "nat", "-X", "PROXY_INIT_REDIRECT"), + } + + fc := &FirewallConfiguration{ + BinPath: "", + InboundPortsToIgnore: []string{"1234"}, + } + cmds := fc.cleanupRules(nil) + assertEqual(t, cmds, wantCommands) + } func assertEqual(t *testing.T, check, expected interface{}) {