mirror of
https://github.com/Swarsel/.dotfiles.git
synced 2026-04-14 13:19:09 +02:00
feat[server]: support multiple wireguard tunnels
This commit is contained in:
parent
1ffb154031
commit
91157e2cca
16 changed files with 546 additions and 357 deletions
|
|
@ -2801,11 +2801,10 @@ This is my main server that I run at home. It handles most tasks that require bi
|
|||
loader.efi.canTouchEfiVariables = true;
|
||||
};
|
||||
|
||||
# globals.hosts.${config.node.name}.ipv4 = config.repo.secrets.local.ipv4;
|
||||
# globals.networks.home.hosts.${config.node.name} = {
|
||||
# ipv4 = config.repo.secrets.local.home-ipv4;
|
||||
# mac = config.repo.secrets.local.home-mac;
|
||||
# };
|
||||
networking.hosts = {
|
||||
${globals.networks.home-lan.hosts.hintbooth.ipv4} = [ "server.hintbooth.${globals.domains.main}" ];
|
||||
${globals.networks.home-lan.hosts.hintbooth.ipv6} = [ "server.hintbooth.${globals.domains.main}" ];
|
||||
};
|
||||
|
||||
swarselsystems = {
|
||||
info = "ASRock J4105-ITX, 32GB RAM";
|
||||
|
|
@ -2818,9 +2817,15 @@ This is my main server that I run at home. It handles most tasks that require bi
|
|||
isNixos = true;
|
||||
proxyHost = "twothreetunnel";
|
||||
server = {
|
||||
wireguard = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
wireguard.interfaces = {
|
||||
wgProxy = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
};
|
||||
wgHome = {
|
||||
isClient = true;
|
||||
serverName = "hintbooth";
|
||||
};
|
||||
};
|
||||
restic = {
|
||||
bucketName = "SwarselWinters";
|
||||
|
|
@ -3270,6 +3275,16 @@ This is my main server that I run at home. It handles most tasks that require bi
|
|||
rootDisk = "/dev/sda";
|
||||
swapSize = "8G";
|
||||
networkKernelModules = [ "igb" ];
|
||||
server = {
|
||||
wireguard.interfaces = {
|
||||
wgHome = {
|
||||
isServer = true;
|
||||
peers = [
|
||||
"winters"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
} // lib.optionalAttrs (!minimal) {
|
||||
|
|
@ -3282,6 +3297,7 @@ This is my main server that I run at home. It handles most tasks that require bi
|
|||
swarselmodules = {
|
||||
server = {
|
||||
nginx = lib.mkForce false; # we get this from the server profile
|
||||
wireguard = true;
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -3681,9 +3697,11 @@ This machine mainly acts as my proxy server to stand before my local machines.
|
|||
isCloud = true;
|
||||
proxyHost = "twothreetunnel";
|
||||
server = {
|
||||
wireguard = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
wireguard.interfaces = {
|
||||
wgProxy = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
};
|
||||
};
|
||||
restic = {
|
||||
bucketName = "SwarselMoonside";
|
||||
|
|
@ -3912,9 +3930,11 @@ This machine mainly acts as my proxy server to stand before my local machines.
|
|||
isCloud = true;
|
||||
proxyHost = "twothreetunnel";
|
||||
server = {
|
||||
wireguard = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
wireguard.interfaces = {
|
||||
wgProxy = {
|
||||
isClient = true;
|
||||
serverName = "twothreetunnel";
|
||||
};
|
||||
};
|
||||
garage = {
|
||||
data_dir = {
|
||||
|
|
@ -4550,15 +4570,17 @@ This machine mainly acts as my proxy server to stand before my local machines.
|
|||
isLinux = true;
|
||||
isCloud = true;
|
||||
server = {
|
||||
wireguard = {
|
||||
ifName = "wg";
|
||||
isServer = true;
|
||||
peers = [
|
||||
"moonside"
|
||||
"winters"
|
||||
"belchsfactory"
|
||||
"eagleland"
|
||||
];
|
||||
wireguard.interfaces = {
|
||||
wgProxy = {
|
||||
# ifName = "wg";
|
||||
isServer = true;
|
||||
peers = [
|
||||
"moonside"
|
||||
"winters"
|
||||
"belchsfactory"
|
||||
# "eagleland"
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
@ -5993,7 +6015,13 @@ in
|
|||
description = "List of external dns nameservers";
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -9079,177 +9107,219 @@ lspci -k -d 14c3:0616
|
|||
#+begin_src nix-ts :tangle modules/nixos/server/wireguard.nix
|
||||
{ self, lib, pkgs, config, confLib, nodes, globals, ... }:
|
||||
let
|
||||
wgInterface = "wg0";
|
||||
inherit (confLib.gen { name = "wireguard"; port = 52829; user = "systemd-network"; group = "systemd-network"; }) servicePort serviceName serviceUser serviceGroup;
|
||||
inherit (confLib.gen {
|
||||
name = "wireguard";
|
||||
port = 52829;
|
||||
user = "systemd-network";
|
||||
group = "systemd-network";
|
||||
}) servicePort serviceName serviceUser serviceGroup;
|
||||
|
||||
inherit (config.swarselsystems) sopsFile;
|
||||
wgSopsFile = self + "/secrets/repo/wg.yaml";
|
||||
inherit (config.swarselsystems.server.wireguard) peers isClient isServer serverName serverNetConfigPrefix ifName;
|
||||
|
||||
cfg = config.swarselsystems.server.wireguard;
|
||||
inherit (cfg) interfaces;
|
||||
ifaceList = builtins.attrValues interfaces;
|
||||
in
|
||||
{
|
||||
options = {
|
||||
swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} settings";
|
||||
swarselmodules.server.${serviceName} =
|
||||
lib.mkEnableOption "enable ${serviceName} settings";
|
||||
|
||||
swarselsystems.server.wireguard = {
|
||||
isServer = lib.mkEnableOption "set this as a wireguard server";
|
||||
isClient = lib.mkEnableOption "set this as a wireguard client";
|
||||
serverName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
};
|
||||
serverNetConfigPrefix = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${if nodes.${serverName}.config.swarselsystems.isCloud then nodes.${serverName}.config.node.name else "home"}";
|
||||
readOnly = true;
|
||||
};
|
||||
ifName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = wgInterface;
|
||||
};
|
||||
peers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "Wireguard peer config names";
|
||||
interfaces = lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ name, config, ... }: {
|
||||
options = {
|
||||
isServer = lib.mkEnableOption "set this interface as a wireguard server";
|
||||
isClient = lib.mkEnableOption "set this interface as a wireguard client";
|
||||
|
||||
serverName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "";
|
||||
description = "Hostname of the WireGuard server this interface connects to (when isClient = true).";
|
||||
};
|
||||
|
||||
serverNetConfigPrefix = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default =
|
||||
let
|
||||
serverCfg = nodes.${config.serverName}.config;
|
||||
in
|
||||
if serverCfg.swarselsystems.isCloud
|
||||
then serverCfg.node.name
|
||||
else "home";
|
||||
readOnly = true;
|
||||
description = "Prefix used to look up the server network in globals.networks.\"<prefix>-wg\".";
|
||||
};
|
||||
|
||||
ifName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = name;
|
||||
description = "Name of the WireGuard interface.";
|
||||
};
|
||||
|
||||
peers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = [ ];
|
||||
description = "WireGuard peer config names (clients when this host is server, or additional peers).";
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "WireGuard interfaces defined on this host.";
|
||||
};
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
wireguard-tools
|
||||
];
|
||||
|
||||
sops = {
|
||||
secrets = {
|
||||
wireguard-private-key = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0600"; };
|
||||
# create this secret only if this is a simple client with only one peer (the server)
|
||||
"wireguard-${serverName}-${config.node.name}-presharedKey" = lib.mkIf (isClient && peers == [ ]) { sopsFile = wgSopsFile; owner = serviceUser; group = serviceGroup; mode = "0600"; };
|
||||
}
|
||||
# create these secrets only if this host has multiple peers
|
||||
// lib.optionalAttrs (peers != [ ]) (builtins.listToAttrs (map
|
||||
(clientName: {
|
||||
name = "wireguard-${config.node.name}-${clientName}-presharedKey";
|
||||
value = { sopsFile = wgSopsFile; owner = serviceUser; group = serviceGroup; mode = "0600"; };
|
||||
})
|
||||
peers));
|
||||
};
|
||||
sops.secrets =
|
||||
lib.mkMerge (
|
||||
[
|
||||
{
|
||||
# shared host private key
|
||||
wireguard-private-key = {
|
||||
inherit sopsFile;
|
||||
owner = serviceUser;
|
||||
group = serviceGroup;
|
||||
mode = "0600";
|
||||
};
|
||||
}
|
||||
] ++ (map
|
||||
(i:
|
||||
let
|
||||
simpleClientSecrets =
|
||||
lib.optionalAttrs (i.isClient && i.peers == [ ]) {
|
||||
"wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey" = {
|
||||
sopsFile = wgSopsFile;
|
||||
owner = serviceUser;
|
||||
group = serviceGroup;
|
||||
mode = "0600";
|
||||
};
|
||||
};
|
||||
|
||||
multiPeerSecrets =
|
||||
lib.optionalAttrs (i.peers != [ ]) (builtins.listToAttrs (map
|
||||
(clientName: {
|
||||
name = "wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey";
|
||||
value = {
|
||||
sopsFile = wgSopsFile;
|
||||
owner = serviceUser;
|
||||
group = serviceGroup;
|
||||
mode = "0600";
|
||||
};
|
||||
})
|
||||
i.peers));
|
||||
in
|
||||
simpleClientSecrets // multiPeerSecrets
|
||||
)
|
||||
ifaceList)
|
||||
);
|
||||
|
||||
networking = {
|
||||
firewall.checkReversePath = lib.mkIf isClient "loose";
|
||||
firewall.allowedUDPPorts = [ servicePort ];
|
||||
# nat = lib.mkIf (config.swarselsystems.isCloud && isServer) {
|
||||
# enable = true;
|
||||
# enableIPv6 = true;
|
||||
# externalInterface = "enp0s6";
|
||||
# internalInterfaces = [ ifName ];
|
||||
# };
|
||||
# interfaces.${ifName}.mtu = 1280; # the default (1420) is not enough!
|
||||
firewall.checkReversePath =
|
||||
lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose";
|
||||
|
||||
firewall.allowedUDPPorts =
|
||||
lib.mkIf (lib.any (i: i.isServer) ifaceList) [ servicePort ];
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
|
||||
networks."50-${ifName}" = {
|
||||
matchConfig.Name = ifName;
|
||||
linkConfig = {
|
||||
MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???)
|
||||
};
|
||||
|
||||
# networkConfig = lib.mkIf (config.swarselsystems.isCloud && isServer) {
|
||||
# IPv4Forwarding = true;
|
||||
# IPv6Forwarding = true;
|
||||
# };
|
||||
|
||||
address = if isServer then [
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-wg".hosts.${config.node.name}.cidrv4
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-wg".hosts.${config.node.name}.cidrv6
|
||||
] else [
|
||||
globals.networks."${serverNetConfigPrefix}-wg".hosts.${config.node.name}.cidrv4
|
||||
globals.networks."${serverNetConfigPrefix}-wg".hosts.${config.node.name}.cidrv6
|
||||
];
|
||||
};
|
||||
|
||||
netdevs."50-${ifName}" = {
|
||||
netdevConfig = {
|
||||
Kind = "wireguard";
|
||||
Name = ifName;
|
||||
};
|
||||
|
||||
wireguardConfig = {
|
||||
ListenPort = lib.mkIf isServer servicePort;
|
||||
|
||||
# ensure file is readable by `systemd-network` user
|
||||
PrivateKeyFile = config.sops.secrets.wireguard-private-key.path;
|
||||
|
||||
# To automatically create routes for everything in AllowedIPs,
|
||||
# add RouteTable=main
|
||||
RouteTable = lib.mkIf isClient "main";
|
||||
|
||||
# FirewallMark marks all packets send and received by wg0
|
||||
# with the number 42, which can be used to define policy rules on these packets.
|
||||
# FirewallMark = 42;
|
||||
};
|
||||
wireguardPeers = lib.optionals isClient [
|
||||
networks = lib.mkMerge (map
|
||||
(i:
|
||||
let
|
||||
inherit (i) ifName;
|
||||
in
|
||||
{
|
||||
PublicKey = builtins.readFile "${self}/secrets/public/wg/${serverName}.pub";
|
||||
PresharedKeyFile = config.sops.secrets."wireguard-${serverName}-${config.node.name}-presharedKey".path;
|
||||
Endpoint = "server.${serverName}.${globals.domains.main}:${toString servicePort}";
|
||||
# Access to the whole network is routed through our entry node.
|
||||
PersistentKeepalive = 25;
|
||||
AllowedIPs =
|
||||
let
|
||||
wgNetwork = globals.networks."${serverNetConfigPrefix}-wg";
|
||||
in
|
||||
(lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4)
|
||||
++ (lib.optional (wgNetwork.cidrv6 != null) wgNetwork.cidrv6);
|
||||
}
|
||||
] ++ lib.optionals isServer (map
|
||||
(clientName: {
|
||||
PublicKey = builtins.readFile "${self}/secrets/public/wg/${clientName}.pub";
|
||||
PresharedKeyFile = config.sops.secrets."wireguard-${config.node.name}-${clientName}-presharedKey".path;
|
||||
# PersistentKeepalive = 25;
|
||||
AllowedIPs =
|
||||
let
|
||||
clientInWgNetwork = globals.networks."${config.swarselsystems.server.netConfigPrefix}-wg".hosts.${clientName};
|
||||
in
|
||||
(lib.optional (clientInWgNetwork.ipv4 != null) (lib.net.cidr.make 32 clientInWgNetwork.ipv4))
|
||||
++ (lib.optional (clientInWgNetwork.ipv6 != null) (lib.net.cidr.make 128 clientInWgNetwork.ipv6));
|
||||
"50-${ifName}" = {
|
||||
matchConfig.Name = ifName;
|
||||
linkConfig = {
|
||||
MTUBytes = 1408; # TODO: figure out where we lose those 12 bits (8 from pppoe maybe + ???)
|
||||
};
|
||||
|
||||
address =
|
||||
if i.isServer then [
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
|
||||
] else [
|
||||
globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
|
||||
globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
|
||||
];
|
||||
};
|
||||
})
|
||||
peers);
|
||||
ifaceList);
|
||||
|
||||
};
|
||||
netdevs = lib.mkMerge (map
|
||||
(i:
|
||||
let
|
||||
inherit (i) ifName;
|
||||
in
|
||||
{
|
||||
"50-${ifName}" = {
|
||||
netdevConfig = {
|
||||
Kind = "wireguard";
|
||||
Name = ifName;
|
||||
};
|
||||
|
||||
wireguardConfig = {
|
||||
ListenPort = lib.mkIf i.isServer servicePort;
|
||||
|
||||
PrivateKeyFile = config.sops.secrets.wireguard-private-key.path;
|
||||
|
||||
RouteTable = lib.mkIf i.isClient "main";
|
||||
};
|
||||
|
||||
wireguardPeers =
|
||||
lib.optionals i.isClient [
|
||||
{
|
||||
PublicKey =
|
||||
builtins.readFile "${self}/secrets/public/wg/${i.serverName}.pub";
|
||||
|
||||
PresharedKeyFile =
|
||||
config.sops.secrets."wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey".path;
|
||||
|
||||
Endpoint =
|
||||
"server.${i.serverName}.${globals.domains.main}:${toString servicePort}";
|
||||
|
||||
PersistentKeepalive = 25;
|
||||
|
||||
AllowedIPs =
|
||||
let
|
||||
wgNetwork = globals.networks."${i.serverNetConfigPrefix}-${i.ifName}";
|
||||
in
|
||||
(lib.optional (wgNetwork.cidrv4 != null) wgNetwork.cidrv4)
|
||||
++ (lib.optional (wgNetwork.cidrv6 != null) wgNetwork.cidrv6);
|
||||
}
|
||||
]
|
||||
++ lib.optionals i.isServer (map
|
||||
(clientName: {
|
||||
PublicKey =
|
||||
builtins.readFile "${self}/secrets/public/wg/${clientName}.pub";
|
||||
|
||||
PresharedKeyFile =
|
||||
config.sops.secrets."wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey".path;
|
||||
|
||||
AllowedIPs =
|
||||
let
|
||||
clientInWgNetwork =
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-${i.ifName}".hosts.${clientName};
|
||||
in
|
||||
(lib.optional (clientInWgNetwork.ipv4 != null)
|
||||
(lib.net.cidr.make 32 clientInWgNetwork.ipv4))
|
||||
++ (lib.optional (clientInWgNetwork.ipv6 != null)
|
||||
(lib.net.cidr.make 128 clientInWgNetwork.ipv6));
|
||||
})
|
||||
i.peers);
|
||||
};
|
||||
})
|
||||
ifaceList);
|
||||
};
|
||||
|
||||
# networking = {
|
||||
# wireguard = {
|
||||
# enable = true;
|
||||
# interfaces = {
|
||||
# wg1 = {
|
||||
# privateKeyFile = config.sops.secrets.wireguard-private-key.path;
|
||||
# ips = [ "192.168.178.201/24" ];
|
||||
# peers = [
|
||||
# {
|
||||
# publicKey = "PmeFInoEJcKx+7Kva4dNnjOEnJ8lbudSf1cbdo/tzgw=";
|
||||
# presharedKeyFile = config.sops.secrets.wireguard-home-preshared-key.path;
|
||||
# name = "moonside";
|
||||
# persistentKeepalive = 25;
|
||||
# # endpoint = "${config.repo.secrets.common.ipv4}:51820";
|
||||
# endpoint = "${config.repo.secrets.common.wireguardEndpoint}";
|
||||
# # allowedIPs = [
|
||||
# # "192.168.3.0/24"
|
||||
# # "192.168.1.0/24"
|
||||
# # ];
|
||||
# allowedIPs = [
|
||||
# "192.168.178.0/24"
|
||||
# ];
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
#+end_src
|
||||
|
|
@ -15332,7 +15402,7 @@ Some standard options that should be set vor every microvm guest. We set the def
|
|||
Hold standard options for nix-topology per config
|
||||
|
||||
#+begin_src nix-ts :tangle modules/nixos/optional/nix-topology-self.nix
|
||||
{ config, globals, ... }:
|
||||
{ lib, config, globals, ... }:
|
||||
{
|
||||
topology.self = {
|
||||
icon = lib.mkIf config.swarselsystems.isCloud "devices.cloud-server";
|
||||
|
|
@ -22436,9 +22506,9 @@ In short, the options defined here are passed to the modules systems using =_mod
|
|||
config.swarselsystems.proxyHost != config.node.name
|
||||
then
|
||||
if
|
||||
config.swarselsystems.server.wireguard.isClient
|
||||
config.swarselsystems.server.wireguard.interfaces.wgProxy.isClient
|
||||
then
|
||||
globals.networks."${config.swarselsystems.server.wireguard.serverNetConfigPrefix}-wg".hosts.${config.node.name}.ipv4
|
||||
globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgProxy.serverNetConfigPrefix}-wgProxy".hosts.${config.node.name}.ipv4
|
||||
else
|
||||
globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue