diff --git a/modules/persist/stores/crypt.nix b/modules/persist/stores/crypt.nix index 7877b1045..bf9710092 100644 --- a/modules/persist/stores/crypt.nix +++ b/modules/persist/stores/crypt.nix @@ -3,8 +3,31 @@ let persist-base = "/nix/persist"; origin = config.sane.persist.stores."cryptClearOnBoot".origin; - key = "${origin}.key"; backing = sane-lib.path.concat [ persist-base "crypt/clearedonboot" ]; + + gocryptfs-ephemeral = pkgs.writeShellApplication { + name = "mount.fuse.gocryptfs-ephemeral"; + runtimeInputs = with pkgs; [ + coreutils-full + gocryptfs + ]; + text = '' + # mount invokes us like this. not sure if that's a guarantee or not: + # -o + backing=$1 + # facing=$2 + + # backing might exist from the last boot, so wipe it: + rm -fr "$backing" + mkdir -p "$backing" + + # the password shows up in /proc/.../env, briefly. + # that's inconsequential: we just care that it's not *persisted*. + pw=$(dd if=/dev/random bs=128 count=1 | base64 --wrap=0) + echo "$pw" | gocryptfs -quiet -passfile /dev/stdin -init "$backing" + echo "$pw" | gocryptfs -quiet -passfile /dev/stdin "$@" + ''; + }; in lib.mkIf config.sane.persist.enable { @@ -16,60 +39,20 @@ lib.mkIf config.sane.persist.enable origin = lib.mkDefault "/mnt/persist/crypt/clearedonboot"; }; - fileSystems."${origin}" = { device = backing; - fsType = "fuse.gocryptfs"; + fsType = "fuse.gocryptfs-ephemeral"; options = [ # "nodev" # "Unknown parameter 'nodev'". gocryptfs requires this be passed as `-ko nodev` # "nosuid" # "Unknown parameter 'nosuid'". gocryptfs requires this be passed as `-ko nosuid` (also, nosuid is default) "allow_other" # root ends up being the user that mounts this, so need to make it visible to other users. - "passfile=${key}" # "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'" ]; noCheck = true; }; # let sane.fs know about our fileSystem and automatically add the appropriate dependencies - sane.fs."${origin}".mount = { - # technically the dependency on the keyfile is extraneous because that *happens* to - # be needed to init the store. - depends = let - cryptfile = config.sane.fs."${backing}/gocryptfs.conf"; - keyfile = config.sane.fs."${key}"; - in [ keyfile.unit cryptfile.unit ]; - }; + sane.fs."${origin}".mount = { }; + sane.fs."${backing}" = sane-lib.fs.wantedDir; - # let sane.fs know how to initialize the gocryptfs store, - # and that it MUST do so - sane.fs."${backing}/gocryptfs.conf".generated = let - script = pkgs.writeShellScript "init-gocryptfs-store" '' - backing="$1" - passfile="$2" - # clear the backing store - # TODO: we should verify that it's not mounted anywhere... - # - specifically, there's a bug here right now where if the `sane.fs` - # details change, a deploy onto a live system will restart this service, - # corrupting all of this store. - rm -rf "''${backing:?}"/* - ${pkgs.gocryptfs}/bin/gocryptfs -quiet -passfile "$passfile" -init "$backing" - ''; - in { - command = [ "${script}" backing key ]; - # we need the key in order to initialize the store - depends = [ config.sane.fs."${key}".unit ]; - }; - - # let sane.fs know how to generate the key for gocryptfs - sane.fs."${key}".generated = let - script = pkgs.writeShellScript "gen-random-gocryptfs-key" '' - dd if=/dev/random bs=128 count=1 | base64 --wrap=0 > "$1" - ''; - in { - command = [ "${script}" key ]; - # no need for anyone else to be able to read the key - acl.mode = "0400"; - }; - - # TODO: could add this *specifically* to the .mount file for the encrypted fs? - system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs + system.fsPackages = [ gocryptfs-ephemeral ]; # fuse needs to find gocryptfs }