From 52a6431bb4663fbb15b9760d5ee1dc6f9864d55c Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Thu, 30 Sep 2021 13:43:03 +0200 Subject: [PATCH] pkg/mesh/routes.go: add flag for generic ACCEPT in FORWARD chain Some linux distros or docker will set the default policy in the FORWARD chain in the filter table to DROP. With the new ip-tables-forward-rules flag a generic ACCEPT for all packages going from and to the pod subnet is added to the FORWARD chain. Signed-off-by: leonnicolas --- cmd/kg/main.go | 6 ++- pkg/mesh/mesh.go | 92 +++++++++++++++++++++++----------------------- pkg/mesh/routes.go | 6 ++- 3 files changed, 56 insertions(+), 48 deletions(-) diff --git a/cmd/kg/main.go b/cmd/kg/main.go index 1abc6ed..d6cb5de 100644 --- a/cmd/kg/main.go +++ b/cmd/kg/main.go @@ -111,6 +111,7 @@ var ( port uint subnet string resyncPeriod time.Duration + iptablesForwardRule bool prioritisePrivateAddr bool printVersion bool @@ -140,7 +141,8 @@ func init() { cmd.Flags().UintVar(&port, "port", mesh.DefaultKiloPort, "The port over which WireGuard peers should communicate.") cmd.Flags().StringVar(&subnet, "subnet", mesh.DefaultKiloSubnet.String(), "CIDR from which to allocate addresses for WireGuard interfaces.") cmd.Flags().DurationVar(&resyncPeriod, "resync-period", 30*time.Second, "How often should the Kilo controllers reconcile?") - cmd.Flags().BoolVar(&prioritisePrivateAddr, "prioritise-private-addresses", false, "Prefer to assign a private IP address to the node's endpoint") + cmd.Flags().BoolVar(&iptablesForwardRule, "ip-tables-forward-rules", false, "Add default accept rules to the FORWARD chain in iptables.") + cmd.Flags().BoolVar(&prioritisePrivateAddr, "prioritise-private-addresses", false, "Prefer to assign a private IP address to the node's endpoint.") cmd.PersistentFlags().BoolVar(&printVersion, "version", false, "Print version and exit") cmd.PersistentFlags().StringVar(&logLevel, "log-level", logLevelInfo, fmt.Sprintf("Log level to use. Possible values: %s", availableLogLevels)) @@ -236,7 +238,7 @@ func runRoot(_ *cobra.Command, _ []string) error { return fmt.Errorf("backend %v unknown; possible values are: %s", backend, availableBackends) } - m, err := mesh.New(b, enc, gr, hostname, uint32(port), s, local, cni, cniPath, iface, cleanUpIface, createIface, mtu, resyncPeriod, prioritisePrivateAddr, log.With(logger, "component", "kilo")) + m, err := mesh.New(b, enc, gr, hostname, uint32(port), s, local, cni, cniPath, iface, cleanUpIface, createIface, mtu, resyncPeriod, prioritisePrivateAddr, iptablesForwardRule, log.With(logger, "component", "kilo")) if err != nil { return fmt.Errorf("failed to create Kilo mesh: %v", err) } diff --git a/pkg/mesh/mesh.go b/pkg/mesh/mesh.go index 7c63ca1..3de41fd 100644 --- a/pkg/mesh/mesh.go +++ b/pkg/mesh/mesh.go @@ -49,27 +49,28 @@ const ( // Mesh is able to create Kilo network meshes. type Mesh struct { Backend - cleanUpIface bool - cni bool - cniPath string - enc encapsulation.Encapsulator - externalIP *net.IPNet - granularity Granularity - hostname string - internalIP *net.IPNet - ipTables *iptables.Controller - kiloIface int - key []byte - local bool - port uint32 - priv []byte - privIface int - pub []byte - resyncPeriod time.Duration - stop chan struct{} - subnet *net.IPNet - table *route.Table - wireGuardIP *net.IPNet + cleanUpIface bool + cni bool + cniPath string + enc encapsulation.Encapsulator + externalIP *net.IPNet + granularity Granularity + hostname string + internalIP *net.IPNet + ipTables *iptables.Controller + kiloIface int + key []byte + local bool + port uint32 + priv []byte + privIface int + pub []byte + resyncPeriod time.Duration + iptablesForwardRule bool + stop chan struct{} + subnet *net.IPNet + table *route.Table + wireGuardIP *net.IPNet // nodes and peers are mutable fields in the struct // and need to be guarded. @@ -86,7 +87,7 @@ type Mesh struct { } // New returns a new Mesh instance. -func New(backend Backend, enc encapsulation.Encapsulator, granularity Granularity, hostname string, port uint32, subnet *net.IPNet, local, cni bool, cniPath, iface string, cleanUpIface bool, createIface bool, mtu uint, resyncPeriod time.Duration, prioritisePrivateAddr bool, logger log.Logger) (*Mesh, error) { +func New(backend Backend, enc encapsulation.Encapsulator, granularity Granularity, hostname string, port uint32, subnet *net.IPNet, local, cni bool, cniPath, iface string, cleanUpIface bool, createIface bool, mtu uint, resyncPeriod time.Duration, prioritisePrivateAddr, iptablesForwardRule bool, logger log.Logger) (*Mesh, error) { if err := os.MkdirAll(kiloPath, 0700); err != nil { return nil, fmt.Errorf("failed to create directory to store configuration: %v", err) } @@ -155,28 +156,29 @@ func New(backend Backend, enc encapsulation.Encapsulator, granularity Granularit return nil, fmt.Errorf("failed to IP tables controller: %v", err) } return &Mesh{ - Backend: backend, - cleanUpIface: cleanUpIface, - cni: cni, - cniPath: cniPath, - enc: enc, - externalIP: externalIP, - granularity: granularity, - hostname: hostname, - internalIP: privateIP, - ipTables: ipTables, - kiloIface: kiloIface, - nodes: make(map[string]*Node), - peers: make(map[string]*Peer), - port: port, - priv: private, - privIface: privIface, - pub: public, - resyncPeriod: resyncPeriod, - local: local, - stop: make(chan struct{}), - subnet: subnet, - table: route.NewTable(), + Backend: backend, + cleanUpIface: cleanUpIface, + cni: cni, + cniPath: cniPath, + enc: enc, + externalIP: externalIP, + granularity: granularity, + hostname: hostname, + internalIP: privateIP, + ipTables: ipTables, + kiloIface: kiloIface, + nodes: make(map[string]*Node), + peers: make(map[string]*Peer), + port: port, + priv: private, + privIface: privIface, + pub: public, + resyncPeriod: resyncPeriod, + iptablesForwardRule: iptablesForwardRule, + local: local, + stop: make(chan struct{}), + subnet: subnet, + table: route.NewTable(), errorCounter: prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "kilo_errors_total", Help: "Number of errors that occurred while administering the mesh.", @@ -498,7 +500,7 @@ func (m *Mesh) applyTopology() { m.errorCounter.WithLabelValues("apply").Inc() return } - ipRules := t.Rules(m.cni) + ipRules := t.Rules(m.cni, m.iptablesForwardRule) // If we are handling local routes, ensure the local // tunnel has an IP address and IPIP traffic is allowed. if m.enc.Strategy() != encapsulation.Never && m.local { diff --git a/pkg/mesh/routes.go b/pkg/mesh/routes.go index 38e75a9..7b03b69 100644 --- a/pkg/mesh/routes.go +++ b/pkg/mesh/routes.go @@ -242,12 +242,16 @@ func encapsulateRoute(route *netlink.Route, encapsulate encapsulation.Strategy, } // Rules returns the iptables rules required by the local node. -func (t *Topology) Rules(cni bool) []iptables.Rule { +func (t *Topology) Rules(cni, iptablesForwardRule bool) []iptables.Rule { var rules []iptables.Rule rules = append(rules, iptables.NewIPv4Chain("nat", "KILO-NAT")) rules = append(rules, iptables.NewIPv6Chain("nat", "KILO-NAT")) if cni { rules = append(rules, iptables.NewRule(iptables.GetProtocol(len(t.subnet.IP)), "nat", "POSTROUTING", "-s", t.subnet.String(), "-m", "comment", "--comment", "Kilo: jump to KILO-NAT chain", "-j", "KILO-NAT")) + if iptablesForwardRule { + rules = append(rules, iptables.NewRule(iptables.GetProtocol(len(t.subnet.IP)), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets from the pod subnet", "-s", t.subnet.String(), "-j", "ACCEPT")) + rules = append(rules, iptables.NewRule(iptables.GetProtocol(len(t.subnet.IP)), "filter", "FORWARD", "-m", "comment", "--comment", "Kilo: forward packets to the pod subnet", "-d", t.subnet.String(), "-j", "ACCEPT")) + } } for _, s := range t.segments { rules = append(rules, iptables.NewRule(iptables.GetProtocol(len(s.wireGuardIP)), "nat", "KILO-NAT", "-d", oneAddressCIDR(s.wireGuardIP).String(), "-m", "comment", "--comment", "Kilo: do not NAT packets destined for WireGuared IPs", "-j", "RETURN"))