From 8e5ca11259a992f7c1dc0ad9786ef27dfa1f54cd Mon Sep 17 00:00:00 2001 From: colin Date: Wed, 28 Dec 2022 09:30:29 +0000 Subject: [PATCH] cleanup gocryptfs mounting there's possibly some latent issues. i think my changes to the gocryptfs package *might* not be necessary: if you work via the fuse front-door, it's a lot harder to get it into these weird places. --- hosts/common/default.nix | 11 ------ hosts/common/users.nix | 25 +++++++++++-- modules/home-manager/zsh/default.nix | 11 ++++-- modules/impermanence.nix | 56 +++++++++++++++++++--------- pkgs/gocryptfs/default.nix | 9 ++++- 5 files changed, 74 insertions(+), 38 deletions(-) diff --git a/hosts/common/default.nix b/hosts/common/default.nix index 66eb1833..7cc9df91 100644 --- a/hosts/common/default.nix +++ b/hosts/common/default.nix @@ -58,19 +58,8 @@ }; # enable zsh completions environment.pathsToLink = [ "/share/zsh" ]; - environment.systemPackages = with pkgs; [ - # required for pam_mount - gocryptfs - ]; # link debug symbols into /run/current-system/sw/lib/debug # hopefully picked up by gdb automatically? environment.enableDebugInfo = true; - - security.pam.mount.enable = true; - # security.pam.mount.debugLevel = 1; - # security.pam.enableSSHAgentAuth = true; # ?? - # needed for `allow_other` in e.g. gocryptfs mounts - # or i guess going through mount.fuse sets suid so that's not necessary? - # programs.fuse.userAllowOther = true; } diff --git a/hosts/common/users.nix b/hosts/common/users.nix index 34b0d53c..34707fc3 100644 --- a/hosts/common/users.nix +++ b/hosts/common/users.nix @@ -54,24 +54,41 @@ in shell = pkgs.zsh; openssh.authorizedKeys.keys = builtins.attrValues (import ../../modules/pubkeys.nix).users; + # some other nix pam users: + # - + # - + # - pamMount = { # mount encrypted stuff at login # requires that login password == fs encryption password - # fstype = "fuse"; + fstype = "fuse"; + path = "gocryptfs#/nix/persist/home/colin/private"; # path = "${pkgs.gocryptfs}/bin/gocryptfs#/nix/persist/home/colin/private"; - fstype = "fuse.gocryptfs"; - path = "/nix/persist/home/colin/private"; + # fstype = "fuse.gocryptfs"; + # path = "/nix/persist/home/colin/private"; mountpoint = "/home/colin/private"; - options="nodev,nosuid,quiet,allow_other"; + # without allow_other, *root* isn't allowed to list anything in ~/private. + # which is weird (root can just `su colin`), but probably doesn't *hurt* anything -- right? + options="nodev,nosuid,quiet"; # allow_other }; }; + # required for PAM to find gocryptfs + security.pam.mount.additionalSearchPaths = [ pkgs.gocryptfs ]; + security.pam.mount.enable = true; + # security.pam.mount.debugLevel = 1; + # security.pam.enableSSHAgentAuth = true; # ?? + # needed for `allow_other` in e.g. gocryptfs mounts + # or i guess going through mount.fuse sets suid so that's not necessary? + # programs.fuse.userAllowOther = true; + sane.impermanence.home-dirs = [ # cache is probably too big to fit on the tmpfs # TODO: we could bind-mount it to something which gets cleared per boot, though. ".cache" ".cargo" ".rustup" + # TODO: move this to ~/private! ".local/share/keyrings" ]; diff --git a/modules/home-manager/zsh/default.nix b/modules/home-manager/zsh/default.nix index 468b61bd..d37a2914 100644 --- a/modules/home-manager/zsh/default.nix +++ b/modules/home-manager/zsh/default.nix @@ -2,9 +2,14 @@ lib.mkIf config.sane.home-manager.enable { - # we don't need to full zsh dir -- just the history file -- - # but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks. - sane.impermanence.home-dirs = [ ".local/share/zsh" ]; + sane.impermanence.home-dirs = [ + # we don't need to full zsh dir -- just the history file -- + # but zsh will sometimes backup the history file and we get fewer errors if we do proper mounts instead of symlinks. + # TODO: should be private? + ".local/share/zsh" + # cache gitstatus otherwise p10k fetched it from the net EVERY BOOT + ".cache/gitstatus" + ]; home-manager.users.colin.programs.zsh = { enable = true; diff --git a/modules/impermanence.nix b/modules/impermanence.nix index 77dede58..12078be2 100644 --- a/modules/impermanence.nix +++ b/modules/impermanence.nix @@ -114,26 +114,46 @@ in }) (lib.mkIf cfg.encrypted-clear-on-boot { - system.activationScripts.mountEncryptedClearedOnBoot.text = let - gocryptfs = "${pkgs.gocryptfs}/bin/gocryptfs"; - backing = "/nix/persist/crypt/cleared-on-boot"; - mountpt = encrypted-clear-on-boot-base; + # without this, we get `fusermount: fuse device not found, try 'modprobe fuse' first`. + # - that only happens after a activation-via-boot -- not activation-after-rebuild-switch. + # it seems likely that systemd loads `fuse` by default. see: + # - + # - triggers: /etc/systemd/system/modprobe@.service + # - calls `modprobe` + # note: even `boot.kernelModules = ...` isn't enough: that option creates /etc/modules-load.d/, which is ingested only by systemd. + # note: `boot.initrd.availableKernelModules` ALSO isn't enough: idk why. + boot.initrd.kernelModules = [ "fuse" ]; + + system.activationScripts.mountEncryptedClearedOnBoot = + let pass-template = "/tmp/encrypted-clear-on-boot.XXXXXXXX"; tmpdir = "/tmp/impermanence"; - in '' - if !(test -e ${mountpt}/init) - then - mkdir -p ${backing} ${mountpt} ${tmpdir} - rm -rf ${backing}/* - passfile=$(mktemp ${pass-template}) - dd if=/dev/random bs=128 count=1 | base64 --wrap=0 > $passfile - ${gocryptfs} -quiet -passfile $passfile -init ${backing} - ${gocryptfs} -quiet -passfile $passfile ${backing} ${mountpt} - rm $passfile - unset passfile - touch ${mountpt}/init - fi - ''; + script = pkgs.writeShellApplication { + name = "mountEncryptedClearedOnBoot"; + runtimeInputs = with pkgs; [ fuse gocryptfs ]; + text = '' + backing="$1" + mountpt="$2" + if ! test -e "$mountpt"/init + then + mkdir -p "$backing" "$mountpt" ${tmpdir} + rm -rf "''${backing:?}"/* + passfile=$(mktemp ${pass-template}) + dd if=/dev/random bs=128 count=1 | base64 --wrap=0 > "$passfile" + gocryptfs -quiet -passfile "$passfile" -init "$backing" + mount.fuse "gocryptfs#$backing" "$mountpt" -o nodev,nosuid,allow_other,passfile="$passfile" + # mount -t fuse.gocryptfs -o passfile="$passfile" "$backing" "$mountpt" + # gocryptfs -quiet -passfile "$passfile" "$backing" "$mountpt" + rm "$passfile" + unset passfile + touch "$mountpt"/init + fi + ''; + }; + in { + deps = [ "modprobe" ]; + text = ''${script}/bin/mountEncryptedClearedOnBoot /nix/persist/crypt/cleared-on-boot "${encrypted-clear-on-boot-base}"''; + }; system.activationScripts.createPersistentStorageDirs.deps = [ "mountEncryptedClearedOnBoot" ]; }) diff --git a/pkgs/gocryptfs/default.nix b/pkgs/gocryptfs/default.nix index 9716e9d3..bbd97ffb 100644 --- a/pkgs/gocryptfs/default.nix +++ b/pkgs/gocryptfs/default.nix @@ -1,4 +1,4 @@ -{ gocryptfs, fuse, util-linux, lib }: +{ fuse, gocryptfs, util-linux, lib }: (gocryptfs.overrideAttrs (upstream: { # XXX `su colin` hangs when pam_mount tries to mount a gocryptfs system @@ -7,9 +7,14 @@ # propagating util-linux through either `environment.systemPackages` or `security.pam.mount.additionalSearchPaths` DOES NOT WORK. # # TODO: see about upstreaming this + # + # additionally, we need /run/wrappers/bin EXPLICITLY in PATH, for when we run not as root. + # but we want to keep `fuse` for when we ARE running as root -- particularly during an activation script BEFORE the wrappers exist. postInstall = '' wrapProgram $out/bin/gocryptfs \ - --suffix PATH : ${lib.makeBinPath [ fuse util-linux ]} + --suffix PATH : ${lib.makeBinPath [ util-linux ]} \ + --suffix PATH : /run/wrappers/bin \ + --suffix PATH : ${lib.makeBinPath [ fuse ]} ln -s $out/bin/gocryptfs $out/bin/mount.fuse.gocryptfs ''; }))