237 lines
7.1 KiB
Nix
237 lines
7.1 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}: let
|
|
serviceName = "netbird";
|
|
|
|
servicePort = config.m3ta.ports.get "netbird";
|
|
|
|
domain = "v.m3ta.dev";
|
|
proxyDomain = "p.m3ta.dev";
|
|
|
|
ipBase = "10.89.0";
|
|
ipOffset = 50;
|
|
|
|
# Database configuration
|
|
dbName = "netbird";
|
|
dbUser = "netbird";
|
|
dbHost = "${ipBase}.1";
|
|
|
|
# NetBird config als Nix attribute set
|
|
netbirdConfig = {
|
|
server = {
|
|
listenAddress = ":80";
|
|
exposedAddress = "https://${domain}:443";
|
|
stunPorts = [3478];
|
|
metricsPort = 9090;
|
|
healthcheckAddress = ":9000";
|
|
logLevel = "info";
|
|
logFile = "console";
|
|
dataDir = "/var/lib/netbird";
|
|
|
|
auth = {
|
|
issuer = "https://${domain}/oauth2";
|
|
localAuthDisabled = true;
|
|
signKeyRefreshEnabled = true;
|
|
dashboardRedirectURIs = [
|
|
"https://${domain}/nb-auth"
|
|
"https://${domain}/nb-silent-auth"
|
|
];
|
|
cliRedirectURIs = ["http://localhost:53000/"];
|
|
};
|
|
|
|
reverseProxy = {
|
|
trustedHTTPProxies = ["${ipBase}.1/32"];
|
|
};
|
|
|
|
# Proxy Feature
|
|
proxy = {
|
|
enabled = true;
|
|
domain = proxyDomain;
|
|
};
|
|
|
|
store = {
|
|
engine = "postgres";
|
|
postgres = {
|
|
host = dbHost;
|
|
port = 5432;
|
|
database = dbName;
|
|
username = dbUser;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
# YAML generieren
|
|
yamlFormat = pkgs.formats.yaml {};
|
|
configYamlBase = yamlFormat.generate "netbird-config-base.yaml" netbirdConfig;
|
|
|
|
# Script das Secrets zur Runtime injiziert
|
|
configGenScript = pkgs.writeShellScript "netbird-gen-config" ''
|
|
set -euo pipefail
|
|
|
|
AUTH_SECRET=$(cat "$1")
|
|
DB_PASSWORD=$(cat "$2")
|
|
ENCRYPTION_KEY=$(cat "$3")
|
|
|
|
${pkgs.yq-go}/bin/yq eval "
|
|
.server.authSecret = \"$AUTH_SECRET\" |
|
|
.server.store.encryptionKey = \"$ENCRYPTION_KEY\" |
|
|
.server.store.postgres.password = \"$DB_PASSWORD\"
|
|
" ${configYamlBase}
|
|
'';
|
|
in {
|
|
age.secrets."${serviceName}-auth-secret".file = ../../../../secrets/${serviceName}-auth-secret.age;
|
|
age.secrets."${serviceName}-db-password".file = ../../../../secrets/${serviceName}-db-password.age;
|
|
age.secrets."${serviceName}-encryption-key".file = ../../../../secrets/${serviceName}-encryption-key.age;
|
|
age.secrets."${serviceName}-dashboard-env".file = ../../../../secrets/${serviceName}-dashboard-env.age;
|
|
age.secrets."${serviceName}-server-env".file = ../../../../secrets/${serviceName}-server-env.age;
|
|
age.secrets."${serviceName}-proxy-env".file = ../../../../secrets/${serviceName}-proxy-env.age;
|
|
# Systemd oneshot Service der die Config generiert
|
|
systemd.services."${serviceName}-config" = {
|
|
description = "Generate NetBird config with secrets";
|
|
wantedBy = ["multi-user.target"];
|
|
before = ["podman-${serviceName}-server.service"];
|
|
requiredBy = ["podman-${serviceName}-server.service"];
|
|
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStart = pkgs.writeShellScript "netbird-write-config" ''
|
|
mkdir -p /var/lib/${serviceName}
|
|
${configGenScript} \
|
|
${config.age.secrets."${serviceName}-auth-secret".path} \
|
|
${config.age.secrets."${serviceName}-db-password".path} \
|
|
${config.age.secrets."${serviceName}-encryption-key".path} \
|
|
> /var/lib/${serviceName}/config.yaml
|
|
chmod 600 /var/lib/${serviceName}/config.yaml
|
|
'';
|
|
};
|
|
};
|
|
|
|
virtualisation.oci-containers.containers = {
|
|
"${serviceName}-dashboard" = {
|
|
image = "netbirdio/dashboard:latest";
|
|
autoStart = true;
|
|
environmentFiles = [config.age.secrets."${serviceName}-dashboard-env".path];
|
|
extraOptions = [
|
|
"--ip=${ipBase}.${toString ipOffset}"
|
|
"--network=web"
|
|
];
|
|
};
|
|
|
|
"${serviceName}-server" = {
|
|
image = "netbirdio/netbird-server:latest";
|
|
autoStart = true;
|
|
ports = ["3478:3478/udp"];
|
|
environmentFiles = [config.age.secrets."${serviceName}-server-env".path];
|
|
volumes = [
|
|
"${serviceName}_data:/var/lib/netbird"
|
|
"/var/lib/${serviceName}/config.yaml:/etc/netbird/config.yaml:ro"
|
|
];
|
|
cmd = ["--config" "/etc/netbird/config.yaml"];
|
|
extraOptions = [
|
|
"--ip=${ipBase}.${toString (ipOffset + 1)}"
|
|
"--network=web"
|
|
];
|
|
};
|
|
|
|
"${serviceName}-proxy" = {
|
|
image = "netbirdio/reverse-proxy:latest";
|
|
autoStart = true;
|
|
ports = ["51820:51820/udp"];
|
|
volumes = [
|
|
"${serviceName}_proxy_certs:/certs"
|
|
];
|
|
environmentFiles = [config.age.secrets."${serviceName}-proxy-env".path];
|
|
cmd = [
|
|
"--domain=p.m3ta.dev"
|
|
"--mgmt=https://${domain}:443"
|
|
"--addr=:8443"
|
|
"--cert-dir=/certs"
|
|
"--acme-certs"
|
|
"--trusted-proxies=${ipBase}.1/32"
|
|
];
|
|
dependsOn = ["${serviceName}-server"];
|
|
extraOptions = [
|
|
"--ip=${ipBase}.${toString (ipOffset + 2)}"
|
|
"--network=web"
|
|
];
|
|
};
|
|
};
|
|
|
|
services.traefik.dynamicConfigOptions = {
|
|
# HTTP Services und Routers
|
|
http = {
|
|
services = {
|
|
"${serviceName}-dashboard".loadBalancer.servers = [
|
|
{url = "http://${ipBase}.${toString ipOffset}:80/";}
|
|
];
|
|
|
|
"${serviceName}-server".loadBalancer.servers = [
|
|
{url = "http://${ipBase}.${toString (ipOffset + 1)}:80/";}
|
|
];
|
|
|
|
"${serviceName}-server-h2c".loadBalancer.servers = [
|
|
{url = "h2c://${ipBase}.${toString (ipOffset + 1)}:80";}
|
|
];
|
|
};
|
|
|
|
routers = {
|
|
# gRPC (Signal + Management)
|
|
"${serviceName}-grpc" = {
|
|
rule = "Host(`${domain}`) && (PathPrefix(`/signalexchange.SignalExchange/`) || PathPrefix(`/management.ManagementService/`) || PathPrefix(`/management.ProxyService/`))";
|
|
entrypoints = "websecure";
|
|
tls.certResolver = "godaddy";
|
|
service = "${serviceName}-server-h2c";
|
|
priority = 100;
|
|
};
|
|
# Backend (relay, WebSocket, API, OAuth2)
|
|
"${serviceName}-backend" = {
|
|
rule = "Host(`${domain}`) && (PathPrefix(`/relay`) || PathPrefix(`/ws-proxy/`) || PathPrefix(`/api`) || PathPrefix(`/oauth2`))";
|
|
entrypoints = "websecure";
|
|
tls.certResolver = "godaddy";
|
|
service = "${serviceName}-server";
|
|
priority = 100;
|
|
};
|
|
|
|
# Dashboard (catch-all, niedrigste Priorität)
|
|
"${serviceName}-dashboard" = {
|
|
rule = "Host(`${domain}`)";
|
|
entrypoints = "websecure";
|
|
tls.certResolver = "godaddy";
|
|
service = "${serviceName}-dashboard";
|
|
priority = 1;
|
|
};
|
|
};
|
|
};
|
|
|
|
# TCP für Proxy TLS Passthrough
|
|
tcp = {
|
|
services."${serviceName}-proxy-tls".loadBalancer.servers = [
|
|
{address = "${ipBase}.${toString (ipOffset + 2)}:8443";}
|
|
];
|
|
|
|
routers."${serviceName}-proxy-passthrough" = {
|
|
entryPoints = ["websecure"];
|
|
rule = "HostSNI(`*`)";
|
|
service = "${serviceName}-proxy-tls";
|
|
priority = 1;
|
|
tls.passthrough = true;
|
|
};
|
|
};
|
|
|
|
# ServersTransport für Proxy Protocol v2 (optional)
|
|
serversTransports."pp-v2" = {
|
|
proxyProtocol.version = 2;
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedUDPPorts = [
|
|
3478 # STUN
|
|
51820 # WireGuard für Proxy
|
|
];
|
|
}
|