Code Monkey home page Code Monkey logo

shavee's Introduction

shavee

GitHub license

shavee is a simple program and a pam module to automatically decrypt and mount encrypted ZFS user home directories using Yubikey HMAC or a Simple USB drive as 2FA written in rust.

NOTE: Shavee v1.0.0 and greater are NOT backwards compatible with Datasets created with earlier versions. See Migration Guide.

Supported methods

This program currently supports two methods for 2FA:

1. Yubikey

Yubikeys are secure authetication USB devices we can use for our Strong second factor.

Yubikey comes pre-programmed with a HMAC key on Slot 2 which can be used to derive our final encryption key along with our password.

Programmed HMAC secret in the Yubikey CANNOT be extracted once programmed in.

If you want to use Multiple keys on the same dataset (eg. backup keys) it is required for you to program SAME fresh HMAC secrets on all those keys.

NOTE: You will need to use the manual unlock options if you want to use a diffrent key as auto mode looks for keys by serial.

Yubikey mode is set with the -y flag.

If diffrent datasets require diffrent keys you can plug all of them together.

In this mode the program looks for a Yubikey on login and uses it's HMAC mode along with your password to derive the final encryption key.

Yubikey HMAC Slot can be set with the -s flag, defaults to SLOT 2

2. File/HTTP(S)/SFTP

In this mode the program looks for a file (can be any file) and use that along with your password to derive the final encryption.

File mode is set using the -f <path to file> option.

File can be a local file, a http(s) or a sftp location

Example HTTPS

shavee -f https://foo.org/secret.png

Exmaple SFTP

shavee -f sftp://[email protected]/mnt/secretfile -P 4242

-P Option Sets port for both HTTP and SFTP.

Exmaple Local File

shavee -f /mnt/usb/secret.png

The idea with this method is to keep the file on a USB storage device or a Netork location you control and have it present during the login to derive the final encryption key.

You can use any pre existing file of your choice.

Or create one using

dd if=/dev/uranson of=./secretfile bs=4096 count=4096

Note: Since the file becomes part of your encryption key and its Security cannot be guaranteed as with Yubikey you are responsible for keeping it secure.

3. Password only

If no second factor is specified the program will use only password as a single factor.

Build and Install

  1. Install Rust
  2. Clone repo using
git clone https://github.com/ashuio/shavee.git
  • [Optional] Enable or diasable yubikey and file feature by modifying shavee-bin Cargo.toml to include or remove those features from the compiled binary.
  • [Optional] Enable or disable verbose debug trace logs by modifying shavee-core Cargo.toml to include or remove that feature from the compiled binary.
    • If trace log feature is enabled, RUST_LOG=trace environment variable must also be set to generate logs. Otherwise no log will be generaged. NOTE: Enabling the trace logs, will increase the binary size and may expose the passphrase in the output logs. ONLY ENABLE IT FOR DEBUGGING PURPOSE AND DISABLE IT IN THE FINAL BINARY!
  1. Build using the binary
cargo build --release
  1. Place the binary in your bin directory with
sudo cp target/release/shavee /usr/bin
  1. Place Pam module in your module directory with
 sudo cp target/release/libshavee_pam.so /usr/lib/security/

Modes

  • Shavee PAM Module : shavee PAM module to unlock home dir on login
  • Shavee Binary : Admin function for dataset management using shavee

Flags/Options

  • -y : Use Yubikey for 2FA. Optionally takes in yubikey serial number or uses the first key
  • -f : Use any file as 2FA, takes filepath or a HTTP(S) location as an argument.
  • -p : Prints out the secret key.
  • -d : Adds dataset name to print output.
  • -P : Set port for HTTP and SFTP requests (Upper case P )
  • -s : Set Yubikey HMAC Slot (Can be either 1 or 2)
  • -c : Create/Change key of ZFS dataset with the derived encryption key
  • -m : Unlocks and Mounts the ZFS Dataset.
  • -r : Perform Operations Recursively to all child datasets.
  • -a : Automatically Detect Dataset Unlock Properties ( can only be used with Print and Mount )
  • -z : ZFS Dataset(s) to operate on. ( can take multiple options )

NOTE: The -y (Yubikey mode) flag and the -f <path to file> (File mode) option are interchangeable.

It is recommended to run the command to change keys again of your Datasets after version updates.

Configure ZFS Datasets

NOTE: If using with PAM your dataset password should be the SAME as your user account password for it to work automatically

NOTE: Remember to update your encryption key as well if you update your password.


You can change/update the key for existing ZFS datasets by running

shavee -c -z <zfs dataset path>

Example

shavee -y -c -z zroot/data/home/hunter zroot/data/home/hunter2

Or to use a specific key eneter it's serial number

shavee -y 12345678 -c -z zroot/data/home/hunter zroot/data/home/hunter2

Here we use Yubikey as our second factor. (Can be omitted for password only auth) and operate on TWO datasets together.

Note: Encryption must already be enabled and the key loaded to change key of an exisiting dataset if not created with shavee.

