aboutsummaryrefslogblamecommitdiff
path: root/nix/wesher_service.nix
blob: d269a2f246128c33939877f2eaa142feb2e1e3f8 (plain) (tree)
1
2
3
4
5


                           
                                       
                               














                                                                              
                                                                                                                                                                                                                                                                                                                   






















































                                                                                                                                                                                    













                                                                                   














                                                                    







                                                                                         

                                   





















                                                                                                                
{ config, lib, pkgs, ... }:
with lib;
let
  keysPath = "/var/lib/wesher/secrets";
  cfg = config.services.wesher;
in {
  options = with types; {
    services.wesher = {
      enable = mkEnableOption "wesher wireguard overlay mesh network manager";

      package = mkOption {
        type = package;
        default = pkgs.wesher;
        defaultText = literalExpression "pkgs.wesher";
        description = "Wesher package to use.";
      };

      clusterKey = mkOption {
        type = nullOr str;
        default = null;
        description = "shared key for cluster membership to use on first initialization, if no key was previously used by Wesher. Must be 32 bytes base64 encoded; will be generated if not provided. Setting this parameter value will not overwrite an existing cluster key; to do so please delete ${keysPath}";
      };

      bindAddr = mkOption {
        type = nullOr str;
        default = null;
        description = "IP address to bind to for cluster membership (cannot be used with --bind-iface)";
      };

      bindIface = mkOption {
        type = nullOr str;
        default = null;
        description = "Interface to bind to for cluster membership (cannot be used with --bind-addr)";
      };

      join = mkOption {
        type = listOf str;
        default = [];
        description = "list of hostnames or IP addresses to existing cluster members; if not provided, will attempt resuming any known state or otherwise wait for further members";
      };

      clusterPort = mkOption {
        type = port;
        default = 7946;
        description = "port used for membership gossip traffic (both TCP and UDP); must be the same accross cluster";
      };

      wireguardPort = mkOption {
        type = port;
        default = 51820;
        description = "port used for wireguard traffic (UDP); must be the same accross cluster";
      };

      overlayNet = mkOption {
        type = str;
        default = "10.0.0.0/8";
        description = "the network in which to allocate addresses for the overlay mesh network (CIDR format); smaller networks increase the chance of IP collision";
      };

      interface = mkOption {
        type = str;
        default = "wgoverlay";
        description = "name of the wireguard interface to create and manage";
      };

      logLevel = mkOption {
        type = str;
        default = "warn";
        description = "set the verbosity (one of debug/info/warn/error)";
      };
      
    };
  };

  config = mkIf cfg.enable (let binWesher = cfg.package + "/bin/wesher";
  in {
    system.activationScripts.wesher = if (cfg.clusterKey != null) then ''
      if [ ! -e ${keysPath} ]
      then
        mkdir --mode=700 -p ${builtins.dirOf keysPath}
        echo "WESHER_CLUSTER_KEY=${cfg.clusterKey}" > ${keysPath}
      fi
    '' else ''
      if [ ! -e ${keysPath} ]
      then
        mkdir --mode=700 -p ${builtins.dirOf keysPath}
        echo "WESHER_CLUSTER_KEY=$(head -c 32 /dev/urandom | base64)" > ${keysPath}
      fi
    '';

    systemd.services.wesher = {
      description = "wesher wireguard overlay mesh network manager";
      bindsTo = [ "network-online.target" ];
      after = [ "network-online.target" ];
      wantedBy = [ "multi-user.target" ];

      environment = {
        WESHER_JOIN = builtins.concatStringsSep "," cfg.join;
        WESHER_CLUSTER_PORT = builtins.toString cfg.clusterPort;
        WESHER_WIREGUARD_PORT = builtins.toString cfg.wireguardPort;
        WESHER_OVERLAY_NET = cfg.overlayNet;
        WESHER_INTERFACE = cfg.interface;
        WESHER_LOG_LEVEL = cfg.logLevel;
        WESHER_NO_ETC_HOSTS = "true";
      } 
      // (if (cfg.bindAddr != null) then { WESHER_BIND_ADDR = cfg.bindAddr; } else {})
      // (if (cfg.bindIface != null) then { WESHER_BIND_IFACE = cfg.bindIface; } else {})
      ;

      serviceConfig = {
        ExecStart = "${binWesher}";
        Restart = "always";

        EnvironmentFile = keysPath;

        User = "wesher";
        DynamicUser = true;
        StateDirectory = "wesher";

        AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
        CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_BIND_SERVICE";
        MemoryDenyWriteExecute = true;
        ProtectControlGroups = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK";
        RestrictNamespaces = true;
        RestrictRealtime = true;
        SystemCallArchitectures = "native";
        SystemCallFilter = "~@clock @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @resources";
      };
    };

    networking.firewall.allowedUDPPorts = mkIf cfg.enable [ cfg.clusterPort cfg.wireguardPort ];
    networking.firewall.allowedTCPPorts = mkIf cfg.enable [ cfg.clusterPort ];
  });
}