{ config, lib, pkgs, ... }: let cfg = config.services.tickwatch; forEachMonitor = f: lib.mapAttrs' (name: cfg: { name = "tickwatch-${name}"; value = f cfg; }) cfg.monitors; monitor = { name, ... }: { options = { monitor = lib.mkOption { type = lib.types.str; example = "ping"; description = "Type of this monitor."; }; target = lib.mkOption { type = lib.types.str; example = "6/example.net"; description = "Target of this monitor."; }; settings = lib.mkOption { type = with lib.types; attrsOf (oneOf [ str int bool ]); default = { }; example = { timestamp = "none"; range = "0:100"; }; description = "Settings for this monitor."; }; logFile = lib.mkOption { type = lib.types.str; default = "/var/log/tickwatch/${name}.log"; description = '' Path to output log file for this monitor. Must be writable by this monitor's user. Set to empty to log to the service's journald. ''; }; }; }; in { meta = { maintainers = with lib.maintainers; [ euxane ]; }; options.services.tickwatch = { package = lib.mkPackageOption pkgs "tickwatch" { }; monitors = lib.mkOption { type = with lib.types; attrsOf (submodule monitor); default = { }; description = "Configuration for tickwatch monitors."; }; }; config = lib.mkIf (cfg.monitors != { }) { systemd.services = forEachMonitor (monCfg: { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; script = '' ${lib.getExe cfg.package} ${ lib.escapeShellArgs ( (lib.cli.toGNUCommandLine { optionValueSeparator = "="; } monCfg.settings) ++ [ monCfg.monitor monCfg.target ] ) } ${lib.optionalString (monCfg.logFile != "") ">> ${monCfg.logFile}"} ''; serviceConfig = { Restart = "on-failure"; RestartSec = 30; DynamicUser = true; User = "tickwatch"; Group = "tickwatch"; LogsDirectory = "tickwatch"; # for ping monitor CapabilityBoundingSet = [ "CAP_NET_RAW" ]; AmbientCapabilities = [ "CAP_NET_RAW" ]; PrivateNetwork = false; # service hardening PrivateTmp = true; PrivateDevices = true; ProtectKernelTunables = true; ProtectControlGroups = true; RestrictSUIDSGID = true; ProtectKernelModules = true; SystemCallArchitectures = "native"; PrivateMounts = true; LockPersonality = true; ProtectHostname = true; RestrictRealtime = true; ProtectSystem = "strict"; ProtectHome = true; NoNewPrivileges = true; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; MemoryDenyWriteExecute = true; PrivateUsers = false; SystemCallErrorNumber = "EPERM"; SystemCallFilter = [ "@system-service" ]; ProtectKernelLogs = true; DevicePolicy = "closed"; ProtectClock = true; ProtectProc = "noaccess"; ProcSubset = "pid"; RestrictNamespaces = true; RemoveIPC = true; }; }); }; }