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"))