{ config, hostName, lib, pkgs, ... }: with lib; let listenPort = 51820; subnet = "2a03:4000:52:ada:1"; subnetLength = 80; links = [ { from = "vidhar"; to = "surtr"; endpointHost = "surtr.yggdrasil.li"; persistentKeepalive = 25; dynamicEndpointRefreshSeconds = 86400; } ]; hostLength = subnetLength + 16; hostIPs = { surtr = ["${subnet}::/${toString hostLength}"]; vidhar = ["${subnet}:1::/${toString hostLength}"]; }; mkPublicKeyPath = host: ./hosts + "/${host}.pub"; mkPrivateKeyPath = host: ./hosts + "/${host}.priv"; publicKeyPath = mkPublicKeyPath hostName; privateKeyPath = mkPrivateKeyPath hostName; inNetwork = pathExists privateKeyPath && pathExists publicKeyPath; hostLinks = filter ({ from, to, ... }: from == hostName || to == hostName) links; linkToPeer = opts@{from, to, ...}: let other = if from == hostName then to else from; in { allowedIPs = hostIPs.${other}; publicKey = trim (readFile (mkPublicKeyPath other)); } // (optionalAttrs (from == hostName) (filterAttrs (n: _v: !(elem n ["from" "to" "endpointHost"])) opts // optionalAttrs (opts ? "endpointHost") { endpoint = "${opts.endpointHost}:${toString listenPort}"; })); trim = str: if hasSuffix "\n" str then trim (removeSuffix "\n" str) else str; stripSubnet = addr: let matchRes = builtins.match "^(.*)/[0-9]+$" addr; in if matchRes == null then addr else elemAt matchRes 0; in { config = { assertions = [ { assertion = inNetwork || !(pathExists privateKeyPath || pathExists publicKeyPath); message = "yggdrasil-wg: Either both public and private keys must exist or neither."; } { assertion = !inNetwork || (hostIPs ? "${hostName}"); message = "yggdrasil-wg: Entry in hostIPs must exist."; } ] ++ map ({from, to, ...}: let other = if from == hostName then to else from; in { assertion = pathExists (mkPublicKeyPath other); message = "yggdrasil-wg: This host (${hostName}) has a link with ‘${other}’, but no public key is available for ‘${other}’."; }) hostLinks; networking.wireguard.interfaces = mkIf inNetwork { yggdrasil = { allowedIPsAsRoutes = false; inherit listenPort; ips = hostIPs.${hostName}; peers = map linkToPeer hostLinks; privateKeyFile = config.sops.secrets."yggdrasil-wg.priv".path; postSetup = '' ${pkgs.iproute2}/bin/ip route replace "${subnet}::/${toString subnetLength}" dev "yggdrasil" table "main" ''; }; }; sops.secrets = mkIf (pathExists privateKeyPath) { "yggdrasil-wg.priv" = { format = "binary"; sopsFile = privateKeyPath; }; }; networking.hosts = mkIf inNetwork (listToAttrs (concatMap ({name, value}: map (ip: nameValuePair (stripSubnet ip) ["${name}.yggdrasil"]) value) (mapAttrsToList nameValuePair hostIPs))); }; }