at 23.11-pre 4.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.nats; 8 9 format = pkgs.formats.json { }; 10 11 configFile = format.generate "nats.conf" cfg.settings; 12 13in { 14 15 ### Interface 16 17 options = { 18 services.nats = { 19 enable = mkEnableOption (lib.mdDoc "NATS messaging system"); 20 21 user = mkOption { 22 type = types.str; 23 default = "nats"; 24 description = lib.mdDoc "User account under which NATS runs."; 25 }; 26 27 group = mkOption { 28 type = types.str; 29 default = "nats"; 30 description = lib.mdDoc "Group under which NATS runs."; 31 }; 32 33 serverName = mkOption { 34 default = "nats"; 35 example = "n1-c3"; 36 type = types.str; 37 description = lib.mdDoc '' 38 Name of the NATS server, must be unique if clustered. 39 ''; 40 }; 41 42 jetstream = mkEnableOption (lib.mdDoc "JetStream"); 43 44 port = mkOption { 45 default = 4222; 46 type = types.port; 47 description = lib.mdDoc '' 48 Port on which to listen. 49 ''; 50 }; 51 52 dataDir = mkOption { 53 default = "/var/lib/nats"; 54 type = types.path; 55 description = lib.mdDoc '' 56 The NATS data directory. Only used if JetStream is enabled, for 57 storing stream metadata and messages. 58 59 If left as the default value this directory will automatically be 60 created before the NATS server starts, otherwise the sysadmin is 61 responsible for ensuring the directory exists with appropriate 62 ownership and permissions. 63 ''; 64 }; 65 66 settings = mkOption { 67 default = { }; 68 type = format.type; 69 example = literalExpression '' 70 { 71 jetstream = { 72 max_mem = "1G"; 73 max_file = "10G"; 74 }; 75 }; 76 ''; 77 description = lib.mdDoc '' 78 Declarative NATS configuration. See the 79 [ 80 NATS documentation](https://docs.nats.io/nats-server/configuration) for a list of options. 81 ''; 82 }; 83 }; 84 }; 85 86 ### Implementation 87 88 config = mkIf cfg.enable { 89 services.nats.settings = { 90 server_name = cfg.serverName; 91 port = cfg.port; 92 jetstream = optionalAttrs cfg.jetstream { store_dir = cfg.dataDir; }; 93 }; 94 95 systemd.services.nats = { 96 description = "NATS messaging system"; 97 wantedBy = [ "multi-user.target" ]; 98 after = [ "network.target" ]; 99 100 serviceConfig = mkMerge [ 101 (mkIf (cfg.dataDir == "/var/lib/nats") { 102 StateDirectory = "nats"; 103 StateDirectoryMode = "0750"; 104 }) 105 { 106 Type = "simple"; 107 ExecStart = "${pkgs.nats-server}/bin/nats-server -c ${configFile}"; 108 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; 109 ExecStop = "${pkgs.coreutils}/bin/kill -SIGINT $MAINPID"; 110 Restart = "on-failure"; 111 112 User = cfg.user; 113 Group = cfg.group; 114 115 # Hardening 116 CapabilityBoundingSet = ""; 117 LimitNOFILE = 800000; # JetStream requires 2 FDs open per stream. 118 LockPersonality = true; 119 MemoryDenyWriteExecute = true; 120 NoNewPrivileges = true; 121 PrivateDevices = true; 122 PrivateTmp = true; 123 PrivateUsers = true; 124 ProcSubset = "pid"; 125 ProtectClock = true; 126 ProtectControlGroups = true; 127 ProtectHome = true; 128 ProtectHostname = true; 129 ProtectKernelLogs = true; 130 ProtectKernelModules = true; 131 ProtectKernelTunables = true; 132 ProtectProc = "invisible"; 133 ProtectSystem = "strict"; 134 ReadOnlyPaths = [ ]; 135 ReadWritePaths = [ cfg.dataDir ]; 136 RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; 137 RestrictNamespaces = true; 138 RestrictRealtime = true; 139 RestrictSUIDSGID = true; 140 SystemCallFilter = [ "@system-service" "~@privileged" ]; 141 UMask = "0077"; 142 } 143 ]; 144 }; 145 146 users.users = mkIf (cfg.user == "nats") { 147 nats = { 148 description = "NATS daemon user"; 149 isSystemUser = true; 150 group = cfg.group; 151 home = cfg.dataDir; 152 }; 153 }; 154 155 users.groups = mkIf (cfg.group == "nats") { nats = { }; }; 156 }; 157 158}