add wg module

This commit is contained in:
Grigory Shipunov 2025-01-04 21:07:54 +00:00 committed by Grisha Shipunov
parent b28314ca95
commit 3572c93df4
7 changed files with 234 additions and 2 deletions

View file

@ -67,6 +67,7 @@
./hosts/toaster/secure-boot.nix ./hosts/toaster/secure-boot.nix
./modules/chromium.nix ./modules/chromium.nix
./modules/mail ./modules/mail
./modules/wg
]; ];
}; };
cloud = nixpkgs-stable.lib.nixosSystem { cloud = nixpkgs-stable.lib.nixosSystem {
@ -80,6 +81,7 @@
./modules/basic-tools ./modules/basic-tools
./modules/server ./modules/server
./modules/binary-caches.nix ./modules/binary-caches.nix
./modules/wg
]; ];
}; };
minime = nixpkgs-stable.lib.nixosSystem { minime = nixpkgs-stable.lib.nixosSystem {
@ -92,6 +94,7 @@
./modules/basic-tools ./modules/basic-tools
./modules/server ./modules/server
./modules/binary-caches.nix ./modules/binary-caches.nix
./modules/wg
]; ];
}; };
}; };

View file

@ -1,7 +1,7 @@
{ ... }: { { ... }: {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
./networking.nix # generated at runtime by nixos-infect ./networking.nix
]; ];
boot.tmp.cleanOnBoot = true; boot.tmp.cleanOnBoot = true;

View file

@ -63,7 +63,8 @@
"${endpoint}/32" "${endpoint}/32"
# "10.0.0.0/8" # "10.0.0.0/8"
"10.13.37.0/24" "10.13.37.0/24"
"10.66.66.0/24" # 0xa-mgmt
"10.89.87.0/24"
# "172.16.0.0/12" # "172.16.0.0/12"
"172.16.0.0/12" "172.16.0.0/12"
# "182.168.0.0/16" # "182.168.0.0/16"

9
modules/wg/default.nix Normal file
View file

@ -0,0 +1,9 @@
{ ... }: {
imports = [
# module
./module.nix
./options.nix
# networks
./mgmt.nix
];
}

35
modules/wg/mgmt.nix Normal file
View file

@ -0,0 +1,35 @@
{ config, ... }:
{
oxalab.wg = [
{
networkName = "0xa-mgmt";
CIDRs = [ "10.89.87.0/24" "fd31:185d:722e::/48" ];
hosts = {
"cloud" = {
address = [ "10.89.87.1/24" "fd31:185d:722e::1/48" ];
publicKey = "zKSaw+SXzWgi/T7ByXHqPk1XNXXapoQYB8UPMTRmhm0=";
privateKeyFile = config.sops.secrets."wg/0xa-mgmt".path;
endpoint = {
enable = true;
endpoint = "188.245.196.27";
port = 51820;
publicIface = "enp1s0";
};
};
"toaster" = {
address = [ "10.89.87.100/24" "fd31:185d:722e::100/48" ];
publicKey = "H+WeYIBdX7ZHwkgm4BGnF0HF0JULkxyNMcvCviHhmks=";
privateKeyFile = config.sops.secrets."wg/0xa-mgmt".path;
};
"minime" = {
address = [ "10.89.87.10/24" "fd31:185d:722e::10/48" ];
publicKey = "zN2Dr/ZGMh1Ftparszp22Qnbz2ISJU12iDVatebOHUE=";
privateKeyFile = config.sops.secrets."wg/0xa-mgmt".path;
};
};
}
];
}

105
modules/wg/module.nix Normal file
View file

