mirror of
https://github.com/Swarsel/.dotfiles.git
synced 2026-04-14 21:29:12 +02:00
feat[server]: add firezone
This commit is contained in:
parent
2d766e8246
commit
2ff914d49d
69 changed files with 2415 additions and 1132 deletions
|
|
@ -20,52 +20,81 @@ in
|
|||
lib.mkEnableOption "enable ${serviceName} settings";
|
||||
|
||||
swarselsystems.server.wireguard = {
|
||||
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";
|
||||
interfaces =
|
||||
let
|
||||
topConfig = config;
|
||||
in
|
||||
lib.mkOption {
|
||||
type = lib.types.attrsOf (lib.types.submodule ({ config, name, ... }: {
|
||||
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).";
|
||||
};
|
||||
serverName = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = if config.isServer then topConfig.node.name else "";
|
||||
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\".";
|
||||
};
|
||||
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.";
|
||||
};
|
||||
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).";
|
||||
port = lib.mkOption {
|
||||
type = lib.types.int;
|
||||
default = servicePort;
|
||||
description = "Port of the WireGuard interface.";
|
||||
};
|
||||
|
||||
peers = lib.mkOption {
|
||||
type = lib.types.listOf lib.types.str;
|
||||
default = lib.attrNames (lib.filterAttrs (name: _: name != topConfig.node.name) globals.networks."${config.serverNetConfigPrefix}-${config.ifName}".hosts);
|
||||
description = "WireGuard peer config names of this wireguardinterface.";
|
||||
};
|
||||
};
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "WireGuard interfaces defined on this host.";
|
||||
};
|
||||
}));
|
||||
default = { };
|
||||
description = "WireGuard interfaces defined on this host.";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf config.swarselmodules.server.${serviceName} {
|
||||
|
||||
assertions = lib.concatLists (
|
||||
lib.flip lib.mapAttrsToList interfaces (
|
||||
ifName: ifCfg:
|
||||
let
|
||||
assertionPrefix = "While evaluating the wireguard network ${ifName}:";
|
||||
in
|
||||
[
|
||||
{
|
||||
assertion = ifCfg.isServer || (ifCfg.isClient && ifCfg.serverName != "");
|
||||
message = "${assertionPrefix}: This node must either be a server for the wireguard network or a client with serverName set.";
|
||||
}
|
||||
{
|
||||
assertion = lib.stringLength ifName < 16;
|
||||
message = "${assertionPrefix}: The specified linkName '${ifName}' is too long (must be max 15 characters).";
|
||||
}
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
environment.systemPackages = with pkgs; [
|
||||
wireguard-tools
|
||||
];
|
||||
|
|
@ -74,7 +103,6 @@ in
|
|||
lib.mkMerge (
|
||||
[
|
||||
{
|
||||
# shared host private key
|
||||
wireguard-private-key = {
|
||||
inherit sopsFile;
|
||||
owner = serviceUser;
|
||||
|
|
@ -85,8 +113,8 @@ in
|
|||
] ++ (map
|
||||
(i:
|
||||
let
|
||||
simpleClientSecrets =
|
||||
lib.optionalAttrs (i.isClient && i.peers == [ ]) {
|
||||
clientSecrets =
|
||||
lib.optionalAttrs i.isClient {
|
||||
"wireguard-${i.serverName}-${config.node.name}-${i.ifName}-presharedKey" = {
|
||||
sopsFile = wgSopsFile;
|
||||
owner = serviceUser;
|
||||
|
|
@ -95,8 +123,8 @@ in
|
|||
};
|
||||
};
|
||||
|
||||
multiPeerSecrets =
|
||||
lib.optionalAttrs (i.peers != [ ]) (builtins.listToAttrs (map
|
||||
serverSecrets =
|
||||
lib.optionalAttrs i.isServer (builtins.listToAttrs (map
|
||||
(clientName: {
|
||||
name = "wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey";
|
||||
value = {
|
||||
|
|
@ -108,17 +136,72 @@ in
|
|||
})
|
||||
i.peers));
|
||||
in
|
||||
simpleClientSecrets // multiPeerSecrets
|
||||
clientSecrets // serverSecrets
|
||||
)
|
||||
ifaceList)
|
||||
);
|
||||
|
||||
networking = {
|
||||
firewall.checkReversePath =
|
||||
lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose";
|
||||
networking.firewall = {
|
||||
checkReversePath = lib.mkIf (lib.any (i: i.isClient) ifaceList) "loose";
|
||||
allowedUDPPorts = lib.mkMerge (
|
||||
lib.flip lib.mapAttrsToList interfaces (
|
||||
_: ifCfg:
|
||||
lib.optional ifCfg.isServer ifCfg.port
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
firewall.allowedUDPPorts =
|
||||
lib.mkIf (lib.any (i: i.isServer) ifaceList) [ servicePort ];
|
||||
networking.nftables.firewall = {
|
||||
zones = lib.mkMerge
|
||||
(
|
||||
lib.flip lib.mapAttrsToList interfaces (
|
||||
ifName: ifCfg:
|
||||
{
|
||||
${ifName}.interfaces = [ ifName ];
|
||||
}
|
||||
// lib.listToAttrs (map
|
||||
(peer:
|
||||
let
|
||||
peerNet = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}".hosts.${peer};
|
||||
in
|
||||
lib.nameValuePair "${ifName}-node-${peer}" {
|
||||
parent = ifName;
|
||||
ipv4Addresses = lib.optional (peerNet.ipv4 != null) peerNet.ipv4;
|
||||
ipv6Addresses = lib.optional (peerNet.ipv6 != null) peerNet.ipv6;
|
||||
}
|
||||
)
|
||||
ifCfg.peers)
|
||||
)
|
||||
);
|
||||
rules = lib.mkMerge (
|
||||
lib.flip lib.mapAttrsToList interfaces (
|
||||
ifName: ifCfg:
|
||||
let
|
||||
inherit (config.networking.nftables.firewall) localZoneName;
|
||||
netCfg = globals.networks."${ifCfg.serverNetConfigPrefix}-${ifName}";
|
||||
in
|
||||
{
|
||||
"${ifName}-to-${localZoneName}" = {
|
||||
inherit (netCfg.firewallRuleForAll) allowedTCPPorts allowedUDPPorts allowedTCPPortRanges allowedUDPPortRanges;
|
||||
from = [ ifName ];
|
||||
to = [ localZoneName ];
|
||||
ignoreEmptyRule = true;
|
||||
};
|
||||
}
|
||||
// lib.listToAttrs (map
|
||||
(peer:
|
||||
lib.nameValuePair "${ifName}-node-${peer}-to-${localZoneName}" (
|
||||
lib.mkIf (netCfg.hosts.${config.node.name}.firewallRuleForNode ? ${peer}) {
|
||||
inherit (netCfg.hosts.${config.node.name}.firewallRuleForNode.${peer}) allowedTCPPorts allowedTCPPortRanges allowedUDPPorts allowedUDPPortRanges;
|
||||
from = [ "${ifName}-node-${peer}" ];
|
||||
to = [ localZoneName ];
|
||||
ignoreEmptyRule = true;
|
||||
}
|
||||
)
|
||||
)
|
||||
ifCfg.peers)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
|
|
@ -136,14 +219,10 @@ in
|
|||
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
|
||||
];
|
||||
address = [
|
||||
globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv4
|
||||
globals.networks."${i.serverNetConfigPrefix}-${ifName}".hosts.${config.node.name}.cidrv6
|
||||
];
|
||||
};
|
||||
})
|
||||
ifaceList);
|
||||
|
|
@ -196,12 +275,12 @@ in
|
|||
builtins.readFile "${self}/secrets/public/wg/${clientName}.pub";
|
||||
|
||||
PresharedKeyFile =
|
||||
config.sops.secrets."wireguard-${config.node.name}-${clientName}-${i.ifName}-presharedKey".path;
|
||||
config.sops.secrets."wireguard-${i.serverName}-${clientName}-${i.ifName}-presharedKey".path;
|
||||
|
||||
AllowedIPs =
|
||||
let
|
||||
clientInWgNetwork =
|
||||
globals.networks."${config.swarselsystems.server.netConfigPrefix}-${i.ifName}".hosts.${clientName};
|
||||
globals.networks."${i.serverNetConfigPrefix}-${i.ifName}".hosts.${clientName};
|
||||
in
|
||||
(lib.optional (clientInWgNetwork.ipv4 != null)
|
||||
(lib.net.cidr.make 32 clientInWgNetwork.ipv4))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue