From 6a25ccbd1ade7b7db47ad9b50ed54bffa6bfe848 Mon Sep 17 00:00:00 2001 From: Tom Hubrecht Date: Sun, 3 Dec 2023 22:13:30 +0100 Subject: [PATCH] feat(netbird): Deploy management server on storage01 --- machines/compute01/kanidm/default.nix | 2 +- machines/storage01/_configuration.nix | 1 + machines/storage01/netbird/default.nix | 46 ++ machines/storage01/netbird/module.nix | 578 ++++++++++++++++++ .../storage01/netbird/package/dashboard.nix | 27 + .../storage01/netbird/package/default.nix | 5 + .../secrets/netbird-auth_client_secret_file | Bin 0 -> 1350 bytes machines/storage01/secrets/secrets.nix | 1 + 8 files changed, 659 insertions(+), 1 deletion(-) create mode 100644 machines/storage01/netbird/default.nix create mode 100644 machines/storage01/netbird/module.nix create mode 100644 machines/storage01/netbird/package/dashboard.nix create mode 100644 machines/storage01/netbird/package/default.nix create mode 100644 machines/storage01/secrets/netbird-auth_client_secret_file diff --git a/machines/compute01/kanidm/default.nix b/machines/compute01/kanidm/default.nix index 8f849de..0850ed3 100644 --- a/machines/compute01/kanidm/default.nix +++ b/machines/compute01/kanidm/default.nix @@ -5,7 +5,7 @@ let cert = config.security.acme.certs.${domain}; - allowedSubDomains = [ "cloud" "git" "videos" "social" "demarches" ]; + allowedSubDomains = [ "cloud" "git" "videos" "social" "demarches" "netbird" ]; in { services.kanidm = { enableServer = true; diff --git a/machines/storage01/_configuration.nix b/machines/storage01/_configuration.nix index e41d0b7..06db92a 100644 --- a/machines/storage01/_configuration.nix +++ b/machines/storage01/_configuration.nix @@ -11,6 +11,7 @@ lib.extra.mkConfig { "atticd" "forgejo" "garage" + "netbird" "peertube" ]; diff --git a/machines/storage01/netbird/default.nix b/machines/storage01/netbird/default.nix new file mode 100644 index 0000000..45acc7b --- /dev/null +++ b/machines/storage01/netbird/default.nix @@ -0,0 +1,46 @@ +{ config, ... }: + +let + domain = "netbird.dgnum.eu"; +in +{ + imports = [ ./module.nix ]; + + services.netbird-server = { + enable = true; + + logLevel = "DEBUG"; + enableDeviceAuthorizationFlow = false; + enableNginx = true; + enableCoturn = false; + setupAutoOidc = true; + + management.dnsDomain = "dgnum"; + + secretFiles.AUTH_CLIENT_SECRET = config.age.secrets."netbird-auth_client_secret_file".path; + + settings = { + NETBIRD_DOMAIN = domain; + + TURN_PASSWORD = "tototest1234"; + + NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT = "https://sso.dgnum.eu/oauth2/openid/netbird_dgn/.well-known/openid-configuration"; + NETBIRD_AUTH_PKCE_USE_ID_TOKEN = true; + + NETBIRD_AUTH_AUDIENCE = "netbird_dgn"; + NETBIRD_AUTH_CLIENT_ID = "netbird_dgn"; + # Updates the preference to use id tokens instead of access token on dashboard + # Okta and Gitlab IDPs can benefit from this + NETBIRD_TOKEN_SOURCE = "idToken"; + + # NETBIRD_AUTH_PKCE_REDIRECT_URLS = builtins.map (p: "http://localhost:${p}") [ + # "53000" + # "54000" + # ]; + + NETBIRD_STORE_CONFIG_ENGINE = "sqlite"; + }; + }; + + # dgn-secrets.matches."^netbird-.*$" = { owner = "netbird"; }; +} diff --git a/machines/storage01/netbird/module.nix b/machines/storage01/netbird/module.nix new file mode 100644 index 0000000..c0d47ad --- /dev/null +++ b/machines/storage01/netbird/module.nix @@ -0,0 +1,578 @@ +{ config, lib, pkgs, ... }: +let + inherit (lib) + filterAttrs literalExpression maintainers mkDefault mkEnableOption mkIf + mkMerge mkOption optionalAttrs optionalString optionals types; + + inherit ((import ./package { inherit pkgs; })) dashboard; + + cfg = config.services.netbird-server; + + stateDir = "/var/lib/netbird-mgmt"; + + settingsFormat = pkgs.formats.keyValue { }; + managementFormat = pkgs.formats.json { }; + + settingsFile = settingsFormat.generate "setup.env" (builtins.mapAttrs (_: val: + if builtins.isList val then + ''"${builtins.concatStringsSep " " val}"'' + else + val) settings); + + managementFile = managementFormat.generate "config.json" cfg.managementConfig; + + settings = rec { + TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; + TURN_PORT = 3478; + TURN_USER = "netbird"; + TURN_MIN_PORT = 49152; + TURN_MAX_PORT = 65535; + TURN_PASSWORD = + if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null; + TURN_SECRET = + if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret"; + + STUN_USERNAME = ""; + STUN_PASSWORD = + if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null; + + NETBIRD_DASHBOARD_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:443"; + NETBIRD_MGMT_API_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ + builtins.toString + cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT + }"; + NETBIRD_SIGNAL_ENDPOINT = "https://${cfg.settings.NETBIRD_DOMAIN}:${ + builtins.toString + cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT + }"; + + NETBIRD_SIGNAL_PROTOCOL = "https"; + NETBIRD_SIGNAL_PORT = 443; + + NETBIRD_AUTH_USER_ID_CLAIM = "sub"; + NETBIRD_AUTH_CLIENT_SECRET = + if cfg.secretFiles.AUTH_CLIENT_SECRET != null then + "$AUTH_CLIENT_SECRET" + else + ""; + NETBIRD_AUTH_SUPPORTED_SCOPES = + [ "openid" "profile" "email" "offline_access" "api" ]; + + NETBIRD_AUTH_REDIRECT_URI = ""; + NETBIRD_AUTH_SILENT_REDIRECT_URI = ""; + + NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none"; + NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE; + NETBIRD_AUTH_DEVICE_AUTH_SCOPE = + [ "openid" "profile" "email" "offline_access" "api" ]; + NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false; + + NETBIRD_MGMT_API_PORT = 443; + + NETBIRD_MGMT_IDP = "none"; + NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_IDP_MGMT_CLIENT_SECRET = + if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then + "$IDP_MGMT_CLIENT_SECRET" + else + cfg.settings.NETBIRD_AUTH_CLIENT_SECRET; + NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials"; + + NETBIRD_TOKEN_SOURCE = "accessToken"; + NETBIRD_DRAG_QUERY_PARAMS = false; + + NETBIRD_USE_AUTH0 = false; + + NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = ""; + + NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ]; + NETBIRD_AUTH_PKCE_REDIRECT_URLS = builtins.map (p: "http://localhost:${p}") + cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS; + } // (optionalAttrs cfg.setupAutoOidc { + NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT = + "$NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT"; + NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = "$NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT"; + NETBIRD_AUTH_TOKEN_ENDPOINT = "$NETBIRD_AUTH_TOKEN_ENDPOINT"; + NETBIRD_AUTH_JWT_CERTS = "$NETBIRD_AUTH_JWT_CERTS"; + NETBIRD_AUTH_AUTHORITY = "$NETBIRD_AUTH_AUTHORITY"; + }) // cfg.settings; +in { + meta = { maintainers = with maintainers; [ thubrecht ]; }; + + options.services.netbird-server = { + enable = mkEnableOption (lib.mdDoc "netbird management service."); + + package = mkOption { + type = types.package; + default = pkgs.netbird; + defaultText = literalExpression "pkgs.netbird"; + description = lib.mdDoc "The package to use for netbird"; + }; + + settings = mkOption { + type = with types; + attrsOf (nullOr (oneOf [ (listOf str) bool int float str ])); + defaultText = lib.literalExpression '' + { + TURN_DOMAIN = cfg.settings.NETBIRD_DOMAIN; + TURN_PORT = 3478; + TURN_USER = "netbird"; + TURN_MIN_PORT = 49152; + TURN_MAX_PORT = 65535; + TURN_PASSWORD = if cfg.secretFiles.TURN_PASSWORD != null then "$TURN_PASSWORD" else null; + TURN_SECRET = if cfg.secretFiles.TURN_SECRET != null then "$TURN_SECRET" else "secret"; + + STUN_USERNAME = ""; + STUN_PASSWORD = if cfg.secretFiles.STUN_PASSWORD != null then "$STUN_PASSWORD" else null; + + NETBIRD_DASHBOARD_ENDPOINT = "https://''${cfg.settings.NETBIRD_DOMAIN}:443"; + NETBIRD_MGMT_API_ENDPOINT = "https://''${cfg.settings.NETBIRD_DOMAIN}:''${builtins.toString cfg.settings.NETBIRD_MGMT_API_PORT or NETBIRD_MGMT_API_PORT}"; + NETBIRD_SIGNAL_ENDPOINT = "https://''${cfg.settings.NETBIRD_DOMAIN}:''${builtins.toString cfg.settings.NETBIRD_SIGNAL_PORT or NETBIRD_SIGNAL_PORT}"; + + NETBIRD_SIGNAL_PROTOCOL = "https"; + NETBIRD_SIGNAL_PORT = 443; + + NETBIRD_AUTH_USER_ID_CLAIM = "sub"; + NETBIRD_AUTH_CLIENT_SECRET = if cfg.secretFiles.AUTH_CLIENT_SECRET != null then "$AUTH_CLIENT_SECRET" else ""; + NETBIRD_AUTH_SUPPORTED_SCOPES = [ "openid" "profile" "email" "offline_access" "api" ]; + + NETBIRD_AUTH_REDIRECT_URI = ""; + NETBIRD_AUTH_SILENT_REDIRECT_URI = ""; + + NETBIRD_AUTH_DEVICE_AUTH_PROVIDER = "none"; + NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE = cfg.settings.NETBIRD_AUTH_AUDIENCE; + NETBIRD_AUTH_DEVICE_AUTH_SCOPE = [ "openid" "profile" "email" "offline_access" "api" ]; + NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN = false; + + NETBIRD_MGMT_API_PORT = 443; + + NETBIRD_MGMT_IDP = "none"; + NETBIRD_IDP_MGMT_CLIENT_ID = cfg.settings.NETBIRD_AUTH_CLIENT_ID; + NETBIRD_IDP_MGMT_CLIENT_SECRET = if cfg.secretFiles.IDP_MGMT_CLIENT_SECRET != null then "$IDP_MGMT_CLIENT_SECRET" else cfg.settings.NETBIRD_AUTH_CLIENT_SECRET; + NETBIRD_IDP_MGMT_GRANT_TYPE = "client_credentials"; + + NETBIRD_TOKEN_SOURCE = "accessToken"; + NETBIRD_DRAG_QUERY_PARAMS = false; + + NETBIRD_USE_AUTH0 = false; + + NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT = ""; + + NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS = [ "53000" ]; + NETBIRD_AUTH_PKCE_REDIRECT_URLS = builtins.map (p: "http://localhost:''${p}") cfg.settings.NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS or NETBIRD_AUTH_PKCE_REDIRECT_URL_PORTS; + } + ''; + description = lib.mdDoc '' + Configuration settings for netbird. + Example config values can be found in [setup.env.example](https://github.com/netbirdio/netbird/blob/main/infrastructure_files/setup.env.example) + List of strings [ a b ] will be concatenated as "a b", useful for setting the supported scopes. + ''; + }; + + managementConfig = mkOption { + inherit (managementFormat) type; + description = lib.mdDoc "Configuration of the netbird management server."; + }; + + idpManagerExtraConfig = mkOption { + type = types.attrsOf types.str; + default = { }; + description = lib.mdDoc "Extra options passed to the IdpManagerConfig."; + }; + + ports.management = mkOption { + type = types.port; + default = 8011; + description = lib.mdDoc "Internal port of the management server."; + }; + + ports.signal = mkOption { + type = types.port; + default = 8012; + description = lib.mdDoc "Internal port of the signal server."; + }; + + logLevel = mkOption { + type = types.enum [ "ERROR" "WARN" "INFO" "DEBUG" ]; + default = "INFO"; + description = lib.mdDoc "Log level of the netbird services."; + }; + + enableDeviceAuthorizationFlow = + mkEnableOption "device authorization flow for netbird." // { + default = true; + }; + + enableNginx = mkEnableOption "NGINX reverse-proxy for the netbird server."; + + enableCoturn = mkEnableOption "a Coturn server used for Netbird."; + + setupAutoOidc = mkEnableOption "the automatic setup of the OIDC."; + + management = { + + dnsDomain = mkOption { + type = types.str; + default = "netbird.selfhosted"; + description = lib.mdDoc "Domain used for peer resolution."; + }; + + singleAccountModeDomain = mkOption { + type = types.str; + default = "netbird.selfhosted"; + description = lib.mdDoc '' + Enables single account mode. + This means that all the users will be under the same account grouped by the specified domain. + If the installation has more than one account, the property is ineffective. + ''; + }; + + disableAnonymousMetrics = mkOption { + type = types.bool; + default = true; + description = + lib.mdDoc "Disables push of anonymous usage metrics to NetBird."; + }; + + disableSingleAccountMode = mkOption { + type = types.bool; + default = false; + description = lib.mdDoc '' + If set to true, disables single account mode. + The `singleAccountModeDomain` property will be ignored and every new user will have a separate NetBird account. + ''; + }; + }; + + secretFiles = { + TURN_PASSWORD = mkOption { + type = with types; nullOr path; + default = null; + description = + lib.mdDoc "Path to a file containing the secret TURN_PASSWORD."; + }; + + TURN_SECRET = mkOption { + type = with types; nullOr path; + default = null; + description = + lib.mdDoc "Path to a file containing the secret TURN_SECRET."; + }; + + STUN_PASSWORD = mkOption { + type = with types; nullOr path; + default = null; + description = + lib.mdDoc "Path to a file containing the secret STUN_PASSWORD."; + }; + + AUTH_CLIENT_SECRET = mkOption { + type = with types; nullOr path; + default = null; + description = lib.mdDoc + "Path to a file containing the secret NETBIRD_AUTH_CLIENT_SECRET."; + }; + + IDP_MGMT_CLIENT_SECRET = mkOption { + type = with types; nullOr path; + default = cfg.secretFiles.AUTH_CLIENT_SECRET; + defaultText = + lib.literalExpression "cfg.secretFiles.AUTH_CLIENT_SECRET;"; + description = lib.mdDoc + "Path to a file containing the secret NETBIRD_IDP_MGMT_CLIENT_SECRET."; + }; + }; + }; + + config = mkMerge [ + (mkIf cfg.enable { + services.netbird-server.managementConfig = with settings; { + Stuns = mkDefault [{ + Proto = "udp"; + URI = "stun:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; + Username = STUN_USERNAME; + Password = STUN_PASSWORD; + }]; + TURNConfig = { + Turns = [{ + Proto = "udp"; + URI = "turn:${TURN_DOMAIN}:${builtins.toString TURN_PORT}"; + Username = TURN_USER; + Password = TURN_PASSWORD; + }]; + CredentialsTTL = "12h"; + Secret = TURN_SECRET; + TimeBasedCredentials = false; + }; + Signal = { + Proto = NETBIRD_SIGNAL_PROTOCOL; + URI = "${NETBIRD_DOMAIN}:${builtins.toString NETBIRD_SIGNAL_PORT}"; + Username = ""; + Password = null; + }; + Datadir = "${stateDir}/data"; + HttpConfig = { + Address = "127.0.0.1:${builtins.toString cfg.ports.management}"; + AuthIssuer = NETBIRD_AUTH_AUTHORITY; + AuthAudience = NETBIRD_AUTH_AUDIENCE; + AuthKeysLocation = NETBIRD_AUTH_JWT_CERTS; + AuthUserIDClaim = NETBIRD_AUTH_USER_ID_CLAIM; + OIDCConfigEndpoint = NETBIRD_AUTH_OIDC_CONFIGURATION_ENDPOINT; + }; + IdpManagerConfig = { + ManagerType = NETBIRD_MGMT_IDP; + ClientConfig = { + Issuer = NETBIRD_AUTH_AUTHORITY; + TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT; + ClientID = NETBIRD_IDP_MGMT_CLIENT_ID; + ClientSecret = NETBIRD_IDP_MGMT_CLIENT_SECRET; + GrantType = NETBIRD_IDP_MGMT_GRANT_TYPE; + }; + ExtraConfig = cfg.idpManagerExtraConfig; + }; + DeviceAuthorizationFlow = mkIf cfg.enableDeviceAuthorizationFlow { + Provider = NETBIRD_AUTH_DEVICE_AUTH_PROVIDER; + ProviderConfig = { + Audience = NETBIRD_AUTH_DEVICE_AUTH_AUDIENCE; + Domain = NETBIRD_AUTH_AUTHORITY; + ClientID = NETBIRD_AUTH_DEVICE_AUTH_CLIENT_ID; + TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT; + DeviceAuthEndpoint = NETBIRD_AUTH_DEVICE_AUTH_ENDPOINT; + Scope = + builtins.concatStringsSep " " NETBIRD_AUTH_DEVICE_AUTH_SCOPE; + UseIDToken = NETBIRD_AUTH_DEVICE_AUTH_USE_ID_TOKEN; + }; + }; + PKCEAuthorizationFlow = { + ProviderConfig = { + Audience = NETBIRD_AUTH_AUDIENCE; + ClientID = NETBIRD_AUTH_CLIENT_ID; + ClientSecret = NETBIRD_AUTH_CLIENT_SECRET; + AuthorizationEndpoint = NETBIRD_AUTH_PKCE_AUTHORIZATION_ENDPOINT; + TokenEndpoint = NETBIRD_AUTH_TOKEN_ENDPOINT; + Scope = builtins.concatStringsSep " " NETBIRD_AUTH_SUPPORTED_SCOPES; + RedirectURLs = NETBIRD_AUTH_PKCE_REDIRECT_URLS; + UseIDToken = NETBIRD_AUTH_PKCE_USE_ID_TOKEN; + }; + }; + }; + + services.nginx.virtualHosts = mkIf cfg.enableNginx { + ${cfg.settings.NETBIRD_DOMAIN} = { + forceSSL = true; + enableACME = true; + + locations = { + "/" = { + root = "${stateDir}/web-ui/"; + tryFiles = "$uri /index.html"; + }; + + "/signalexchange.SignalExchange/".extraConfig = '' + grpc_pass grpc://localhost:${builtins.toString cfg.ports.signal}; + grpc_read_timeout 1d; + grpc_send_timeout 1d; + grpc_socket_keepalive on; + ''; + + "/api".proxyPass = + "http://localhost:${builtins.toString cfg.ports.management}"; + + "/management.ManagementService/".extraConfig = '' + grpc_pass grpc://localhost:${ + builtins.toString cfg.ports.management + }; + grpc_read_timeout 1d; + grpc_send_timeout 1d; + grpc_socket_keepalive on; + ''; + }; + }; + }; + + systemd.services = { + netbird-setup = { + wantedBy = [ + "netbird-management.service" + "netbird-signal.service" + "multi-user.target" + ]; + serviceConfig = { + Type = "oneshot"; + RuntimeDirectory = "netbird-mgmt"; + StateDirectory = "netbird-mgmt"; + WorkingDirectory = stateDir; + EnvironmentFile = [ settingsFile ]; + }; + unitConfig = { + StartLimitInterval = 5; + StartLimitBurst = 10; + }; + + path = (with pkgs; [ coreutils findutils gettext gnused ]) + ++ (optionals cfg.setupAutoOidc (with pkgs; [ curl jq ])); + + script = '' + cp ${managementFile} ${stateDir}/management.json.copy + '' + (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' < ${stateDir}/management.json.copy > ${stateDir}/management.json + + rm -rf ${stateDir}/web-ui + mkdir -p ${stateDir}/web-ui + cp -R ${dashboard}/* ${stateDir}/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 ${stateDir}/web-ui/static/js/main.*js) + OIDC_TRUSTED_DOMAINS=${stateDir}/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" + ''; + }; + + netbird-signal = { + after = [ "network.target" ]; + 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 = stateDir; + }; + 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; + }; + }; + }) + + (mkIf cfg.enableCoturn { + services.coturn = { + enable = true; + + realm = settings.NETBIRD_DOMAIN; + lt-cred-mech = true; + no-cli = true; + + extraConfig = '' + fingerprint + + user=${settings.TURN_USER}:${builtins.toString settings.TURN_PASSWORD} + no-software-attribute + ''; + }; + + networking.firewall = { + allowedUDPPorts = with settings; [ + TURN_PORT + (TURN_PORT + 1) + 5349 + 5350 + ]; + allowedTCPPorts = with settings; [ TURN_PORT (TURN_PORT + 1) ]; + allowedUDPPortRanges = [{ + from = settings.TURN_MIN_PORT; + to = settings.TURN_MAX_PORT; + }]; + }; + }) + + (mkIf (cfg.enableNginx && cfg.enableCoturn) { + services.coturn = + let cert = config.security.acme.certs.${settings.TURN_DOMAIN}; + in { + cert = "${cert.directory}/fullchain.pem"; + pkey = "${cert.directory}/key.pem"; + }; + + users.users.nginx.extraGroups = [ "turnserver" ]; + + # share certs with coturn and restart on renewal + security.acme.certs.${settings.TURN_DOMAIN} = { + group = "turnserver"; + postRun = + "systemctl reload nginx.service; systemctl restart coturn.service"; + }; + }) + ]; +} diff --git a/machines/storage01/netbird/package/dashboard.nix b/machines/storage01/netbird/package/dashboard.nix new file mode 100644 index 0000000..7b27166 --- /dev/null +++ b/machines/storage01/netbird/package/dashboard.nix @@ -0,0 +1,27 @@ +{ lib, buildNpmPackage, fetchFromGitHub }: + +buildNpmPackage rec { + pname = "netbird-dashboard"; + version = "1.17.6"; + + src = fetchFromGitHub { + owner = "netbirdio"; + repo = "dashboard"; + rev = "v${version}"; + hash = "sha256-MDxN/58dv6OqPYnNgDVZ+YRzfw2dER7x8mEWe14rQ40="; + }; + + npmDepsHash = "sha256-x7YyzBPAiXyxaIcAvUrXBexYaw0TaYnKgQKT3KadW8w="; + npmFlags = [ "--legacy-peer-deps" ]; + + installPhase = '' + cp -R build $out + ''; + + meta = with lib; { + description = "NetBird Management Service Web UI Panel"; + homepage = "https://github.com/netbirdio/dashboard"; + license = licenses.bsd3; + maintainers = with maintainers; [ thubrecht ]; + }; +} diff --git a/machines/storage01/netbird/package/default.nix b/machines/storage01/netbird/package/default.nix new file mode 100644 index 0000000..40c4992 --- /dev/null +++ b/machines/storage01/netbird/package/default.nix @@ -0,0 +1,5 @@ +{ pkgs ? import {} }: + +{ + dashboard = pkgs.callPackage ./dashboard.nix { }; +} diff --git a/machines/storage01/secrets/netbird-auth_client_secret_file b/machines/storage01/secrets/netbird-auth_client_secret_file new file mode 100644 index 0000000000000000000000000000000000000000..177c27b0eea6e23cd20cbe0106bf7c98a8690c00 GIT binary patch literal 1350 zcmZA0JFDb$7{_rfw1~KiY-1(UN;sR#%p?;KA(u%qNoJD&Os<1X?vqUJ*U4xhz5**7 z3$c(@JMC-)3kyrj1sf48WEU*ftrR>K$6{Z>=i&G8b>r|REc|Awx}+=~mQ9Qd7VSq1}7&U9eveU z+^|AlHH#ib_E=KrFB=0kw1bem0h)jP5o zmic`%ZUyv2Y+53&6q@5*Nk1~X{l?t9s5NjQBVabtGQ6n>`v};A6l<&^B8gfs0?Td} z3z4${RRBAWSvqYYS=#wS+938S2dcfG3VziO6)=#EcoiL807UKdrAG%keWx|8J3BWP zs{lwHTLw*c7JJkKd=4M|xL|xNpVV{Ec4tmpgHtf_X+6s(<~wO`I%9f;`}rO^TRax=H;y0qZ%{2C3~SfXvd3m ztg^o0_y>(SpIjqbpkvZcylv`|hPMpCAE+2!9f#3vT8^q?lLB4hIbv9n+at6A!$dZv zjRXoa_)V7QCZeF5tKV{kGNQtE#qq0)naSmP=r(sOn@c(PyRe}s7@WD*#v?faEh7>?j`GSVZ1qB*c(a0jSVo)G?DI(dpt zM#s$6q{@irUDW5R6{|-kU9_ZK0sVBnopJJZqJv#U^zOHJ8oH;*+e+|&GeQCmECc7( zsMQ_P@Ra(wXps)WVWoxo_!b*`JBb(2oKSWw$6J%VpD-~P%W+-W!^L#=x*SfRN~_w@ zqoZ>Ls~0s%xRASe#_&Y1k)tIaZ`&MbTgVmLNUcyK%5@f;s%GVJl$VyM?m&C)nsya| zui;+Mf^E=gS!kZejlspkMUXc&mKTd6^JFvrPm5fCc@sCG+lCOD6w=D{j>^WO6XkR| zEHPW)uQkEgWf7W+gWB68x|;04aXI2P>6@EbTlvx4sP~SXN)Y*C``Oq)-Uw!)c(WejO=g(dXKYL?*bP31z{}F!vuKex8pB{hkMVgK}%e*rrI B!JYsB literal 0 HcmV?d00001 diff --git a/machines/storage01/secrets/secrets.nix b/machines/storage01/secrets/secrets.nix index f9aa867..c7683b9 100644 --- a/machines/storage01/secrets/secrets.nix +++ b/machines/storage01/secrets/secrets.nix @@ -6,6 +6,7 @@ in lib.setDefault { inherit publicKeys; } [ "atticd-credentials_file" "forgejo-database_password_file" "garage-environment_file" + "netbird-auth_client_secret_file" "peertube-secrets_file" "peertube-service_environment_file" "peertube-smtp_password_file"