@ -0,0 +1,105 @@
{ lib
, config
, self
, registry
, ... }: {
config =
let
currenthost = config.networking.hostName;
wg = config.oxalab.wg;
# get all the networks we participate in
networks = builtins.filter (net: builtins.hasAttr "${currenthost}" net.hosts) wg;
# create wg networks
network-attrset = map (net: {
name = "30-wg-${net.networkName}";
value = {
matchConfig.Name = "wg-${net.networkName}";
networkConfig = {
Address = net.hosts.${currenthost}.address;
IPv6AcceptRA = false; # for now static IPv6
} // (if net.hosts.${currenthost}.endpoint.enable then {IPv4Forwarding=true; IPv6Forwarding=true; } else {});
};
}) networks;
systemd-networks = builtins.listToAttrs network-attrset;
# get all the networks we client in
net-client = builtins.filter (net: !net.hosts.${currenthost}.endpoint.enable) networks;
# get all the networks we are endpoint of
net-endpoint = builtins.filter (net: net.hosts.${currenthost}.endpoint.enable) networks;
# wg netdevs
# client
netdev-client-list = map (net: {
name = "30-wg-${net.networkName}";
value = {
netdevConfig = {
Kind = "wireguard";
Name = "wg-${net.networkName}";
};
wireguardConfig.PrivateKeyFile = net.hosts.${currenthost}.privateKeyFile;
# for client this is only endpoint for now
wireguardPeers =
let
endpoint = lib.attrsets.filterAttrs (_k: v: v.endpoint.enable) net.hosts;
wg-peers-attrs = lib.attrsets.mapAttrs (_k: v:
{
PersistentKeepalive = 29;
PublicKey = v.publicKey;
Endpoint = "${v.endpoint.endpoint}:${toString v.endpoint.port}";
AllowedIPs = net.CIDRs;
}) endpoint;
wg-peers = lib.attrsets.attrValues wg-peers-attrs;
in
wg-peers;
};
}) net-client;
netdev-client = builtins.listToAttrs netdev-client-list;
maskip = (net: hostattrs:
if hostattrs.endpoint.enable then hostattrs.address else map (baseaddr:
if lib.strings.hasInfix "." baseaddr then "${baseaddr}/32" else "${baseaddr}/128"
) (map (addr: builtins.elemAt (lib.strings.splitString "/" addr) 0) hostattrs.address));
# endpoint
# TODO: this requires bit more logic for allowedIPs if we have more then
# 2 endpoints e.g. for routing client -> endpoint1 -> endpoint2 ->
# client2
netdev-endpoint-list = map (net: {
name = "30-wg-${net.networkName}";
value = {
netdevConfig = {
Kind = "wireguard";
Name = "wg-${net.networkName}";
};
wireguardConfig.PrivateKeyFile = net.hosts.${currenthost}.privateKeyFile;
wireguardConfig.ListenPort = net.hosts.${currenthost}.endpoint.port;
wireguardPeers =
let
peers = lib.attrsets.filterAttrs (k: _v: k != currenthost) net.hosts;
wg-peers-attrs = lib.attrsets.mapAttrs (_k: v:
{
PersistentKeepalive = 29;
PublicKey = v.publicKey;
# only route to /32 or /128, i.e. single client
AllowedIPs = maskip net v;
} // (if !isNull v.endpoint.endpoint then { Endpoint = "${v.endpoint.endpoint}:${toString v.endpoint.port}"; } else {})) peers;
wg-peers = lib.attrsets.attrValues wg-peers-attrs;
in
wg-peers;
};
}) net-endpoint;
netdev-endpoint = builtins.listToAttrs netdev-endpoint-list;
in
{
# make sure that the networkd and wg are enabled
networking.wireguard.enable = true;
systemd.network.enable = true;
systemd.network.networks = systemd-networks;
systemd.network.netdevs = netdev-client // netdev-endpoint;
};
}

79
modules/wg/options.nix Normal file
View file

@ -0,0 +1,79 @@
{ lib
, ...}:
{
options.oxalab.wg = with lib;
lib.mkOption {
default = [];
type = types.listOf (types.submodule {
options = {
# general network stuff
networkName = mkOption {
type = types.nullOr types.str;
default = null;
};
CIDRs = mkOption {
type = types.nullOr (types.listOf types.str);
default = null;
};
hosts = mkOption {
default = {};
type = types.attrsOf (types.submodule {
options = {
enable = mkOption {
type = types.bool;
default = true;
};
address = mkOption {
type = types.listOf types.str;
default = null;
};
publicKey = mkOption {
type = types.str;
default = null;
};
privateKeyFile = mkOption {
type = types.path;
default = null;
};
endpoint.enable = mkOption {
type = types.bool;
default = false;
};
endpoint.endpoint = mkOption {
type = types.nullOr types.str;
default = null;
};
endpoint.port = mkOption {
type = types.nullOr types.int;
default = null;
};
endpoint.publicIface = mkOption {
type = types.nullOr types.str;
default = null;
};
endpoint.extraPeers = mkOption {
default = [];
type = types.listOf (types.submodule {
options = {
address = mkOption {
type = types.listOf types.str;
default = [];
};
publicKey = mkOption {
type = types.nullOr types.str;
default = null;
};
};
});
};
};
});
};
};
});
};
}