334 lines
10 KiB
Nix
334 lines
10 KiB
Nix
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
...
|
|
}: let
|
|
inherit
|
|
(lib)
|
|
mkEnableOption
|
|
mkOption
|
|
types
|
|
mkPackageOption
|
|
mkIf
|
|
;
|
|
cfg = config.services.netbird-server;
|
|
|
|
configFile = formatType.generate "config.json" cfg.settings;
|
|
|
|
formatType = pkgs.formats.json {};
|
|
in {
|
|
options.services.netbird-server = {
|
|
enable = mkEnableOption "netbird, a self hosted wireguard VPN";
|
|
package = mkPackageOption pkgs "netbird" {};
|
|
enableCoturn = mkEnableOption "the coturn service for running the TURN/STUN server";
|
|
domain = mkOption {
|
|
type = types.str;
|
|
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 {
|
|
type = types.str;
|
|
example = "https://example.eu.auth0.com/.well-known/openid-configuration";
|
|
description = "The oidc discovery endpoint";
|
|
};
|
|
signalPort = mkOption {
|
|
description = "The listening port for the signal protocol";
|
|
default = 3001;
|
|
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 = {
|
|
domain = mkOption {
|
|
description = "The domain under which the TURN server is reachable";
|
|
type = types.str;
|
|
example = "localhost";
|
|
default = cfg.domain;
|
|
};
|
|
port = mkOption {
|
|
description = "The port under which the TURN server is reachable";
|
|
type = types.port;
|
|
default = 3478;
|
|
};
|
|
userName = mkOption {
|
|
description = "The Username for logging into your turn server";
|
|
type = types.str;
|
|
default = "netbird";
|
|
};
|
|
password = mkOption {
|
|
description = "The password for logging into your turn server";
|
|
type = types.str;
|
|
default = lib.trace "should not be part of the final config" "netbird";
|
|
};
|
|
};
|
|
settings = mkOption {
|
|
default = {};
|
|
description = ''
|
|
This will be converted to json and used as the management config.
|
|
Sadly the exact configuration is undocumented there only exists
|
|
this [template](https://github.com/netbirdio/netbird/blob/main/infrastructure_files/management.json.tmpl)
|
|
The default values are usable, for a normal setup you don't need to set anything here.
|
|
Be advised that any secret you set in here will be in the nix store
|
|
and thus world readable. For compliant setups you don't need these secrets
|
|
as you should use a oidc public client, some client, e.g. google do not support
|
|
this without a secret, which is why you sometimes need to set a secret here.
|
|
This is not a problem as this secret will be exposed on your server publicly and only allows
|
|
client to initiate a authorization flow.
|
|
Even though the template contains oidc values you don't need to set any except for the
|
|
ConfigEndpoint as netbird will fetch the rest.
|
|
'';
|
|
type = types.submodule {
|
|
freeformType = formatType.type;
|
|
config = {
|
|
Stuns = [
|
|
{
|
|
Proto = "udp";
|
|
Uri = "stun:${cfg.turn.domain}:${toString cfg.turn.port}";
|
|
# TODO fairly certain with this config anyone can use your STUN server
|
|
Username = "";
|
|
Password = null;
|
|
}
|
|
];
|
|
TURNConfig = {
|
|
Turns = [
|
|
{
|
|
Proto = "udp";
|
|
Uri = "turn:${cfg.turn.domain}:${toString cfg.turn.port}";
|
|
Username = cfg.turn.userName;
|
|
Password = cfg.turn.password;
|
|
}
|
|
];
|
|
CredentialsTTL = "12h";
|
|
# This is not used with the standard coturn configuration
|
|
Secret = "secret";
|
|
TimeBasedCredentials = false;
|
|
};
|
|
|
|
Signal = {
|
|
Proto = "https";
|
|
URI = "${cfg.domain}:443";
|
|
Username = "";
|
|
Password = null;
|
|
};
|
|
ReverseProxy = {
|
|
TrustedHTTPProxies = [];
|
|
TrustedHTTPProxiesCount = 0;
|
|
TrustedPeers = [
|
|
"0.0.0.0/0"
|
|
];
|
|
};
|
|
Datadir = "/var/lib/netbird-mgmt";
|
|
DataStoreEncryptionKey = lib.trace "uppsi wuppsi ich hab mein netbird unsiccccccher gemacht" "X4/obyAolDVhjGsz8NDb4TJqgCfwmCA7lOtJFHt9L3w=";
|
|
StoreConfig = {
|
|
Engine = "sqlite";
|
|
};
|
|
HttpConfig = {
|
|
Address = "0.0.0.0:${toString cfg.port}";
|
|
AuthAudience = "netbird";
|
|
AuthUserIDClaim = "preferred_username";
|
|
OIDCConfigEndpoint = cfg.oidcConfigEndpoint;
|
|
};
|
|
IdpManagerConfig = {
|
|
ManagerType = "none";
|
|
};
|
|
DeviceAuthorizationFlow = {
|
|
ProviderConfig = {
|
|
Audience = "netbird";
|
|
Scope = "openid profile email";
|
|
};
|
|
};
|
|
PKCEAuthorizationFlow = {
|
|
ProviderConfig = {
|
|
Audience = "netbird";
|
|
ClientID = "netbird";
|
|
ClientSecret = "";
|
|
Domain = "";
|
|
Scope = "openid profile email";
|
|
RedirectURLs = ["http://localhost:53000"];
|
|
UseIDToken = true;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
config = mkIf cfg.enable {
|
|
services.coturn = mkIf cfg.enableCoturn {
|
|
enable = true;
|
|
|
|
realm = cfg.dorain;
|
|
lt-cred-mech = true;
|
|
no-cli = true;
|
|
|
|
# Official documentation says that external-ip has to be
|
|
# an IP which is not true as [this](https://github.com/coturn/coturn/blob/9b1cca1fbe909e7cc7c7ac28865f9c190af3515b/src/client/ns_turn_ioaddr.c#L234)
|
|
# will resolve a dns name as well
|
|
extraConfig = ''
|
|
fingerprint
|
|
|
|
user=${cfg.turn.userName}:${cfg.turn.password}
|
|
no-software-attribute
|
|
external-ip=${cfg.domain}
|
|
'';
|
|
};
|
|
systemd.services = {
|
|
netbird-signal = {
|
|
after = ["network.target"];
|
|
wantedBy = ["netbird-management.service"];
|
|
restartTriggers = [
|
|
configFile
|
|
];
|
|
|
|
serviceConfig = {
|
|
ExecStart = ''
|
|
${cfg.package}/bin/netbird-signal run \
|
|
--log-file console \
|
|
--port ${builtins.toString cfg.signalPort}
|
|
'';
|
|
Restart = "always";
|
|
RuntimeDirectory = "netbird-mgmt";
|
|
StateDirectory = "netbird-mgmt";
|
|
WorkingDirectory = "/var/lib/netbird-mgmt";
|
|
RestartSec = "60";
|
|
|
|
# hardening
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = true;
|
|
NoNewPrivileges = true;
|
|
PrivateMounts = true;
|
|
PrivateTmp = true;
|
|
ProtectClock = true;
|
|
ProtectControlGroups = true;
|
|
ProtectHome = true;
|
|
ProtectHostname = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectKernelModules = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectSystem = true;
|
|
RemoveIPC = true;
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
|
|
# Hardening
|
|
#CapabilityBoundingSet = "";
|
|
#PrivateUsers = true;
|
|
#ProtectProc = "invisible";
|
|
#ProcSubset = "pid";
|
|
#RestrictAddressFamilies = [
|
|
# "AF_INET"
|
|
# "AF_INET6"
|
|
# "AF_NETLINK"
|
|
#];
|
|
#SystemCallArchitectures = "native";
|
|
#SystemCallFilter = [
|
|
# "@system-service"
|
|
# "@pkey"
|
|
#];
|
|
UMask = "0077";
|
|
};
|
|
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 = [
|
|
configFile
|
|
];
|
|
|
|
serviceConfig = {
|
|
# Should we automatically disable metrics?
|
|
ExecStart = ''
|
|
${cfg.package}/bin/netbird-mgmt management \
|
|
--config ${configFile} \
|
|
--datadir /var/lib/netbird-mgmt/data \
|
|
--disable-anonymous-metrics=true \
|
|
${
|
|
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 console
|
|
'';
|
|
# TODO add extraCommandLine option
|
|
Restart = "always";
|
|
RuntimeDirectory = "netbird-mgmt";
|
|
StateDirectory = [
|
|
"netbird-mgmt"
|
|
"netbird-mgmt/data"
|
|
];
|
|
WorkingDirectory = "/var/lib/netbird-mgmt";
|
|
|
|
# hardening
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = true;
|
|
NoNewPrivileges = true;
|
|
PrivateMounts = true;
|
|
PrivateTmp = true;
|
|
ProtectClock = true;
|
|
ProtectControlGroups = true;
|
|
ProtectHome = true;
|
|
ProtectHostname = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectKernelModules = true;
|
|
ProtectKernelTunables = true;
|
|
ProtectSystem = true;
|
|
RemoveIPC = true;
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
|
|
# Hardening
|
|
CapabilityBoundingSet = "";
|
|
PrivateUsers = true;
|
|
ProtectProc = "invisible";
|
|
ProcSubset = "pid";
|
|
RestrictAddressFamilies = [
|
|
"AF_INET"
|
|
"AF_INET6"
|
|
"AF_NETLINK"
|
|
];
|
|
SystemCallArchitectures = "native";
|
|
SystemCallFilter = [
|
|
"@system-service"
|
|
"@pkey"
|
|
];
|
|
UMask = "0077";
|
|
};
|
|
unitConfig = {
|
|
StartLimitInterval = 5;
|
|
StartLimitBurst = 10;
|
|
};
|
|
stopIfChanged = false;
|
|
};
|
|
};
|
|
};
|
|
}
|