at master 6.7 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 systemd.services.galene = { 132 description = "galene"; 133 after = [ "network.target" ]; 134 wantedBy = [ "multi-user.target" ]; 135 136 preStart = '' 137 ${optionalString (cfg.insecure != true && cfg.certFile != null && cfg.keyFile != null) '' 138 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.certFile} ${cfg.dataDir}/cert.pem 139 install -m 700 -o '${cfg.user}' -g '${cfg.group}' ${cfg.keyFile} ${cfg.dataDir}/key.pem 140 ''} 141 ''; 142 143 serviceConfig = mkMerge [ 144 { 145 Type = "simple"; 146 User = cfg.user; 147 Group = cfg.group; 148 WorkingDirectory = cfg.stateDir; 149 ExecStart = '' 150 ${cfg.package}/bin/galene \ 151 ${optionalString (cfg.insecure) "-insecure"} \ 152 -http ${cfg.httpAddress}:${toString cfg.httpPort} \ 153 -turn ${cfg.turnAddress} \ 154 -data ${cfg.dataDir} \ 155 -groups ${cfg.groupsDir} \ 156 -recordings ${cfg.recordingsDir} \ 157 -static ${cfg.staticDir}''; 158 Restart = "always"; 159 # Upstream Requirements 160 LimitNOFILE = 65536; 161 StateDirectory = 162 [ ] 163 ++ optional (cfg.stateDir == defaultstateDir) "galene" 164 ++ optional (cfg.dataDir == defaultdataDir) "galene/data" 165 ++ optional (cfg.groupsDir == defaultgroupsDir) "galene/groups" 166 ++ optional (cfg.recordingsDir == defaultrecordingsDir) "galene/recordings"; 167 168 # Hardening 169 CapabilityBoundingSet = [ "" ]; 170 DeviceAllow = [ "" ]; 171 LockPersonality = true; 172 MemoryDenyWriteExecute = true; 173 NoNewPrivileges = true; 174 PrivateDevices = true; 175 PrivateTmp = true; 176 PrivateUsers = true; 177 ProcSubset = "pid"; 178 ProtectClock = true; 179 ProtectControlGroups = true; 180 ProtectHome = true; 181 ProtectHostname = true; 182 ProtectKernelLogs = true; 183 ProtectKernelModules = true; 184 ProtectKernelTunables = true; 185 ProtectProc = "invisible"; 186 ProtectSystem = "strict"; 187 ReadWritePaths = cfg.recordingsDir; 188 RemoveIPC = true; 189 RestrictAddressFamilies = [ 190 "AF_INET" 191 "AF_INET6" 192 "AF_NETLINK" 193 ]; 194 RestrictNamespaces = true; 195 RestrictRealtime = true; 196 RestrictSUIDSGID = true; 197 SystemCallArchitectures = "native"; 198 SystemCallFilter = [ 199 "@system-service" 200 "~@privileged" 201 ]; 202 UMask = "0077"; 203 } 204 ]; 205 }; 206 207 users.users = mkIf (cfg.user == "galene") { 208 galene = { 209 description = "galene Service"; 210 group = cfg.group; 211 isSystemUser = true; 212 }; 213 }; 214 215 users.groups = mkIf (cfg.group == "galene") { 216 galene = { }; 217 }; 218 }; 219 meta.maintainers = with lib.maintainers; [ rgrunbla ]; 220}