Context
Two problems in internal/iptables/iptables.go, both of which become traffic leaks once gluetun shares the pod's network namespace.
1. Rules are applied with a full flush. ApplyRules runs iptables-restore without --noflush (:14-21), which replaces the entire *nat and *filter tables in the namespace on every peer sync. gluetun installs its killswitch into those same tables in that same namespace — so every peer add/remove wipes it. The result is intermittent leaks correlated with peer churn.
2. The masquerade rule hardcodes eth0. -A POSTROUTING -s %s -o eth0 -j MASQUERADE at :124, and the v6 equivalent at :155. With gluetun in play, peer traffic must masquerade out the tunnel interface — otherwise it egresses via the pod's normal interface and silently bypasses the VPN entirely, which looks like it is working.
3. Non-matching rules are not a killswitch. Simply binding the rule to the tunnel interface is not enough: if that interface is gone the rule stops matching and packets fall through, where the node's own SNAT (kube-proxy or Cilium masquerading) may pick them up and NAT them out with the node IP.
Scope
- Apply rules with
--noflush into chains the operator creates and owns, so gluetun's rules survive.
- Derive the egress interface instead of hardcoding it.
- Add a terminal DROP so peer traffic that does not leave via the tunnel is dropped rather than falling through.
Acceptance criteria
Blocks #12 (route peer egress through the gluetun tunnel). See docs/ROADMAP.md § Phase 0.3.
Context
Two problems in
internal/iptables/iptables.go, both of which become traffic leaks once gluetun shares the pod's network namespace.1. Rules are applied with a full flush.
ApplyRulesrunsiptables-restorewithout--noflush(:14-21), which replaces the entire*natand*filtertables in the namespace on every peer sync. gluetun installs its killswitch into those same tables in that same namespace — so every peer add/remove wipes it. The result is intermittent leaks correlated with peer churn.2. The masquerade rule hardcodes
eth0.-A POSTROUTING -s %s -o eth0 -j MASQUERADEat:124, and the v6 equivalent at:155. With gluetun in play, peer traffic must masquerade out the tunnel interface — otherwise it egresses via the pod's normal interface and silently bypasses the VPN entirely, which looks like it is working.3. Non-matching rules are not a killswitch. Simply binding the rule to the tunnel interface is not enough: if that interface is gone the rule stops matching and packets fall through, where the node's own SNAT (kube-proxy or Cilium masquerading) may pick them up and NAT them out with the node IP.
Scope
--noflushinto chains the operator creates and owns, so gluetun's rules survive.Acceptance criteria
Blocks #12 (route peer egress through the gluetun tunnel). See
docs/ROADMAP.md§ Phase 0.3.