/* TODO: Translate this to a service/module at some point? Something like 'cryto.network' that handles all the internal-networking stuff. */ { hostname, nodes, pingInterval ? 10 }: { pkgs, lib, ... }: let /* NOTE: We cannot just use simple string interpolation, because tinc's configuration format is not indentation-tolerant. Therefore, we do some programmatic concatenation magic to ensure that everything is indentation-free, without turning this file into a mess of wrong indentation. */ generateConfiguration = options: let keys = builtins.attrNames options; toPairs = map (key: {key = key; value = options.${key};}); createConfigEntries = map (item: "${item.key} = ${toString item.value}"); in builtins.concatStringsSep "\n" (createConfigEntries (toPairs keys)); in { deployment.secrets = { "tinc-key" = { source = "../private/${hostname}/tinc-key.priv"; destination = "/etc/tinc/cryto/ed25519_key.priv"; owner = { user = "tinc.cryto"; }; action = [ "systemctl" "restart" "tinc.cryto.service" ]; }; }; services.tinc.networks.cryto = { debugLevel = 3; chroot = false; ed25519PrivateKeyFile = "/etc/tinc/cryto/ed25519_key.priv"; extraConfig = generateConfiguration { AutoConnect = "yes"; PingInterval = pingInterval; }; hosts = let escapeHostname = hostname: builtins.replaceStrings [ "." "-" ] [ "_" "_" ] hostname; stripSuffix = hostname: builtins.head (builtins.match "^(.+?)\.cryto\.net$" hostname); makeMapper = keyMapper: ( nodeName: nodeConfiguration: lib.nameValuePair /* NOTE: The below is because for a machine named `foo.bar-baz.net`, tinc expects a configuration file named `foo_bar_baz_net`. */ # ( builtins.replaceStrings [ "." "-" ] [ "_" "_" ] nodeName ) ( keyMapper nodeName ) ( generateConfiguration { # Address = nodeName; /* TODO: Figure out why a DNS name doesn't work here ("Error looking up machine-borg2-01.cryto.net port 655: Device or resource busy") */ Address = nodeConfiguration.ipv4; Subnet = "${nodeConfiguration.internalIpv4}/32"; Ed25519PublicKey = nodeConfiguration.tincPublicKey; } ) ); # NOTE: We generate both hostname formats and then just use one, since this seems to keep changing... this makes it easier to revert later mapperA = makeMapper ( nodeName: escapeHostname (stripSuffix nodeName) ); mapperB = makeMapper ( nodeName: escapeHostname nodeName ); hostsA = lib.mapAttrs' mapperA nodes; # hostsB = lib.mapAttrs' mapperB nodes; hostsB = {}; in hostsA // hostsB; }; # networking.interfaces."tinc.cryto".ipv4.addresses = [{ # address = nodes.${hostname}.internalIpv4; # prefixLength = 24; # }]; networking.firewall = { allowedTCPPorts = [ 655 ]; allowedUDPPorts = [ 655 ]; trustedInterfaces = [ "tinc.cryto" ]; }; # FIXME: Make the netmask be generated from the prefixLength, instead of hard-coding it environment.etc = { "tinc/cryto/tinc-up".source = pkgs.writeScript "tinc-up-cryto" '' #!${pkgs.stdenv.shell} ${pkgs.nettools}/bin/ifconfig tinc.cryto ${nodes.${hostname}.internalIpv4} netmask 255.255.255.0 ''; "tinc/cryto/tinc-down".source = pkgs.writeScript "tinc-down-cryto" '' #!${pkgs.stdenv.shell} /run/wrappers/bin/sudo ${pkgs.nettools}/bin/ifconfig tinc.cryto down ''; }; security.sudo.extraRules = [{ users = [ "tinc.cryto" ]; commands = [{ command = "${pkgs.nettools}/bin/ifconfig tinc.cryto down"; options = [ "NOPASSWD" ]; }]; }]; # Override this to get rid of the automatic key generation systemd.services."tinc.cryto".preStart = lib.mkForce '' mkdir -p /etc/tinc/cryto/hosts chown tinc.cryto /etc/tinc/cryto/hosts mkdir -p /etc/tinc/cryto/invitations chown tinc.cryto /etc/tinc/cryto/invitations ''; }