nixos/actual: Fix access denied errors by exposing user, group and dataDir options (#470256)
This commit is contained in:
@@ -17,7 +17,6 @@ let
|
||||
;
|
||||
|
||||
cfg = config.services.actual;
|
||||
dataDir = "/var/lib/actual";
|
||||
|
||||
formatType = pkgs.formats.json { };
|
||||
in
|
||||
@@ -32,6 +31,26 @@ in
|
||||
description = "Whether to open the firewall for the specified port.";
|
||||
};
|
||||
|
||||
user = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
User account under which Actual runs.
|
||||
|
||||
If null is specified (default), a temporary user will be created by systemd. Otherwise won't be automatically created by the service.
|
||||
'';
|
||||
};
|
||||
|
||||
group = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.str;
|
||||
default = null;
|
||||
description = ''
|
||||
Group account under which Actual runs.
|
||||
|
||||
If null is specified (default), a temporary user will be created by systemd. Otherwise won't be automatically created by the service.
|
||||
'';
|
||||
};
|
||||
|
||||
settings = mkOption {
|
||||
default = { };
|
||||
description = ''
|
||||
@@ -53,12 +72,34 @@ in
|
||||
description = "The port to listen on";
|
||||
default = 3000;
|
||||
};
|
||||
};
|
||||
|
||||
config = {
|
||||
serverFiles = mkDefault "${dataDir}/server-files";
|
||||
userFiles = mkDefault "${dataDir}/user-files";
|
||||
dataDir = mkDefault dataDir;
|
||||
dataDir = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "/var/lib/actual";
|
||||
description = ''
|
||||
Directory under which Actual runs and saves its data.
|
||||
|
||||
Changing this after you already have a working instance may make Actual fail to start, even if you move all files in the data dir. If migration is needed, refer to [this comment](https://github.com/actualbudget/actual/issues/3957#issuecomment-2567076794) for a fix.
|
||||
'';
|
||||
};
|
||||
|
||||
serverFiles = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${cfg.settings.dataDir}/server-files";
|
||||
defaultText = "\${cfg.settings.dataDir}/server-files";
|
||||
description = ''
|
||||
The server will put an account.sqlite file in this directory, which will contain the (hashed) server password, a list of all the budget files the server knows about, and the active session token (along with anything else the server may want to store in the future).
|
||||
'';
|
||||
};
|
||||
|
||||
userFiles = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
default = "${cfg.settings.dataDir}/user-files";
|
||||
defaultText = "\${cfg.settings.dataDir}/user-files";
|
||||
description = ''
|
||||
The server will put all the budget files in this directory as binary blobs.
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -80,12 +121,9 @@ in
|
||||
|
||||
serviceConfig = {
|
||||
ExecStart = getExe cfg.package;
|
||||
DynamicUser = true;
|
||||
User = "actual";
|
||||
Group = "actual";
|
||||
StateDirectory = "actual";
|
||||
RuntimeDirectory = "actual";
|
||||
WorkingDirectory = dataDir;
|
||||
WorkingDirectory = cfg.settings.dataDir;
|
||||
LimitNOFILE = "1048576";
|
||||
PrivateTmp = true;
|
||||
PrivateDevices = true;
|
||||
@@ -107,6 +145,11 @@ in
|
||||
ProtectProc = "invisible";
|
||||
ProcSubset = "pid";
|
||||
ProtectSystem = "strict";
|
||||
ReadWritePaths = [
|
||||
cfg.settings.dataDir
|
||||
cfg.settings.serverFiles
|
||||
cfg.settings.userFiles
|
||||
];
|
||||
RestrictAddressFamilies = [
|
||||
"AF_INET"
|
||||
"AF_INET6"
|
||||
@@ -120,7 +163,21 @@ in
|
||||
"@pkey"
|
||||
];
|
||||
UMask = "0077";
|
||||
};
|
||||
}
|
||||
// (
|
||||
if cfg.user != null then
|
||||
{
|
||||
DynamicUser = false;
|
||||
Group = cfg.group;
|
||||
User = cfg.user;
|
||||
}
|
||||
else
|
||||
{
|
||||
DynamicUser = true;
|
||||
User = "actual";
|
||||
Group = "actual";
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,47 @@
|
||||
services.actual.enable = true;
|
||||
};
|
||||
|
||||
nodes.machine2 =
|
||||
{ ... }:
|
||||
{
|
||||
services.actual = {
|
||||
enable = true;
|
||||
user = "actual";
|
||||
group = "actual";
|
||||
settings = {
|
||||
port = 7000;
|
||||
dataDir = "/var/lib/actual-test";
|
||||
};
|
||||
};
|
||||
|
||||
users.users.actual = {
|
||||
group = "actual";
|
||||
home = "/var/lib/actual-test";
|
||||
isSystemUser = true;
|
||||
};
|
||||
|
||||
users.groups.actual = { };
|
||||
|
||||
systemd.tmpfiles.settings = {
|
||||
"10-actualdir" = {
|
||||
"/var/lib/actual-test" = {
|
||||
d = {
|
||||
group = "actual";
|
||||
mode = "0755";
|
||||
user = "actual";
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
machine.wait_for_open_port(3000)
|
||||
machine.succeed("curl -fvvv -Ls http://localhost:3000/ | grep 'Actual'")
|
||||
|
||||
machine2.wait_for_open_port(7000)
|
||||
machine2.succeed("curl -fvvv -Ls http://localhost:7000/ | grep 'Actual'")
|
||||
'';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user