einfra logoDocumentation
Kubernetes

Wireguard

Run a Pod with WireGuard Interface

This guide explains how to securely attach a WireGuard interface to a Pod using a Kubernetes Secret for key management.

Why Use WireGuard?
WireGuard creates encrypted tunnels between the Pod and a node outside the Kubernetes cluster, enabling secure communication across networks (e.g., cross-cluster connectivity, bypassing NAT, or encrypting traffic).

Step 1: Create a Secret for WireGuard Private Key

Create the file config.json with the following content:

{
  "address": "1.2.3.4/32",
  "privateKey": "AAev16ZVYhmCQliIYKXMje1zObRp6TmET0KiUx7MJXc=",
  "peers": [
    {
      "endpoint": "5.6.7.8:51820",
      "publicKey": "+gXCSfkib2xFMeebKXIYBVZxV/Vh2mbi1dJeHCCjQmg=",
      "allowedIPs": [
        "9.10.11.12/24"
      ],
      "persistentKeepalive": "25s"
    }
  ]
}

Replace all three IP adresses and both keys with real content.

Current limitations

  • Even if the endpoint supports multiple client addresses, current implementation in Kubernetes supports only a single address.
  • The name of the file must be strictly config.json.
  • The address and allowedIPs must not be from the same network. E.g., "address": "10.1.2.3/32" and "allowedIPs": ["10.1.2.0/24"] will not work.

Create the secret:

kubectl create secret generic wireguard-config --from-file ./config.json

Step 2: Create a Pod with WireGuard Interface

Deploy a Pod with the WireGuard interface, it will be net1 (attached via the k8s.v1.cni.cncf.io/networks annotation).

apiVersion: v1
kind: Pod
metadata:
  name: wireguard-pod
  annotations:
    k8s.v1.cni.cncf.io/networks: default/wgnet    # Attach WireGuard interface `net1`
    wgcni.schu.io/configsecret: wireguard-config  # references the created secret
spec:
  securityContext:
    runAsNonRoot: true
    seccompProfile:
      type: RuntimeDefault
  containers:
    - name: main
      image: your-application-image
      command:
      - as-needed
      securityContext:
        runAsUser: 1000
        allowPrivilegeEscalation: false
        capabilities:
          drop: [ALL]

Verification

  1. Check if net1 interface exists (requires ip command in the Pod):

    kubectl exec wireguard-pod -n [namespace] -- ip a show net1

    Expect output showing the WireGuard interface with an IP.

  2. Test connectivity (requires ping command in the Pod):

    kubectl exec wireguard-pod -n [namespace] -- ping <PEER_IP>

    Replace <PEER_IP> with the peer’s WireGuard IP from the config.json.


Caveats

The WG CNI currently supports assigning only a single IP address, which means it can configure either an IPv4 or an IPv6 address—but not both simultaneously. This poses a limitation when targeting dual-stack endpoints such as:

$ host kubas-pub.cloud.trusted.e-infra.cz
kubas-pub.cloud.trusted.e-infra.cz has address 10.16.48.119
kubas-pub.cloud.trusted.e-infra.cz has IPv6 address 2001:718:801:42bf:8:4:0:1

In such scenarios, a Pod using WireGuard may experience intermittent connectivity. This happens because DNS resolution may return either an IPv4 or IPv6 address, and only one of these will work in the WireGuard configuration. As a result, the connection may alternate between working and timing out, depending on which address family is used.

Recommendation

To avoid this issue, we recommend configuring the Pod for single-stack networking. Choose either IPv4 or IPv6 and consistently use that stack throughout:

  • Set both the address and allowedIPs fields to match the chosen IP family in the WireGUard configuration.
  • Ensure that the connection to the remote WireGuard peer uses the same stack.
  • Align the stack used for communication with the address family specified in the WireGuard configuration.

Example: IPv6-Only Reverse Proxy with NGINX

Below is an example configuration for NGINX where the reverse proxy connects to an IPv6 address directly, bypassing DNS resolution. The Host header is explicitly set to ensure proper virtual host routing:

location / {
    proxy_pass https://[2001:718:801:42bf:8:4:0:1];
    proxy_buffering off;
    proxy_set_header Host vllm.cloud.trusted.e-infra.cz;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
}

Multiple Pods

By design, a single WireGuard configuration cannot be used simultaneously across multiple Pods or devices. Each Pod requires a unique WireGuard configuration that must not be shared or reused elsewhere.

This limitation arises because WireGuard effectively establishes a Layer 2-like network among peers. If multiple clients use the same IP address within this network, it leads to IP address collisions, resulting in unstable behavior.

Symptom

A common symptom of this issue is connectivity flapping in regular intervals—typically every 10 seconds. For example, the connection may be stable for 10 seconds, then drop for the next 10 seconds, repeating in a loop.

Last updated on

publicity banner

On this page

einfra banner