13 kB · 460 lines · Created 5mo ago
Nix
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460{ config, lib, pkgs, nodes, ...}:let domain = "netbird.forall.systems";
found_relay_domains = lib.mapAttrsToList (_: value: value.config.forallsys.netbird-relay) ( lib.filterAttrs ( _: value: (builtins.hasAttr "forallsys" value.config) && value.config.forallsys.netbird-relay.enable ) nodes );
client_id = "0d345520-cad2-42c1-8ec3-b1cc5fc7e8cf"; dashboard_fileserver_port = 8080;in{ systemd.services = { netbird-management = { requires = [ config.deployment.keys."relay_secret".service config.deployment.keys."data_store_encryption_key".service ]; serviceConfig = { EnvironmentFile = [ config.deployment.keys."management.env".path
# completely rely on id.althaea.zone to run the identity # https://docs.netbird.io/selfhosted/identity-providers/advanced/pocketid # # Cannot translate these into services.netbird.server.management.settings.IdpManagerConfig # because then it will never read the token from NETBIRD_IDP_MGMT_EXTRA_API_TOKEN (pkgs.writeText "pocketid.env" '' NETBIRD_TOKEN_SOURCE="idToken" NETBIRD_MGMT_IDP="pocketid" NETBIRD_IDP_MGMT_CLIENT_ID="netbird" NETBIRD_IDP_MGMT_EXTRA_MANAGEMENT_ENDPOINT="https://id.althaea.zone" '') ]; }; }; };
forallsys = { traefik-shared = true;
netbird-relay = { enable = true; enableProxy = true; domain = "netbird-fin.forall.systems"; }; };
services = { netbird = { server = { enable = true; inherit domain;
enableNginx = false;
dashboard = { enable = true; enableNginx = true; inherit domain; settings = { AUTH_AUTHORITY = "https://id.althaea.zone"; AUTH_CLIENT_ID = client_id; AUTH_AUDIENCE = client_id; USE_AUTH0 = false; NETBIRD_TOKEN_SOURCE = "idToken"; AUTH_SUPPORTED_SCOPES = "openid profile email groups"; AUTH_REDIRECT_URI = "/auth"; AUTH_SILENT_REDIRECT_URI = "/silent-auth"; }; };
signal = { enable = true; inherit domain; };
# replaced by netbird-relay coturn.enable = false;
management = { enable = true; inherit domain;
disableSingleAccountMode = true; oidcConfigEndpoint = "https://id.althaea.zone/.well-known/openid-configuration"; turnDomain = domain;
logLevel = "DEBUG";
settings = { Signal.URI = "${domain}:443";
PKCEAuthorizationFlow.ProviderConfig = { ClientID = client_id; Audience = client_id; Scope = "openid profile email groups";
# https://github.com/netbirdio/netbird/issues/3834#issuecomment-2887549087 # DisablePromptLogin = true; # UseIDToken = true;
RedirectURLs = [ "http://localhost:53000/" "http://localhost:54000/" "https://${domain}/auth" "https://${domain}/silent-auth" ]; };
HttpConfig = { AuthAudience = client_id; IdpSignKeyRefreshEnabled = true; # https://docs.netbird.io/selfhosted/migration/enable-reverse-proxy#step-1-add-callback-url-to-management-json-multi-container-only AuthClientId = client_id; AuthCallbackURL = "https://${domain}/api/reverse-proxy/callback"; };
DeviceAuthorizationFlow = { Provider = "none"; ProviderConfig = { ClientID = client_id; Audience = client_id; Scope = "openid profile email groups"; UseIDToken = true; }; };
TURNConfig = { Secret = ""; Turns = [ ]; };
Stuns = map (relay: { Proto = "udp"; URI = "stun:${relay.domain}:${toString relay.stun_port}"; }) found_relay_domains;
Relay = { Addresses = map (relay: "rels://${relay.domain}:443") found_relay_domains; CredentialsTTL = "12h"; Secret._secret = config.deployment.keys."relay_secret".path; };
DataStoreEncryptionKey._secret = config.deployment.keys."data_store_encryption_key".path; }; }; }; };
# stop the nginx config the dashboard module creates from listening on 80, instead # listen on 8080 locally. nginx.virtualHosts.${domain}.listen = [ { addr = "127.0.0.1"; port = dashboard_fileserver_port; } ];
traefik = { # values translated from https://docs.netbird.io/selfhosted/external-reverse-proxy#traefik-multi-container dynamicConfigOptions.http = { routers = let tls = { certResolver = "letsencrypt"; }; in { netbird-management-api = { rule = "Host(`${domain}`) && (PathPrefix(`/api`) || PathPrefix(`/api`))"; service = "netbird-api"; entryPoints = [ "websecure" ]; inherit tls; };
netbird-management-ws = { rule = "Host(`${domain}`) && PathPrefix(`/ws-proxy/management`)"; service = "netbird-mgmt-ws"; entryPoints = [ "websecure" ]; inherit tls; };
netbird-management-grpc = { rule = "Host(`${domain}`) && (PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))"; service = "netbird-mgmt-grpc"; entryPoints = [ "websecure" ]; inherit tls; };
netbird-signal-ws = { rule = "Host(`${domain}`) && PathPrefix(`/ws-proxy/signal`)"; service = "netbird-signal-ws"; entryPoints = [ "websecure" ]; inherit tls; };
netbird-signal-grpc = { rule = "Host(`${domain}`) && PathPrefix(`/signalexchange.SignalExchange/`)"; service = "netbird-signal-grpc"; entryPoints = [ "websecure" ]; inherit tls; };
netbird-dashboard = { rule = "Host(`${domain}`)"; service = "netbird-dashboard"; entryPoints = [ "websecure" ]; priority = 1; inherit tls; }; };
services = { netbird-api.loadBalancer.servers = [ { url = "http://127.0.0.1:${toString config.services.netbird.server.management.port}"; } ];
netbird-mgmt-ws.loadBalancer.servers = [ { url = "http://127.0.0.1:${toString config.services.netbird.server.management.port}"; } ];
netbird-mgmt-grpc.loadBalancer.servers = [ { url = "h2c://127.0.0.1:${toString config.services.netbird.server.management.port}"; } ];
netbird-signal-ws.loadBalancer.servers = [ { url = "http://127.0.0.1:${toString config.services.netbird.server.signal.port}"; } ];
netbird-signal-grpc.loadBalancer.servers = [ { url = "h2c://127.0.0.1:10000"; } ];
netbird-dashboard.loadBalancer.servers = [ { url = "http://127.0.0.1:${toString dashboard_fileserver_port}"; } ]; }; }; }; };}
{ config, pkgs, lib, ...}:let cfg = config.forallsys.netbird-relay; relay_port = 33080; proxy_port = 8443;in{ options = { forallsys.netbird-relay = { enable = lib.mkEnableOption "netbird remote relay"; enableProxy = lib.mkEnableOption "netbird remote proxy"; domain = lib.mkOption { type = lib.types.str; }; stun_port = lib.mkOption { type = lib.types.number; default = 3478; }; }; }; config = lib.mkMerge [ (lib.mkIf cfg.enable { deployment.keys = { "relay_secret" = { destDir = "/etc/keys"; source = [ "sops" "-d" "--extract" ''["netbird"]["relay_secret"]'' "${../secrets.yaml}" ]; }; "relay_secret_env" = { destDir = "/etc/keys"; source = [ "sops" "-d" "--extract" ''["netbird"]["relay_secret_env"]'' "${../secrets.yaml}" ]; }; };
networking.firewall.allowedUDPPorts = [ cfg.stun_port ];
# the relay is not in the module yet! systemd.services.netbird-relay = { enable = true; wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; serviceConfig = { ExecStart = "${pkgs.netbird-relay}/bin/netbird-relay --exposed-address rels://${cfg.domain}:443 --listen-address :${toString relay_port} --metrics-port 9092 --auth-secret $RELAY_SECRET --enable-stun --stun-log-level debug --stun-ports ${toString cfg.stun_port}"; Restart = "always"; EnvironmentFile = config.deployment.keys."relay_secret_env".path; }; };
forallsys.traefik-shared = true;
services.traefik = { dynamicConfigOptions.http = { routers.netbird-relay = { rule = "Host(`${cfg.domain}`) && PathPrefix(`/relay`)"; service = "netbird-relay"; entryPoints = [ "websecure" ]; tls = { certResolver = "letsencrypt"; }; };
services.netbird-relay.loadBalancer.servers = [ { url = "http://127.0.0.1:${toString relay_port}"; } ]; }; }; }) (lib.mkIf cfg.enableProxy { deployment.keys."proxy_secret_env" = { destDir = "/etc/keys"; source = [ "sops" "-d" "--extract" ''["netbird"]["proxy_secret_env"]'' "${../secrets.yaml}" ]; };
forallsys.traefik-shared = true;
virtualisation.oci-containers.containers.netbird-proxy = { image = "netbirdio/reverse-proxy:latest"; serviceName = "netbird-proxy"; ports = [ "127.0.0.1:${toString proxy_port}:${toString proxy_port}" ]; environmentFiles = [ config.deployment.keys."proxy_secret_env".path ]; environment = { NB_PROXY_DOMAIN = cfg.domain; NB_PROXY_MANAGEMENT_ADDRESS = "https://netbird.forall.systems:443"; NB_PROXY_ALLOW_INSECURE = "false"; NB_PROXY_ADDRESS = ":${toString proxy_port}"; NB_PROXY_ACME_CERTIFICATES = "true"; NB_PROXY_ACME_CHALLENGE_TYPE = "tls-alpn-01"; NB_PROXY_CERTIFICATE_DIRECTORY = "/certs"; NB_PROXY_DEBUG_LOGS = "true"; }; volumes = [ "netbird_proxy_certs:/certs" ]; extraOptions = [ "--network=host" ]; };
services.traefik = { dynamicConfigOptions.tcp = { routers.proxy-passthrough = { rule = "HostSNI(`*`)"; service = "proxy-tls"; entryPoints = [ "websecure" ]; priority = 1; tls = { passthrough = true; }; };
services.proxy-tls.loadBalancer.servers = [ { address = "127.0.0.1:${toString proxy_port}"; } ]; }; }; }) ];}
{ config, lib, ...}:let enabled = config.forallsys.traefik-shared;in{ options = { forallsys.traefik-shared = lib.mkEnableOption "shared traefik stuff"; };
config = lib.mkIf enabled { networking.firewall = { allowedTCPPorts = [ 80 443 ]; allowedUDPPorts = [ 443 ]; };
services.traefik = { enable = lib.mkDefault true;
staticConfigOptions = { entryPoints = lib.mkDefault { # redirect 80 to 443 web = { address = ":80"; http.redirections.entryPoint = { to = "websecure"; scheme = "https"; }; };
websecure = { address = ":443"; http.tls.certResolver = "letsencrypt"; # https://docs.netbird.io/selfhosted/migration/enable-reverse-proxy#3-increase-traefiks-idle-timeout-for-g-rpc transport.respondingTimeouts = { idleTimeout = 0;
# there appear to be issues with the latency between fin & aus, these seem to help? not sure. readTimeout = 0; writeTimeout = 0; }; }; };
certificatesResolvers = lib.mkDefault { letsencrypt = { acme = { email = "hostmaster@forall.systems"; storage = "${config.services.traefik.dataDir}/acme.json";
httpChallenge.entryPoint = "web"; }; }; }; }; }; };}