{ config, pkgs, ... }: let hostname = config.networking.hostName; conf = hosts."${hostname}"; privateKeyPath = ./secrets/wireguard/${hostname}.txt; lib = pkgs.lib; wgPort = 51820; # Common port used on all peers firewallMark = 42; # The topology is hub-and-spoke/star # sagittarius is the hub == 2301:db8:acad:a::1 # it hosts authoritative DNS and spokes do keepalive with it. hosts = { sagittarius = { address = "2301:db8:acad:a::1/128"; publicKey = "GrrN8j9ZlPjTU5sQD4l8RDCGAn2YYszbSIE1zuG4OiI="; endpoint = "95.216.136.85:${toString wgPort}"; hub = true; }; nyaan = { address = "2301:db8:acad:a::2/128"; publicKey = "u5nh+YNV84IbS7g0ncfs/V+cqEudNh500LQ7pmdS7j0="; }; }; peers = lib.attrsets.filterAttrs (k: v: k != hostname) hosts; hub = let filtered = lib.attrsets.filterAttrs (_: v: v.hub == true) hosts; mapped = map (k: (builtins.getAttr k hosts) // { hostname = "k"; }) builtins.attrNames filtered; in builtins.elemAt 0 mapped; generatePeer = hostname: values: { PublicKey = values.publicKey; AllowedIPs = [ values.address ]; } // lib.optionalAttrs (builtins.hasAttr "endpoint" values) { Endpoint = values.endpoint; PersistentKeepalive = 1; }; generatedPeers = lib.attrsets.mapAttrsToList generatePeer peers; stripNetmask = addr: lib.strings.removeSuffix "/128" addr; # generatedHosts = lib.attrsets.mapAttrs' (hostname: value: { # name = stripNetmask value.address; # value = [ # hostname # "${hostname}.internal" # ]; # }) peers; in { sops.secrets."wireguard-${hostname}-pk" = { sopsFile = privateKeyPath; owner = "systemd-network"; group = "systemd-network"; mode = "0640"; format = "binary"; }; services.resolved = { enable = true; dnsDelegates.wg = { Domains = lib.attrsets.mapAttrsToList (host: _: "${host}.internal") hosts; DNS = stripNetmask hub.address; }; }; services.nsd = { enable = config.networking.hostName == hub.hostname; interfaces = [ stripNetmask hub.address ]; ipv4 = false; ipv6 = true; serverCount = 1; tcpCount = 100; zones = { sagittarius = { data = '' $ORIGIN sagittarius.internal. $TTL 300 @ IN SOA ns1.sagittarius.internal. hostmaster.mydomain.internal. ( 2024053101 ; serial — YYYYMMDDNN 3600 ; refresh 900 ; retry 1209600 ; expire 300 ; minimum TTL ) ; Nameservers (required for a valid zone) @ IN NS ns1.mydomain.internal. ns1 IN A 10.0.0.1 ; Wildcard — catches any undefined subdomain * IN A 10.0.0.1 ; Explicit host entries server IN A 10.0.0.1 alpha IN A 10.0.0.10 bravo IN A 10.0.0.11 charlie IN A 10.0.0.12 ; SRV records for service discovery _http._tcp IN SRV 10 5 80 server _https._tcp IN SRV 10 5 443 server ''; }; }; }; systemd.network = { enable = true; networks."50-wg" = { matchConfig.Name = "wg0"; address = [ conf.address ]; }; netdevs."50-wg" = { netdevConfig = { Kind = "wireguard"; Name = "wg0"; }; wireguardConfig = { ListenPort = wgPort; PrivateKeyFile = config.sops.secrets."wireguard-${hostname}-pk".path; # To automatically create routes for everything in AllowedIPs, # add RouteTable=main RouteTable = "main"; # FirewallMark marks all packets send and received by wg0 with the # number, which can be used to define policy rules on these packets. FirewallMark = firewallMark; }; wireguardPeers = generatedPeers; }; }; }