gocryptfs: sandbox with bunpen

This commit is contained in:
2024-09-10 00:02:03 +00:00
parent 6f72453f5d
commit 8ae7e255e5
6 changed files with 34 additions and 20 deletions

View File

@@ -1,11 +1,13 @@
{ ... }:
{
sane.programs.gocryptfs = {
sandbox.method = "landlock";
sandbox.method = "bunpen";
sandbox.autodetectCliPaths = "existing";
sandbox.capabilities = [
# CAP_SYS_ADMIN is only required if directly invoking gocryptfs
# i.e. not leverage a mount helper like `mount.fuse3-sane`.
# CAP_SYS_ADMIN is only required if directly invoking gocryptfs.
# it's not *necessarily* required if using a mount helper like `mount.fuse3-sane`
# however if using a namespace-based sandbox method (bunpen, bwrap), and you wish
# to preserve user mappings, it's still required.
"sys_admin"
"chown"
"dac_override"
@@ -16,8 +18,10 @@
"setgid"
"setuid"
];
sandbox.tryKeepUsers = true;
sandbox.keepPids = true;
suggestedPrograms = [
"util-linux" #< gocryptfs complains that it can't exec `logger`, otherwise
"util-linux" #< gocryptfs complains that it can't exec `logger`, otherwise. TODO(2024-09-09): is this still needed?
];
};
}

View File

@@ -17,10 +17,12 @@ lib.mkIf config.sane.persist.enable
"gocryptfs"
];
};
sandbox.method = "landlock";
suggestedPrograms = [ "gocryptfs" ];
sandbox.method = "bunpen";
sandbox.autodetectCliPaths = "existing";
sandbox.capabilities = [
# "sys_admin" #< omitted: not required if using fuse3-sane with -o pass_fuse_fd
"sys_admin" #< XXX: this is required to keep user mappings; for single-user it's actually not necessary if using fuse3-sane with -o pass_fuse_fd
"chown"
"dac_override"
"dac_read_search"
@@ -30,7 +32,8 @@ lib.mkIf config.sane.persist.enable
"setgid"
"setuid"
];
suggestedPrograms = [ "gocryptfs" ];
sandbox.tryKeepUsers = true;
sandbox.keepPids = true;
};
sane.persist.stores."ephemeral" = {
@@ -59,6 +62,7 @@ lib.mkIf config.sane.persist.enable
mount.depends = [
config.sane.fs."${backing}".unit
];
# hardening (systemd-analyze security mnt-persist-ephemeral.mount)
mount.mountConfig.AmbientCapabilities = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
# CAP_LEASE is probably not necessary -- does any fs user use leases?
@@ -73,7 +77,7 @@ lib.mkIf config.sane.persist.enable
#VVV this includes anything it reads from, e.g. /bin/sh; /nix/store/...
# see `systemd-analyze filesystems` for a full list
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse pipefs";
mount.mountConfig.RestrictNamespaces = true;
# mount.mountConfig.RestrictNamespaces = true;
mount.mountConfig.RestrictNetworkInterfaces = "";
mount.mountConfig.RestrictRealtime = true;
mount.mountConfig.RestrictSUIDSGID = true;

View File

@@ -7,11 +7,12 @@ backing=$1
# facing=$2
# backing might exist from the last boot, so wipe it:
# TODO: should be `rm $backing/*`??
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/fd/0 -init "$backing"
echo "$pw" | exec gocryptfs -quiet -passfile /dev/fd/0 "$@"
echo "$pw" | gocryptfs -quiet -nosyslog -passfile /dev/fd/0 -init "$backing"
echo "$pw" | exec gocryptfs -quiet -nosyslog -passfile /dev/fd/0 "$@"

View File

@@ -20,6 +20,7 @@ lib.mkIf config.sane.persist.enable
sandbox.method = "bunpen";
sandbox.autodetectCliPaths = "parent";
sandbox.tryKeepUsers = true;
sandbox.keepPids = true;
sandbox.capabilities = [ "dac_read_search" ]; #< TODO: this and `tryKeepUsers` shouldn't be needed (it wasn't needed with bwrap)...
};
sane.programs.gocryptfs-private = {
@@ -28,10 +29,10 @@ lib.mkIf config.sane.persist.enable
srcRoot = ./.;
pkgs = [ "gocryptfs" ];
};
sandbox.method = "landlock";
sandbox.method = "bunpen";
sandbox.autodetectCliPaths = "existing";
sandbox.capabilities = [
# "sys_admin" #< omitted: not required if using fuse3-sane with -o pass_fuse_fd
"sys_admin" #< XXX: this is required to keep user mappings; for single-user it's actually not necessary if using fuse3-sane with -o pass_fuse_fd
"chown"
"dac_override"
"dac_read_search"
@@ -41,8 +42,10 @@ lib.mkIf config.sane.persist.enable
"setgid"
"setuid"
];
sandbox.tryKeepUsers = true;
sandbox.keepPids = true;
sandbox.extraPaths = [
"/run/gocryptfs" #< TODO: teach sanebox about `-o FLAG1=VALUE1,FLAG2=VALUE2` style of argument passing, then use `existingOrParent` autodetect, and remove this
"/run/gocryptfs/private.key" #< TODO: teach sanebox about `-o FLAG1=VALUE1,FLAG2=VALUE2` style of argument passing, then use `existing` autodetect, and remove this
];
suggestedPrograms = [ "gocryptfs" ];
};
@@ -77,10 +80,10 @@ 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.
# "quiet"
# "defaults" # "unknown flag: --defaults. Try 'gocryptfs -help'"
"passfile=/run/gocryptfs/private.key"
# "passfile=/run/gocryptfs/private.key"
# options so that we can block for the password file *without* systemd killing us.
# see: <https://bbs.archlinux.org/viewtopic.php?pid=1906174#p1906174>
"x-systemd.mount-timeout=infinity"
# "x-systemd.mount-timeout=infinity"
# "retry=10000"
# "fg"
"pass_fuse_fd"
@@ -96,7 +99,7 @@ lib.mkIf config.sane.persist.enable
config.sane.fs."/run/gocryptfs/private.key".unit
];
# unitConfig.DefaultDependencies = "no";
mount.mountConfig.TimeoutSec = "infinity";
# mount.mountConfig.TimeoutSec = "infinity";
# hardening (systemd-analyze security mnt-persist-private.mount)
mount.mountConfig.AmbientCapabilities = "CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_DAC_READ_SEARCH CAP_CHOWN CAP_MKNOD CAP_LEASE CAP_SETGID CAP_SETUID CAP_FOWNER";
@@ -110,7 +113,7 @@ lib.mkIf config.sane.persist.enable
mount.mountConfig.RemoveIPC = true;
mount.mountConfig.RestrictAddressFamilies = "AF_UNIX"; # "none" works, but then it can't connect to the logger
mount.mountConfig.RestrictFileSystems = "@common-block @basic-api fuse pipefs";
mount.mountConfig.RestrictNamespaces = true;
# mount.mountConfig.RestrictNamespaces = true;
mount.mountConfig.RestrictNetworkInterfaces = "";
mount.mountConfig.RestrictRealtime = true;
mount.mountConfig.RestrictSUIDSGID = true;

View File

@@ -1,6 +1,7 @@
#!/usr/bin/env nix-shell
#!nix-shell -i bash -p bash -p gocryptfs
passfile=/run/gocryptfs/private.key
gocryptfs --sanebox-path "$passfile" "$@"
rm "$passfile"
pass_file=/run/gocryptfs/private.key
pass_str=$(cat "$pass_file")
rm "$pass_file"
echo "$pass_str" | exec gocryptfs -nosyslog -passfile /dev/fd/0 "$@"

View File

@@ -32,6 +32,7 @@ waitForPassfile() {
done
}
validatePassword() {
echo "validating password ..."
if ! cat "$passfile" | gocryptfs-xray -dumpmasterkey "$conffile" > /dev/null; then
echo "failed key validation"
rm -f "$passfile"