diff --git a/modules/nixos/services/crowdsec/default.nix b/modules/nixos/services/crowdsec/default.nix index 1295801..f177599 100755 --- a/modules/nixos/services/crowdsec/default.nix +++ b/modules/nixos/services/crowdsec/default.nix @@ -129,6 +129,36 @@ let # secrets.apiKeyPath = config.sops.secrets."jallen-nas/crowdsec-firewall-bouncer-api-key".path; }; }; + + # The upstream crowdsec module uses ReadWritePaths (not StateDirectory) on + # crowdsec.service, meaning it expects /var/lib/crowdsec to exist as a real + # directory (created by tmpfiles). However, crowdsec-firewall-bouncer-register + # declares StateDirectory=crowdsec with DynamicUser=true, which conflicts: it + # tries to create /var/lib/private/crowdsec and symlink /var/lib/crowdsec → it, + # but /var/lib/crowdsec already exists as a real dir. Disabling DynamicUser on + # those two services lets them use the real crowdsec user/group instead, which is + # consistent with how crowdsec.service itself runs. + systemd.services.crowdsec.serviceConfig.DynamicUser = lib.mkForce false; + systemd.services.crowdsec-firewall-bouncer.serviceConfig.DynamicUser = lib.mkForce false; + systemd.services.crowdsec-firewall-bouncer-register.serviceConfig.DynamicUser = lib.mkForce false; + + # crowdsec-firewall-bouncer-register calls cscli without -c, so cscli + # looks for /etc/crowdsec/config.yaml. The upstream crowdsec.service uses + # a nix store path via -c and never creates that file. Expose the config + # at /etc/crowdsec/config.yaml by extracting the store path from the + # crowdsec service's ExecStart list at NixOS eval time. + environment.etc."crowdsec/config.yaml" = + let + # ExecStart is [ " " "/crowdsec -c -info" ] + execStart = builtins.elemAt config.systemd.services.crowdsec.serviceConfig.ExecStart 1; + configPath = builtins.head (builtins.match ".* -c ([^ ]+) .*" execStart); + in + { + source = configPath; + mode = "0440"; + user = "crowdsec"; + group = "crowdsec"; + }; }; }; in diff --git a/modules/nixos/services/samba/default.nix b/modules/nixos/services/samba/default.nix index 37a068b..2a2248c 100755 --- a/modules/nixos/services/samba/default.nix +++ b/modules/nixos/services/samba/default.nix @@ -20,7 +20,8 @@ let "create mask" = share.createMask; "directory mask" = share.directoryMask; } - // optionalAttrs (cfg.forceGroup != "") { "force group" = cfg.forceGroup; }; + // optionalAttrs (cfg.forceGroup != "") { "force group" = cfg.forceGroup; } + // optionalAttrs (cfg.forceUser != "") { "force user" = cfg.forceUser; }; timeMachineAttrs = { "vfs objects" = "catia fruit streams_xattr"; diff --git a/modules/nixos/services/samba/options.nix b/modules/nixos/services/samba/options.nix index a04b404..f4b82ea 100755 --- a/modules/nixos/services/samba/options.nix +++ b/modules/nixos/services/samba/options.nix @@ -16,6 +16,12 @@ with lib; description = "If non-empty, force all file creation to use this group."; }; + forceUser = mkOption { + type = types.str; + default = ""; + description = "If non-empty, force all connections (including guests) to run as this user. Required when using forceGroup with guest access, since guest maps to nobody which is not in the forced group."; + }; + enableTimeMachine = mkOption { type = types.bool; default = false; diff --git a/systems/x86_64-linux/jallen-nas/default.nix b/systems/x86_64-linux/jallen-nas/default.nix index 958304a..0a6513c 100755 --- a/systems/x86_64-linux/jallen-nas/default.nix +++ b/systems/x86_64-linux/jallen-nas/default.nix @@ -201,6 +201,7 @@ in enable = true; hostsAllow = "10.0.1. 127.0.0.1 localhost"; forceGroup = "jallen-nas"; + forceUser = "nix-apps"; enableTimeMachine = true; timeMachinePath = "/media/nas/main/timemachine"; @@ -280,6 +281,12 @@ in "/etc".neededForBoot = true; }; + # Ensure Samba share root directories are owned by nix-apps:jallen-nas + # so that force user = nix-apps can write to them. + systemd.tmpfiles.rules = [ + "d /media/nas/main 0775 nix-apps jallen-nas - -" + ]; + boot.initrd = { supportedFilesystems = { bcachefs = true;