at 25.11-pre 3.5 kB view raw
1{ 2 lib, 3 config, 4 pkgs, 5 utils, 6 ... 7}: 8 9let 10 inherit (lib) 11 mkEnableOption 12 mkIf 13 mkOption 14 types 15 ; 16 17 cfg = config.services.imaginary; 18in 19{ 20 options.services.imaginary = { 21 enable = mkEnableOption "imaginary image processing microservice"; 22 23 address = mkOption { 24 type = types.str; 25 default = "localhost"; 26 description = '' 27 Bind address. Corresponds to the `-a` flag. 28 Set to `""` to bind to all addresses. 29 ''; 30 example = "[::1]"; 31 }; 32 33 port = mkOption { 34 type = types.port; 35 default = 8088; 36 description = "Bind port. Corresponds to the `-p` flag."; 37 }; 38 39 settings = mkOption { 40 description = '' 41 Command line arguments passed to the imaginary executable, stripped of 42 the prefix `-`. See upstream's 43 [README](https://github.com/h2non/imaginary#command-line-usage) for all 44 options. 45 ''; 46 type = types.submodule { 47 freeformType = 48 with types; 49 attrsOf (oneOf [ 50 bool 51 int 52 (nonEmptyListOf str) 53 str 54 ]); 55 56 options = { 57 return-size = mkOption { 58 type = types.bool; 59 default = false; 60 description = "Return the image size in the HTTP headers."; 61 }; 62 }; 63 }; 64 }; 65 }; 66 67 config = mkIf cfg.enable { 68 assertions = [ 69 { 70 assertion = !lib.hasAttr "a" cfg.settings; 71 message = "Use services.imaginary.address to specify the -a flag."; 72 } 73 { 74 assertion = !lib.hasAttr "p" cfg.settings; 75 message = "Use services.imaginary.port to specify the -p flag."; 76 } 77 ]; 78 79 systemd.services.imaginary = { 80 after = [ "network.target" ]; 81 wantedBy = [ "multi-user.target" ]; 82 serviceConfig = rec { 83 ExecStart = 84 let 85 args = 86 lib.mapAttrsToList 87 (key: val: "-" + key + "=" + lib.concatStringsSep "," (map toString (lib.toList val))) 88 ( 89 cfg.settings 90 // { 91 a = cfg.address; 92 p = cfg.port; 93 } 94 ); 95 in 96 "${pkgs.imaginary}/bin/imaginary ${utils.escapeSystemdExecArgs args}"; 97 ProtectProc = "invisible"; 98 BindReadOnlyPaths = lib.optional (cfg.settings ? mount) cfg.settings.mount; 99 CapabilityBoundingSet = if cfg.port < 1024 then [ "CAP_NET_BIND_SERVICE" ] else [ "" ]; 100 AmbientCapabilities = CapabilityBoundingSet; 101 NoNewPrivileges = true; 102 DynamicUser = true; 103 ProtectSystem = "strict"; 104 ProtectHome = true; 105 TemporaryFileSystem = [ "/:ro" ]; 106 PrivateTmp = true; 107 PrivateDevices = true; 108 PrivateUsers = cfg.port >= 1024; 109 ProtectHostname = true; 110 ProtectClock = true; 111 ProtectKernelTunables = true; 112 ProtectKernelModules = true; 113 ProtectKernelLogs = true; 114 ProtectControlGroups = true; 115 RestrictAddressFamilies = [ 116 "AF_INET" 117 "AF_INET6" 118 ]; 119 RestrictNamespaces = true; 120 LockPersonality = true; 121 MemoryDenyWriteExecute = true; 122 RestrictRealtime = true; 123 PrivateMounts = true; 124 SystemCallFilter = [ 125 "@system-service" 126 "~@privileged" 127 ]; 128 DevicePolicy = "closed"; 129 }; 130 }; 131 }; 132 133 meta = { 134 maintainers = with lib.maintainers; [ dotlambda ]; 135 }; 136}