Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/imaginary: init #215222

Merged
merged 2 commits into from
Feb 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions nixos/doc/manual/release-notes/rl-2305.section.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ In addition to numerous new and upgraded packages, this release has the followin

- [stevenblack-blocklist](https://github.com/StevenBlack/hosts), A unified hosts file with base extensions for blocking unwanted websites. Available as [networking.stevenblack](options.html#opt-networking.stevenblack.enable).

- [imaginary](https://github.com/h2non/imaginary), a microservice for high-level image processing that Nextcloud can use to generate previews. Available as [services.imaginary](#opt-services.imaginary.enable).

- [goeland](https://github.com/slurdge/goeland), an alternative to rss2email written in golang with many filters. Available as [services.goeland](#opt-services.goeland.enable).

- [atuin](https://github.com/ellie/atuin), a sync server for shell history. Available as [services.atuin](#opt-services.atuin.enable).
Expand Down
1 change: 1 addition & 0 deletions nixos/modules/module-list.nix
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@
./services/networking/i2pd.nix
./services/networking/icecream/daemon.nix
./services/networking/icecream/scheduler.nix
./services/networking/imaginary.nix
./services/networking/inspircd.nix
./services/networking/iodine.nix
./services/networking/iperf3.nix
Expand Down
110 changes: 110 additions & 0 deletions nixos/modules/services/networking/imaginary.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
{ lib, config, pkgs, utils, ... }:

let
inherit (lib) mdDoc mkEnableOption mkIf mkOption types;

cfg = config.services.imaginary;
in {
options.services.imaginary = {
enable = mkEnableOption (mdDoc "imaginary image processing microservice");

address = mkOption {
type = types.str;
default = "";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does emptry string equal to localhost? If I understand the nextcloud doc correct it sounds like you want to run imaginary always bound on localhost.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it does mean that according to https://pkg.go.dev/net#Dial. I went with upstream's default: https://github.com/h2non/imaginary/blob/master/imaginary.go#L20

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, it means any address. That's also what it says in https://github.com/h2non/imaginary#command-line-usage.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it should be changed to localhost by default. See #100192. But the problem is that localhost means 127.0.0.1 and doesn't include ::1.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use [::1]?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, gotta love it. golang/go#9334

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we set address = "localhost" by default anyway?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if it's primarily not meant to be accessed from other hosts, probably? don't know enough about the service to be sure. but then again, if it makes for such interesting complications it might just be better to rely on the firewall existing and a note that by default all addresses are bound? 😕

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the nextcloud use case it is only accessed through localhost.

description = mdDoc "Bind address. Corresponds to the `-a` flag.";
example = "localhost";
};

port = mkOption {
type = types.port;
default = 8088;
description = mdDoc "Bind port. Corresponds to the `-p` flag.";
};

settings = mkOption {
description = mdDoc ''
Command line arguments passed to the imaginary executable, stripped of
the prefix `-`. See upstream's
[README](https://github.com/h2non/imaginary#command-line-usage) for all
options.
'';
type = types.submodule {
freeformType = with types; attrsOf (oneOf [
bool
int
(nonEmptyListOf str)
str
]);

options = {
return-size = mkOption {
type = types.bool;
default = false;
description = mdDoc "Return the image size in the HTTP headers.";
};
};
};
};
};

config = mkIf cfg.enable {
assertions = [ {
assertion = ! lib.hasAttr "a" cfg.settings;
message = "Use services.imaginary.address to specify the -a flag.";
} {
assertion = ! lib.hasAttr "p" cfg.settings;
message = "Use services.imaginary.port to specify the -p flag.";
} ];

systemd.services.imaginary = {
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = rec {
ExecStart = let
args = lib.mapAttrsToList (key: val:
"-" + key + "=" + lib.concatStringsSep "," (map toString (lib.toList val))
) (cfg.settings // { a = cfg.address; p = cfg.port; });
in "${pkgs.imaginary}/bin/imaginary ${utils.escapeSystemdExecArgs args}";
ProtectProc = "invisible";
BindReadOnlyPaths = lib.optional (cfg.settings ? mount) cfg.settings.mount;
CapabilityBoundingSet = if cfg.port < 1024 then
[ "CAP_NET_BIND_SERVICE" ]
else
[ "" ];
AmbientCapabilities = CapabilityBoundingSet;
NoNewPrivileges = true;
DynamicUser = true;
ProtectSystem = "strict";
ProtectHome = true;
TemporaryFileSystem = [ "/:ro" ];
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = cfg.port >= 1024;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
PrivateMounts = true;
SystemCallFilter = [
"@system-service"
"~@privileged"
];
DevicePolicy = "closed";
};
};
};

meta = {
maintainers = with lib.maintainers; [ dotlambda ];
};
}
20 changes: 18 additions & 2 deletions pkgs/servers/imaginary/default.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
{ lib, buildGoModule, fetchFromGitHub, pkg-config, vips }:
{ lib
, buildGoModule
, fetchFromGitHub
, fetchpatch
, pkg-config
, vips
}:

buildGoModule rec {
pname = "imaginary";
Expand All @@ -11,6 +17,16 @@ buildGoModule rec {
hash = "sha256-oEkFoZMaNNJPMisqpIneeLK/sA23gaTWJ4nqtDHkrwA=";
};

patches = [
dotlambda marked this conversation as resolved.
Show resolved Hide resolved
# add -return-size flag recommend by Nextcloud
# https://github.com/h2non/imaginary/pull/382
(fetchpatch {
name = "return-width-and-height-of-generated-images.patch";
url = "https://github.com/h2non/imaginary/commit/cfbf8d724cd326e835dfcb01e7224397c46037d3.patch";
hash = "sha256-TwZ5WU5g9LXrenpfY52jYsc6KsEt2fjDq7cPz6ILlhA=";
})
];

vendorHash = "sha256-BluY6Fz4yAKJ/A9aFuPPsgQN9N/5yd8g8rDfIZeYz5U=";

buildInputs = [ vips ];
Expand All @@ -28,6 +44,6 @@ buildGoModule rec {
changelog = "https://github.com/h2non/${pname}/releases/tag/v${version}";
description = "Fast, simple, scalable, Docker-ready HTTP microservice for high-level image processing";
license = licenses.mit;
maintainers = with maintainers; [ urandom ];
maintainers = with maintainers; [ dotlambda urandom ];
};
}