Skip to content

Commit 525f662

Browse files
authored
Install iptables rules to allow WireGuard packets (#7030)
This change is to actively configure the iptables rules (filter table) to allow input and output UDP traffic to the WireGuard port when WireGuard is used as the encryption mode. This can avoid traffic issues if the Node is configured with an iptables default DROP policy. Fixes #7009 Signed-off-by: Wenying Dong <[email protected]>
1 parent b7e0c38 commit 525f662

File tree

6 files changed

+205
-42
lines changed

6 files changed

+205
-42
lines changed

cmd/antrea-agent/agent.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,9 @@ func run(o *Options) error {
244244
multicastEnabled,
245245
o.config.SNATFullyRandomPorts,
246246
*o.config.Egress.SNATFullyRandomPorts,
247-
serviceCIDRProvider)
247+
serviceCIDRProvider,
248+
wireguardConfig.Port,
249+
)
248250
if err != nil {
249251
return fmt.Errorf("error creating route client: %v", err)
250252
}

docs/network-requirements.md

+15-12
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,24 @@
33
Antrea has a few network requirements to get started, ensure that your hosts and
44
firewalls allow the necessary traffic based on your configuration.
55

6-
| Configuration | Host(s) | Protocols/Ports | Other |
7-
|------------------------------------------------|---------------------------------------|--------------------------------------------|------------------------------|
8-
| Antrea with VXLAN enabled | All | UDP 4789 | |
9-
| Antrea with Geneve enabled | All | UDP 6081 | |
10-
| Antrea with STT enabled | All | TCP 7471 | |
11-
| Antrea with GRE enabled | All | IP Protocol ID 47 | No support for IPv6 clusters |
12-
| Antrea with IPsec ESP enabled | All | IP protocol ID 50 and 51, UDP 500 and 4500 | |
13-
| Antrea with WireGuard enabled | All | UDP 51820 | |
14-
| Antrea Multi-cluster with WireGuard encryption | Multi-cluster Gateway Node | UDP 51821 | |
15-
| Antrea with feature BGPPolicy enabled | Selected by user-provided BGPPolicies | TCP 179<sup>[1]</sup> | |
16-
| All | Kube-apiserver host | TCP 443 or 6443<sup>[2]</sup> | |
17-
| All | All | TCP 10349, 10350, 10351, UDP 10351 | |
6+
| Configuration | Host(s) | Protocols/Ports | Configurable | Other |
7+
|------------------------------------------------|---------------------------------------|--------------------------------------------|--------------|------------------------------|
8+
| Antrea with VXLAN enabled | All | UDP 4789 | Yes | |
9+
| Antrea with Geneve enabled | All | UDP 6081 | Yes | |
10+
| Antrea with STT enabled | All | TCP 7471 | Yes | |
11+
| Antrea with GRE enabled | All | IP Protocol ID 47 | No | No support for IPv6 clusters |
12+
| Antrea with IPsec ESP enabled | All | IP protocol ID 50 and 51, UDP 500 and 4500 | No | |
13+
| Antrea with WireGuard enabled | All | UDP 51820<sup>[3]</sup> | Yes | |
14+
| Antrea Multi-cluster with WireGuard encryption | Multi-cluster Gateway Node | UDP 51821 | Yes | |
15+
| Antrea with feature BGPPolicy enabled | Selected by user-provided BGPPolicies | TCP 179<sup>[1]</sup> | Yes | |
16+
| All | Kube-apiserver host | TCP 443 or 6443<sup>[2]</sup> | Yes | |
17+
| All | All | TCP 10349, 10350, 10351, UDP 10351 | Yes | |
1818

1919
[1] _The default value is 179, but a user created BGPPolicy can assign a different
2020
port number._
2121

2222
[2] _The value is passed to kube-apiserver `--secure-port` flag. You can find the port
2323
number from the output of `kubectl get svc kubernetes -o yaml`._
24+
25+
[3] _Antrea automatically adds the firewall rules to allow the WireGuard packets
26+
(starting from v2.4), so the manual configuration on the host is not needed._

pkg/agent/route/route_linux.go

+69-22
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/containernetworking/plugins/pkg/ip"
2929
"github.com/vishvananda/netlink"
3030
"golang.org/x/sys/unix"
31+
"k8s.io/apimachinery/pkg/util/intstr"
3132
"k8s.io/apimachinery/pkg/util/sets"
3233
"k8s.io/apimachinery/pkg/util/wait"
3334
"k8s.io/klog/v2"
@@ -158,10 +159,17 @@ type Client struct {
158159
nodeNetworkPolicyIPTablesIPv4 sync.Map
159160
// nodeNetworkPolicyIPTablesIPv6 caches all existing IPv6 iptables chains and rules for NodeNetworkPolicy.
160161
nodeNetworkPolicyIPTablesIPv6 sync.Map
162+
// wireguardIPTablesIPv4 caches all existing IPv4 iptables chains and rules for WireGuard.
163+
wireguardIPTablesIPv4 sync.Map
164+
// wireguardIPTablesIPv6 caches all existing IPv6 iptables chains and rules for WireGuard.
165+
wireguardIPTablesIPv6 sync.Map
161166
// deterministic represents whether to write iptables chains and rules for NodeNetworkPolicy deterministically when
162167
// syncIPTables is called. Enabling it may carry a performance impact. It's disabled by default and should only be
163168
// used in testing.
164169
deterministic bool
170+
// wireguardPort is the port used for the WireGuard UDP tunnels. When WireGuard is enabled (used as the encryption
171+
// mode), we add iptables rules to the filter table to accept input and output UDP traffic destined to this port.
172+
wireguardPort int
165173
}
166174

167175
// NewClient returns a route client.
@@ -173,7 +181,8 @@ func NewClient(networkConfig *config.NetworkConfig,
173181
multicastEnabled bool,
174182
nodeSNATRandomFully bool,
175183
egressSNATRandomFully bool,
176-
serviceCIDRProvider servicecidr.Interface) (*Client, error) {
184+
serviceCIDRProvider servicecidr.Interface,
185+
wireguardPort int) (*Client, error) {
177186
return &Client{
178187
networkConfig: networkConfig,
179188
noSNAT: noSNAT,
@@ -194,6 +203,7 @@ func NewClient(networkConfig *config.NetworkConfig,
194203
antreaExternalIPIPSet: {},
195204
antreaExternalIPIP6Set: {},
196205
},
206+
wireguardPort: wireguardPort,
197207
}, nil
198208
}
199209

@@ -265,7 +275,9 @@ func (c *Client) Initialize(nodeConfig *config.NodeConfig, done func()) error {
265275
if c.nodeNetworkPolicyEnabled {
266276
c.initNodeNetworkPolicy()
267277
}
268-
278+
if c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard {
279+
c.initWireguard()
280+
}
269281
return nil
270282
}
271283

