243 lines
6.5 KiB
Nix
243 lines
6.5 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}: let
|
|
inherit
|
|
(lib)
|
|
attrNames
|
|
getExe
|
|
literalExpression
|
|
maintainers
|
|
mapAttrs'
|
|
mkDefault
|
|
mkEnableOption
|
|
mkIf
|
|
mkMerge
|
|
mkOption
|
|
mkPackageOption
|
|
nameValuePair
|
|
optional
|
|
versionOlder
|
|
;
|
|
|
|
inherit
|
|
(lib.types)
|
|
attrsOf
|
|
port
|
|
str
|
|
submodule
|
|
bool
|
|
nullOr
|
|
path
|
|
;
|
|
|
|
kernel = config.boot.kernelPackages;
|
|
|
|
cfg = config.services.netbird;
|
|
in {
|
|
meta.maintainers = with maintainers; [
|
|
misuzu
|
|
thubrecht
|
|
patrickdag
|
|
];
|
|
meta.doc = ./netbird.md;
|
|
|
|
options.services.netbird = {
|
|
enable = mkEnableOption (lib.mdDoc "Netbird daemon");
|
|
package = mkPackageOption pkgs "netbird" {};
|
|
|
|
tunnels = mkOption {
|
|
type = attrsOf (
|
|
submodule (
|
|
{
|
|
name,
|
|
config,
|
|
...
|
|
}: {
|
|
options = {
|
|
port = mkOption {
|
|
type = port;
|
|
default = 51820;
|
|
description = ''
|
|
Port for the ${name} netbird interface.
|
|
'';
|
|
};
|
|
|
|
userAccess = mkOption {
|
|
type = bool;
|
|
description = "Allow unprivileged users access to the control socket";
|
|
default = false;
|
|
};
|
|
|
|
environmentFile = mkOption {
|
|
type = nullOr path;
|
|
default = null;
|
|
description = "An additional environment file for this service.";
|
|
};
|
|
environment = mkOption {
|
|
type = attrsOf str;
|
|
defaultText = literalExpression ''
|
|
{
|
|
NB_CONFIG = "/var/lib/''${stateDir}/config.json";
|
|
NB_LOG_FILE = "console";
|
|
NB_WIREGUARD_PORT = builtins.toString port;
|
|
NB_INTERFACE_NAME = name;
|
|
NB_DAMEON_ADDR = "/var/run/''${stateDir}"
|
|
}
|
|
'';
|
|
description = ''
|
|
Environment for the netbird service, used to pass configuration options.
|
|
'';
|
|
};
|
|
|
|
stateDir = mkOption {
|
|
type = str;
|
|
default = "netbird-${name}";
|
|
description = ''
|
|
Directory storing the netbird configuration.
|
|
'';
|
|
};
|
|
};
|
|
|
|
config.environment = builtins.mapAttrs (_: mkDefault) {
|
|
NB_CONFIG = "/var/lib/${config.stateDir}/config.json";
|
|
NB_LOG_FILE = "console";
|
|
NB_WIREGUARD_PORT = builtins.toString config.port;
|
|
NB_INTERFACE_NAME = name;
|
|
NB_DAEMON_ADDR = "unix:///var/run/${config.stateDir}/sock";
|
|
};
|
|
}
|
|
)
|
|
);
|
|
default = {};
|
|
description = ''
|
|
Attribute set of Netbird tunnels, each one will spawn a daemon listening on ...
|
|
'';
|
|
};
|
|
};
|
|
|
|
config = mkMerge [
|
|
(mkIf cfg.enable {
|
|
# For backwards compatibility
|
|
services.netbird.tunnels.wt0.stateDir = "netbird";
|
|
})
|
|
|
|
(mkIf (cfg.tunnels != {}) {
|
|
boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard;
|
|
|
|
environment.systemPackages = [cfg.package];
|
|
|
|
networking.dhcpcd.denyInterfaces = attrNames cfg.tunnels;
|
|
|
|
systemd.network.networks = mkIf config.networking.useNetworkd (
|
|
mapAttrs'
|
|
(
|
|
name: _:
|
|
nameValuePair "50-netbird-${name}" {
|
|
matchConfig = {
|
|
Name = name;
|
|
};
|
|
linkConfig = {
|
|
Unmanaged = true;
|
|
ActivationPolicy = "manual";
|
|
};
|
|
}
|
|
)
|
|
cfg.tunnels
|
|
);
|
|
|
|
systemd.tmpfiles.settings."10-netbird-access" = lib.flip lib.mapAttrs' cfg.tunnels (
|
|
_: {
|
|
stateDir,
|
|
userAccess,
|
|
...
|
|
}: (nameValuePair "/run/${stateDir}" {
|
|
d.mode =
|
|
if userAccess
|
|
then "0755"
|
|
else "0750";
|
|
})
|
|
);
|
|
|
|
systemd.services =
|
|
mapAttrs'
|
|
(
|
|
name: {
|
|
environment,
|
|
stateDir,
|
|
environmentFile,
|
|
...
|
|
}:
|
|
nameValuePair "netbird-${name}" {
|
|
description = "A WireGuard-based mesh network that connects your devices into a single private network";
|
|
|
|
documentation = ["https://netbird.io/docs/"];
|
|
|
|
after = ["network.target"];
|
|
wantedBy = ["multi-user.target"];
|
|
|
|
path = with pkgs; [openresolv];
|
|
|
|
inherit environment;
|
|
|
|
serviceConfig = {
|
|
EnvironmentFile = mkIf (environmentFile != null) environmentFile;
|
|
ExecStart = "${getExe cfg.package} service run";
|
|
Restart = "always";
|
|
RuntimeDirectory = stateDir;
|
|
StateDirectory = stateDir;
|
|
StateDirectoryMode = "0700";
|
|
WorkingDirectory = "/var/lib/${stateDir}";
|
|
|
|
# hardening
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = true;
|
|
NoNewPrivileges = true;
|
|
PrivateMounts = true;
|
|
PrivateTmp = true;
|
|
ProtectClock = true;
|
|
ProtectControlGroups = true;
|
|
ProtectHome = true;
|
|
ProtectHostname = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectKernelModules = false; # needed to load wg module for kernel-mode WireGuard
|
|
ProtectKernelTunables = false;
|
|
ProtectSystem = true;
|
|
RemoveIPC = true;
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
|
|
# Hardening
|
|
#CapabilityBoundingSet = "";
|
|
#PrivateUsers = true;
|
|
#ProtectProc = "invisible";
|
|
#ProcSubset = "pid";
|
|
#RestrictAddressFamilies = [
|
|
# "AF_INET"
|
|
# "AF_INET6"
|
|
# "AF_NETLINK"
|
|
#];
|
|
#SystemCallArchitectures = "native";
|
|
#SystemCallFilter = [
|
|
# "@system-service"
|
|
# "@pkey"
|
|
#];
|
|
UMask = "0077";
|
|
};
|
|
|
|
unitConfig = {
|
|
StartLimitInterval = 5;
|
|
StartLimitBurst = 10;
|
|
};
|
|
|
|
stopIfChanged = false;
|
|
}
|
|
)
|
|
cfg.tunnels;
|
|
})
|
|
];
|
|
}
|