{ lib, config, pkgs, self, ... }: let inherit (lib) mkIf mkOption mkEnableOption types ; inherit (pkgs) stdenv; inherit (stdenv.hostPlatform) system; cfg = config.services.specimen; in { options.services.specimen = { enable = mkEnableOption "specimen application"; package = mkOption { type = types.package; description = "specimen package to use."; default = self.packages.${system}.default; }; user = mkOption { type = types.nonEmptyStr; default = "specimen"; description = "user under which specimen will run."; }; group = mkOption { type = types.nonEmptyStr; default = "specimen"; description = "group under which specimen will run."; }; port = mkOption { type = types.port; default = 4444; description = "port that specimen will listen on."; }; listenAddress = mkOption { type = types.str; default = "0.0.0.0"; description = "address that specimen will listen on."; }; openFirewall = mkOption { type = types.bool; default = false; description = "open specimen port in firewall for incoming connections."; }; nameSecret = mkOption { type = types.attrs; description = "secret from which specimen will take the name from."; }; }; config = mkIf cfg.enable { assertions = with builtins; [ { assertion = hasAttr "path" cfg.nameSecret; message = "name secret needs to include path"; } { assertion = hasAttr "file" cfg.nameSecret; message = "name secret needs to include store file"; } ]; networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.port ]; users.users.${cfg.user} = { description = "specimen user"; group = cfg.group; isSystemUser = true; }; users.groups.${cfg.group} = { }; systemd.services.specimen = { description = "specimen application service"; wantedBy = [ "multi-user.target" ]; wants = [ "network.target" ]; after = [ "network.target" ]; restartTriggers = [ cfg.nameSecret.file ]; serviceConfig = { User = cfg.user; Group = cfg.user; Type = "exec"; Restart = "always"; ExecStart = "${cfg.package}/bin/specimen -address ${cfg.listenAddress} -port ${toString cfg.port} -name ${cfg.nameSecret.path}"; # a gigantic amount of hardening!! # realistically this much wouldn't be necessary. # mostly here to show off ;3 # for documentation, see: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html LockPersonality = true; CapabilityBoundingSet = [ "" ]; DeviceAllow = [ "" ]; MemoryDenyWriteExecute = true; NoNewPrivileges = true; PrivateDevices = true; PrivateTmp = true; ProtectClock = true; ProtectProc = "invisible"; ProtectControlGroups = true; ProtectHome = true; ProtectHostname = true; ProtectKernelLogs = true; ProtectKernelModules = true; ProtectKernelTunables = true; ProtectSystem = "strict"; RemoveIPC = true; RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; SystemCallArchitectures = "native"; }; }; }; }