pkg/mesh/routes.go: add flag for generic ACCEPT in FORWARD chain (#244)

* 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 <leonloechner@gmx.de>

* Update cmd/kg/main.go

Co-authored-by: Lucas Servén Marín <lserven@gmail.com>

* Update cmd/kg/main.go

Co-authored-by: Lucas Servén Marín <lserven@gmail.com>
This commit is contained in:
leonnicolas 2021-09-30 15:39:06 +03:00 committed by GitHub
parent e2745b453f
commit 9b14c227a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 56 additions and 48 deletions

View File

@ -111,6 +111,7 @@ var (
port uint port uint
subnet string subnet string
resyncPeriod time.Duration resyncPeriod time.Duration
iptablesForwardRule bool
prioritisePrivateAddr bool prioritisePrivateAddr bool
printVersion 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().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().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().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, "iptables-forward-rules", false, "Add default accept rules to the FORWARD chain in iptables. Warning: this may break firewalls with a deny all policy and is potentially insecure!")
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().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)) 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) 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 { if err != nil {
return fmt.Errorf("failed to create Kilo mesh: %v", err) return fmt.Errorf("failed to create Kilo mesh: %v", err)
} }

View File

@ -49,27 +49,28 @@ const (
// Mesh is able to create Kilo network meshes. // Mesh is able to create Kilo network meshes.
type Mesh struct { type Mesh struct {
Backend Backend
cleanUpIface bool cleanUpIface bool
cni bool cni bool
cniPath string cniPath string
enc encapsulation.Encapsulator enc encapsulation.Encapsulator
externalIP *net.IPNet externalIP *net.IPNet
granularity Granularity granularity Granularity
hostname string hostname string
internalIP *net.IPNet internalIP *net.IPNet
ipTables *iptables.Controller ipTables *iptables.Controller
kiloIface int kiloIface int
key []byte key []byte
local bool local bool
port uint32 port uint32
priv []byte priv []byte
privIface int privIface int
pub []byte pub []byte
resyncPeriod time.Duration resyncPeriod time.Duration
stop chan struct{} iptablesForwardRule bool
subnet *net.IPNet stop chan struct{}
table *route.Table subnet *net.IPNet
wireGuardIP *net.IPNet table *route.Table
wireGuardIP *net.IPNet
// nodes and peers are mutable fields in the struct // nodes and peers are mutable fields in the struct
// and need to be guarded. // and need to be guarded.
@ -86,7 +87,7 @@ type Mesh struct {
} }
// New returns a new Mesh instance. // 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 { if err := os.MkdirAll(kiloPath, 0700); err != nil {
return nil, fmt.Errorf("failed to create directory to store configuration: %v", err) 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 nil, fmt.Errorf("failed to IP tables controller: %v", err)
} }
return &Mesh{ return &Mesh{
Backend: backend, Backend: backend,
cleanUpIface: cleanUpIface, cleanUpIface: cleanUpIface,
cni: cni, cni: cni,
cniPath: cniPath, cniPath: cniPath,
enc: enc, enc: enc,
externalIP: externalIP, externalIP: externalIP,
granularity: granularity, granularity: granularity,
hostname: hostname, hostname: hostname,
internalIP: privateIP, internalIP: privateIP,
ipTables: ipTables, ipTables: ipTables,
kiloIface: kiloIface, kiloIface: kiloIface,
nodes: make(map[string]*Node), nodes: make(map[string]*Node),
peers: make(map[string]*Peer), peers: make(map[string]*Peer),
port: port, port: port,
priv: private, priv: private,
privIface: privIface, privIface: privIface,
pub: public, pub: public,
resyncPeriod: resyncPeriod, resyncPeriod: resyncPeriod,
local: local, iptablesForwardRule: iptablesForwardRule,
stop: make(chan struct{}), local: local,
subnet: subnet, stop: make(chan struct{}),
table: route.NewTable(), subnet: subnet,
table: route.NewTable(),
errorCounter: prometheus.NewCounterVec(prometheus.CounterOpts{ errorCounter: prometheus.NewCounterVec(prometheus.CounterOpts{
Name: "kilo_errors_total", Name: "kilo_errors_total",
Help: "Number of errors that occurred while administering the mesh.", Help: "Number of errors that occurred while administering the mesh.",
@ -498,7 +500,7 @@ func (m *Mesh) applyTopology() {
m.errorCounter.WithLabelValues("apply").Inc() m.errorCounter.WithLabelValues("apply").Inc()
return return
} }
ipRules := t.Rules(m.cni) ipRules := t.Rules(m.cni, m.iptablesForwardRule)
// If we are handling local routes, ensure the local // If we are handling local routes, ensure the local
// tunnel has an IP address and IPIP traffic is allowed. // tunnel has an IP address and IPIP traffic is allowed.
if m.enc.Strategy() != encapsulation.Never && m.local { if m.enc.Strategy() != encapsulation.Never && m.local {

View File

@ -242,12 +242,16 @@ func encapsulateRoute(route *netlink.Route, encapsulate encapsulation.Strategy,
} }
// Rules returns the iptables rules required by the local node. // 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 var rules []iptables.Rule
rules = append(rules, iptables.NewIPv4Chain("nat", "KILO-NAT")) rules = append(rules, iptables.NewIPv4Chain("nat", "KILO-NAT"))
rules = append(rules, iptables.NewIPv6Chain("nat", "KILO-NAT")) rules = append(rules, iptables.NewIPv6Chain("nat", "KILO-NAT"))
if cni { 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")) 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 { 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")) 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"))