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