unl0kr: split the gocryptfs unlocking into its own separate service
/mnt/persist/private can be depended on by both s6 user services and systemd system services (which will become useful for servo) /mnt/persist/private can be unlocked by dropping the key in remotely, however that won't kill unl0kr TODO: fix unl0kr to not also output text to the tty TODO: ensure gocryptfs mount can handle being fed a wrong password
This commit is contained in:
@@ -265,6 +265,7 @@ in
|
|||||||
# N.B.: gtk apps support absolute paths for this; webkit apps (e.g. geary) support only relative paths (relative to $XDG_RUNTIME_DIR)
|
# N.B.: gtk apps support absolute paths for this; webkit apps (e.g. geary) support only relative paths (relative to $XDG_RUNTIME_DIR)
|
||||||
env.WAYLAND_DISPLAY = "wl/wayland-1";
|
env.WAYLAND_DISPLAY = "wl/wayland-1";
|
||||||
|
|
||||||
|
services.private-storage.dependencyOf = [ "sway" ]; #< HACK: prevent unl0kr and sway from fighting over the tty
|
||||||
services.sway = {
|
services.sway = {
|
||||||
description = "sway: tiling wayland desktop environment";
|
description = "sway: tiling wayland desktop environment";
|
||||||
partOf = [
|
partOf = [
|
||||||
|
@@ -65,18 +65,18 @@ in
|
|||||||
services.unl0kr = {
|
services.unl0kr = {
|
||||||
description = "unl0kr framebuffer password entry/filesystem unlocker";
|
description = "unl0kr framebuffer password entry/filesystem unlocker";
|
||||||
partOf = [ "private-storage" ];
|
partOf = [ "private-storage" ];
|
||||||
# TODO: lift the gocryptfs stuff into a separate service
|
|
||||||
command = pkgs.writeShellScript "unl0kr-start" ''
|
command = pkgs.writeShellScript "unl0kr-start" ''
|
||||||
# if ! test -d $XDG_RUNTIME_DIR/unl0kr; then
|
while ! test -f /mnt/persist/private/init; do
|
||||||
# mkdir $XDG_RUNTIME_DIR/unl0kr
|
unl0kr > /run/gocryptfs/private.key.incoming
|
||||||
# fi
|
cp /run/gocryptfs/private.key.incoming /run/gocryptfs/private.key
|
||||||
# unl0kr > $XDG_RUNTIME_DIR/unl0kr/passwd
|
#v give time for the fs to be mounted, before assuming user entered the wrong key & we should restart
|
||||||
if ! test -f /mnt/persist/private/init; then
|
# TODO: use inotify to wait for `init`
|
||||||
unl0kr | sudo gocryptfs -fg /nix/persist/private /mnt/persist/private -o allow_other
|
sleep 3
|
||||||
fi
|
done
|
||||||
#^ otherwise, if already unlocked, exit true
|
while true; do
|
||||||
|
sleep infinity
|
||||||
|
done
|
||||||
'';
|
'';
|
||||||
readiness.waitExists = [ "/mnt/persist/private/init" ];
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -38,17 +38,56 @@ lib.mkIf config.sane.persist.enable
|
|||||||
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
"allow_other" # root ends up being the user that mounts this, so need to make it visible to other users.
|
||||||
# "quiet"
|
# "quiet"
|
||||||
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
|
||||||
|
"passfile=/run/gocryptfs/private.key"
|
||||||
];
|
];
|
||||||
noCheck = true;
|
noCheck = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# let sane.fs know about the mount
|
# let sane.fs know about the mount, and let systemd know to wait for the pass key before attempting a mount
|
||||||
sane.fs."${origin}".mount = {};
|
sane.fs."${origin}".mount = {
|
||||||
|
depends = let
|
||||||
|
keyfile = config.sane.fs."/run/gocryptfs/private.key";
|
||||||
|
in [ keyfile.unit ];
|
||||||
|
};
|
||||||
# it also needs to know that the underlying device is an ordinary folder
|
# it also needs to know that the underlying device is an ordinary folder
|
||||||
sane.fs."${backing}" = sane-lib.fs.wanted {
|
sane.fs."${backing}" = sane-lib.fs.wanted {
|
||||||
dir.acl.user = config.sane.defaultUser;
|
dir.acl.user = config.sane.defaultUser;
|
||||||
# dir.acl.mode = "755";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sane.fs."/run/gocryptfs/private.key".generated = let
|
||||||
|
script = pkgs.writeShellScript "wait-for-gocryptfs-private" ''
|
||||||
|
file="$1"
|
||||||
|
dir=$(dirname "$file")
|
||||||
|
|
||||||
|
succeedOrWait() {
|
||||||
|
if [ -f "$file" ]; then
|
||||||
|
exit 0
|
||||||
|
else
|
||||||
|
# wait for some file to be created inside the directory.
|
||||||
|
# inotifywait returns 0 if the file was created. 1 or 2 if timeout was hit or it was interrupted by a different event.
|
||||||
|
${lib.getExe' pkgs.inotify-tools "inotifywait"} --timeout "$1" --event create "$dir" || true
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
# there's a race condition between testing the path and starting `inotifywait`.
|
||||||
|
# therefore, use a retry loop. exponential backoff to decrease the impact of the race condition,
|
||||||
|
# especially near the start of boot to allow for quick reboots even if/when i hit the race.
|
||||||
|
for i in 4 4 8 8 16 16 16 16 16 16 16 16; do
|
||||||
|
succeedOrWait "$i"
|
||||||
|
done
|
||||||
|
while true; do
|
||||||
|
succeedOrWait 30
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
in {
|
||||||
|
command = [ "${script}" "/run/gocryptfs/private.key" ];
|
||||||
|
# no need for anyone else to be able to read the key
|
||||||
|
acl.mode = "0400";
|
||||||
|
};
|
||||||
|
sane.fs."/run/gocryptfs" = sane-lib.fs.wanted {
|
||||||
|
dir.acl.user = config.sane.defaultUser;
|
||||||
|
dir.acl.mode = "0700";
|
||||||
|
};
|
||||||
|
|
||||||
# in order for non-systemd `mount` to work, the mount point has to already be created, so make that a default target
|
# in order for non-systemd `mount` to work, the mount point has to already be created, so make that a default target
|
||||||
systemd.units = let
|
systemd.units = let
|
||||||
originUnit = config.sane.fs."${origin}".generated.unit;
|
originUnit = config.sane.fs."${origin}".generated.unit;
|
||||||
@@ -58,5 +97,11 @@ lib.mkIf config.sane.persist.enable
|
|||||||
|
|
||||||
# TODO: could add this *specifically* to the .mount file for the encrypted fs?
|
# TODO: could add this *specifically* to the .mount file for the encrypted fs?
|
||||||
system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs
|
system.fsPackages = [ pkgs.gocryptfs ]; # fuse needs to find gocryptfs
|
||||||
|
|
||||||
|
sane.user.services.gocryptfs-private = {
|
||||||
|
description = "wait for /mnt/persist/private to be mounted";
|
||||||
|
startCommand = "${lib.getExe' pkgs.systemd "systemctl"} start mnt-persist-private.mount";
|
||||||
|
partOf = [ "private-storage" ];
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -178,8 +178,7 @@ let
|
|||||||
config = lib.mkMerge [
|
config = lib.mkMerge [
|
||||||
# if we're the default user, inherit whatever settings were routed to the default user
|
# if we're the default user, inherit whatever settings were routed to the default user
|
||||||
(lib.mkIf config.default {
|
(lib.mkIf config.default {
|
||||||
inherit (sane-user-cfg) fs persist environment;
|
inherit (sane-user-cfg) fs environment persist services;
|
||||||
services = lib.mapAttrs (_: lib.mkMerge) sane-user-cfg.services;
|
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
fs."/".dir.acl = {
|
fs."/".dir.acl = {
|
||||||
@@ -295,6 +294,10 @@ let
|
|||||||
# grouping it like this is mostly a power-saving thing to make certain services not auto-launched
|
# grouping it like this is mostly a power-saving thing to make certain services not auto-launched
|
||||||
description = "service (bundle) which provides high-precision location info (e.g. from GPS)";
|
description = "service (bundle) which provides high-precision location info (e.g. from GPS)";
|
||||||
};
|
};
|
||||||
|
services."private-storage" = {
|
||||||
|
description = "service (bundle) which is active once the persist.private datastore has been opened";
|
||||||
|
dependencyOf = [ "graphical-session" ]; #< prevent any graphical environment from competing with the login/unlocker service over the framebuffer
|
||||||
|
};
|
||||||
services."sound" = {
|
services."sound" = {
|
||||||
description = "service (bundle) which represents functional sound input/output when active";
|
description = "service (bundle) which represents functional sound input/output when active";
|
||||||
# partOf = [ "default" ];
|
# partOf = [ "default" ];
|
||||||
|
Reference in New Issue
Block a user