WIP: netbird

This commit is contained in:
Patrick 2024-03-21 20:39:59 +01:00
parent 86593e3b7d
commit 03e0b54183
Signed by: patrick
GPG key ID: 451F95EFB8BECD0F
12 changed files with 381 additions and 196 deletions

View file

@ -57,4 +57,6 @@
nixpkgs.config.permittedInsecurePackages = lib.trace "remove when possible" [ nixpkgs.config.permittedInsecurePackages = lib.trace "remove when possible" [
"nix-2.16.2" "nix-2.16.2"
]; ];
services.netbird.enable = true;
} }

View file

@ -21,6 +21,7 @@
apispotify = "apisptfy"; apispotify = "apisptfy";
kanidm = "auth"; kanidm = "auth";
oauth2-proxy = "oauth2"; oauth2-proxy = "oauth2";
netbird = "netbird";
}; };
in "${domains.${hostName}}.${config.secrets.secrets.global.domains.web}"; in "${domains.${hostName}}.${config.secrets.secrets.global.domains.web}";
# TODO hard coded elisabeth nicht so schön # TODO hard coded elisabeth nicht so schön
@ -61,6 +62,49 @@ in {
{ {
enable = true; enable = true;
recommendedSetup = true; recommendedSetup = true;
upstreams.netbird = {
servers."${ipOf "netbird"}:80" = {};
extraConfig = ''
zone netbird 64k ;
keepalive 5 ;
'';
};
upstreams.netbird-mgmt = {
servers."${ipOf "netbird"}:3000" = {};
extraConfig = ''
zone netbird 64k ;
keepalive 5 ;
'';
};
virtualHosts.${domainOf "netbird"} = {
forceSSL = true;
useACMEHost = "web";
locations = {
"/" = {
proxyPass = "http://netbird";
proxyWebsockets = true;
X-Frame-Options = "SAMEORIGIN";
};
"/signalexchange.SignalExchange/".extraConfig = ''
grpc_pass grpc://${ipOf "netbird"}:3001;
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
"/api".proxyPass = "http://netbird-mgmt";
"/management.ManagementService/".extraConfig = ''
grpc_pass grpc://${ipOf "netbird"}:3000;
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
};
extraConfig = ''
client_max_body_size 500M ;
'';
};
} }
(blockOf "vaultwarden" {maxBodySize = "1G";}) (blockOf "vaultwarden" {maxBodySize = "1G";})
(blockOf "forgejo" {maxBodySize = "1G";}) (blockOf "forgejo" {maxBodySize = "1G";})
@ -154,7 +198,7 @@ in {
} }
]) ])
(blockOf "paperless" {maxBodySize = "5G";}) (blockOf "paperless" {maxBodySize = "5G";})
(blockOf "ttrss" {port = 80;}) #(blockOf "ttrss" {port = 80;})
(blockOf "yourspotify" {port = 80;}) (blockOf "yourspotify" {port = 80;})
(blockOf "apispotify" { (blockOf "apispotify" {
port = 80; port = 80;
@ -262,8 +306,9 @@ in {
// mkContainer "vaultwarden" {} // mkContainer "vaultwarden" {}
// mkContainer "ddclient" {} // mkContainer "ddclient" {}
// mkContainer "ollama" {} // mkContainer "ollama" {}
// mkContainer "ttrss" {} #// mkContainer "ttrss" {}
// mkContainer "yourspotify" {} // mkContainer "yourspotify" {}
// mkContainer "netbird" {}
// mkContainer "kanidm" {} // mkContainer "kanidm" {}
// mkContainer "nextcloud" { // mkContainer "nextcloud" {
enablePanzer = true; enablePanzer = true;

View file

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF0+o9G3hA/5PbaxVy+EoOOJw5cHKu3p5yjAaHDHFQ8Q

View file

@ -0,0 +1,107 @@
{
pkgs,
config,
lib,
...
}: let
inherit
(lib)
mkPackageOption
mkIf
mkEnableOption
mkOption
types
isBool
boolToString
;
toStringEnv = value:
if isBool value
then boolToString value
else toString value;
cfg = config.services.netbird-dashboard;
in {
options.services.netbird-dashboard = {
enable = mkEnableOption "the static netbird dashboard frontend";
package = mkPackageOption pkgs "netbird-dashboard" {};
enableNginx = mkEnableOption "Nginx as a webserver serving the backend";
domain = mkOption {
type = types.str;
description = "The domain under which the dashboard runs.";
default = "localhost";
};
settings = mkOption {
type = types.submodule {
freeformType = types.attrsOf (types.oneOf [types.str types.bool]);
config = {
#AUTH_AUTHORITY = ""; #${AUTH_AUTHORITY:-https://$AUTH0_DOMAIN}
#AUTH_CLIENT_ID = ""; #${AUTH_CLIENT_ID:-$AUTH0_CLIENT_ID}
# Due to how the backend and frontend work this secret will be templated into the backend
# and then served statically from your website
# This enables you to login without the normally needed indirection through the backend
# but this also means anyone that can reach your website can
# fetch this secret, which is why there is no real need to put it into
# special options as its public anyway
# As far as I know leaking this secret is just
# an information leak as one can fetch some basic app
# informations from the IDP
# To actually do something one still needs to have login
# data and this secret so this being public will not
# suffice for anything just decreasing security
AUTH_CLIENT_SECRET = ""; #${AUTH_CLIENT_SECRET}
AUTH_AUDIENCE = "netbird"; #${AUTH_AUDIENCE:-$AUTH0_AUDIENCE}
#AUTH_REDIRECT_URI=${AUTH_REDIRECT_URI}
#AUTH_SILENT_REDIRECT_URI=${AUTH_SILENT_REDIRECT_URI}
USE_AUTH0 = false; #${USE_AUTH0:-true}
AUTH_SUPPORTED_SCOPES = "openid profile email"; #${AUTH_SUPPORTED_SCOPES:-openid profile email api offline_access email_verified}
NETBIRD_MGMT_API_ENDPOINT = config.services.netbird-server.domain; #$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
NETBIRD_MGMT_GRPC_API_ENDPOINT = config.services.netbird-server.domain; #${NETBIRD_MGMT_GRPC_API_ENDPOINT}
#NETBIRD_HOTJAR_TRACK_ID=${NETBIRD_HOTJAR_TRACK_ID}
#NETBIRD_GOOGLE_ANALYTICS_ID=${NETBIRD_GOOGLE_ANALYTICS_ID}
NETBIRD_TOKEN_SOURCE = "idToken";
#NETBIRD_DRAG_QUERY_PARAMS=${NETBIRD_DRAG_QUERY_PARAMS:-false}
};
};
};
};
config = let
deriv = pkgs.runCommand "template-netbird-dashboard" {} ''
cp -r ${cfg.package} ./temp
${
lib.concatStringsSep "\n" (lib.mapAttrsToList (name: value: ''export "${name}"="${toStringEnv value}"'') cfg.settings)
}
# replace ENVs in the config
ENV_STR="\$\$USE_AUTH0 \$\$AUTH_AUDIENCE \$\$AUTH_AUTHORITY \$\$AUTH_CLIENT_ID \$\$AUTH_CLIENT_SECRET \$\$AUTH_SUPPORTED_SCOPES \$\$NETBIRD_MGMT_API_ENDPOINT \$\$NETBIRD_MGMT_GRPC_API_ENDPOINT \$\$NETBIRD_HOTJAR_TRACK_ID \$\$NETBIRD_GOOGLE_ANALYTICS_ID \$\$AUTH_REDIRECT_URI \$\$AUTH_SILENT_REDIRECT_URI \$\$NETBIRD_TOKEN_SOURCE \$\$NETBIRD_DRAG_QUERY_PARAMS"
find temp -type d -exec chmod 755 {} \;
OIDC_TRUSTED_DOMAINS="./temp/OidcTrustedDomains.js"
${pkgs.gettext}/bin/envsubst "$ENV_STR" < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
for f in $(grep -R -l AUTH_SUPPORTED_SCOPES ./); do
${pkgs.gettext}/bin/envsubst "$ENV_STR" < "$f" > "$f".copy
mv -f "$f".copy "$f"
done
mkdir -p $out
cp -r ./temp/. $out/
'';
in
mkIf cfg.enable
{
services.nginx = mkIf cfg.enableNginx {
enable = true;
virtualHosts = {
${cfg.domain} = {
locations = {
"/" = {
root = "${deriv}/";
tryFiles = "$uri /index.html";
};
};
};
};
};
};
}

View file

@ -9,39 +9,54 @@
mkEnableOption mkEnableOption
mkOption mkOption
types types
mkDefault mkPackageOption
mkIf mkIf
; ;
cfg = config.services.netbird; cfg = config.services.netbird-server;
configFile = formatType.generate config.json cfg.settings; configFile = formatType.generate "config.json" cfg.settings;
formatType = pkgs.format.json {}; formatType = pkgs.formats.json {};
in { in {
options.services.netbird = { options.services.netbird-server = {
enable = mkEnableOption "netbird, a self hosted wireguard VPN"; enable = mkEnableOption "netbird, a self hosted wireguard VPN";
package = mkPackageOption pkgs "netbird" {};
domain = mkOption { domain = mkOption {
description = "The domain of your netbird instance"; description = "The domain of your netbird instance";
}; };
port = mkOption {
description = "The port the management interface will listen on";
type = types.port;
default = 3000;
};
oidcConfigEndpoint = mkOption { oidcConfigEndpoint = mkOption {
type = types.str; type = types.str;
example = "https://example.eu.auth0.com/.well-known/openid-configuration"; example = "https://example.eu.auth0.com/.well-known/openid-configuration";
description = "The oidc discovery endpoint"; description = "The oidc discovery endpoint";
}; };
dataDir = mkOption { signalPort = mkOption {
description = "Runtime directory where netbird stores its data"; description = "The listening port for the signal protocol";
types = types.path; default = 3001;
default = /var/lib/netbird; type = types.port;
}; };
singleAccountModeDomain = mkOption {
description = "Optional domain for single account mode, set to null to disable singleAccountMode";
type = types.nullOr types.str;
default = "netbird.selfhosted";
example = null;
};
turn = { turn = {
domain = mkOption { domain = mkOption {
description = "The domain under which the TURN server is reachable"; description = "The domain under which the TURN server is reachable";
type = types.str; type = types.str;
example = "localhost"; example = "localhost";
default = cfg.domain;
}; };
port = mkOption { port = mkOption {
description = "The port under which the TURN server is reachable"; description = "The port under which the TURN server is reachable";
type = types.int; type = types.port;
default = 3478; default = 3478;
}; };
userName = mkOption { userName = mkOption {
@ -56,15 +71,14 @@ in {
}; };
}; };
settings = mkOption { settings = mkOption {
default = {};
type = types.submodule { type = types.submodule {
freeformType = formatType.type; freeformType = formatType.type;
options = { config = {
};
config = mkDefault {
Stuns = [ Stuns = [
{ {
Proto = "udp"; Proto = "udp";
Uri = "stun:${cfg.turn.domain}:${cfg.turn.domain}"; Uri = "turn:${cfg.turn.domain}:${toString cfg.turn.port}";
Username = ""; Username = "";
Password = null; Password = null;
} }
@ -73,7 +87,7 @@ in {
Turns = [ Turns = [
{ {
Proto = "udp"; Proto = "udp";
Uri = "stun:${cfg.turn.domain}:${cfg.turn.port}"; Uri = "stun:${cfg.turn.domain}:${toString cfg.turn.port}";
Username = cfg.turn.userName; Username = cfg.turn.userName;
Password = cfg.turn.password; Password = cfg.turn.password;
} }
@ -96,13 +110,13 @@ in {
"0.0.0.0/0" "0.0.0.0/0"
]; ];
}; };
Datadir = cfg.dataDir; Datadir = "/var/lib/netbird-mgmt";
DataStoreEncryptionKey = lib.trace "uppsi wuppsi ich hab mein netbird unsiccccccher gemacht" "$NETBIRD_DATASTORE_ENC_KEY"; DataStoreEncryptionKey = lib.trace "uppsi wuppsi ich hab mein netbird unsiccccccher gemacht" "X4/obyAolDVhjGsz8NDb4TJqgCfwmCA7lOtJFHt9L3w=";
StoreConfig = { StoreConfig = {
Engine = "sqlite"; Engine = "sqlite";
}; };
HttpConfig = { HttpConfig = {
Address = "0.0.0.0:3000"; Address = "0.0.0.0:${toString cfg.port}";
#"AuthIssuer" = "$NETBIRD_AUTH_AUTHORITY"; #"AuthIssuer" = "$NETBIRD_AUTH_AUTHORITY";
#"AuthAudience" = "$NETBIRD_AUTH_AUDIENCE"; #"AuthAudience" = "$NETBIRD_AUTH_AUDIENCE";
#"AuthKeysLocation" = "$NETBIRD_AUTH_JWT_CERTS"; #"AuthKeysLocation" = "$NETBIRD_AUTH_JWT_CERTS";
@ -127,198 +141,111 @@ in {
#"KeycloakClientCredentials" = null; #"KeycloakClientCredentials" = null;
#"ZitadelClientCredentials" = null; #"ZitadelClientCredentials" = null;
}; };
#DeviceAuthorizationFlow = { DeviceAuthorizationFlow = {
# Provider = "$NETBIRD_AUTH_DEVICE_AUTH_PROVIDER"; #Provider = "$NETBIRD_AUTH_DEVICE_AUTH_PROVIDER";
# "ProviderConfig" = { ProviderConfig = {
# "Audience" = "$NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE"; Audience = "netbird";
# "AuthorizationEndpoint" = ""; #"AuthorizationEndpoint" = "";
# "Domain" = "$NETBIRD_AUTH0_DOMAIN"; #"Domain" = "$NETBIRD_AUTH0_DOMAIN";
# "ClientID" = "$NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID"; #"ClientID" = "$NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID";
# "ClientSecret" = ""; #"ClientSecret" = "";
# "TokenEndpoint" = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; #"TokenEndpoint" = "$NETBIRD_AUTH_TOKEN_ENDPOINT";
# "DeviceAuthEndpoint" = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"; #"DeviceAuthEndpoint" = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT";
# "Scope" = "$NETBIRD_AUTH_DEVICE_AUTH_SCOPE"; Scope = "openid profile email";
# "UseIDToken" = "$NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN"; #"UseIDToken" = "$NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN";
# "RedirectURLs" = null; #"RedirectURLs" = null;
# }; };
#}; };
PKCEAuthorizationFlow = { PKCEAuthorizationFlow = {
ProviderConfig = { ProviderConfig = {
#Audience = "$NETBIRD_AUTH_PKCE_AUDIENCE"; Audience = "netbird";
ClientID = "netbird"; ClientID = "netbird";
ClientSecret = lib.trace "oho bei zo vielen sicherheitzlücken" "$NETBIRD_AUTH_CLIENT_SECRET"; ClientSecret = lib.trace "oho bei zo vielen sicherheitzlücken" "";
Domain = ""; Domain = "";
#AuthorizationEndpoint = "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT"; #AuthorizationEndpoint = "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT";
#TokenEndpoint = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; #TokenEndpoint = "$NETBIRD_AUTH_TOKEN_ENDPOINT";
Scope = "openid profile email"; Scope = "openid profile email";
RedirectURLs = ["localhost:53000"]; RedirectURLs = ["http://localhost:53000"];
UseIDToken = "$NETBIRD_AUTH_PKCE_USE_ID_TOKEN"; UseIDToken = true;
}; };
}; };
}; };
}; };
}; };
}; };
config = config = mkIf cfg.enable {
mkIf cfg.enable { systemd.services = {
systemd.services = { netbird-signal = {
netbird-setup = { after = ["network.target"];
wantedBy = [ wantedBy = ["netbird-management.service"];
"netbird-management.service" restartTriggers = [
"netbird-signal.service" configFile
"multi-user.target" ];
];
serviceConfig = {
Type = "oneshot";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = "netbird-mgmt";
WorkingDirectory = cfg.dataDir;
EnvironmentFile = [ ];
};
unitConfig = {
StartLimitInterval = 5;
StartLimitBurst = 10;
};
path = serviceConfig = {
[ ExecStart = ''
pkgs.coreutils ${cfg.package}/bin/netbird-signal run \
pkgs.findutils --log-file console \
pkgs.gettext --port ${builtins.toString cfg.signalPort}
pkgs.gnused '';
# ] Restart = "always";
# ++ (optionals cfg.setupAutoOidc [ RuntimeDirectory = "netbird-mgmt";
# pkgs.curl StateDirectory = "netbird-mgmt";
# pkgs.jq WorkingDirectory = "/var/lib/netbird-mgmt";
];
script =
''
cp ${configFile} ${cfg.dataDir}/management.json
''
#+ (optionalString cfg.setupAutoOidc ''
# mv ${stateDir}/management.json.copy ${stateDir}/management.json
# echo "loading OpenID configuration from $NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT to the openid-configuration.json file"
# curl "$NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT" -q -o ${stateDir}/openid-configuration.json
# export NETBIRD_AUTH_AUTHORITY=$(jq -r '.issuer' ${stateDir}/openid-configuration.json)
# export NETBIRD_AUTH_JWT_CERTS=$(jq -r '.jwks_uri' ${stateDir}/openid-configuration.json)
# export NETBIRD_AUTH_TOKEN_ENDPOINT=$(jq -r '.token_endpoint' ${stateDir}/openid-configuration.json)
# export NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT=$(jq -r '.device_authorization_endpoint' ${stateDir}/openid-configuration.json)
# export NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT=$(jq -r '.authorization_endpoint' ${stateDir}/openid-configuration.json)
# envsubst '$NETBIRD_AUTH_AUTHORITY $NETBIRD_AUTH_JWT_CERTS $NETBIRD_AUTH_TOKEN_ENDPOINT $NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT $NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT' < ${stateDir}/management.json > ${stateDir}/management.json.copy
#'')
#+ ''
# # Update secrets in management.json
# ${builtins.concatStringsSep "\n" (
# builtins.attrValues (
# builtins.mapAttrs (name: path: "export ${name}=$(cat ${path})") (
# filterAttrs (_: p: p != null) cfg.secretFiles
# )
# )
# )}
+ ''
#envsubst '$TURN_PASSWORD $TURN_SECRET $STUN_PASSWORD $AUTH_CLIENT_SECRET $IDP_MGMT_CLIENT_SECRET' < ${cfg.dataDir}/management.json.copy > ${cfg.dataDir}/management.json
rm -rf ${cfg.dataDir}/web-ui
mkdir -p ${cfg.dataDir}/web-ui
cp -R ${cfg.dashboard}/* ${cfg.dataDir}/web-ui
export AUTH_AUTHORITY="$NETBIRD_AUTH_AUTHORITY"
export AUTH_CLIENT_ID="$NETBIRD_AUTH_CLIENT_ID"
${optionalString (cfg.secretFiles.AUTH_CLIENT_SECRET == null)
''export AUTH_CLIENT_SECRET="$NETBIRD_AUTH_CLIENT_SECRET"''}
export AUTH_AUDIENCE="$NETBIRD_AUTH_AUDIENCE"
export AUTH_REDIRECT_URI="$NETBIRD_AUTH_REDIRECT_URI"
export AUTH_SILENT_REDIRECT_URI="$NETBIRD_AUTH_SILENT_REDIRECT_URI"
export USE_AUTH0="$NETBIRD_USE_AUTH0"
export AUTH_SUPPORTED_SCOPES=$(echo $NETBIRD_AUTH_SUPPORTED_SCOPES | sed -E 's/"//g')
export NETBIRD_MGMT_API_ENDPOINT=$(echo $NETBIRD_MGMT_API_ENDPOINT | sed -E 's/(:80|:443)$//')
MAIN_JS=$(find ${cfg.dataDir}/web-ui/static/js/main.*js)
OIDC_TRUSTED_DOMAINS=${cfg.dataDir}/web-ui/OidcTrustedDomains.js
mv "$MAIN_JS" "$MAIN_JS".copy
envsubst '$USE_AUTH0 $AUTH_AUTHORITY $AUTH_CLIENT_ID $AUTH_CLIENT_SECRET $AUTH_SUPPORTED_SCOPES $AUTH_AUDIENCE $NETBIRD_MGMT_API_ENDPOINT $NETBIRD_MGMT_GRPC_API_ENDPOINT $NETBIRD_HOTJAR_TRACK_ID $AUTH_REDIRECT_URI $AUTH_SILENT_REDIRECT_URI $NETBIRD_TOKEN_SOURCE $NETBIRD_DRAG_QUERY_PARAMS' < "$MAIN_JS".copy > "$MAIN_JS"
envsubst '$NETBIRD_MGMT_API_ENDPOINT' < "$OIDC_TRUSTED_DOMAINS".tmpl > "$OIDC_TRUSTED_DOMAINS"
'';
}; };
unitConfig = {
netbird-signal = { StartLimitInterval = 5;
after = [ "network.target" ]; StartLimitBurst = 10;
wantedBy = [ "netbird-management.service" ];
restartTriggers = [
settingsFile
managementFile
];
serviceConfig = {
ExecStart = ''
${cfg.package}/bin/netbird-signal run \
--port ${builtins.toString cfg.ports.signal} \
--log-file console \
--log-level ${cfg.logLevel}
'';
Restart = "always";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = "netbird-mgmt";
WorkingDirectory = cfg.dataDir;
};
unitConfig = {
StartLimitInterval = 5;
StartLimitBurst = 10;
};
stopIfChanged = false;
};
netbird-management = {
description = "The management server for Netbird, a wireguard VPN";
documentation = [ "https://netbird.io/docs/" ];
after = [
"network.target"
"netbird-setup.service"
];
wantedBy = [ "multi-user.target" ];
wants = [
"netbird-signal.service"
"netbird-setup.service"
];
restartTriggers = [
settingsFile
managementFile
];
serviceConfig = {
ExecStart = ''
${cfg.package}/bin/netbird-mgmt management \
--config ${stateDir}/management.json \
--datadir ${stateDir}/data \
${optionalString cfg.management.disableAnonymousMetrics "--disable-anonymous-metrics"} \
${optionalString cfg.management.disableSingleAccountMode "--disable-single-account-mode"} \
--dns-domain ${cfg.management.dnsDomain} \
--single-account-mode-domain ${cfg.management.singleAccountModeDomain} \
--idp-sign-key-refresh-enabled \
--port ${builtins.toString cfg.ports.management} \
--log-file console \
--log-level ${cfg.logLevel}
'';
Restart = "always";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = [
"netbird-mgmt"
"netbird-mgmt/data"
];
WorkingDirectory = stateDir;
};
unitConfig = {
StartLimitInterval = 5;
StartLimitBurst = 10;
};
stopIfChanged = false;
}; };
stopIfChanged = false;
};
netbird-management = {
description = "The management server for Netbird, a wireguard VPN";
documentation = ["https://netbird.io/docs/"];
after = [
"network.target"
"netbird-setup.service"
];
wantedBy = ["multi-user.target"];
wants = [
"netbird-signal.service"
"netbird-setup.service"
];
restartTriggers = [
configFile
];
serviceConfig = {
ExecStart = ''
${cfg.package}/bin/netbird-mgmt management \
--config ${configFile} \
--datadir /var/lib/netbird-mgmt/data \
--disable-anonymous-metrics \
${
if cfg.singleAccountModeDomain == null
then "--disable-single-account-mode"
else "--single-account-mode-domain ${cfg.singleAccountModeDomain}"
} \
--idp-sign-key-refresh-enabled \
--port ${builtins.toString cfg.port} \
--log-file consolef
'';
# TODO add extraCOmmandLine option
Restart = "always";
RuntimeDirectory = "netbird-mgmt";
StateDirectory = [
"netbird-mgmt"
"netbird-mgmt/data"
];
WorkingDirectory = "/var/lib/netbird-mgmt";
};
unitConfig = {
StartLimitInterval = 5;
StartLimitBurst = 10;
};
stopIfChanged = false;
}; };
})
}; };
};
} }

View file

@ -119,6 +119,8 @@ in {
scopeMaps."immich.access" = ["openid" "email" "profile"]; scopeMaps."immich.access" = ["openid" "email" "profile"];
preferShortUsername = true; preferShortUsername = true;
}; };
groups."netbird.access" = {
};
groups."forgejo.access" = { groups."forgejo.access" = {
members = ["forgejo.admins"]; members = ["forgejo.admins"];

View file

@ -0,0 +1,68 @@
{config, ...}: {
imports = [
../netbird-server.nix
../netbird-dashboard.nix
];
wireguard.elisabeth = {
client.via = "elisabeth";
firewallRuleForNode.elisabeth.allowedTCPPorts = [80 3000 3001];
};
networking.firewall.allowedTCPPorts = [80 3000 3001];
networking.firewall.allowedUDPPorts = [3478];
services.netbird-dashboard = {
enable = true;
enableNginx = true;
domain = "netbird.${config.secrets.secrets.global.domains.web}";
settings = {
AUTH_AUTHORITY = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/openid/netbird";
AUTH_CLIENT_ID = "netbird";
};
};
services.netbird-server = {
enable = true;
domain = "netbird.${config.secrets.secrets.global.domains.web}";
# TODO remove
oidcConfigEndpoint = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/openid/netbird/.well-known/openid-configuration";
singleAccountModeDomain = "netbird.patrick";
settings = {
HttpConfig = {
AuthIssuer = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/openid/netbird";
AuthKeysLocation = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/openid/netbird/public_key.jwk";
};
# Seems to be only useful for idp that netbird supports
IdpManagerConfig.ClientConfig = {
Issuer = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/openid/netbird";
TokenEndpoint = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/token";
};
DeviceAuthorizationFlow = {
Provider = "none";
ProviderConfig = {
AuthorizationEndpoint = "https://auth.${config.secrets.secrets.global.domains.web}/ui/oauth2/";
ClientID = "netbird";
#ClientSecret = "";
TokenEndpoint = "https://auth.${config.secrets.secrets.global.domains.web}/oauth2/token";
#RedirectURLs = ["http://localhost:53000"];
};
};
PKCEAuthorizationFlow.ProviderConfig = {
AuthorizationEndpoint = "https://auth.${config.secrets.secrets.global.domains.web}/ui/oauth2/";
};
};
};
services.coturn = {
enable = true;
realm = "netbird.${config.secrets.secrets.global.domains.web}";
lt-cred-mech = true;
no-cli = true;
extraConfig = ''
fingerprint
user=turn:netbird
no-software-attribute
external-ip=87.170.9.213
'';
};
}

Binary file not shown.

View file

@ -0,0 +1,16 @@
age-encryption.org/v1
-> X25519 zghXrLqQhlVqAAbMi1k8gvG5IjG9boIJCyEx63DwwGo
/ae8dzj7mPxZdpciA+lLiR6H/WCrIvTkUfaXGP+RZiY
-> piv-p256 XTQkUA A4PgmdpN1WmH++JUTIdADZBqDrCQ2N8HP9FzQ7DtyJuU
CIzSKNP8YYYfMycueE564094XeKJ9mNEceAuUEnvFFI
-> piv-p256 ZFgiIw AgxtRiqyF4Fo6Us/l8vXhWl2tQakCQGwd1Dogf/Wqnyv
Gi9O1lFR2hhfkXoC7cmlpT+iHx0DxeDFmuU9i+Gc4Ms
-> piv-p256 5vmPtQ AsbmH20Pc58VF7tBnoE5iqzlrsahCDTHkvuyAQ4W5SPy
BcJr9QsIDanypSNZ0UWrt0VnJK99LM0FOmCQWc+2rPY
-> piv-p256 ZFgiIw A5CT86jvz263c1GoDrtGVBXZx9EZeQwCL2d/tCXGqay3
8kHhsuD77fPPLPe8JYTuHNcCtp0VJcdrTg220BVdyGc
-> v-"@h-grease sJN %C \ ?mh0`=L
FarOmtacPX3pzMNzucQdNxI8MpVZdumJghhEPiukRJxp5+3InvEp7lvBhtZv49i3
QPoKNFjUweN6aXA9Vs1cpSQ
--- k49nSQRFr22Pc4QtH0WlYQ2/yMpBXSJasmQ97ZcxLkU
^sÛø¬hÈÊ<C388>LÜvÕçøí©++'•å8¶{ZŠïÀÑCÆðŽ}ö¯ZúPQ0U$¸±²¨þ•:YÀ—õ”ïËÊ1­NO l'

View file

@ -0,0 +1 @@
yv8nqlqgBxDIf6oYrn01FRKoKnqZPfdenWIFHxfSLiA=

View file

@ -0,0 +1,16 @@
age-encryption.org/v1
-> X25519 bq+eQrKzKWG2cvp+7cKzpkN7KEbxf4H8aSOBxOBNeVE
uiZloroeAw+q0T9CTGbAg6cdHShGaa5YOVk0iE5FLMM
-> piv-p256 XTQkUA A5CqoI0rxRrOyHv6LksBqtzWPapfCLi6IdK3KAUATzJF
d3VMdZpw0TjU8kZ6WNLcbvenDD4WWxJp2rEogNnW43o
-> piv-p256 ZFgiIw Ah/2IZobkAFu0r0rSHvB9RyQhXh+wk1R9Vlky8J44xib
5GXXZuXybVXcrpU8G8bWYwMOjnzdw7X+YjQaQlA1F4E
-> piv-p256 5vmPtQ AjmJ3ZgFxcbSbGefvufWZNzo0nOc8vl+4jA7kb5kwSbI
2ks2FzxZ/YloeAVCRT/0NEo4hRWzUbknj+pnwtGuEZM
-> piv-p256 ZFgiIw ApvFPxETdpXGYLa9srv+pKFHNOGfa7ie8oyOInKDbOqC
8rIukUZzrkWdH11pnTYfPd259ql/UGg5/Z6SuNvslUA
-> X=N9-grease CPXXj9j! Mf6?oC AuDyAWo z5x1TGOh
CYoYan7n
--- 9xwTgosTBqh7i3YCpHUhvkYV6bormJ3hYP4WHTwwQk4
íIˆy»0Ö[Ûž$ÞŒ‹Ž- ¦¨:k@™ Ê}é9 Ÿåµ
2òîl'*Ô­[Sêr$ÿ*ÅWjüBì,-w£RÒ1ãBý&ø!€.ó@