From c2d822e6b02a7f20c82d22457f3b09ff305001e3 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Tue, 23 Jan 2024 16:24:26 +0100 Subject: [PATCH] nixos/netbird: Allow running multiple netbird networks in parallel --- .../manual/release-notes/rl-2405.section.md | 2 + nixos/modules/services/networking/netbird.md | 56 +++++ nixos/modules/services/networking/netbird.nix | 203 ++++++++++++++---- 3 files changed, 215 insertions(+), 46 deletions(-) create mode 100644 nixos/modules/services/networking/netbird.md diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index aba4d3d72d1d..aad351d61aed 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -165,6 +165,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m existing process, but will need to start that process from gdb (so it is a child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0. +- The netbird module now allows running multiple tunnels in parallel through [`services.netbird.tunnels`](#opt-services.netbird.tunnels). + - [Nginx virtual hosts](#opt-services.nginx.virtualHosts) using `forceSSL` or `globalRedirect` can now have redirect codes other than 301 through `redirectCode`. diff --git a/nixos/modules/services/networking/netbird.md b/nixos/modules/services/networking/netbird.md new file mode 100644 index 000000000000..a326207becc8 --- /dev/null +++ b/nixos/modules/services/networking/netbird.md @@ -0,0 +1,56 @@ +# Netbird {#module-services-netbird} + +## Quickstart {#module-services-netbird-quickstart} + +The absolute minimal configuration for the netbird daemon looks like this: + +```nix +services.netbird.enable = true; +``` + +This will set up a netbird service listening on the port `51820` associated to the +`wt0` interface. + +It is strictly equivalent to setting: + +```nix +services.netbird.tunnels.wt0.stateDir = "netbird"; +``` + +The `enable` option is mainly kept for backward compatibility, as defining netbird +tunnels through the `tunnels` option is more expressive. + +## Multiple connections setup {#module-services-netbird-multiple-connections} + +Using the `services.netbird.tunnels` option, it is also possible to define more than +one netbird service running at the same time. + +The following configuration will start a netbird daemon using the interface `wt1` and +the port 51830. Its configuration file will then be located at `/var/lib/netbird-wt1/config.json`. + +```nix +services.netbird.tunnels = { + wt1 = { + port = 51830; + }; +}; +``` + +To interact with it, you will need to specify the correct daemon address: + +```bash +netbird --daemon-addr unix:///var/run/netbird-wt1/sock ... +``` + +The address will by default be `unix:///var/run/netbird-`. + +It is also possible to overwrite default options passed to the service, for +example: + +```nix +services.netbird.tunnels.wt1.environment = { + NB_DAEMON_ADDR = "unix:///var/run/toto.sock" +}; +``` + +This will set the socket to interact with the netbird service to `/var/run/toto.sock`. diff --git a/nixos/modules/services/networking/netbird.nix b/nixos/modules/services/networking/netbird.nix index 4b0bd63e9dbc..6a1511d4d084 100644 --- a/nixos/modules/services/networking/netbird.nix +++ b/nixos/modules/services/networking/netbird.nix @@ -1,60 +1,171 @@ -{ config, lib, pkgs, ... }: - -with lib; +{ + config, + lib, + pkgs, + ... +}: let - cfg = config.services.netbird; + inherit (lib) + attrNames + getExe + literalExpression + maintainers + mapAttrs' + mkDefault + mkEnableOption + mkIf + mkMerge + mkOption + mkPackageOption + nameValuePair + optional + versionOlder + ; + + inherit (lib.types) + attrsOf + port + str + submodule + ; + kernel = config.boot.kernelPackages; - interfaceName = "wt0"; -in { - meta.maintainers = with maintainers; [ misuzu ]; + + cfg = config.services.netbird; +in +{ + meta.maintainers = with maintainers; [ + misuzu + thubrecht + ]; + meta.doc = ./netbird.md; options.services.netbird = { enable = mkEnableOption (lib.mdDoc "Netbird daemon"); package = mkPackageOption pkgs "netbird" { }; - }; - config = mkIf cfg.enable { - boot.extraModulePackages = optional (versionOlder kernel.kernel.version "5.6") kernel.wireguard; + tunnels = mkOption { + type = attrsOf ( + submodule ( + { name, config, ... }: + { + options = { + port = mkOption { + type = port; + default = 51820; + description = '' + Port for the ${name} netbird interface. + ''; + }; - environment.systemPackages = [ cfg.package ]; + 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. + ''; + }; - networking.dhcpcd.denyInterfaces = [ interfaceName ]; + stateDir = mkOption { + type = str; + default = "netbird-${name}"; + description = '' + Directory storing the netbird configuration. + ''; + }; + }; - systemd.network.networks."50-netbird" = mkIf config.networking.useNetworkd { - matchConfig = { - Name = interfaceName; - }; - linkConfig = { - Unmanaged = true; - ActivationPolicy = "manual"; - }; - }; - - systemd.services.netbird = { - 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 - ]; - serviceConfig = { - Environment = [ - "NB_CONFIG=/var/lib/netbird/config.json" - "NB_LOG_FILE=console" - ]; - ExecStart = "${cfg.package}/bin/netbird service run"; - Restart = "always"; - RuntimeDirectory = "netbird"; - StateDirectory = "netbird"; - WorkingDirectory = "/var/lib/netbird"; - }; - unitConfig = { - StartLimitInterval = 5; - StartLimitBurst = 10; - }; - stopIfChanged = false; + 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.services = + mapAttrs' + ( + name: + { environment, stateDir, ... }: + 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 = { + ExecStart = "${getExe cfg.package} service run"; + Restart = "always"; + RuntimeDirectory = stateDir; + StateDirectory = stateDir; + StateDirectoryMode = "0700"; + WorkingDirectory = "/var/lib/${stateDir}"; + }; + + unitConfig = { + StartLimitInterval = 5; + StartLimitBurst = 10; + }; + + stopIfChanged = false; + } + ) + cfg.tunnels; + }) + ]; }