nix-config/modules/netbird-client.nix

238 lines
6.4 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";
};
stopIfChanged = false;
}
)
cfg.tunnels;
})
];
}