diff --git a/Dockerfile b/Dockerfile index f0717063..83bedaf1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,7 +9,7 @@ FROM --platform=$BUILDPLATFORM golang:1.21-alpine as go WORKDIR /build COPY --link go.mod go.sum . COPY --link ./proxy-init ./proxy-init -COPY --link ./internal ./internal +COPY --link ./pkg ./pkg RUN go mod download ARG TARGETARCH RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH GO111MODULE=on \ diff --git a/Dockerfile-cni-plugin b/Dockerfile-cni-plugin index 8bc2da01..4180ac73 100644 --- a/Dockerfile-cni-plugin +++ b/Dockerfile-cni-plugin @@ -6,7 +6,7 @@ WORKDIR /build COPY --link go.mod go.sum ./ COPY --link ./cni-plugin ./cni-plugin COPY --link ./proxy-init ./proxy-init -COPY --link ./internal ./internal +COPY --link ./pkg ./pkg RUN go mod download ARG TARGETARCH RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH GO111MODULE=on \ diff --git a/cni-plugin/integration/Dockerfile-tester b/cni-plugin/integration/Dockerfile-tester index 7bedef80..27a908de 100644 --- a/cni-plugin/integration/Dockerfile-tester +++ b/cni-plugin/integration/Dockerfile-tester @@ -14,6 +14,6 @@ ENV GOCACHE=/tmp/ WORKDIR /src COPY --link go.mod go.sum . COPY --link cni-plugin cni-plugin -COPY --link internal internal +COPY --link pkg pkg COPY --link proxy-init proxy-init RUN go mod tidy && go mod download diff --git a/cni-plugin/main.go b/cni-plugin/main.go index 9eb68980..d5e0676e 100644 --- a/cni-plugin/main.go +++ b/cni-plugin/main.go @@ -30,7 +30,7 @@ import ( "github.com/containernetworking/cni/pkg/types" cniv1 "github.com/containernetworking/cni/pkg/types/100" "github.com/containernetworking/cni/pkg/version" - "github.com/linkerd/linkerd2-proxy-init/internal/iptables" + "github.com/linkerd/linkerd2-proxy-init/pkg/iptables" "github.com/linkerd/linkerd2-proxy-init/proxy-init/cmd" "github.com/sirupsen/logrus" diff --git a/justfile b/justfile index ba3cb506..07b313c2 100644 --- a/justfile +++ b/justfile @@ -111,7 +111,7 @@ proxy-init-lint *flags: # Run proxy-init unit tests proxy-init-test-unit: go test -v ./proxy-init/... - go test -v ./internal/... + go test -v ./pkg/... # Run proxy-init integration tests after preparing dependencies proxy-init-test-integration: proxy-init-test-integration-deps proxy-init-test-integration-run @@ -161,7 +161,7 @@ build-cni-plugin-test-image *args='--load': ## ## CNI plugin integration -## +## # Run cni-plugin integration tests after preparing dependencies By default, diff --git a/internal/iptables/iptables.go b/pkg/iptables/iptables.go similarity index 80% rename from internal/iptables/iptables.go rename to pkg/iptables/iptables.go index 4356c04b..be1a8933 100644 --- a/internal/iptables/iptables.go +++ b/pkg/iptables/iptables.go @@ -10,7 +10,7 @@ import ( log "github.com/sirupsen/logrus" - util "github.com/linkerd/linkerd2-proxy-init/internal/util" + util "github.com/linkerd/linkerd2-proxy-init/pkg/util" ) const ( @@ -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 removes 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,39 @@ func ConfigureFirewall(firewallConfiguration FirewallConfiguration) error { return nil } -// 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 (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 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 +337,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/internal/iptables/iptables_test.go b/pkg/iptables/iptables_test.go similarity index 79% rename from internal/iptables/iptables_test.go rename to pkg/iptables/iptables_test.go index c6f2f0bb..8e1f7bd8 100644 --- a/internal/iptables/iptables_test.go +++ b/pkg/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{}) { diff --git a/internal/util/portrange.go b/pkg/util/portrange.go similarity index 100% rename from internal/util/portrange.go rename to pkg/util/portrange.go diff --git a/internal/util/portrange_test.go b/pkg/util/portrange_test.go similarity index 100% rename from internal/util/portrange_test.go rename to pkg/util/portrange_test.go diff --git a/proxy-init/cmd/root.go b/proxy-init/cmd/root.go index 3c8fa8f7..accb7ff2 100644 --- a/proxy-init/cmd/root.go +++ b/proxy-init/cmd/root.go @@ -9,8 +9,8 @@ import ( log "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "github.com/linkerd/linkerd2-proxy-init/internal/iptables" - "github.com/linkerd/linkerd2-proxy-init/internal/util" + "github.com/linkerd/linkerd2-proxy-init/pkg/iptables" + "github.com/linkerd/linkerd2-proxy-init/pkg/util" ) // RootOptions provides the information that will be used to build a firewall configuration. diff --git a/proxy-init/cmd/root_test.go b/proxy-init/cmd/root_test.go index d1b31b28..e8c8a7ef 100644 --- a/proxy-init/cmd/root_test.go +++ b/proxy-init/cmd/root_test.go @@ -4,7 +4,7 @@ import ( "reflect" "testing" - "github.com/linkerd/linkerd2-proxy-init/internal/iptables" + "github.com/linkerd/linkerd2-proxy-init/pkg/iptables" ) func TestBuildFirewallConfiguration(t *testing.T) {