Skip to content

Commit

Permalink
Expose ip tables package (#361)
Browse files Browse the repository at this point in the history
- enable the use iptables as a library
- adda functionality to remove already configured rules.

Signed-off-by: Zahari Dichev <zaharidichev@gmail.com>
  • Loading branch information
zaharidichev committed Jun 6, 2024
1 parent 21dce30 commit 61a8d25
Show file tree
Hide file tree
Showing 11 changed files with 125 additions and 36 deletions.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile-cni-plugin
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
2 changes: 1 addition & 1 deletion cni-plugin/integration/Dockerfile-tester
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 1 addition & 1 deletion cni-plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 2 additions & 2 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -161,7 +161,7 @@ build-cni-plugin-test-image *args='--load':

##
## CNI plugin integration
##
##


# Run cni-plugin integration tests after preparing dependencies By default,
Expand Down
93 changes: 83 additions & 10 deletions internal/iptables/iptables.go → pkg/iptables/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -35,15 +35,15 @@ 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`)
redirectChainRegex = regexp.MustCompile(`(?m)^:PROXY_INIT_REDIRECT `)
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
Expand All @@ -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)

Expand All @@ -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)
}
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -53,16 +51,16 @@ func TestAddIncomingTrafficRules(t *testing.T) {
name: "no existing rules, create new chain and PREROUTING rule",
wantCommands: []*exec.Cmd{
exec.Command("<iptables>", "-t", "nat", "-N", "PROXY_INIT_REDIRECT"),
exec.Command("<iptables>", "-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("<iptables>", "-t", "nat", "-A", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting/testExecutionTraceID"),
exec.Command("<iptables>", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234"),
exec.Command("<iptables>", "-t", "nat", "-A", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting"),
},
},
{
name: "existing rules, flush existing chain and reuse PREROUTING rule",
existingRules: existingRules,
wantCommands: []*exec.Cmd{
exec.Command("<iptables>", "-t", "nat", "-F", "PROXY_INIT_REDIRECT"),
exec.Command("<iptables>", "-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("<iptables>", "-t", "nat", "-A", "PROXY_INIT_REDIRECT", "-p", "tcp", "--match", "multiport", "--dports", "1234", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-port-1234"),
},
},
} {
Expand All @@ -78,8 +76,6 @@ func TestAddIncomingTrafficRules(t *testing.T) {
}

func TestAddOutgoingTrafficRules(t *testing.T) {
ExecutionTraceID = "testExecutionTraceID"

for _, tt := range []struct {
name string
existingRules []byte
Expand All @@ -89,18 +85,18 @@ func TestAddOutgoingTrafficRules(t *testing.T) {
name: "no existing rules, create new chain and OUTPUT rule",
wantCommands: []*exec.Cmd{
exec.Command("<iptables>", "-t", "nat", "-N", "PROXY_INIT_OUTPUT"),
exec.Command("<iptables>", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback/testExecutionTraceID"),
exec.Command("<iptables>", "-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("<iptables>", "-t", "nat", "-A", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output/testExecutionTraceID"),
exec.Command("<iptables>", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback"),
exec.Command("<iptables>", "-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("<iptables>", "-t", "nat", "-A", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output"),
},
},
{
name: "existing rules, flush existing chain and reuse OUTPUT rule",
existingRules: existingRules,
wantCommands: []*exec.Cmd{
exec.Command("<iptables>", "-t", "nat", "-F", "PROXY_INIT_OUTPUT"),
exec.Command("<iptables>", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback/testExecutionTraceID"),
exec.Command("<iptables>", "-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("<iptables>", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-o", "lo", "-j", "RETURN", "-m", "comment", "--comment", "proxy-init/ignore-loopback"),
exec.Command("<iptables>", "-t", "nat", "-A", "PROXY_INIT_OUTPUT", "-p", "tcp", "-j", "REDIRECT", "--to-port", "1234", "-m", "comment", "--comment", "proxy-init/redirect-all-outgoing-to-proxy-port"),
},
},
} {
Expand All @@ -113,6 +109,26 @@ func TestAddOutgoingTrafficRules(t *testing.T) {
assertEqual(t, cmds, tt.wantCommands)
})
}

}

func TestCleanupFirewallConfig(t *testing.T) {
wantCommands := []*exec.Cmd{
exec.Command("<iptables>", "-t", "nat", "-D", "PREROUTING", "-j", "PROXY_INIT_REDIRECT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-prerouting"),
exec.Command("<iptables>", "-t", "nat", "-D", "OUTPUT", "-j", "PROXY_INIT_OUTPUT", "-m", "comment", "--comment", "proxy-init/install-proxy-init-output"),
exec.Command("<iptables>", "-t", "nat", "-F", "PROXY_INIT_OUTPUT"),
exec.Command("<iptables>", "-t", "nat", "-F", "PROXY_INIT_REDIRECT"),
exec.Command("<iptables>", "-t", "nat", "-X", "PROXY_INIT_OUTPUT"),
exec.Command("<iptables>", "-t", "nat", "-X", "PROXY_INIT_REDIRECT"),
}

fc := &FirewallConfiguration{
BinPath: "<iptables>",
InboundPortsToIgnore: []string{"1234"},
}
cmds := fc.cleanupRules(nil)
assertEqual(t, cmds, wantCommands)

}

func assertEqual(t *testing.T, check, expected interface{}) {
Expand Down
File renamed without changes.
File renamed without changes.
4 changes: 2 additions & 2 deletions proxy-init/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion proxy-init/cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 61a8d25

Please sign in to comment.