diff --git a/nixos/modules/services/networking/netbird.nix b/nixos/modules/services/networking/netbird.nix index c19cf7d88edb..179c9fc374e9 100644 --- a/nixos/modules/services/networking/netbird.nix +++ b/nixos/modules/services/networking/netbird.nix @@ -20,6 +20,7 @@ let mapAttrsToList mkAliasOptionModule mkDefault + mkEnableOption mkIf mkMerge mkOption @@ -31,6 +32,7 @@ let optionalAttrs optionalString optionals + pipe toShellVars versionAtLeast versionOlder @@ -40,6 +42,7 @@ let attrsOf bool enum + listOf nullOr package path @@ -222,6 +225,26 @@ in ''; }; + login.enable = mkEnableOption "automated login for NetBird client"; + login.setupKeyFile = mkOption { + type = nullOr str; + default = null; + example = "/run/secrets/netbird-priv/setup-key"; + description = '' + A Setup Key file path used for automated login of the machine. + ''; + }; + login.systemdDependencies = mkOption { + type = listOf str; + default = [ ]; + example = lib.literalExpression '' + [ "sops-install-secrets.service" ] + ''; + description = '' + Additional systemd dependencies required to succeed before the Setup Key file becomes available. + ''; + }; + openFirewall = mkOption { type = bool; default = true; @@ -697,6 +720,71 @@ in }); ''; }) + # Setup Keys login automation + { + systemd.services = pipe cfg.clients [ + (filterAttrs (_: client: client.login.enable)) + (mapAttrs' ( + _: client: + nameValuePair "${client.service.name}-login" { + after = [ "${client.service.name}.service" ] ++ client.login.systemdDependencies; + requires = [ "${client.service.name}.service" ] ++ client.login.systemdDependencies; + wantedBy = [ "${client.service.name}.service" ]; + + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + + User = client.user.name; + Group = client.user.group; + + RemoveIPC = true; + PrivateTmp = "disconnected"; # "disconnected" puts /tmp on `tmpfs` + ProtectSystem = "strict"; + ProtectHome = "yes"; + + LoadCredential = [ "setup-key:${client.login.setupKeyFile}" ]; + }; + + environment.NB_SETUP_KEY_FILE = "%d/setup-key"; + /* + might want to do something similar to the docker entrypoint (watching log messages) instead + see https://github.com/netbirdio/netbird/blob/dc30dcacce4c322502975f1f491e6774efd7e1e9/client/netbird-entrypoint.sh + */ + script = '' + set -x + # uses a file on a `tmpfs`, because variable updates get lost in the loop + status_file="/tmp/status.txt" + + refresh_status() { + '${lib.getExe client.wrapper}' status &>"$status_file" || : + } + + print_short_setup_key() { + cut -b1-8 <"$NB_SETUP_KEY_FILE" + } + + main() { + refresh_status + <"$status_file" sed 's/^/STATUS:PRE-CONNECT : /g' + + until refresh_status && <"$status_file" grep --quiet 'Connected\|NeedsLogin' ; do + sleep 1 + done + <"$status_file" sed 's/^/STATUS:POST-CONNECT: /g' + + if <"$status_file" grep --quiet 'NeedsLogin' ; then + echo "Using Setup Key File with key: $(print_short_setup_key)" >&2 + '${lib.getExe client.wrapper}' up --setup-key-file="$NB_SETUP_KEY_FILE" + fi + } + + main "$@" + ''; + } + )) + ]; + } # migration & temporary fixups section { systemd.services = toClientAttrs (