Create a new dataset

To create a new dataset with our derived encryption key simply run

sudo shavee -c -z <Desired dataset>

Example

sudo shavee -f /mnt/usb/secretfile -c -z zroot/data/home/hunter

Here we use a FILE for our second factor (Can be omitted for password auth only)

Use shavee to unlock and mount any zfs patition

Simply use the option -m to unlock any zfs dataset

Example

shavee -y -m -z zroot/data/home/hunter/secrets

Backup Keys

To backup the key simply use the -p option to print the secret key to stdout

Example

shavee -p -y -z zroot/data/home/hunter/secrets

NOTE: Secret Keys are unique to your dataset even if you use the same password for multiple datasets.

Use in Scripts

You can also pipe the password directly into shavee to use with scripts

Example

echo "hunter2" | shavee -y -m -z zroot/data/home/hunter/secrets

Here "hunter2" will be treated as the password

Use a USB Drive instead of a Yubikey

You can use the -f option instead of the -y flag to substitute a Yubikey with any USB Drive.

Auto mount the USB so shavee can find the required keyfile on login

We can use udev for this, simply create and add the following to /etc/udev/rules.d/99-usb-automount.rules

ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_UUID}=="<UUID of partition>", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode <Desired Mount point>"

Example

ACTION=="add", SUBSYSTEMS=="usb", SUBSYSTEM=="block", ENV{ID_FS_UUID}=="ADB0-DA9C", RUN{program}+="/usr/bin/systemd-mount --no-block --automount=yes --collect $devnode /media/usb"

Here we're mounting the first partition of the usb disk to /media/usb

You can get the UUID by running

udevadm info --query=all --name=<Target disk> | grep ID_FS_UUID=

Example

udevadm info --query=all --name=/dev/sdb1 | grep ID_FS_UUID=

Run udevadm control --reload-rules after to make sure new rules are loaded.

Use shavee with PAM to auto unlock homedir

This program comes with a pam module to execute during the login process.

simply add the following line to your desired pam login method file.

In our example we will be adding it to /etc/pam.d/sddm to handle graphical logins and /etc/pam.d/login to handle CLI logins.

Add the following line to you pam config file

auth       optional    libshavee_pam.so <Base home Dataset>
session    optional    libshavee_pam.so <Base home Dataset>

Example

auth       optional    libshavee_pam.so zroot/data/home
session    optional    libshavee_pam.so zroot/data/home

Where zroot/data/home mounts to /home

NOTE: PAM module unlocks and mounts datasets recursively, any failure in any dataset will result in Failed Auth. This shold not stop you from logging in if PAM module is set to optional like we did in the Example.

To Force fail auth on dataset mount failure change it from optional to required

Dual home directories in ZFS

Since ZFS mounts datasets OVER preexisting directories and we defined our module in PAM as optional we still get authenticated with JUST the pass even though our dataset is NOT decrypted (eg. Because Yubikey was not inserted).

We can use this to our advantage and essentially have TWO home directories.

First which would be your normal encrypted home directory which would be unlocked and mounted when your Yubikey is present at login.

Second would be the directory which would already be present and would be loaded on decryption failure i.e when no Yubikey is inserted during login.

Let me know if interested and maybe i can write up a more detailed guide.

shavee's People

Contributors

ashuio avatar kiavash-at-work avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

shavee's Issues

Remove hard-coded salt in password.rs

On line 4 of password.rs in shavee-core consider replacing the hard-coded salt with a user configurable build time or environment variable that can be used for the salt parameter.

  • Consider throwing an error if salt is not defined by the user themselves.

let salt = b"This Project is Dedicated to Aveesha.";

Create minimalist version without File and network HTTP(S) / SFTP capabilites

Hello and thanks for this project. We are very interested in the Yubikey integration of shavee.

We have also been trying to evaluate what is needed for a comprehensive audit of shavee. So far we have identified the network retrieval options and possibly the File options as a potential burden/blocker with regard to 3rd party security auditing. Although we appreciate the comprehensive nature of the current implementation, we feel that a minimalist version that focuses of Yubikey would be great.

The current Cargo.lock file is over 700 lines and imports a large number of Rust packages, including Windows 32 bit and Windows 64 bit libraries.

  • winapi-i686-pc-windows-gnu
  • winapi-x86_64-pc-windows-gnu
  • winapi-util
[package]]
name = "termcolor"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4"
dependencies = [
 "winapi-util",
]

Since ZFS is primarily targeted towards *Nix systems we really want to understand why some of these libraries are being used / referenced. Or would prefer to remove them from the shavee supply chain altogether.

We know that we have an option to fork the repository here and create our own minimalist fork. However, we invite you as the creator / primary maintainer of this project to consider creating a functional branch, or project fork that essentially focuses strictly on Yubikey integration. We believe that this will reduce the attack surface of shavee. And also reduce the overhead with regard to 3rd party security auditing.

Thanks for consideration!

Please add cargo.lock

