feat: add netbird (and coturn)

This commit is contained in:
oddlama 2024-05-15 22:17:21 +02:00
parent 4f3a379b3f
commit 9daa744334
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
32 changed files with 372 additions and 5 deletions

81
hosts/sentinel/coturn.nix Normal file
View file

@ -0,0 +1,81 @@
{
config,
lib,
pkgs,
...
}: let
inherit
(lib)
getExe
mkAfter
mkForce
;
hostDomain = config.repo.secrets.global.domains.me;
coturnDomain = "coturn.${hostDomain}";
in {
age.secrets.coturn-password-netbird = {
generator.script = "alnum";
group = "turnserver";
mode = "440";
};
networking.firewall.allowedUDPPorts = [
config.services.coturn.listening-port
config.services.coturn.alt-listening-port
config.services.coturn.tls-listening-port
config.services.coturn.alt-tls-listening-port
];
networking.firewall.allowedTCPPorts = [
config.services.coturn.listening-port
config.services.coturn.alt-listening-port
config.services.coturn.tls-listening-port
config.services.coturn.alt-tls-listening-port
];
networking.firewall.allowedUDPPortRanges = [
{
from = config.services.coturn.min-port;
to = config.services.coturn.max-port;
}
];
networking.providedDomains.coturn = coturnDomain;
services.coturn = {
enable = true;
realm = coturnDomain;
lt-cred-mech = true;
no-cli = true;
extraConfig = ''
fingerprint
user=netbird:@password@
no-software-attribute
'';
cert = "@cert@";
pkey = "@pkey@";
};
systemd.services.coturn = let
certsDir = config.security.acme.certs.${hostDomain}.directory;
in {
preStart = mkAfter ''
${getExe pkgs.replace-secret} @password@ ${config.age.secrets.coturn-password-netbird.path} /run/coturn/turnserver.cfg
${getExe pkgs.replace-secret} @cert@ <(echo "$CREDENTIALS_DIRECTORY/cert.pem") /run/coturn/turnserver.cfg
${getExe pkgs.replace-secret} @pkey@ <(echo "$CREDENTIALS_DIRECTORY/pkey.pem") /run/coturn/turnserver.cfg
'';
serviceConfig = {
LoadCredential = [
"cert.pem:${certsDir}/fullchain.pem"
"pkey.pem:${certsDir}/key.pem"
];
Restart = mkForce "always";
RestartSec = "60"; # Retry every minute
};
};
security.acme.certs.${hostDomain}.postRun = ''
systemctl restart coturn.service
'';
}

View file

@ -11,6 +11,7 @@
../../modules/optional/zfs.nix
./acme.nix
./coturn.nix
./fs.nix
./net.nix
./oauth2.nix

View file

@ -107,6 +107,7 @@
// mkMicrovm "adguardhome"
// mkMicrovm "forgejo"
// mkMicrovm "kanidm"
// mkMicrovm "netbird"
// mkMicrovm "radicale"
// mkMicrovm "vaultwarden"
);

View file

