2023-03-29 15:04:14 +02:00
|
|
|
{
|
|
|
|
lib,
|
|
|
|
config,
|
|
|
|
pkgs,
|
|
|
|
...
|
|
|
|
}:
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.services.wgautomesh;
|
|
|
|
settingsFormat = pkgs.formats.toml { };
|
|
|
|
configFile =
|
|
|
|
# Have to remove nulls manually as TOML generator will not just skip key
|
|
|
|
# if value is null
|
|
|
|
settingsFormat.generate "wgautomesh-config.toml" (
|
|
|
|
filterAttrs (k: v: v != null) (
|
|
|
|
mapAttrs (k: v: if k == "peers" then map (e: filterAttrs (k: v: v != null) e) v else v) cfg.settings
|
|
|
|
)
|
|
|
|
);
|
|
|
|
runtimeConfigFile =
|
|
|
|
if cfg.enableGossipEncryption then "/run/wgautomesh/wgautomesh.toml" else configFile;
|
|
|
|
in
|
|
|
|
{
|
|
|
|
options.services.wgautomesh = {
|
|
|
|
enable = mkEnableOption "the wgautomesh daemon";
|
|
|
|
logLevel = mkOption {
|
|
|
|
type = types.enum [
|
|
|
|
"trace"
|
|
|
|
"debug"
|
|
|
|
"info"
|
|
|
|
"warn"
|
|
|
|
"error"
|
|
|
|
];
|
|
|
|
default = "info";
|
|
|
|
description = "wgautomesh log level.";
|
|
|
|
};
|
|
|
|
enableGossipEncryption = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = "Enable encryption of gossip traffic.";
|
|
|
|
};
|
|
|
|
gossipSecretFile = mkOption {
|
|
|
|
type = types.path;
|
|
|
|
description = ''
|
2023-06-13 10:01:12 +02:00
|
|
|
File containing the gossip secret, a shared secret key to use for gossip
|
|
|
|
encryption. Required if `enableGossipEncryption` is set. This file
|
|
|
|
may contain any arbitrary-length utf8 string. To generate a new gossip
|
|
|
|
secret, use a command such as `openssl rand -base64 32`.
|
2023-03-29 15:04:14 +02:00
|
|
|
'';
|
|
|
|
};
|
|
|
|
enablePersistence = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = "Enable persistence of Wireguard peer info between restarts.";
|
|
|
|
};
|
|
|
|
openFirewall = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = "Automatically open gossip port in firewall (recommended).";
|
|
|
|
};
|
|
|
|
settings = mkOption {
|
|
|
|
type = types.submodule {
|
|
|
|
freeformType = settingsFormat.type;
|
|
|
|
options = {
|
|
|
|
|
|
|
|
interface = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
|
|
|
Wireguard interface to manage (it is NOT created by wgautomesh, you
|
|
|
|
should use another NixOS option to create it such as
|
|
|
|
`networking.wireguard.interfaces.wg0 = {...};`).
|
|
|
|
'';
|
|
|
|
example = "wg0";
|
|
|
|
};
|
|
|
|
gossip_port = mkOption {
|
|
|
|
type = types.port;
|
|
|
|
description = ''
|
|
|
|
wgautomesh gossip port, this MUST be the same number on all nodes in
|
|
|
|
the wgautomesh network.
|
|
|
|
'';
|
|
|
|
default = 1666;
|
|
|
|
};
|
|
|
|
lan_discovery = mkOption {
|
|
|
|
type = types.bool;
|
|
|
|
default = true;
|
|
|
|
description = "Enable discovery of peers on the same LAN using UDP broadcast.";
|
|
|
|
};
|
|
|
|
upnp_forward_external_port = mkOption {
|
|
|
|
type = types.nullOr types.port;
|
|
|
|
default = null;
|
|
|
|
description = ''
|
|
|
|
Public port number to try to redirect to this machine's Wireguard
|
|
|
|
daemon using UPnP IGD.
|
|
|
|
'';
|
|
|
|
};
|
|
|
|
peers = mkOption {
|
|
|
|
type = types.listOf (
|
|
|
|
types.submodule {
|
|
|
|
options = {
|
|
|
|
pubkey = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = "Wireguard public key of this peer.";
|
|
|
|
};
|
|
|
|
address = mkOption {
|
|
|
|
type = types.str;
|
|
|
|
description = ''
|
2023-05-19 22:11:38 -04:00
|
|
|
Wireguard address of this peer (a single IP address, multiple
|
2023-03-29 15:04:14 +02:00
|
|
|
addresses or address ranges are not supported).
|
|
|
|
'';
|
|
|
|
example = "10.0.0.42";
|
|
|
|
};
|
|
|
|
endpoint = mkOption {
|
|
|
|
type = types.nullOr types.str;
|
|
|
|
description = ''
|
|
|
|
Bootstrap endpoint for connecting to this Wireguard peer if no
|
|
|
|
other address is known or none are working.
|
|
|
|
'';
|
|
|
|
default = null;
|
|
|
|
example = "wgnode.mydomain.example:51820";
|
2024-12-10 20:27:17 +01:00
|
|
|
};
|
2023-03-29 15:04:14 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
);
|
|
|
|
default = [ ];
|
|
|
|
description = "wgautomesh peer list.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
};
|
|
|
|
default = { };
|
|
|
|
description = "Configuration for wgautomesh.";
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
|
|
|
services.wgautomesh.settings = {
|
|
|
|
gossip_secret_file = mkIf cfg.enableGossipEncryption "$CREDENTIALS_DIRECTORY/gossip_secret";
|
|
|
|
persist_file = mkIf cfg.enablePersistence "/var/lib/wgautomesh/state";
|
|
|
|
};
|
|
|
|
|
|
|
|
systemd.services.wgautomesh = {
|
|
|
|
path = [ pkgs.wireguard-tools ];
|
|
|
|
environment = {
|
|
|
|
RUST_LOG = "wgautomesh=${cfg.logLevel}";
|
|
|
|
};
|
|
|
|
description = "wgautomesh";
|
|
|
|
serviceConfig = {
|
|
|
|
Type = "simple";
|
|
|
|
|
|
|
|
ExecStart = "${getExe pkgs.wgautomesh} ${runtimeConfigFile}";
|
|
|
|
Restart = "always";
|
|
|
|
RestartSec = "30";
|
|
|
|
LoadCredential = mkIf cfg.enableGossipEncryption [ "gossip_secret:${cfg.gossipSecretFile}" ];
|
|
|
|
|
|
|
|
ExecStartPre = mkIf cfg.enableGossipEncryption [
|
|
|
|
''
|
|
|
|
${pkgs.envsubst}/bin/envsubst \
|
|
|
|
-i ${configFile} \
|
|
|
|
-o ${runtimeConfigFile}''
|
|
|
|
];
|
|
|
|
|
|
|
|
DynamicUser = true;
|
|
|
|
StateDirectory = "wgautomesh";
|
|
|
|
StateDirectoryMode = "0700";
|
|
|
|
RuntimeDirectory = "wgautomesh";
|
|
|
|
AmbientCapabilities = "CAP_NET_ADMIN";
|
|
|
|
CapabilityBoundingSet = "CAP_NET_ADMIN";
|
|
|
|
};
|
|
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
};
|
|
|
|
networking.firewall.allowedUDPPorts = mkIf cfg.openFirewall [ cfg.settings.gossip_port ];
|
|
|
|
};
|
|
|
|
}
|