Hi,

I'd love for you to add the Cargo.lock file to the repo to enable reproducible builds.
Thanks ๐Ÿ‘

Ignore already loaded key

Hi,

It would by nice to test if key is already load before asking for a password.

Currently it give an error Error in mounting user ZFS dataset: Key load error: Key already loaded for

Thanks,

Ignore prepare_zpool test on failure?

Hello, I am almost done with packaging Shavee for NixOS. However, I see a unit test that needs root permission. This isn't supported is there an alternative or can you ignore this specific test?

error: test failed, to rerun pass `-p shavee --bin shavee`
error: builder for '/nix/store/nr969jrh81fln3j79ipbpkyhkx4f1wyd-shavee-0.5.drv' failed with exit code 101;

Unlock via PAM with Yubikey results in "No such file or directory"

When trying out 0824841, I was unable to get PAM to unlock my home directory with a Yubikey plugged in, as indicated by the example. Adding a log parameter to the pam_exec.so command reveals:

Error: Failed to run zfs command for rpool/USERDATA/hunter
Error: No such file or directory (os error 2)

I'm on Ubuntu 20.04 with root on ZFS. I created rpool/USERDATA/hunter via shavee -y -c -z rpool/USERDATA/hunter. I manually set the mountpoint to /home/hunter and canmount to noauto (prevents asking for the password on boot). I also set overlay to on to get rid of the warning that the directory is not empty.

I am able to unlock the directory manually with shavee -y -z rpool/USERDATA/hunter.

Odd piece of code

In main.rs it looks like dataset passwords are being suffixed with "Aveesha". Is this a remnant from testing that should be removed?

pass.push_str("Aveesha");

[TODO] Implement config file

To parse a config file in addition to command line arguments.

Prerequisite:

  • Load and Parse Config file
  • Store config in ZFS Properties to simplify PAM module unlock

[Feature Request] Max Limit for file used for hashing

Currently, there is no upper for the size of the file using to generate hash. If this file is small, the hash is generated quite fast however as it grows, it takes longer. For example, the program never exits if this command shavee -f /dev/zero is executed, because /dev/zero has no EOF. While this doesn't seem to be a safe usage of the program, it demonstrate a corner case.

A potential solution is to either hardcode a max size limit or pass it as an optional argument to the program.

Unlock ZFS Datasets with Shavee during boot

I'm using Shavee to unlock a ZFS dataset as part of my boot process, and thought I'd share how I'm doing it:

/etc/systemd/system/[email protected]

[Unit]
Description=Unlock ZFS Dataset %I with Shavee
DefaultDependencies=no
Before=systemd-user-sessions.service
Before=zfs-mount.service
After=zfs-import.target
After=systemd-vconsole-setup.service

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/sh -c 'set -eu;keystatus="$$(/sbin/zfs get -H -o value keystatus "%I")";[ "$$keystatus" = "unavailable" ] || exit 0;count=0;while [ $$count -lt 3 ];do  systemd-ask-password --id="zfs:%I"    "Enter passphrase for %I"|    shavee -y -s 1 -z "%I" && exit 0;  count=$$((count + 1));done;exit 1'
ExecStop=/bin/sh -c 'set -eu;keystatus="$$(/sbin/zfs get -H -o value keystatus "%I")";[ "$$keystatus" = "available" ] || exit 0;/sbin/zfs unload-key "%I"'

[Install]
WantedBy=zfs-mount.service

I'm using Slot 1 for HMAC challenges on my Yubikey, so you may need to alter the Shavee command if you're using a different slot

Then just enable the service for your encrypted pool, e.g. to unlock zroot/data you'd do systemctl enable zfs-shavee-unlock@zroot-data

[bug] Command line parse error

While testing 0.1.4 branch (9089e75), (most definitely main branch has the same bug too) I noticed that an unexpected error happens with this command line. Only if PAM_USER environment variable is not set.

$ ./shavee unexpected --pam -z testpool/testdataset
thread 'main' panicked at 'Panic! Something unexpected happened! Please help by reporting it as a bug.: NotPresent', shavee-bin/src/args.rs:198:55

This seems to be caused by a corner case when the binary is executed in PAM mode while passing an unexpected argument to the binary. Clap fails to reject it correctly.

It seems that this section causes Clap to replace PAM_USER with unexpected argument, instead of providing error for lack of the existence of PAM_USER environment variable.

Then here PAM_USER is being used while it doesn't exists and throws a Panic!

Unit test didn't catch it because it sets PAM_USER environment.

If the plan is that 0.1.4 branch will have a separate libpam_shavee.so instead of --pam PAM mode, then it should be better to to move PAM_USER validating and appending it to the dataset to this PAM module and remove it from the main binary argument.

[TODO] Complete unit test coverage

Current missing unit tests coverage as of PR #19 :

  • Pam Module functions in shavee-pam::lib.rs
  • All Yubikey related functions
  • Simple (2~4 lines) functions in shavee-core::logic.rs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.