@ -106,12 +106,24 @@ in {
basicSecretFile = config.age.secrets.kanidm-oauth2-immich.path;
preferShortUsername = true;
# XXX: PKCE is currently not supported by immich
# XXX: Also RS256 is used instead of ES256 so additionally needed:
# kanidm system oauth2 warning-enable-legacy-crypto immich
allowInsecureClientDisablePkce = true;
# XXX: RS256 is used instead of ES256 so additionally we need legacy crypto
enableLegacyCrypto = true;
scopeMaps."immich.access" = ["openid" "email" "profile"];
};
# Netbird
groups."netbird.access" = {};
systems.oauth2.netbird = {
public = true;
displayName = "Netbird";
originUrl = "https://${sentinelCfg.networking.providedDomains.netbird}/";
preferShortUsername = true;
enableLocalhostRedirects = true;
enableLegacyCrypto = true;
scopeMaps."netbird.access" = ["openid" "email" "profile"];
};
# Paperless
groups."paperless.access" = {};
systems.oauth2.paperless = {

View file

@ -0,0 +1,134 @@
{
config,
lib,
nodes,
...
}: let
sentinelCfg = nodes.sentinel.config;
netbirdDomain = "netbird.${config.repo.secrets.global.domains.me}";
in {
wireguard.proxy-sentinel = {
client.via = "sentinel";
firewallRuleForNode.sentinel.allowedTCPPorts = [3000 3001];
};
# Mirror the original coturn password
age.secrets.coturn-password-netbird = {
inherit (sentinelCfg.age.secrets.coturn-password-netbird) rekeyFile;
};
age.secrets.coturn-secret = {
generator.script = "alnum";
};
age.secrets.netbird-data-store-encryption-key = {
generator.script = {pkgs, ...}: ''
${lib.getExe pkgs.openssl} rand -base64 32
'';
};
environment.persistence."/persist".directories = [
{
directory = "/var/lib/netbird-mgmt";
mode = "640";
user = "netbird";
group = "netbird";
}
];
services.netbird = {
server = {
enable = true;
domain = netbirdDomain;
dashboard.settings.AUTH_AUTHORITY = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/openid/netbird";
management = {
port = 3000;
dnsDomain = "internal.${config.repo.secrets.global.domains.me}";
singleAccountModeDomain = "home.lan";
oidcConfigEndpoint = "https://${sentinelCfg.networking.providedDomains.kanidm}/oauth2/openid/netbird/.well-known/openid-configuration";
turnDomain = sentinelCfg.networking.providedDomains.coturn;
turnPort = sentinelCfg.services.coturn.tls-listening-port;
settings = {
TURNConfig = {
Secret._secret = config.age.secrets.coturn-secret.path;
Turns = [
{
Proto = "udp";
URI = "turn:${config.services.netbird.server.management.turnDomain}:${builtins.toString config.services.netbird.server.management.turnPort}";
Username = "netbird";
Password._secret = config.age.secrets.coturn-password-netbird.path;
}
];
};
DataStoreEncryptionKey._secret = config.age.secrets.netbird-data-store-encryption-key.path;
};
};
};
};
nodes.sentinel = {
networking.providedDomains.netbird = netbirdDomain;
services.nginx = {
upstreams.netbird = {
servers."${config.wireguard.proxy-sentinel.ipv4}:80" = {};
extraConfig = ''
zone netbird 64k;
keepalive 5;
'';
};
upstreams.netbird-mgmt = {
servers."${config.wireguard.proxy-sentinel.ipv4}:3000" = {};
extraConfig = ''
zone netbird 64k;
keepalive 5;
'';
};
upstreams.netbird-signal = {
servers."${config.wireguard.proxy-sentinel.ipv4}:3001" = {};
extraConfig = ''
zone netbird 64k;
keepalive 5;
'';
};
virtualHosts.${netbirdDomain} = {
forceSSL = true;
useACMEWildcardHost = true;
locations = {
"/" = {
root = config.services.netbird.server.dashboard.finalDrv;
tryFiles = "$uri $uri.html $uri/ =404";
X-Frame-Options = "SAMEORIGIN";
};
"/signalexchange.SignalExchange/".extraConfig = ''
grpc_pass grpc://netbird-signal;
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
"/api".proxyPass = "http://netbird-mgmt";
"/management.ManagementService/".extraConfig = ''
grpc_pass grpc://netbird-mgmt;
grpc_read_timeout 1d;
grpc_send_timeout 1d;
grpc_socket_keepalive on;
'';
};
extraConfig = ''
client_max_body_size 500M ;
client_header_timeout 1d;
client_body_timeout 1d;
'';
};
};
};
systemd.services.netbird-signal.serviceConfig.RestartSec = "60"; # Retry every minute
systemd.services.netbird-management.serviceConfig.RestartSec = "60"; # Retry every minute
}

View file

@ -110,9 +110,29 @@ in {
late = true; # Only accept after any rejects have been processed
verdict = "accept";
};
#masquerade-vpn = {
# from = ["wg-home"];
# to = ["lan"];
# masquerade = true;
#};
#outbound-vpn = {
# from = ["wg-home"];
# to = ["lan"];
# late = true; # Only accept after any rejects have been processed
# verdict = "accept";
#};
};
};
# Allow accessing influx
wireguard.proxy-sentinel.client.via = "sentinel";
#wireguard.home.server = {
# host = todo # config.networking.fqdn;
# port = 51192;
# reservedAddresses = ["10.10.0.1/24" "fd00:10::/120"];
# openFirewall = true;
#};
}

View file

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJt2DE0HJjmePYjuZVRcsb0/SfoHSmm06T4ayzIgxUOp