str4d / rage

A simple, secure and modern file encryption tool (and Rust library) with small explicit keys, no config options, and UNIX-style composability.
https://age-encryption.org/v1
Apache License 2.0
2.5k stars 97 forks source link

rage-mount but more like overlayfs #188

Open benjojo opened 3 years ago

benjojo commented 3 years ago

This is a feature request/change to rage-mount.

Problem space:

I have a set of directories that are full of encrypt tar.gz / tar / zip files:

# ls -alh
total 58G
drwxr-xr-x 1 root root 4.0K Jan 11 23:00 .
drwxr-xr-x 1 root root 4.0K Dec 23 14:13 ..
-rw-r--r-- 1 root root 1.8G Nov 11 22:23 xxxxxxxxxxxxxxxxxxxxxx.zip.age
-rw-r--r-- 1 root root 976M Nov 11 22:21 xxxxxxxxxxxxxxxxxxx.zip.age
-rw-r--r-- 1 ben  ben  2.0G Nov 11 22:17 xxxxxxxxxxxxxxx.tgz.age
-rw-r--r-- 1 root root  12G Nov 12 00:10 xxxxxxxxxxxxxxxx.tgz.age
-rw-r--r-- 1 root root  24G Jan 11 20:13 xxxxxxxxxxxxxxxx.age

I would like to open these tar.gz / zip files natively, without having to teach tools like file-roller how to decrypt the age wrapper.

I noticed rage-mount exists, and it's sort of close to what I would want, except I don't want mount the actual files, I would prefer an overlay FS instead that just decrypts the files transparently, and leaves non age files around.

So in my above example, the overlay directory would look like:

# ls -alh
total 58G
drwxr-xr-x 1 root root 4.0K Jan 11 23:00 .
drwxr-xr-x 1 root root 4.0K Dec 23 14:13 ..
-rw-r--r-- 1 root root 1.8G Nov 11 22:23 xxxxxxxxxxxxxxxxxxxxxx.zip
-rw-r--r-- 1 root root 976M Nov 11 22:21 xxxxxxxxxxxxxxxxxxx.zip
-rw-r--r-- 1 ben  ben  2.0G Nov 11 22:17 xxxxxxxxxxxxxxx.tgz
-rw-r--r-- 1 root root  12G Nov 12 00:10 xxxxxxxxxxxxxxxx.tgz
-rw-r--r-- 1 root root  24G Jan 11 20:13 xxxxxxxxxxxxxxxx

So I can then use other tools easily, obviously this only has to be read only. In fact it's preferable to be that way!

FiloSottile commented 3 years ago

I think this would be cleaner implemented as an individual file mount, so that the whole directory doesn't have to be implemented with the same key, and so that the fuse filesystem doesn't have to proxy plaintext files.

It should also match the rage-mount CLI better, as the input would still be a single age file.

str4d commented 3 years ago

I can see a benefit for both kinds of approaches, and technically both could work in rage-mount. I intended its UX to basically be close to mount for familiarity, so while its current API is:

rage-mount [-i IDENTITY] -t TYPE AGE_FILE MOUNT_DIR

it could be generalised to:

rage-mount [-i IDENTITY] [-t TYPE] AGE_FILE|MOUNT_DIR
rage-mount [-i IDENTITY] [-t TYPE] AGE_FILE MOUNT_POINT

for parity with:

mount [-o options] device|dir
mount [-o options] [-t fstype] device dir

I'm also amenable to keeping rage-mount focused on a single file, and instead doing:

rage-mount [-i IDENTITY] -t TYPE AGE_FILE [MOUNT_POINT]

where omission of MOUNT_POINT triggers a bind mount on the same file. UX suggestions absolutely welcome!

Bind mounts

This would require an explicit user action to enable, but once done there would be a file object that could be read like any other. Main question is how the file object should be presented:

OverlayFS approach

I think the ideal UX for this would be that you have some write-through process that you configure with:

Then any time you go to interact with any age file in that subtree, the write-through process intercepts it and attempts a decryption (which ideally then pops up a pinentry window requesting a passphrase or a YubiKey PIN). The process could cache successful decryptions for some (potentially configurable) period of time since last access.

The main design decision here (I think) is how the filenames are presented:

FiloSottile commented 3 years ago

Oh, I was thinking of keeping the mount point explicit, which bypasses all of the choices above and fits in the current CLI as-is.

rage-mount [-i IDENTITY] -t file foo.age foo

mount only works with a single device|dir argument when the other is already specified in a config file, so there is no precedent to get an expected behavior for rage-mount foo.age without a target.

str4d commented 3 years ago

rage-mount [-i IDENTITY] -t file foo.age foo

Yep, this matches what I was envisaging as a bind-style mount alongside the age file. It's also probably the easiest to get going...

str4d commented 3 years ago

LOL NOPE

Mounting an age file inside a single-file FUSE filesystem was relatively easy. However, I cannot get a bind mount to work from that fuse FS to the target mount point. And even if I could, bind mounts require root. (Tools like bindfs emulate bind mounts via FUSE, and similarly only support directories).

str4d commented 3 years ago

I decided to give up on bind-mount, and instead just use a symbolic link (that I clean up on exit). This is implemented in #190.

str4d commented 3 years ago

UX notes:

For dir-to-dir: