diff --git a/modules/nixos/samba.nix b/modules/nixos/samba.nix new file mode 100644 index 00000000..198db7a5 --- /dev/null +++ b/modules/nixos/samba.nix @@ -0,0 +1,192 @@ +{ + config, + lib, + pkgs, + ... +}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge mkDefault mkOptionDefault; + inherit (lib.attrsets) mapAttrs' mapAttrsToList nameValuePair; + inherit (lib.strings) hasPrefix concatMapStringsSep; + inherit (config.services) samba-wsdd; + cfg = config.services.samba; + settingValue = value: + if builtins.isList value then concatMapStringsSep ", " settingValue value + else if value == true then "yes" + else if value == false then "no" + else toString value; +in { + options.services.samba = with lib.types; let + settingPrimitive = oneOf [ str int bool ]; + settingType = oneOf [ settingPrimitive (listOf settingPrimitive) ]; + in { + ldap = { + enable = mkEnableOption "LDAP"; + idmapDomain = mkOption { + type = str; + default = "*"; + }; + url = mkOption { + type = str; + }; + baseDn = mkOption { + type = str; + }; + adminDn = mkOption { + type = str; + default = "name=anonymous,${cfg.ldap.baseDn}"; + }; + adminPasswordPath = mkOption { + type = nullOr path; + default = null; + }; + }; + usershare = { + enable = mkEnableOption "usershare"; + group = mkOption { + type = str; + default = "users"; + }; + path = mkOption { + type = path; + default = "/var/lib/samba/usershares"; + }; + templateShare = mkOption { + type = str; + default = "usershare-template"; + }; + }; + idmap = let + idmapModule = { config, name, ... }: { + options = { + backend = mkOption { + type = str; + }; + domain = mkOption { + type = str; + default = name; + }; + range = { + min = mkOption { + type = int; + default = 1000; + }; + max = mkOption { + type = int; + default = 10000; + }; + }; + readOnly = mkOption { + type = bool; + default = true; + }; + settings = mkOption { + type = attrsOf settingType; + default = { }; + }; + }; + config = { + settings = { + backend = mkOptionDefault config.backend; + "read only" = mkOptionDefault config.readOnly; + range = mkOptionDefault "${toString config.range.min} - ${toString config.range.max}"; + }; + }; + }; + in { + domains = mkOption { + type = attrsOf (submodule idmapModule); + default = { + nss = { + backend = "nss"; + domain = "*"; + }; + }; + }; + }; + passdb.smbpasswd.path = mkOption { + type = nullOr path; + default = null; + }; + settings = mkOption { + type = attrsOf settingType; + default = { }; + }; + }; + + config = { + services.samba = { + package = mkIf cfg.ldap.enable (mkDefault (pkgs.samba.override { + enableLDAP = true; + })); + ldap = { + adminPasswordPath = mkIf (hasPrefix "name=anonymous," cfg.ldap.adminDn) (mkDefault ( + pkgs.writeText "smb-ldap-anonymous" "anonymous" + )); + }; + idmap.domains = mkMerge [ + (mkIf cfg.ldap.enable { + ldap = { + domain = mkDefault cfg.ldap.idmapDomain; + }; + }) + ]; + settings = mkMerge ([ + (mkIf (cfg.passdb.smbpasswd.path != null) { + "passdb backend" = "smbpasswd:${cfg.passdb.smbpasswd.path}"; + }) + (mkIf cfg.ldap.enable { + "passdb backend" = mkOptionDefault ''ldapsam:"${cfg.ldap.url}"''; + "ldap ssl" = mkIf (hasPrefix "ldaps://" cfg.ldap.url) (mkOptionDefault "off"); + "ldap admin dn" = mkOptionDefault "name=anonymous,${cfg.ldap.baseDn}"; + "ldap suffix" = mkOptionDefault cfg.ldap.baseDn; + }) + (mkIf (cfg.ldap.enable && true) { + "ntlm auth" = mkOptionDefault "disabled"; + "encrypt passwords" = mkOptionDefault false; + }) + (mkIf cfg.usershare.enable { + "usershare allow guests" = mkOptionDefault true; + "usershare max shares" = mkOptionDefault 16; + "usershare owner only" = mkOptionDefault true; + "usershare template share" = mkOptionDefault cfg.usershare.templateShare; + "usershare path" = mkOptionDefault cfg.usershare.path; + "usershare prefix allow list" = mkOptionDefault [ cfg.usershare.path ]; + }) + ] ++ mapAttrsToList (_: idmap: mapAttrs' (key: value: nameValuePair "idmap config ${idmap.domain} : ${key}" (mkOptionDefault value)) idmap.settings) cfg.idmap.domains); + extraConfig = mkMerge (mapAttrsToList (key: value: ''${key} = ${settingValue value}'') cfg.settings); + shares.${cfg.usershare.templateShare} = mkIf cfg.usershare.enable { + "-valid" = false; + }; + }; + + systemd.services.samba-smbd = mkIf cfg.enable { + serviceConfig = let + ldap-pass = pkgs.writeShellScript "samba-ldap-pass" '' + ${cfg.package}/bin/smbpasswd -c /etc/samba/smb.conf -w $(cat ${cfg.ldap.adminPasswordPath}) + ''; + in { + ExecStartPre = mkMerge [ + (mkIf (cfg.ldap.enable && cfg.ldap.adminPasswordPath != null) [ + "${ldap-pass}" + ]) + ]; + }; + }; + + systemd.tmpfiles.rules = mkIf (cfg.enable && cfg.usershare.enable) [ + "d ${cfg.usershare.path} 1770 root ${cfg.usershare.group}" + ]; + + networking.firewall.interfaces.local = { + allowedTCPPorts = mkMerge [ + (mkIf (cfg.enable && !cfg.openFirewall) [ 139 445 ]) + (mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [ 5357 ]) + ]; + allowedUDPPorts = mkMerge [ + (mkIf (cfg.enable && !cfg.openFirewall) [ 137 138 ]) + (mkIf (samba-wsdd.enable && !samba-wsdd.openFirewall) [ 3702 ]) + ]; + }; + }; +} diff --git a/nixos/bazarr.nix b/nixos/bazarr.nix index d3a94eef..a2dada88 100644 --- a/nixos/bazarr.nix +++ b/nixos/bazarr.nix @@ -8,4 +8,5 @@ in { enable = mkDefault true; listenPort = mkDefault 6767; }; + users.users.bazarr.extraGroups = [ "kyuuto" ]; } diff --git a/nixos/deluge.nix b/nixos/deluge.nix index b8e51344..51296bdd 100644 --- a/nixos/deluge.nix +++ b/nixos/deluge.nix @@ -57,4 +57,7 @@ in { download (mkIf (completedDir != null && !hasCompletedSubdir) completed) ]); + users.users.deluge = mkIf cfg.enable { + extraGroups = [ "kyuuto" ]; + }; } diff --git a/nixos/kyuuto/mount.nix b/nixos/kyuuto/mount.nix new file mode 100644 index 00000000..f23cd451 --- /dev/null +++ b/nixos/kyuuto/mount.nix @@ -0,0 +1,62 @@ +{ + config, + lib, + ... +}: let + inherit (lib.options) mkOption mkEnableOption; + inherit (lib.modules) mkIf mkMerge; + cfg = config.kyuuto; +in { + options.kyuuto = with lib.types; { + setup = mkEnableOption "directory and permission setup"; + mountDir = mkOption { + type = path; + default = "/mnt/kyuuto-media"; + }; + libraryDir = mkOption { + type = path; + default = cfg.mountDir + "/library"; + }; + transferDir = mkOption { + type = path; + default = cfg.mountDir + "/transfer"; + }; + }; + + config = { + systemd.tmpfiles.rules = mkIf cfg.setup [ + "d ${cfg.transferDir} 3775 root kyuuto" + "d ${cfg.libraryDir} 3775 root kyuuto" + "d ${cfg.libraryDir}/unsorted 3775 root kyuuto" + "d ${cfg.libraryDir}/music 7775 sonarr kyuuto" + "d ${cfg.libraryDir}/anime 7775 sonarr kyuuto" + "d ${cfg.libraryDir}/tv 7775 sonarr kyuuto" + "d ${cfg.libraryDir}/movies 7775 radarr kyuuto" + ]; + + users = let + mapId = id: if config.proxmoxLXC.privileged or true then 100000 + id else id; + mkDummyUsers = { + name, + group ? name, + enable ? !config.services.${serviceName}.enable, serviceName ? name, + uid ? config.ids.uids.${name}, + gid ? config.ids.gids.${group} + }: mkIf enable { + users.${name} = { + group = mkIf (group != null) group; + uid = mapId uid; + isSystemUser = true; + }; + groups.${group} = { + gid = mapId gid; + }; + }; + in mkMerge [ + (mkDummyUsers { name = "deluge"; }) + (mkDummyUsers { name = "radarr"; }) + (mkDummyUsers { name = "sonarr"; }) + (mkDummyUsers { name = "lidarr"; }) + ]; + }; +} diff --git a/nixos/kyuuto/nfs.nix b/nixos/kyuuto/nfs.nix new file mode 100644 index 00000000..f501607f --- /dev/null +++ b/nixos/kyuuto/nfs.nix @@ -0,0 +1,26 @@ + +{ + config, + lib, + ... +}: let + inherit (lib.lists) optionals; + inherit (lib.strings) concatStringsSep; + inherit (config.networking.access) cidrForNetwork; + inherit (config) kyuuto; +in { + services.nfs.server.exports = let + mapPerm = perm: map (addr: "${addr}(${perm})"); + toPerms = concatStringsSep " "; + localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all; + tailAddrs = optionals config.services.tailscale.enable cidrForNetwork.tail.all; + allAddrs = localAddrs ++ tailAddrs; + kyuutoPerms = + mapPerm "ro" localAddrs + ++ mapPerm "rw" tailAddrs; + transferPerms = mapPerm "rw" allAddrs; + in '' + ${kyuuto.mountDir} ${toPerms kyuutoPerms} + ${kyuuto.transferDir} ${toPerms transferPerms} + ''; +} diff --git a/nixos/kyuuto/samba.nix b/nixos/kyuuto/samba.nix new file mode 100644 index 00000000..fdbeaefb --- /dev/null +++ b/nixos/kyuuto/samba.nix @@ -0,0 +1,49 @@ + +{ + config, + lib, + ... +}: let + inherit (lib.modules) mkIf mkDefault; + inherit (lib.lists) optionals; + inherit (config.networking.access) cidrForNetwork; + inherit (config) kyuuto; + cfg = config.services.samba; + localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all + ++ optionals config.services.tailscale.enable cidrForNetwork.tail.all; +in { + services.samba = { + usershare = { + enable = mkDefault true; + path = mkDefault (kyuuto.mountDir + "/usershares"); + }; + shares = mkIf cfg.enable { + kyuuto-transfer = { + path = kyuuto.transferDir; + writeable = true; + browseable = true; + public = true; + "acl group control" = true; + #"guest only" = true; + comment = "Kyuuto Media Transfer Area"; + "hosts allow" = localAddrs; + }; + kyuuto-access = { + path = kyuuto.libraryDir; + writeable = false; + browseable = true; + public = true; + comment = "Kyuuto Media Access"; + "hosts allow" = localAddrs; + }; + kyuuto-media = { + path = kyuuto.mountDir; + writeable = true; + browseable = true; + public = false; + comment = "Kyuuto Media"; + "valid users" = [ "@kyuuto" ]; + }; + }; + }; +} diff --git a/nixos/lidarr.nix b/nixos/lidarr.nix index a82e7c25..df05bd67 100644 --- a/nixos/lidarr.nix +++ b/nixos/lidarr.nix @@ -2,4 +2,5 @@ _: { services.lidarr = { enable = true; }; + users.users.lidarr.extraGroups = [ "kyuuto" ]; } diff --git a/nixos/radarr.nix b/nixos/radarr.nix index 462c44e2..271b4158 100644 --- a/nixos/radarr.nix +++ b/nixos/radarr.nix @@ -2,4 +2,6 @@ _: { services.radarr = { enable = true; }; + + users.users.radarr.extraGroups = [ "kyuuto" ]; } diff --git a/nixos/readarr.nix b/nixos/readarr.nix index 0f183d5d..2e744eed 100644 --- a/nixos/readarr.nix +++ b/nixos/readarr.nix @@ -2,4 +2,5 @@ _: { services.readarr = { enable = true; }; + users.users.readarr.extraGroups = [ "kyuuto" ]; } diff --git a/nixos/samba.nix b/nixos/samba.nix index 5b8dcda8..879a5b10 100644 --- a/nixos/samba.nix +++ b/nixos/samba.nix @@ -7,7 +7,7 @@ }: let inherit (lib.modules) mkIf mkMerge mkDefault; inherit (lib.lists) any; - inherit (lib.strings) hasInfix; + inherit (lib.strings) hasInfix concatMapStringsSep splitString; inherit (config.services) samba samba-wsdd; system = access.systemFor "tei"; inherit (system.services) kanidm; @@ -19,55 +19,29 @@ in { enableWinbindd = mkDefault false; enableNmbd = mkDefault hasIpv4; securityType = mkDefault "user"; - package = mkIf enableLdap (mkDefault (pkgs.samba.override { - enableLDAP = true; - })); - extraConfig = mkMerge [ - '' - workgroup = GENSOKYO - local master = no - preferred master = no - winbind offline logon = yes - winbind scan trusted domains = no - winbind use default domain = yes - domain master = no - valid users = nobody, arc, kat, @nfs - map to guest = Bad User - guest account = nobody - '' - (mkIf hasIpv4 '' - remote announce = 10.1.1.255/GENSOKYO - '') - (mkIf enableLdap '' - idmap config * : backend = ldap - idmap config * : range = 1000 - 2000 - idmap config * : read only = yes - idmap config * : ldap_url = ldaps://ldap.local.${config.networking.domain} - idmap config * : ldap_base_dn = ${kanidm.server.ldap.baseDn} - passdb backend = ldapsam:"ldaps://ldap.local.${config.networking.domain}" - ldap ssl = off - ldap admin dn = name=anonymous,${kanidm.server.ldap.baseDn} - ldap suffix = ${kanidm.server.ldap.baseDn} - ntlm auth = disabled - encrypt passwords = no - '') - (mkIf (!enableLdap) '' - passdb backend = smbpasswd:${config.sops.secrets.smbpasswd.path} - idmap config * : backend = nss - idmap config * : range = 1000 - 2000 - idmap config * : read only = yes - '') - ]; - }; - - systemd.services.samba-smbd = mkIf samba.enable { - serviceConfig.ExecStartPre = let - ldap-pass = pkgs.writeShellScript "smb-ldap-pass" '' - ${samba.package}/bin/smbpasswd -c /etc/samba/smb.conf -w anonymous - ''; - in mkIf enableLdap [ - "${ldap-pass}" - ]; + ldap = { + url = mkDefault "ldaps://ldap.local.${config.networking.domain}"; + baseDn = mkDefault (concatMapStringsSep "," (part: "dc=${part}") (splitString "." config.networking.domain)); + }; + usershare = { + group = mkDefault "peeps"; + }; + passdb.smbpasswd.path = mkDefault config.sops.secrets.smbpasswd.path; + settings = { + workgroup = "GENSOKYO"; + "local master" = false; + "preferred master" = false; + "winbind offline logon" = true; + "winbind scan trusted domains" = false; + "winbind use default domain" = true; + "domain master" = false; + "valid users" = [ "nobody" "@peeps" ]; + "map to guest" = "Bad User"; + "guest account" = "nobody"; + "remote announce" = mkIf hasIpv4 [ + "10.1.1.255/${samba.settings.workgroup}" + ]; + }; }; services.samba-wsdd = mkIf samba.enable { @@ -75,17 +49,6 @@ in { hostname = mkDefault config.networking.hostName; }; - networking.firewall.interfaces.local = { - allowedTCPPorts = mkMerge [ - (mkIf samba.enable [ 139 445 ]) - (mkIf samba-wsdd.enable [ 5357 ]) - ]; - allowedUDPPorts = mkMerge [ - (mkIf samba.enable [ 137 138 ]) - (mkIf samba-wsdd.enable [ 3702 ]) - ]; - }; - sops.secrets.smbpasswd = { sopsFile = mkDefault ./secrets/samba.yaml; #path = "/var/lib/samba/private/smbpasswd"; diff --git a/nixos/sonarr.nix b/nixos/sonarr.nix index 30bd2848..7ebbc5bc 100644 --- a/nixos/sonarr.nix +++ b/nixos/sonarr.nix @@ -2,4 +2,5 @@ _: { services.sonarr = { enable = true; }; + users.users.sonarr.extraGroups = [ "kyuuto" ]; } diff --git a/systems/mediabox/nixos.nix b/systems/mediabox/nixos.nix index 6c06edbe..4971f51f 100644 --- a/systems/mediabox/nixos.nix +++ b/systems/mediabox/nixos.nix @@ -9,13 +9,12 @@ inherit (lib.attrsets) mapAttrs mapAttrsToList; inherit (lib.strings) removePrefix; inherit (config.services) deluge plex tautulli ombi sonarr radarr bazarr lidarr readarr prowlarr cloudflared; - kyuuto = "/mnt/kyuuto-media"; - kyuuto-library = kyuuto + "/library"; + inherit (config) kyuuto; plexLibrary = { - "/mnt/Anime".hostPath = kyuuto-library + "/anime"; - "/mnt/Shows".hostPath = kyuuto-library + "/tv"; - "/mnt/Movies".hostPath = kyuuto-library + "/movies"; - "/mnt/Music".hostPath = kyuuto-library + "/music"; + "/mnt/Anime".hostPath = kyuuto.libraryDir + "/anime"; + "/mnt/Shows".hostPath = kyuuto.libraryDir + "/tv"; + "/mnt/Movies".hostPath = kyuuto.libraryDir + "/movies"; + "/mnt/Music".hostPath = kyuuto.libraryDir + "/music"; }; in { imports = let @@ -29,6 +28,7 @@ in { ./cloudflared.nix # media + nixos.kyuuto nixos.plex nixos.tautulli nixos.ombi @@ -48,16 +48,16 @@ in { serverName = "tewi"; mediaDirectories = let mkLibraryDir = dir: { - path = kyuuto-library + "/${dir}"; - mountPoint = kyuuto-library; + path = kyuuto.libraryDir + "/${dir}"; + mountPoint = kyuuto.libraryDir; }; libraryDir = { - path = kyuuto-library; - mountPoint = kyuuto-library; + path = kyuuto.libraryDir; + mountPoint = kyuuto.libraryDir; subdirectories = mapAttrsToList ( _: {hostPath, ...}: - removePrefix "${kyuuto-library}/" hostPath + removePrefix "${kyuuto.libraryDir}/" hostPath ) plexLibrary ++ ["tlmc" "music-raw"]; @@ -88,7 +88,7 @@ in { "${deluge.downloadDir}" = mkIf deluge.enable (mkMerge [ bind { - device = kyuuto + "/downloads/deluge/download"; + device = kyuuto.mountDir + "/downloads/deluge/download"; } ]); }; diff --git a/systems/reimu/nfs.nix b/systems/reimu/nfs.nix deleted file mode 100644 index dddf23f4..00000000 --- a/systems/reimu/nfs.nix +++ /dev/null @@ -1,51 +0,0 @@ -{ - config, - lib, - ... -}: let - kyuuto = "/mnt/kyuuto-media"; - kyuuto-transfer = kyuuto + "/transfer"; - inherit (lib.lists) optionals; - inherit (lib.strings) concatStringsSep; - inherit (config.networking.access) cidrForNetwork; -in { - services.nfs.server.exports = let - mapPerm = perm: map (addr: "${addr}(${perm})"); - toPerms = concatStringsSep " "; - localAddrs = cidrForNetwork.loopback.all ++ cidrForNetwork.local.all; - tailAddrs = optionals config.services.tailscale.enable cidrForNetwork.tail.all; - allAddrs = localAddrs ++ tailAddrs; - kyuutoPerms = - mapPerm "ro" localAddrs - ++ mapPerm "rw" tailAddrs; - transferPerms = mapPerm "rw" allAddrs; - in '' - ${kyuuto} ${toPerms kyuutoPerms} - ${kyuuto-transfer} ${toPerms transferPerms} - ''; - - services.samba.shares = { - kyuuto-transfer = { - path = kyuuto-transfer; - writeable = "yes"; - browseable = "yes"; - public = "yes"; - "guest only" = "yes"; - comment = "Kyuuto Media Transfer Area"; - }; - kyuuto-access = { - path = kyuuto; - writeable = false; - browseable = "yes"; - public = "yes"; - comment = "Kyuuto Media Access"; - }; - kyuuto-media = { - path = kyuuto; - writeable = "yes"; - browseable = "yes"; - public = "no"; - comment = "Kyuuto Media"; - }; - }; -} diff --git a/systems/reimu/nixos.nix b/systems/reimu/nixos.nix index 3ceb2ada..7122d280 100644 --- a/systems/reimu/nixos.nix +++ b/systems/reimu/nixos.nix @@ -8,12 +8,16 @@ nixos.sops nixos.base nixos.reisen-ct + nixos.kyuuto nixos.tailscale nixos.nfs nixos.samba - ./nfs.nix ]; + kyuuto.setup = true; + + proxmoxLXC.privileged = true; + systemd.network.networks.eth0 = { name = "eth0"; matchConfig = {