diff --git a/hosts/elisabeth/secrets/samba/netbird-env.age b/hosts/elisabeth/secrets/samba/netbird-env.age new file mode 100644 index 0000000..f000c26 --- /dev/null +++ b/hosts/elisabeth/secrets/samba/netbird-env.age @@ -0,0 +1,15 @@ +age-encryption.org/v1 +-> X25519 FTk4whtXQ4QKgotU+0iBZxrUcUVQReiHyhGwv/3pC2w +PGSxFJqC21n737Jyc4pQgv/7tsblQBB47dZlfNynOC0 +-> piv-p256 XTQkUA A1mVNcwBxkH0rysZRt1irvyi0k0ME5sccJox/xS1FRC4 +Sy6Zz0a+Y5Z7J6F9M/b1OEKOau5JQm5JAUFsl4Ewk6k +-> piv-p256 ZFgiIw AsVavBKMJ+/39us+c0k7niiJab3Ev4Dj+SOo8SH73g3S +ZoUlA/qcdfJ6ctaCeQ/OQYu2wFrIqJ5aR0/aPXCjl4o +-> piv-p256 5vmPtQ AnX/v0upSdNStu6uCpC3nVdqWsxX/iUjTpDvKwsdJfNs +lUR+WRlyxqqRuO0hBai6hdYk4ytpEL8SbQHxmR7sK94 +-> piv-p256 ZFgiIw Ax5SdGlJs1Gqusw6Lag/9bOuib7Ts3bksfdVN/FGRB4D +Euvy40vrJVrC+W27xYHb0muLuK5SIPmY0zv3+SJgAy4 +-> z:&o*}s-grease 4eL2m +xIA4Vo9Z8niU+0+FsD8P6RsdLC/duMh4XtoLu3jYwuh3vA +--- TKHpQOtXIUtjoH4HNwcW5gKI8g9Ou6pXbNtt5ba0qQY +q{+pl>]v7Kl݅B"Pм)3oK[(3> XU "=^jTUwu \ No newline at end of file diff --git a/modules/netbird-client.nix b/modules/netbird-client.nix new file mode 100644 index 0000000..4345c0a --- /dev/null +++ b/modules/netbird-client.nix @@ -0,0 +1,226 @@ +{ + 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 + 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. + ''; + }; + + autoStart = mkEnableOption '' automatically starting this tunnel on startup. + Need a setup key to work. + ''; + + environmentFile = mkOption { + type = path; + 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.services = + mapAttrs' + ( + name: { + environment, + stateDir, + environmentFile, + autoStart, + ... + }: + 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 = environmentFile; + ExecStart = "${getExe cfg.package} service run"; + ExecStartPost = mkIf autoStart "${getExe cfg.package} up"; + 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; + }) + ]; +} diff --git a/modules/netbird-server.nix b/modules/netbird-server.nix index ce47478..a33788b 100644 --- a/modules/netbird-server.nix +++ b/modules/netbird-server.nix @@ -23,6 +23,7 @@ in { package = mkPackageOption pkgs "netbird" {}; enableCoturn = mkEnableOption "the coturn service for running the TURN/STUN server"; domain = mkOption { + type = types.str; description = "The domain of your netbird instance"; }; port = mkOption { @@ -93,7 +94,8 @@ in { Stuns = [ { Proto = "udp"; - Uri = "turn:${cfg.turn.domain}:${toString cfg.turn.port}"; + Uri = "stun:${cfg.turn.domain}:${toString cfg.turn.port}"; + # TODO fairly certain with this config anyone can use your STUN server Username = ""; Password = null; } @@ -102,13 +104,14 @@ in { Turns = [ { Proto = "udp"; - Uri = "stun:${cfg.turn.domain}:${toString cfg.turn.port}"; + Uri = "turn:${cfg.turn.domain}:${toString cfg.turn.port}"; Username = cfg.turn.userName; Password = cfg.turn.password; } ]; CredentialsTTL = "12h"; - Secret = lib.trace "this should probably be an option as well" "secret"; + # This is not used with the standard coturn configuration + Secret = "secret"; TimeBasedCredentials = false; }; @@ -170,7 +173,7 @@ in { # Official documentation says that external-ip has to be # an IP which is not true as [this](https://github.com/coturn/coturn/blob/9b1cca1fbe909e7cc7c7ac28865f9c190af3515b/src/client/ns_turn_ioaddr.c#L234) - # will resolve and dns name as well + # will resolve a dns name as well extraConfig = '' fingerprint @@ -197,6 +200,43 @@ in { RuntimeDirectory = "netbird-mgmt"; StateDirectory = "netbird-mgmt"; WorkingDirectory = "/var/lib/netbird-mgmt"; + RestartSec = "60"; + + # hardening + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateMounts = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + 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; @@ -222,6 +262,7 @@ in { ]; serviceConfig = { + # Should we automatically disable metrics? ExecStart = '' ${cfg.package}/bin/netbird-mgmt management \ --config ${configFile} \ @@ -236,7 +277,7 @@ in { --port ${builtins.toString cfg.port} \ --log-file console ''; - # TODO add extraCOmmandLine option + # TODO add extraCommandLine option Restart = "always"; RuntimeDirectory = "netbird-mgmt"; StateDirectory = [ @@ -244,6 +285,42 @@ in { "netbird-mgmt/data" ]; WorkingDirectory = "/var/lib/netbird-mgmt"; + + # hardening + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateMounts = true; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + 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; diff --git a/modules/services/samba.nix b/modules/services/samba.nix index 8935af9..69befe1 100644 --- a/modules/services/samba.nix +++ b/modules/services/samba.nix @@ -3,10 +3,28 @@ lib, ... }: { + age.secrets.netbird = { + rekeyFile = config.node.secretsDir + "/netbird-env.age"; + mode = "440"; + }; + services.samba-wsdd = { enable = true; # make shares visible for windows 10 clients openFirewall = true; }; + + disabledModules = ["services/networking/netbird.nix"]; + + imports = [../netbird-client.nix]; + services.netbird.tunnels = { + samba = { + environment.NB_MANAGEMENT_URL = "https://netbird.${config.secrets.secrets.global.domains.web}"; + autoStart = true; + port = 56789; + environmentFile = config.age.secrets.netbird.path; + }; + }; + age.secrets.resticpasswd = { generator.script = "alnum"; };