{ config, lib, ... }: # TODO: make a remote-build user on nixos boxes, instead of giving access to pbsds # TODO: https://exozy.me/about let inherit (builtins) map fromTOML toString readFile elem attrNames attrValues ; known-hosts = let known-hosts' = lib.importTOML ../hosts/known-hosts.toml; # TODO: eww in lib.pipe known-hosts' [ (lib.flip lib.removeAttrs ["__default__"]) (lib.mapAttrs (fqdn: host: lib.recursiveUpdate (known-hosts'."__default__" or {}) host )) (lib.mapAttrsToList (fqdn: host: let allHostnames = [ fqdn ] ++ host.aliases; in lib.forEach allHostnames (alias: lib.nameValuePair alias (host // { aliases = lib.remove alias allHostnames; isAlias = fqdn != alias; }) ) )) lib.flatten lib.listToAttrs ]; hostNames = attrNames known-hosts; thisHost = known-hosts.${config.networking.fqdn}; thisHostIsBuilder = thisHost.buildMachine.maxJobs > 0; thisHostIsBuildee = thisHost.ssh ? userPublicKey; thisHostIsHopHost = elem config.networking.fqdn (lib.forEach (attrValues known-hosts) (host: host.ssh.proxyJump or null)); mkRemoteConfig = fqdn: let thatHost = known-hosts.${fqdn}; thatJump = known-hosts.${thatHost.ssh.proxyJump}; buildMachine = thatHost.buildMachine // { hostName = fqdn; sshUser = thatHost.ssh.listenUser; }; thatHostIsBuilder = thatHost.buildMachine.maxJobs > 0; thatHostIsBuildee = thatHost.ssh ? userPublicKey && thisHostIsBuilder; thatHostIsThis = elem config.networking.fqdn ([ fqdn ] ++ thatHost.aliases); in lib.mkIf (!thatHostIsThis) ( lib.mkMerge [ # out (lib.mkIf (thisHostIsBuildee && thatHostIsBuilder) { # TODO: Allow setting speedFactor for local builds, as local is currently fixed to 0 # https://github.com/NixOS/nix/issues/2457 nix.distributedBuilds = true; # useful when the builder has a faster internet connection than i do nix.settings.builders-use-substitutes = true; nix.buildMachines = lib.mkIf (!thatHost.isAlias) [ buildMachine ]; }) # out or jump (lib.mkIf (thisHostIsBuildee && thatHost.ssh ? listenPublicKey) { programs.ssh.knownHosts.${fqdn}.publicKey = thatHost.ssh.listenPublicKey; # TODO: use nix.buildMachines.*.publicHostKey ? # timeouts are great when remote is unresponsive. nix doesn't care, lix is way and tests each remote only once programs.ssh.extraConfig = '' Host ${fqdn} ConnectTimeout ${toString thatHost.ssh.connectTimeout} Port ${toString thatHost.ssh.listenPort} ${lib.optionalString (thatHost.ssh ? proxyJump) '' ProxyJump ${thatJump.ssh.listenUser}@${thatHost.ssh.proxyJump}:${toString thatJump.ssh.listenPort} ''} ${lib.optionalString (thatHost.ssh ? userPrivateKey) '' IdentityFile ${thatHost.ssh.userPrivateKey} ''} ''; sops.secrets = lib.mkIf (lib.hasPrefix "/run/secrets/" (thatHost.ssh.userPrivateKey or "")) { "${lib.removePrefix "/run/secrets/" thatHost.ssh.userPrivateKey}" = { }; }; }) # in (lib.mkIf ((thisHostIsBuilder || thisHostIsHopHost) && thatHostIsBuildee) { users.users.${thisHost.ssh.listenUser} = { isSystemUser = lib.mkDefault (!config.users.users.${thisHost.ssh.listenUser}.isNormalUser); openssh.authorizedKeys.keys = [ thatHost.ssh.userPublicKey ]; group = lib.mkOptionDefault "nogroup"; }; }) (lib.mkIf (thisHostIsBuilder && thatHostIsBuildee) { nix.settings.allowed-users = [ thisHost.ssh.listenUser ]; nix.settings.trusted-users = [ thisHost.ssh.listenUser ]; }) ]); in { imports = lib.forEach hostNames mkRemoteConfig; }