nixos/netbird: automated login using Setup Keys file (#444291)

This commit is contained in:
Sandro
2025-11-27 01:07:30 +00:00
committed by GitHub
@@ -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 (