at 25.11-pre 7.0 kB view raw
1{ 2 config, 3 lib, 4 options, 5 pkgs, 6 ... 7}: 8 9with lib; 10let 11 cfg = config.services.galene; 12 opt = options.services.galene; 13 defaultstateDir = "/var/lib/galene"; 14 defaultrecordingsDir = "${cfg.stateDir}/recordings"; 15 defaultgroupsDir = "${cfg.stateDir}/groups"; 16 defaultdataDir = "${cfg.stateDir}/data"; 17in 18{ 19 options = { 20 services.galene = { 21 enable = mkEnableOption "Galene Service"; 22 23 stateDir = mkOption { 24 default = defaultstateDir; 25 type = types.path; 26 description = '' 27 The directory where Galene stores its internal state. If left as the default 28 value this directory will automatically be created before the Galene server 29 starts, otherwise the sysadmin is responsible for ensuring the directory 30 exists with appropriate ownership and permissions. 31 ''; 32 }; 33 34 user = mkOption { 35 type = types.str; 36 default = "galene"; 37 description = "User account under which galene runs."; 38 }; 39 40 group = mkOption { 41 type = types.str; 42 default = "galene"; 43 description = "Group under which galene runs."; 44 }; 45 46 insecure = mkOption { 47 type = types.bool; 48 default = false; 49 description = '' 50 Whether Galene should listen in http or in https. If left as the default 51 value (false), Galene needs to be fed a private key and a certificate. 52 ''; 53 }; 54 55 certFile = mkOption { 56 type = types.nullOr types.path; 57 default = null; 58 example = "/path/to/your/cert.pem"; 59 description = '' 60 Path to the server's certificate. The file is copied at runtime to 61 Galene's data directory where it needs to reside. 62 ''; 63 }; 64 65 keyFile = mkOption { 66 type = types.nullOr types.path; 67 default = null; 68 example = "/path/to/your/key.pem"; 69 description = '' 70 Path to the server's private key. The file is copied at runtime to 71 Galene's data directory where it needs to reside. 72 ''; 73 }; 74 75 httpAddress = mkOption { 76 type = types.str; 77 default = ""; 78 description = "HTTP listen address for galene."; 79 }; 80 81 httpPort = mkOption { 82 type = types.port; 83 default = 8443; 84 description = "HTTP listen port."; 85 }; 86 87 turnAddress = mkOption { 88 type = types.str; 89 default = "auto"; 90 example = "127.0.0.1:1194"; 91 description = "Built-in TURN server listen address and port. Set to \"\" to disable."; 92 }; 93 94 staticDir = mkOption { 95 type = types.path; 96 default = "${cfg.package.static}/static"; 97 defaultText = literalExpression ''"''${package.static}/static"''; 98 example = "/var/lib/galene/static"; 99 description = "Web server directory."; 100 }; 101 102 recordingsDir = mkOption { 103 type = types.path; 104 default = defaultrecordingsDir; 105 defaultText = literalExpression ''"''${config.${opt.stateDir}}/recordings"''; 106 example = "/var/lib/galene/recordings"; 107 description = "Recordings directory."; 108 }; 109 110 dataDir = mkOption { 111 type = types.path; 112 default = defaultdataDir; 113 defaultText = literalExpression ''"''${config.${opt.stateDir}}/data"''; 114 example = "/var/lib/galene/data"; 115 description = "Data directory."; 116 }; 117 118 groupsDir = mkOption { 119 type = types.path; 120 default = defaultgroupsDir; 121 defaultText = literalExpression ''"''${config.${opt.stateDir}}/groups"''; 122 example = "/var/lib/galene/groups"; 123 description = "Web server directory."; 124 }; 125 126 package = mkPackageOption pkgs "galene" { }; 127 }; 128 }; 129 130 config = mkIf cfg.enable { 131 assertions = [ 132 { 133 assertion = cfg.insecure || (cfg.certFile != null && cfg.keyFile != null); 134 message = '' 135 Galene needs both certFile and keyFile defined for encryption, or 136 the insecure flag. 137 ''; 138 } 139 ]; 140 141 systemd.services.galene = { 142 description = "galene"; 143 after = [ "network.target" ]; 144 wantedBy = [ "multi-user.target" ]; 145 146 preStart = '' 147 ${optionalString (cfg.insecure != true) '' 148 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.certFile} ${cfg.dataDir}/cert.pem 149 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.keyFile} ${cfg.dataDir}/key.pem 150 ''} 151 ''; 152 153 serviceConfig = mkMerge [ 154 { 155 Type = "simple"; 156 User = cfg.user; 157 Group = cfg.group; 158 WorkingDirectory = cfg.stateDir; 159 ExecStart = '' 160 ${cfg.package}/bin/galene \ 161 ${optionalString (cfg.insecure) "-insecure"} \ 162 -http ${cfg.httpAddress}:${toString cfg.httpPort} \ 163 -turn ${cfg.turnAddress} \ 164 -data ${cfg.dataDir} \ 165 -groups ${cfg.groupsDir} \ 166 -recordings ${cfg.recordingsDir} \ 167 -static ${cfg.staticDir}''; 168 Restart = "always"; 169 # Upstream Requirements 170 LimitNOFILE = 65536; 171 StateDirectory = 172 [ ] 173 ++ optional (cfg.stateDir == defaultstateDir) "galene" 174 ++ optional (cfg.dataDir == defaultdataDir) "galene/data" 175 ++ optional (cfg.groupsDir == defaultgroupsDir) "galene/groups" 176 ++ optional (cfg.recordingsDir == defaultrecordingsDir) "galene/recordings"; 177 178 # Hardening 179 CapabilityBoundingSet = [ "" ]; 180 DeviceAllow = [ "" ]; 181 LockPersonality = true; 182 MemoryDenyWriteExecute = true; 183 NoNewPrivileges = true; 184 PrivateDevices = true; 185 PrivateTmp = true; 186 PrivateUsers = true; 187 ProcSubset = "pid"; 188 ProtectClock = true; 189 ProtectControlGroups = true; 190 ProtectHome = true; 191 ProtectHostname = true; 192 ProtectKernelLogs = true; 193 ProtectKernelModules = true; 194 ProtectKernelTunables = true; 195 ProtectProc = "invisible"; 196 ProtectSystem = "strict"; 197 ReadWritePaths = cfg.recordingsDir; 198 RemoveIPC = true; 199 RestrictAddressFamilies = [ 200 "AF_INET" 201 "AF_INET6" 202 "AF_NETLINK" 203 ]; 204 RestrictNamespaces = true; 205 RestrictRealtime = true; 206 RestrictSUIDSGID = true; 207 SystemCallArchitectures = "native"; 208 SystemCallFilter = [ 209 "@system-service" 210 "~@privileged" 211 ]; 212 UMask = "0077"; 213 } 214 ]; 215 }; 216 217 users.users = mkIf (cfg.user == "galene") { 218 galene = { 219 description = "galene Service"; 220 group = cfg.group; 221 isSystemUser = true; 222 }; 223 }; 224 225 users.groups = mkIf (cfg.group == "galene") { 226 galene = { }; 227 }; 228 }; 229 meta.maintainers = with lib.maintainers; [ rgrunbla ]; 230}