2022-04-19 20:03:58 +00:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
2022-04-20 08:50:42 +00:00
|
|
|
keysPath = "/var/lib/wesher/secrets";
|
2022-04-19 20:03:58 +00:00
|
|
|
cfg = config.services.wesher;
|
|
|
|
in {
|
|
|
|
options = with types; {
|
|
|
|
services.wesher = {
|
|
|
|
enable = mkEnableOption "wesher wireguard overlay mesh network manager";
|
|
|
|
|
|
|
|
package = mkOption {
|
|
|
|
type = package;
|
|
|
|
default = pkgs.wesher;
|
|
|
|
defaultText = literalExpression "pkgs.wesher";
|
|
|
|
description = "Wesher package to use.";
|
|
|
|
};
|
|
|
|
|
|
|
|
clusterKey = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
default = null;
|
2022-04-20 08:50:42 +00:00
|
|
|
description = "shared key for cluster membership to use on first initialization, if no key was previously used by Wesher. Must be 32 bytes base64 encoded; will be generated if not provided. Setting this parameter value will not overwrite an existing cluster key; to do so please delete ${keysPath}";
|
2022-04-19 20:03:58 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
bindAddr = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
default = null;
|
|
|
|
description = "IP address to bind to for cluster membership (cannot be used with --bind-iface)";
|
|
|
|
};
|
|
|
|
|
|
|
|
bindIface = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
default = null;
|
|
|
|
description = "Interface to bind to for cluster membership (cannot be used with --bind-addr)";
|
|
|
|
};
|
|
|
|
|
|
|
|
join = mkOption {
|
|
|
|
type = listOf str;
|
|
|
|
default = [];
|
|
|
|
description = "list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members";
|
|
|
|
};
|
|
|
|
|
|
|
|
clusterPort = mkOption {
|
|
|
|
type = port;
|
|
|
|
default = 7946;
|
|
|
|
description = "port used for membership gossip traffic (both TCP and UDP); must be the same accross cluster";
|
|
|
|
};
|
|
|
|
|
|
|
|
wireguardPort = mkOption {
|
|
|
|
type = port;
|
|
|
|
default = 51820;
|
|
|
|
description = "port used for wireguard traffic (UDP); must be the same accross cluster";
|
|
|
|
};
|
|
|
|
|
|
|
|
overlayNet = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "10.0.0.0/8";
|
|
|
|
description = "the network in which to allocate addresses for the overlay mesh network (CIDR format); smaller networks increase the chance of IP collision";
|
|
|
|
};
|
|
|
|
|
|
|
|
interface = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "wgoverlay";
|
|
|
|
description = "name of the wireguard interface to create and manage";
|
|
|
|
};
|
|
|
|
|
|
|
|
logLevel = mkOption {
|
|
|
|
type = str;
|
|
|
|
default = "warn";
|
|
|
|
description = "set the verbosity (one of debug/info/warn/error)";
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable (let binWesher = cfg.package + "/bin/wesher";
|
|
|
|
in {
|
2022-04-20 08:50:42 +00:00
|
|
|
system.activationScripts.wesher = if (cfg.clusterKey != null) then ''
|
|
|
|
if [ ! -e ${keysPath} ]
|
|
|
|
then
|
|
|
|
mkdir --mode=700 -p ${builtins.dirOf keysPath}
|
|
|
|
echo "WESHER_CLUSTER_KEY=${cfg.clusterKey}" > ${keysPath}
|
|
|
|
fi
|
|
|
|
'' else ''
|
|
|
|
if [ ! -e ${keysPath} ]
|
|
|
|
then
|
|
|
|
mkdir --mode=700 -p ${builtins.dirOf keysPath}
|
|
|
|
echo "WESHER_CLUSTER_KEY=$(head -c 32 /dev/urandom | base64)" > ${keysPath}
|
|
|
|
fi
|
|
|
|
'';
|
|
|
|
|
2022-04-19 20:03:58 +00:00
|
|
|
systemd.services.wesher = {
|
|
|
|
description = "wesher wireguard overlay mesh network manager";
|
|
|
|
bindsTo = [ "network-online.target" ];
|
|
|
|
after = [ "network-online.target" ];
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
|
|
|
|
environment = {
|
|
|
|
WESHER_JOIN = builtins.concatStringsSep "," cfg.join;
|
|
|
|
WESHER_CLUSTER_PORT = builtins.toString cfg.clusterPort;
|
|
|
|
WESHER_WIREGUARD_PORT = builtins.toString cfg.wireguardPort;
|
|
|
|
WESHER_OVERLAY_NET = cfg.overlayNet;
|
|
|
|
WESHER_INTERFACE = cfg.interface;
|
|
|
|
WESHER_LOG_LEVEL = cfg.logLevel;
|
|
|
|
WESHER_NO_ETC_HOSTS = "true";
|
|
|
|
}
|
|
|
|
// (if (cfg.bindAddr != null) then { WESHER_BIND_ADDR = cfg.bindAddr; } else {})
|
|
|
|
// (if (cfg.bindIface != null) then { WESHER_BIND_IFACE = cfg.bindIface; } else {})
|
|
|
|
;
|
|
|
|
|
|
|
|
serviceConfig = {
|
|
|
|
ExecStart = "${binWesher}";
|
|
|
|
Restart = "always";
|
|
|
|
|
2022-04-20 08:50:42 +00:00
|
|
|
EnvironmentFile = keysPath;
|
|
|
|
|
2022-04-19 20:03:58 +00:00
|
|
|
User = "wesher";
|
|
|
|
DynamicUser = true;
|
|
|
|
StateDirectory = "wesher";
|
|
|
|
|
|
|
|
AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
|
|
|
CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
|
|
|
|
MemoryDenyWriteExecute = true;
|
|
|
|
ProtectControlGroups = true;
|
|
|
|
ProtectKernelModules = true;
|
|
|
|
ProtectKernelTunables = true;
|
|
|
|
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
|
|
|
|
RestrictNamespaces = true;
|
|
|
|
RestrictRealtime = true;
|
|
|
|
SystemCallArchitectures = "native";
|
|
|
|
SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @resources";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
networking.firewall.allowedUDPPorts = mkIf cfg.enable [ cfg.clusterPort cfg.wireguardPort ];
|
|
|
|
networking.firewall.allowedTCPPorts = mkIf cfg.enable [ cfg.clusterPort ];
|
|
|
|
});
|
|
|
|
}
|