When using WireGuard in Kubernetes with hostNetwork, a successful handshake but no internet access usually stems from the pod’s IP not being included in the server’s allowed peers list or missing kernel-level packet forwarding rules. This guide resolves connectivity by ensuring the client’s pod IP is correctly configured and that the node’s firewall permits forwarded traffic.
Understanding the Host Network Constraint
In this specific scenario, you are running WireGuard clients as pods withhostNetwork: true. This configuration means the pod shares the network namespace of the underlying Kubernetes node. Consequently, the pod uses the node’s primary IP address for all outbound traffic, rather than an internal ClusterIP or PodCIDR. This simplifies networking but introduces specific constraints regarding how the WireGuard tunnel interacts with the host’s routing table and firewall rules.
The most common point of failure occurs because the WireGuard server only accepts packets from specific peer IPs. If your Kubernetes node has multiple interfaces or if the pod’s effective IP differs from what the server expects, the handshake succeeds (because the UDP port is open) but data packets are silently dropped. You must ensure that the IP address the WireGuard client on the node uses to reach the server is explicitly listed in the AllowedIPs field on the server side.
For more details on managing WireGuard clients in mixed environments, see WireGuard Client Works Perfectly with Docker and Kubernetes.
Verifying Server-Side AllowedIPs Configuration
The first step is to inspect the WireGuard server configuration file, typically located at/etc/wireguard/wg0.conf. Look for the [Peer] section corresponding to your Kubernetes node. The critical directive here is AllowedIPs.
If you have set AllowedIPs = 0.0.0.0/0, the server will accept all traffic from that peer. However, if you have restricted it to a specific subnet, such as AllowedIPs = 192.168.1.50/32, the server will drop any traffic coming from a different source IP. Since your pod is using hostNetwork, the source IP is the node’s IP.
Ensure that the AllowedIPs matches the exact public IP address of the Kubernetes node where the pod is running. If the node has a dynamic IP or changes addresses, consider using a broader CIDR range if security policies allow, or implement a mechanism to update the server config dynamically. A mismatch here results in the "Handshake OK" symptom because the initial UDP negotiation works, but subsequent data packets are rejected by the kernel module.
Enabling Kernel Packet Forwarding
Even with correct peer configurations, Linux kernels disable IP forwarding by default for security reasons. When a pod on a node sends traffic through the WireGuard interface, that traffic must be routed out through the node’s physical interface to the internet. If forwarding is disabled, the packets are dropped internally before they leave the node. Check the current status of IP forwarding on the Kubernetes node by running:sysctl net.ipv4.ip_forward
If the output is net.ipv4.ip_forward = 0, you must enable it. Add or modify the following line in /etc/sysctl.conf:
net.ipv4.ip_forward = 1
Then apply the changes immediately without rebooting:
sysctl -p
Verify that the change took effect by running the sysctl command again; it should now return 1. This setting persists across reboots due to the configuration file update. Without this, the node acts as a dead end for any tunneled traffic attempting to exit to the public internet.
Configuring Firewall Rules for Forwarded Traffic
Many Linux distributions useufw (Uncomplicated Firewall) or iptables directly. If you are using ufw, it often blocks forwarded traffic by default. You need to explicitly allow forwarding between the WireGuard interface (usually wg0) and the physical interface (often eth0 or ens5).
If you are using ufw, edit /etc/default/ufw and change:
DEFAULT_FORWARD_POLICY="DROP"
to:
DEFAULT_FORWARD_POLICY="ACCEPT"
After changing this, restart the firewall service:
systemctl restart ufw
If you are managing rules manually with iptables, ensure there is a rule in the FORWARD chain that accepts traffic from the wg0 interface. You can check existing rules with:
iptables -L FORWARD -v -n
If no such rule exists, you may need to add one. However, note that some cloud providers manage their own firewall rules at the hypervisor level. Ensure that the security group or firewall associated with the Kubernetes node allows inbound and outbound UDP traffic on the WireGuard port (default 51820) and allows ICMP if you rely on ping for diagnostics.
DNS Resolution within the Tunnel
A successful handshake does not guarantee DNS resolution. Even if you can ping external IPs (e.g.,ping 8.8.8.8), you might fail when trying to access domains like google.com. In a hostNetwork setup, the pod inherits the node’s DNS settings.
Ensure that the WireGuard client configuration includes a valid DNS server. In the client’s /etc/wireguard/wg0.conf, add the DNS directive:
[Interface]
PrivateKey = ...
Address = ...
DNS = 1.1.1.1, 8.8.8.8
This tells the local WireGuard daemon to push these DNS servers into the route table for traffic going through the tunnel. If you are using systemd-networkd or NetworkManager, verify that they are respecting the DNS attribute passed by the WireGuard interface. Failure to configure this results in the ability to connect to IPs but inability to resolve hostnames, which mimics a lack of internet access.
Troubleshooting Steps
If you have completed the above steps and still face issues, perform these diagnostic checks:- Check Route Table: Run
ip routeon the node. Verify that traffic destined for the remote network is routed via thewg0interface. - Inspect Logs: Check
dmesg | grep wireguardfor errors during packet processing. Look for messages indicating dropped packets or invalid checksums. - Test Internally: Ping the WireGuard server’s internal IP from the node to confirm the tunnel layer is functional.
- Verify NAT: If the server performs NAT, ensure the client’s IP is translated correctly. This is less common in pure peer-to-peer setups but relevant if the server is behind a NAT gateway.
Frequently Asked Questions
Why does the handshake succeed but pings fail?
The handshake succeeds because the initial UDP packets reach the server and are accepted. Pings fail because subsequent data packets are either dropped by the server’sAllowedIPs filter, blocked by the node’s firewall, or lost due to disabled IP forwarding.
Can I use a private IP for the WireGuard client in Kubernetes?
No, when usinghostNetwork, the client presents the node’s public or private IP depending on its network position. Using a private IP in the AllowedIPs field will fail if the server sees the public IP, so match the actual source IP observed by the server.
Does enabling IP forwarding affect other containers?
Enabling IP forwarding allows the node to route traffic between interfaces. While generally safe, ensure your firewall rules do not inadvertently expose internal cluster traffic to the public internet through the WireGuard interface.What if my node has multiple network interfaces?
You must specify which interface the WireGuard traffic should egress through. Useiptables MASQUERADE rules or policy routing to ensure traffic from wg0 exits via the correct upstream interface, especially if the node has both management and data planes.
How do I debug DNS issues in the tunnel?
Usenslookup inside the pod. If it fails, check the DNS setting in the WireGuard config and verify that the DNS server is reachable. Also, ensure that the node’s resolver is not overriding the tunnel’s DNS settings.