mirror of
https://github.com/Swarsel/.dotfiles.git
synced 2026-04-14 21:29:12 +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
|
|
@ -1,176 +1,217 @@
|
|||
{ 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"
|
||||
# ];
|
||||
# }
|
||||
# ];
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
# };
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue