WireGuard tunnel with netns

This example configures a WireGuard tunnel for a branch office using netns namespace isolation:

  • configures an uplink interface in a dedicated outside netns namespace
  • create a WireGuard interface wg0 in the root netns namespace while the encrypted traffic originates from the outside netns namespace
  • configure routing in both netns namespaces
interfaces:
  # inside interface
  eth0:
    addresses:
    - 192.0.2.129/25
    link:
      state: up
      kind: physical
    identify:
      parent_dev_name: '0000:05:00.0'
      parent_dev_bus_name: pci
  # wireguard vpn
  wg0:
    addresses:
    - 192.0.2.1/25
    link:
      state: up
      kind: wireguard
      bind_netns: outside
    wireguard:
      private_key: !include /etc/wireguard/peer_A.key
      peers:
        oef+ZSlMWWCF1bEHPaw04TmjPyHKcz2b81njwIQI0xA=:
          endpoint: 198.51.100.2:4711
          allowedips:
          - 0.0.0.0/0

routing:
  routes:
    # default route via VPN
    - to: 0.0.0.0/0
      dev: wg0

namespaces:
  outside:
    interfaces:
      # outside interface
      eth0:
        addresses:
        - 198.51.100.2/31
        link:
          state: up
          kind: physical
        identify:
          parent_dev_name: '0000:06:00.0'
          parent_dev_bus_name: pci
    routing:
      routes:
        # default route for encrypted VPN traffic
        - to: 0.0.0.0/0
          via: 198.51.100.1
{ config, ... }:
{
  sops.secrets."wireguard/private-key/wg0" = { };

  networking.ifstate = {
    enable = true;
    settings = {

      interfaces = {
        # inside interface
        eth0 = {
          addresses = [
            "192.0.2.129/25"
          ];
          link = {
            state = "up";
            kind = "physical";
          };
          identify = {
            parent_dev_name = "0000:05:00.0";
            parent_dev_bus_name = "pci";
          };
        };
        # wireguard vpn
        wg0 = {
          addresses = [
            "192.0.2.1/25"
          ];
          link = {
            state = "up";
            kind = "wireguard";
            bind_netns = "outside";
          };
          wireguard = {
            private_key = "!include ${config.sops.secrets."wireguard/private-key/wg0".path}";
            peers = {
              "oef+ZSlMWWCF1bEHPaw04TmjPyHKcz2b81njwIQI0xA=" = {
                endpoint = "198.51.100.2:4711";
                allowedips = [
                  "0.0.0.0/0"
                ];
              };
            };
          };
        };
      };

      routing.routes = [
        # default route via VPN
        {
          to = "0.0.0.0/0";
          dev = "wg0";
        }
      ];

      namespaces.outside = {
        # outside interface
        interfaces.eth0 = {
          addresses = [
            "198.51.100.2/31"
          ];
          link = {
            state = "up";
            kind = "physical";
          };
          identify = {
            parent_dev_name = "0000:06:00.0";
            parent_dev_bus_name = "pci";
          };
        };
        routing.routes = [
          # default route for encrypted VPN traffic
          {
            to = "0.0.0.0/0";
            via = "198.51.100.1";
          }
        ];
      };
    };
  };
}