lol

nixos/pocket-id: init

Co-authored-by: ymstnt <21342713+YMSTNT@users.noreply.github.com>

gepbird.tngl.sh 01be6580 8dc9adb7

verified
+333
+2
nixos/doc/manual/release-notes/rl-2505.section.md
··· 166 166 167 167 - [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable). 168 168 169 + - [pocket-id](https://pocket-id.org/), an OIDC provider with passkeys support. Available as [services.pocket-id](#opt-services.pocket-id.enable). 170 + 169 171 - [nvidia-gpu](https://github.com/utkuozdemir/nvidia_gpu_exporter), a Prometheus exporter that scrapes `nvidia-smi` for GPU metrics. Available as [services.prometheus.exporters.nvidia-gpu](#opt-services.prometheus.exporters.nvidia-gpu.enable). 170 172 171 173 - [OpenGamepadUI](https://github.com/ShadowBlip/OpenGamepadUI/), an open source gamepad-native game launcher and overlay for Linux. Available as [programs.opengamepadui](#opt-programs.opengamepadui.enable).
+1
nixos/modules/module-list.nix
··· 1419 1419 ./services/security/paretosecurity.nix 1420 1420 ./services/security/pass-secret-service.nix 1421 1421 ./services/security/physlock.nix 1422 + ./services/security/pocket-id.nix 1422 1423 ./services/security/shibboleth-sp.nix 1423 1424 ./services/security/sks.nix 1424 1425 ./services/security/sshguard.nix
+278
nixos/modules/services/security/pocket-id.nix
··· 1 + { 2 + lib, 3 + pkgs, 4 + config, 5 + ... 6 + }: 7 + 8 + let 9 + inherit (lib) 10 + mkEnableOption 11 + mkIf 12 + mkOption 13 + optionalAttrs 14 + optional 15 + mkPackageOption 16 + ; 17 + inherit (lib.types) 18 + bool 19 + path 20 + str 21 + submodule 22 + ; 23 + 24 + cfg = config.services.pocket-id; 25 + 26 + format = pkgs.formats.keyValue { }; 27 + settingsFile = format.generate "pocket-id-env-vars" cfg.settings; 28 + in 29 + { 30 + meta.maintainers = with lib.maintainers; [ 31 + gepbird 32 + ymstnt 33 + ]; 34 + 35 + options.services.pocket-id = { 36 + enable = mkEnableOption "Pocket ID server"; 37 + 38 + package = mkPackageOption pkgs "pocket-id" { }; 39 + 40 + environmentFile = mkOption { 41 + type = path; 42 + description = '' 43 + Path to an environment file loaded for the Pocket ID service. 44 + 45 + This can be used to securely store tokens and secrets outside of the world-readable Nix store. 46 + 47 + Example contents of the file: 48 + MAXMIND_LICENSE_KEY=your-license-key 49 + ''; 50 + default = "/dev/null"; 51 + example = "/var/lib/secrets/pocket-id"; 52 + }; 53 + 54 + settings = mkOption { 55 + type = submodule { 56 + freeformType = format.type; 57 + 58 + options = { 59 + PUBLIC_APP_URL = mkOption { 60 + type = str; 61 + description = '' 62 + The URL where you will access the app. 63 + ''; 64 + default = "http://localhost"; 65 + }; 66 + 67 + TRUST_PROXY = mkOption { 68 + type = bool; 69 + description = '' 70 + Whether the app is behind a reverse proxy. 71 + ''; 72 + default = false; 73 + }; 74 + }; 75 + }; 76 + 77 + default = { }; 78 + 79 + description = '' 80 + Environment variables that will be passed to Pocket ID, see 81 + [configuration options](https://pocket-id.org/docs/configuration/environment-variables) 82 + for supported values. 83 + ''; 84 + }; 85 + 86 + dataDir = mkOption { 87 + type = path; 88 + default = "/var/lib/pocket-id"; 89 + description = '' 90 + The directory where Pocket ID will store its data, such as the database. 91 + ''; 92 + }; 93 + 94 + user = mkOption { 95 + type = str; 96 + default = "pocket-id"; 97 + description = "User account under which Pocket ID runs."; 98 + }; 99 + 100 + group = mkOption { 101 + type = str; 102 + default = "pocket-id"; 103 + description = "Group account under which Pocket ID runs."; 104 + }; 105 + }; 106 + 107 + config = mkIf cfg.enable { 108 + warnings = ( 109 + optional (cfg.settings ? MAXMIND_LICENSE_KEY) 110 + "config.services.pocket-id.settings.MAXMIND_LICENSE_KEY will be stored as plaintext in the Nix store. Use config.services.pocket-id.environmentFile instead." 111 + ); 112 + 113 + systemd.tmpfiles.rules = [ 114 + "d ${cfg.dataDir} 0755 ${cfg.user} ${cfg.group}" 115 + ]; 116 + 117 + systemd.services = { 118 + pocket-id-backend = { 119 + description = "Pocket ID backend"; 120 + after = [ "network.target" ]; 121 + wantedBy = [ "multi-user.target" ]; 122 + restartTriggers = [ 123 + cfg.package 124 + cfg.environmentFile 125 + settingsFile 126 + ]; 127 + 128 + serviceConfig = { 129 + Type = "simple"; 130 + User = cfg.user; 131 + Group = cfg.group; 132 + WorkingDirectory = cfg.dataDir; 133 + ExecStart = "${cfg.package}/bin/pocket-id-backend"; 134 + Restart = "always"; 135 + EnvironmentFile = [ 136 + cfg.environmentFile 137 + settingsFile 138 + ]; 139 + 140 + # Hardening 141 + AmbientCapabilities = ""; 142 + CapabilityBoundingSet = ""; 143 + DeviceAllow = ""; 144 + DevicePolicy = "closed"; 145 + #IPAddressDeny = "any"; # communicates with the frontend 146 + LockPersonality = true; 147 + MemoryDenyWriteExecute = true; 148 + NoNewPrivileges = true; 149 + PrivateDevices = true; 150 + PrivateNetwork = false; # communicates with the frontend 151 + PrivateTmp = true; 152 + PrivateUsers = true; 153 + ProcSubset = "pid"; 154 + ProtectClock = true; 155 + ProtectControlGroups = true; 156 + ProtectHome = true; 157 + ProtectHostname = true; 158 + ProtectKernelLogs = true; 159 + ProtectKernelModules = true; 160 + ProtectKernelTunables = true; 161 + ProtectProc = "invisible"; 162 + ProtectSystem = "full"; # needs to write in cfg.dataDir 163 + RemoveIPC = true; 164 + RestrictAddressFamilies = [ 165 + "AF_INET" 166 + "AF_INET6" 167 + ]; 168 + RestrictNamespaces = true; 169 + RestrictRealtime = true; 170 + RestrictSUIDSGID = true; 171 + SystemCallArchitectures = "native"; 172 + SystemCallFilter = lib.concatStringsSep " " [ 173 + "~" 174 + "@clock" 175 + "@cpu-emulation" 176 + "@debug" 177 + "@module" 178 + "@mount" 179 + "@obsolete" 180 + "@privileged" 181 + "@raw-io" 182 + "@reboot" 183 + #"@resources" # vm test segfaults 184 + "@swap" 185 + ]; 186 + UMask = "0077"; 187 + }; 188 + }; 189 + 190 + pocket-id-frontend = { 191 + description = "Pocket ID frontend"; 192 + after = [ 193 + "network.target" 194 + "pocket-id-backend.service" 195 + ]; 196 + wantedBy = [ "multi-user.target" ]; 197 + restartTriggers = [ 198 + cfg.package 199 + cfg.environmentFile 200 + settingsFile 201 + ]; 202 + 203 + serviceConfig = { 204 + Type = "simple"; 205 + User = cfg.user; 206 + Group = cfg.group; 207 + ExecStart = "${cfg.package}/bin/pocket-id-frontend"; 208 + Restart = "always"; 209 + EnvironmentFile = [ 210 + cfg.environmentFile 211 + settingsFile 212 + ]; 213 + 214 + # Hardening 215 + AmbientCapabilities = ""; 216 + CapabilityBoundingSet = ""; 217 + DeviceAllow = ""; 218 + DevicePolicy = "closed"; 219 + #IPAddressDeny = "any"; # communicates with the backend and client 220 + LockPersonality = true; 221 + MemoryDenyWriteExecute = false; # V8_Fatal segfault 222 + NoNewPrivileges = true; 223 + PrivateDevices = true; 224 + PrivateNetwork = false; # communicates with the backend and client 225 + PrivateTmp = true; 226 + PrivateUsers = true; 227 + ProcSubset = "pid"; 228 + ProtectClock = true; 229 + ProtectControlGroups = true; 230 + ProtectHome = true; 231 + ProtectHostname = true; 232 + ProtectKernelLogs = true; 233 + ProtectKernelModules = true; 234 + ProtectKernelTunables = true; 235 + ProtectProc = "invisible"; 236 + ProtectSystem = "strict"; 237 + RemoveIPC = true; 238 + RestrictAddressFamilies = [ 239 + "AF_INET" 240 + "AF_INET6" 241 + ]; 242 + RestrictNamespaces = true; 243 + RestrictRealtime = true; 244 + RestrictSUIDSGID = true; 245 + SystemCallArchitectures = "native"; 246 + SystemCallFilter = lib.concatStringsSep " " [ 247 + "~" 248 + "@clock" 249 + "@cpu-emulation" 250 + "@debug" 251 + "@module" 252 + "@mount" 253 + "@obsolete" 254 + "@privileged" 255 + "@raw-io" 256 + "@reboot" 257 + "@resources" 258 + "@swap" 259 + ]; 260 + UMask = "0077"; 261 + }; 262 + }; 263 + }; 264 + 265 + users.users = optionalAttrs (cfg.user == "pocket-id") { 266 + pocket-id = { 267 + isSystemUser = true; 268 + group = cfg.group; 269 + description = "Pocket ID backend user"; 270 + home = cfg.dataDir; 271 + }; 272 + }; 273 + 274 + users.groups = optionalAttrs (cfg.group == "pocket-id") { 275 + pocket-id = { }; 276 + }; 277 + }; 278 + }
+1
nixos/tests/all-tests.nix
··· 1039 1039 pleroma = handleTestOn [ "x86_64-linux" "aarch64-linux" ] ./pleroma.nix { }; 1040 1040 plikd = handleTest ./plikd.nix { }; 1041 1041 plotinus = handleTest ./plotinus.nix { }; 1042 + pocket-id = handleTest ./pocket-id.nix { }; 1042 1043 podgrab = handleTest ./podgrab.nix { }; 1043 1044 podman = handleTestOn [ "aarch64-linux" "x86_64-linux" ] ./podman/default.nix { }; 1044 1045 podman-tls-ghostunnel = handleTestOn [
+47
nixos/tests/pocket-id.nix
··· 1 + import ./make-test-python.nix ( 2 + { lib, ... }: 3 + 4 + { 5 + name = "pocket-id"; 6 + meta.maintainers = with lib.maintainers; [ 7 + gepbird 8 + ymstnt 9 + ]; 10 + 11 + nodes = { 12 + machine = 13 + { ... }: 14 + { 15 + services.pocket-id = { 16 + enable = true; 17 + settings = { 18 + PORT = 10001; 19 + INTERNAL_BACKEND_URL = "http://localhost:10002"; 20 + BACKEND_PORT = 10002; 21 + }; 22 + }; 23 + }; 24 + }; 25 + 26 + testScript = 27 + { nodes, ... }: 28 + let 29 + inherit (nodes.machine.services.pocket-id) settings; 30 + inherit (builtins) toString; 31 + in 32 + '' 33 + machine.wait_for_unit("pocket-id-backend.service") 34 + machine.wait_for_open_port(${toString settings.BACKEND_PORT}) 35 + machine.wait_for_unit("pocket-id-frontend.service") 36 + machine.wait_for_open_port(${toString settings.PORT}) 37 + 38 + backend_status = machine.succeed("curl -L -o /tmp/backend-output -w '%{http_code}' http://localhost:${toString settings.BACKEND_PORT}/api/users/me") 39 + assert backend_status == "401" 40 + machine.succeed("grep 'You are not signed in' /tmp/backend-output") 41 + 42 + frontend_status = machine.succeed("curl -L -o /tmp/frontend-output -w '%{http_code}' http://localhost:${toString settings.PORT}") 43 + assert frontend_status == "200" 44 + machine.succeed("grep 'Sign in to Pocket ID' /tmp/frontend-output") 45 + ''; 46 + } 47 + )
+4
pkgs/by-name/po/pocket-id/package.nix
··· 7 7 makeWrapper, 8 8 nodejs, 9 9 stdenvNoCC, 10 + nixosTests, 10 11 nix-update-script, 11 12 }: 12 13 ··· 91 92 ''; 92 93 93 94 passthru = { 95 + tests = { 96 + inherit (nixosTests) pocket-id; 97 + }; 94 98 updateScript = nix-update-script { 95 99 extraArgs = [ 96 100 "--subpackage"