# strictly *decrease* the scope of the default nixos installation/config { lib, pkgs, ... }: let suidlessPam = pkgs.pam.overrideAttrs (upstream: { # nixpkgs' pam hardcodes unix_chkpwd path to the /run/wrappers one, # but i don't want the wrapper, so undo that. # ideally i would patch this via an overlay, but pam is in the bootstrap so that forces a full rebuild. # TODO: add a `package` option to the nixos' pam module and substitute it that way. postPatch = (if upstream.postPatch != null then upstream.postPatch else "") + '' substituteInPlace modules/pam_unix/Makefile.am --replace-fail \ "/run/wrappers/bin/unix_chkpwd" "$out/bin/unix_chkpwd" ''; }); in { # remove a few items from /run/wrappers we don't need. options.security.wrappers = lib.mkOption { apply = lib.filterAttrs (name: _: !(builtins.elem name [ # from "pkexec" "polkit-agent-helper-1" #< used by systemd; without this you'll have to `sudo systemctl daemon-reload` instead of unauth'd `systemctl daemon-reload` # from "dbus-daemon-launch-helper" # from "fusermount" #< only needed if you want to mount entries declared in /etc/fstab or mtab as unprivileged user "fusermount3" "mount" #< only needed if you want to mount entries declared in /etc/fstab or mtab as unprivileged user "umount" # from "newgidmap" "newgrp" "newuidmap" "sg" "su" # from: # requires associated `pam` patch to not hardcode unix_chkpwd path "unix_chkpwd" ])); }; options.security.pam.services = lib.mkOption { apply = services: let filtered = lib.filterAttrs (name: _: !(builtins.elem name [ # from "i3lock" "i3lock-color" "vlock" "xlock" "xscreensaver" "runuser" "runuser-l" # from ?? "chfn" "chpasswd" "chsh" "groupadd" "groupdel" "groupmems" "groupmod" "useradd" "userdel" "usermod" # from "systemd-user" #< N.B.: this causes the `systemd --user` service manager to not be started! ])) services; in lib.mapAttrs (_serviceName: service: service // { # replace references with the old pam_unix, which calls into /run/wrappers/bin/unix_chkpwd, # with a pam_unix that calls into unix_chkpwd via the nix store. # TODO: use `security.pam.package` instead once lands. text = lib.replaceStrings [" pam_unix.so" ] [ " ${suidlessPam}/lib/security/pam_unix.so" ] service.text; }) filtered; }; options.environment.systemPackages = lib.mkOption { # see: # it's 31 "requiredPackages", with no explanation of why they're "required"... # most of these can be safely removed without breaking the *boot*, # but some core system services DO implicitly depend on them. # TODO: see which more of these i can remove (or shadow/sandbox) apply = let requiredPackages = builtins.map (pkg: lib.setPrio ((pkg.meta.priority or 5) + 3) pkg) [ # pkgs.acl # pkgs.attr # pkgs.bashInteractive # pkgs.bzip2 # pkgs.coreutils-full # pkgs.cpio # pkgs.curl # pkgs.diffutils # pkgs.findutils # pkgs.gawk # pkgs.stdenv.cc.libc # pkgs.getent # pkgs.getconf # pkgs.gnugrep # pkgs.gnupatch # pkgs.gnused # pkgs.gnutar # pkgs.gzip # pkgs.xz pkgs.less # pkgs.libcap #< implicitly required by NetworkManager/wpa_supplicant! # pkgs.ncurses pkgs.netcat # config.programs.ssh.package # pkgs.mkpasswd pkgs.procps # pkgs.su # pkgs.time # pkgs.util-linux # pkgs.which # pkgs.zstd ]; in lib.filter (p: ! builtins.elem p requiredPackages); }; options.system.fsPackages = lib.mkOption { # adds `mtools` and `dosfstools` # dosfstools actually makes its way into the initrd (`fsck.vfat`). # mtools is like "MS-DOS for Linux", ancient functionality i'll never use. apply = lib.filter (p: p != pkgs.mtools); }; config = { # disable non-required packages like nano, perl, rsync, strace environment.defaultPackages = []; # remove all the non-existent default directories from XDG_DATA_DIRS, XDG_CONFIG_DIRS to simplify debugging. # this is defaulted in , # without being gated by any higher config. environment.profiles = lib.mkForce [ "/etc/profiles/per-user/$USER" "/run/current-system/sw" ]; # NIXPKGS_CONFIG defaults to "/etc/nix/nixpkgs-config.nix" in . # that's never existed on my system and everything does fine without it set empty (no nixpkgs API to forcibly *unset* it). environment.variables.NIXPKGS_CONFIG = lib.mkForce ""; # XDG_CONFIG_DIRS defaults to "/etc/xdg", which doesn't exist. # in practice, pam appends the values i want to XDG_CONFIG_DIRS, though this approach causes an extra leading `:` environment.sessionVariables.XDG_CONFIG_DIRS = lib.mkForce []; # XCURSOR_PATH: defaults to `[ "$HOME/.icons" "$HOME/.local/share/icons" ]`, neither of which i use, just adding noise. # see: environment.sessionVariables.XCURSOR_PATH = lib.mkForce []; # disable nixos' portal module, otherwise /share/applications gets linked into the system and complicates things (sandboxing). # instead, i manage portals myself via the sane.programs API (e.g. sane.programs.xdg-desktop-portal). xdg.portal.enable = false; xdg.menus.enable = false; #< links /share/applications, and a bunch of other empty (i.e. unused) dirs # xdg.autostart.enable defaults to true, and links /etc/xdg/autostart into the environment, populated with .desktop files. # see: # .desktop files are a questionable way to autostart things: i generally prefer a service manager for that. xdg.autostart.enable = false; # nix.channel.enable: populates `/nix/var/nix/profiles/per-user/root/channels`, `/root/.nix-channels`, `$HOME/.nix-defexpr/channels` # # TODO: may want to recreate NIX_PATH, nix.settings.nix-path nix.channel.enable = false; # environment.stub-ld: populate /lib/ld-linux.so with an object that unconditionally errors on launch, # so as to inform when trying to run a non-nixos binary? # IMO that's confusing: i thought /lib/ld-linux.so was some file actually required by nix. environment.stub-ld.enable = false; # `less.enable` sets LESSKEYIN_SYSTEM, LESSOPEN, LESSCLOSE env vars, which does confusing "lesspipe" things, so disable that. # it's enabled by default from ``, who also sets `PAGER="less"` and `EDITOR="nano"` (keep). programs.less.enable = lib.mkForce false; environment.variables.PAGER = lib.mkOverride 900 ""; # mkDefault sets 1000. non-override is 100. 900 will beat the nixpkgs `mkDefault` but not anyone else. environment.variables.EDITOR = lib.mkOverride 900 ""; # several packages (dconf, modemmanager, networkmanager, gvfs, polkit, udisks, bluez/blueman, feedbackd, etc) # will add themselves to the dbus search path. # i prefer dbus to only search XDG paths (/share/dbus-1) for service files, as that's more introspectable. # see: # TODO: sandbox dbus? i pretty explicitly don't want to use it as a launcher. services.dbus.packages = lib.mkForce [ "/run/current-system/sw" # config.system.path # pkgs.dbus # pkgs.polkit.out # pkgs.modemmanager # pkgs.networkmanager # pkgs.udisks # pkgs.wpa_supplicant ]; # systemd by default forces shitty defaults for e.g. /tmp/.X11-unix. # nixos propagates those in: # by overwriting this with an empty file, we can effectively remove it. environment.etc."tmpfiles.d/x11.conf".text = "# (removed by Colin)"; # see: # it was enabled by default before 23.11 boot.swraid.enable = lib.mkDefault false; # see: # these allow you to use the Linux block cache (cool! doesn't need to be a default though) boot.bcache.enable = lib.mkDefault false; # see: # by default, it adds to boot.initrd.availableKernelModules: # - SATA: "ahci" "sata_nv" "sata_via" "sata_sis" "sata_uli" "ata_piix" "pata_marvell" # - "nvme" # - scsi: "sd_mod" "sr_mod" # - SD/eMMC: "mmc_block" # - USB keyboards: "uhci_hcd" "ehci_hcd" "ehci_pci" "ohci_hcd" "ohci_pci" "xhci_hcd" "xhci_pci" "usbhid" "hid_generic" "hid_lenovo" "hid_apple" "hid_roccat" "hid_logitech_hidpp" "hid_logitech_dj" "hid_microsoft" "hid_cherry" "hid_corsair" # - LVM: "dm_mod" # - on x86 only: more keyboard stuff: "pcips2" "atkbd" "i8042" boot.initrd.includeDefaultModules = lib.mkDefault false; # see: boot.enableContainers = lib.mkDefault false; }; }