@@ -675,7 +687,7 @@ func (c *Client) syncIPTables() error {
675687
if c.proxyAll {
676688
jumpRules = append(jumpRules, jumpRule{iptables.NATTable, iptables.OutputChain, antreaOutputChain, "Antrea: jump to Antrea output rules", true})
677689
}
678-
if c.nodeNetworkPolicyEnabled {
690+
if c.nodeNetworkPolicyEnabled || c.networkConfig.TrafficEncryptionMode == config.TrafficEncryptionModeWireGuard {
679691
jumpRules = append(jumpRules, jumpRule{iptables.FilterTable, iptables.InputChain, antreaInputChain, "Antrea: jump to Antrea input rules", false})
680692
jumpRules = append(jumpRules, jumpRule{iptables.FilterTable, iptables.OutputChain, antreaOutputChain, "Antrea: jump to Antrea output rules", false})
681693
}
@@ -711,20 +723,24 @@ func (c *Client) syncIPTables() error {
711723
return true
712724
})
713725

714-
nodeNetworkPolicyIPTablesIPv4 := map[string][]string{}
715-
nodeNetworkPolicyIPTablesIPv6 := map[string][]string{}
716-
c.nodeNetworkPolicyIPTablesIPv4.Range(func(key, value interface{}) bool {
717-
chain := key.(string)
718-
rules := value.([]string)
719-
nodeNetworkPolicyIPTablesIPv4[chain] = rules
720-
return true
721-
})
722-
c.nodeNetworkPolicyIPTablesIPv6.Range(func(key, value interface{}) bool {
723-
chain := key.(string)
724-
rules := value.([]string)
725-
nodeNetworkPolicyIPTablesIPv6[chain] = rules
726-
return true
727-
})
726+
addFilterRulesToChain := func(iptablesRulesByChain map[string][]string, m *sync.Map) {
727+
m.Range(func(key, value interface{}) bool {
728+
chain := key.(string)
729+
rules := value.([]string)
730+
iptablesRulesByChain[chain] = append(iptablesRulesByChain[chain], rules...)
731+
return true
732+
})
733+
}
734+
735+
iptablesFilterRulesByChainV4 := make(map[string][]string)
736+
// Install the static rules (WireGuard for now) before the dynamic rules (e.g., NodeNetworkPolicy)
737+
// for performance reasons.
738+
addFilterRulesToChain(iptablesFilterRulesByChainV4, &c.wireguardIPTablesIPv4)
739+
addFilterRulesToChain(iptablesFilterRulesByChainV4, &c.nodeNetworkPolicyIPTablesIPv4)
740+
741+
iptablesFilterRulesByChainV6 := make(map[string][]string)
742+
addFilterRulesToChain(iptablesFilterRulesByChainV6, &c.wireguardIPTablesIPv6)
743+
addFilterRulesToChain(iptablesFilterRulesByChainV6, &c.nodeNetworkPolicyIPTablesIPv6)
728744

729745
// Use iptables-restore to configure IPv4 settings.
730746
if c.networkConfig.IPv4Enabled {
@@ -737,7 +753,7 @@ func (c *Client) syncIPTables() error {
737753
config.VirtualNodePortDNATIPv4,
738754
config.VirtualServiceIPv4,
739755
snatMarkToIPv4,
740-
nodeNetworkPolicyIPTablesIPv4,
756+
iptablesFilterRulesByChainV4,
741757
false)
742758

743759
// Setting --noflush to keep the previous contents (i.e. non antrea managed chains) of the tables.
@@ -757,7 +773,7 @@ func (c *Client) syncIPTables() error {
757773
config.VirtualNodePortDNATIPv6,
758774
config.VirtualServiceIPv6,
759775
snatMarkToIPv6,
760-
nodeNetworkPolicyIPTablesIPv6,
776+
iptablesFilterRulesByChainV6,
761777
true)
762778
// Setting --noflush to keep the previous contents (i.e. non antrea managed chains) of the tables.
763779
if err := c.iptables.Restore(iptablesData.String(), false, true); err != nil {
@@ -777,7 +793,7 @@ func (c *Client) restoreIptablesData(podCIDR *net.IPNet,
777793
nodePortDNATVirtualIP,
778794
serviceVirtualIP net.IP,
779795
snatMarkToIP map[uint32]net.IP,
780-
nodeNetWorkPolicyIPTables map[string][]string,
796+
iptablesFiltersRuleByChain map[string][]string,
781797
isIPv6 bool) *bytes.Buffer {
782798
// Create required rules in the antrea chains.
783799
// Use iptables-restore as it flushes the involved chains and creates the desired rules
@@ -897,7 +913,7 @@ func (c *Client) restoreIptablesData(podCIDR *net.IPNet,
897913
writeLine(iptablesData, iptables.MakeChainLine(antreaForwardChain))
898914

899915
var nodeNetworkPolicyIPTablesChains []string
900-
for chain := range nodeNetWorkPolicyIPTables {
916+
for chain := range iptablesFiltersRuleByChain {
901917
nodeNetworkPolicyIPTablesChains = append(nodeNetworkPolicyIPTablesChains, chain)
902918
}
903919
if c.deterministic {
@@ -937,7 +953,7 @@ func (c *Client) restoreIptablesData(podCIDR *net.IPNet,
937953
}...)
938954
}
939955
for _, chain := range nodeNetworkPolicyIPTablesChains {
940-
for _, rule := range nodeNetWorkPolicyIPTables[chain] {
956+
for _, rule := range iptablesFiltersRuleByChain[chain] {
941957
writeLine(iptablesData, rule)
942958
}
943959
}
@@ -1198,6 +1214,37 @@ func (c *Client) initNodeNetworkPolicy() {
11981214
}
11991215
}
12001216

1217+
func (c *Client) initWireguard() {
1218+
wireguardPort := intstr.FromInt(c.wireguardPort)
1219+
antreaInputChainRules := []string{
1220+
iptables.NewRuleBuilder(antreaInputChain).
1221+
SetComment("Antrea: allow WireGuard input packets").
1222+
MatchTransProtocol(iptables.ProtocolUDP).
1223+
MatchPortDst(&wireguardPort, nil).
1224+
SetTarget(iptables.AcceptTarget).
1225+
Done().
1226+
GetRule(),
1227+
}
1228+
antreaOutputChainRules := []string{
1229+
iptables.NewRuleBuilder(antreaOutputChain).
1230+
SetComment("Antrea: allow WireGuard output packets").
1231+
MatchTransProtocol(iptables.ProtocolUDP).
1232+
MatchPortDst(&wireguardPort, nil).
1233+
SetTarget(iptables.AcceptTarget).
1234+
Done().
1235+
GetRule(),
1236+
}
1237+
1238+
if c.networkConfig.IPv6Enabled {
1239+
c.wireguardIPTablesIPv6.Store(antreaInputChain, antreaInputChainRules)
1240+
c.wireguardIPTablesIPv6.Store(antreaOutputChain, antreaOutputChainRules)
1241+
}
1242+
if c.networkConfig.IPv4Enabled {
1243+
c.wireguardIPTablesIPv4.Store(antreaInputChain, antreaInputChainRules)
1244+
c.wireguardIPTablesIPv4.Store(antreaOutputChain, antreaOutputChainRules)
1245+
}
1246+
}
1247+
12011248
// Reconcile removes orphaned podCIDRs from ipset and removes routes to orphaned podCIDRs
12021249
// based on the desired podCIDRs.
12031250
func (c *Client) Reconcile(podCIDRs []string) error {

0 commit comments

Comments
 (0)