From 397d5560f235d9a23e46e7a6ef751d7ce1c4733a Mon Sep 17 00:00:00 2001 From: Jonathan Davies Date: Sun, 24 Aug 2025 12:45:48 +0000 Subject: [PATCH] nixos/temporal: init module --- nixos/modules/module-list.nix | 1 + .../services/cluster/temporal/default.nix | 146 ++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 nixos/modules/services/cluster/temporal/default.nix diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4f5224274d1a..b4d2ebc3c7ae 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -484,6 +484,7 @@ ./services/cluster/patroni/default.nix ./services/cluster/rke2/default.nix ./services/cluster/spark/default.nix + ./services/cluster/temporal/default.nix ./services/computing/boinc/client.nix ./services/computing/foldingathome/client.nix ./services/computing/slurm/slurm.nix diff --git a/nixos/modules/services/cluster/temporal/default.nix b/nixos/modules/services/cluster/temporal/default.nix new file mode 100644 index 000000000000..57a3e39157d3 --- /dev/null +++ b/nixos/modules/services/cluster/temporal/default.nix @@ -0,0 +1,146 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.temporal; + + settingsFormat = pkgs.formats.yaml { }; + + usingDefaultDataDir = cfg.dataDir == "/var/lib/temporal"; + usingDefaultUserAndGroup = cfg.user == "temporal" && cfg.group == "temporal"; +in +{ + meta.maintainers = [ lib.maintainers.jpds ]; + + options.services.temporal = { + enable = lib.mkEnableOption "Temporal"; + + package = lib.mkPackageOption pkgs "Temporal" { + default = [ "temporal" ]; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + }; + + description = '' + Temporal configuration. + + See for more + information about Temporal configuration options + ''; + }; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/temporal"; + apply = lib.converge (lib.removeSuffix "/"); + description = '' + Data directory for Temporal. If you change this, you need to + manually create the directory. You also need to create the + `temporal` user and group, or change + [](#opt-services.temporal.user) and + [](#opt-services.temporal.group) to existing ones with + access to the directory. + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "temporal"; + description = '' + The user Temporal runs as. Should be left at default unless + you have very specific needs. + ''; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "temporal"; + description = '' + The group temporal runs as. Should be left at default unless + you have very specific needs. + ''; + }; + + restartIfChanged = lib.mkOption { + type = lib.types.bool; + description = '' + Automatically restart the service on config change. + This can be set to false to defer restarts on a server or cluster. + Please consider the security implications of inadvertently running an older version, + and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option. + ''; + default = true; + }; + }; + + config = lib.mkIf cfg.enable { + environment.etc."temporal/temporal-server.yaml".source = + settingsFormat.generate "temporal-server.yaml" cfg.settings; + + systemd.services.temporal = { + description = "Temporal server"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + inherit (cfg) restartIfChanged; + restartTriggers = [ config.environment.etc."temporal/temporal-server.yaml".source ]; + environment = { + HOME = cfg.dataDir; + }; + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/temporal-server --root / --config /etc/temporal/ -e temporal-server start + ''; + User = cfg.user; + Group = cfg.group; + Restart = "on-failure"; + DynamicUser = usingDefaultUserAndGroup && usingDefaultDataDir; + CapabilityBoundingSet = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectHome = true; + ProtectHostname = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = [ + cfg.dataDir + ]; + RestrictAddressFamilies = [ + "AF_NETLINK" + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + # 1. allow a reasonable set of syscalls + "@system-service @resources" + # 2. and deny unreasonable ones + "~@privileged" + # 3. then allow the required subset within denied groups + "@chown" + ]; + } + // (lib.optionalAttrs (usingDefaultDataDir) { + StateDirectory = "temporal"; + StateDirectoryMode = "0700"; + }); + }; + }; +}