nix-config/modules/netbird-server.nix
Patrick f9990eb01c
fix: samba wireguard access
feat: netbird samba host
2024-03-28 14:40:40 +01:00

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;
};
};
};
}