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.
This commit is contained in:
colin 2022-12-28 09:30:29 +00:00
parent 121936620a
commit 8e5ca11259
5 changed files with 74 additions and 38 deletions

View File

@ -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;
}

View File

@ -54,24 +54,41 @@ in
shell = pkgs.zsh;
openssh.authorizedKeys.keys = builtins.attrValues (import ../../modules/pubkeys.nix).users;
# some other nix pam users:
# - <https://github.com/g00pix/nixconf/blob/32c04f6fa843fed97639dd3f09e157668d3eea1f/profiles/sshfs.nix>
# - <https://github.com/lourkeur/distro/blob/11173454c6bb50f7ccab28cc2c757dca21446d1d/nixos/profiles/users/louis-full.nix>
# - <https://github.com/dnr/sample-nix-code/blob/03494480c1fae550c033aa54fd96aeb3827761c5/nixos/laptop.nix>
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"
];

View File

@ -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;

View File

@ -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:
# - </etc/systemd/system/sysinit.target.wants/sys-fs-fuse-connections.mount>
# - 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" ];
})

View File

@ -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
'';
}))