Skip to content

Commit

Permalink
Yubikey two factor authentication for ZFS root filesystem.
Browse files Browse the repository at this point in the history
  • Loading branch information
tschaefer committed Apr 2, 2024
0 parents commit d6217ca
Show file tree
Hide file tree
Showing 15 changed files with 1,026 additions and 0 deletions.
23 changes: 23 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
name: Release
on:
push:
tags:
- "*"
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Install build dependencies
run: |
sudo apt-get update
sudo apt-get install -y make gzip pandoc
- name: Make debian package
run: make
- uses: ncipollo/release-action@v1
with:
artifacts: yubikey-zfs-initramfs-*.deb
bodyFile: changelog.Debian
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package/usr/share/doc/yubikey-zfs-initramfs/README.md.gz
package/usr/share/doc/yubikey-zfs-initramfs/changelog.Debian.gz
package/usr/share/man/
yubikey-zfs-initramfs-1.0-1.deb
10 changes: 10 additions & 0 deletions .yamllint
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
extends: default
rules:
indentation:
indent-sequences: consistent
truthy:
allowed-values: ['true', 'false', 'yes', 'no', 'on', 'off', '1', '0']
check-keys: true

# vim:ft=yaml
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
VERSION = 1.0-1

all: deb

deb: changelog manpage
dpkg-deb --root-owner-group --build package yubikey-zfs-initramfs-$(VERSION).deb

changelog:
gzip --best --no-name --stdout < changelog.Debian > package/usr/share/doc/yubikey-zfs-initramfs/changelog.Debian.gz

manpage:
gzip --best --no-name --stdout < README.md > package/usr/share/doc/yubikey-zfs-initramfs/README.md.gz
mkdir --parents package/usr/share/man/man8
pandoc --standalone --to man yubikey-zfs-enroll.8.md | gzip --best --no-name --stdout > package/usr/share/man/man8/yubikey-zfs-enroll.8.gz

lintian:
lintian --suppress-tags-from-file lintian.suppress yubikey-zfs-initramfs-$(VERSION).deb

clean:
rm --force package/usr/share/doc/yubikey-zfs-initramfs/changelog.Debian.gz
rm --recursive --force package/usr/share/man
rm --force package/usr/share/doc/yubikey-zfs-initramfs/README.md.gz

clean-all: clean
rm --force yubikey-zfs-initramfs-$(VERSION).deb

19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# yubikey-zfs-initramfs

Yubikey two factor authentication for ZFS root filesystem.

With this extension to the zfs-initramfs package, you can unlock a ZFS
encrypted root filesystem using your YubiKey as a second factor.
The challenge-response mechanism of the YubiKey is used to generate a response
based on a passphrase (challenge). Only the combination of the challenge and
the enrolled YubiKey will generate the valid key (response).

For general setup of ZFS as root filesystem please follow the instructions in the
[OpenZFS Documentation](https://openzfs.github.io/openzfs-docs/Getting%20Started/Debian/Debian%20Bookworm%20Root%20on%20ZFS.html).

For the challenge-response mechanism of the YubiKey the second slot is used
and maybe set up as follows:

```
$ ykman otp chalresp --generate 2
```
5 changes: 5 additions & 0 deletions changelog.Debian
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
yubikey-zfs-initramfs (1.0-1) stable; urgency=low

* Yubikey two factor authentication for ZFS root filesystem.

-- Tobias Schäfer <[email protected]> Wed, 20 Mar 2024 18:30:00 +0200
1 change: 1 addition & 0 deletions lintian.suppress
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
initial-upload-closes-no-bugs
16 changes: 16 additions & 0 deletions package/DEBIAN/control
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Package: yubikey-zfs-initramfs
Version: 1.0-1
Section: contrib/kernel
Priority: optional
Architecture: all
Depends: yubikey-manager, yubikey-personalization, zfs-initramfs, zfs | zfsutils-linux
Maintainer: Tobias Schäfer <[email protected]>
Installed-Size: 180 kB
Homepage: https://github.com/tschaefer/yubikey-zfs-initramfs
Description: Yubikey two factor authentication for ZFS root filesystem.
With this extension to the zfs-initramfs package, you can unlock a ZFS
encrypted root filesystem using your YubiKey as a second factor.
.
The challenge-response mechanism of the YubiKey is used to generate a response
based on a passphrase (challenge). Only the combination of the challenge and
the YubiKey will generate the valid key (response).
26 changes: 26 additions & 0 deletions package/etc/zfs/initramfs-tools-load-key
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/sh

if /bin/plymouth --ping 2>/dev/null; then
for _ in 1 2 3; do
plymouth ask-for-password --prompt "Encrypted ZFS challenge for ${ENCRYPTIONROOT}" | \
ykchalresp -2 -i- | $ZFS load-key "${ENCRYPTIONROOT}" && break
done
elif [ -e /run/systemd/system ]; then
for _ in 1 2 3; do
systemd-ask-password --no-tty "Encrypted ZFS challenge for ${ENCRYPTIONROOT}" | \
ykchalresp -2 -i- | $ZFS load-key "${ENCRYPTIONROOT}" && break
done
else
trap 'stty echo' INT

read -r storeprintk _ < /proc/sys/kernel/printk
echo 7 > /proc/sys/kernel/printk
stty -echo
printf "Encrypted ZFS challenge for %s: " "${ENCRYPTIONROOT}"
read -r challenge
stty echo
printf "\n"
echo "$storeprintk" > /proc/sys/kernel/printk

echo "${challenge}" | ykchalresp -2 -i- | $ZFS load-key "${ENCRYPTIONROOT}"
fi
133 changes: 133 additions & 0 deletions package/sbin/yubikey-zfs-enroll
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/bin/sh

set -e

if [ "$(id -u)" -ne 0 ]
then
echo "You must be root." 1>&2
exit 1
fi

usage() {
cat <<EOF
Usage:
yubikey-zfs-enroll [-f] ZFS [CHALLENGE]
yubikey-zfs-enroll -h
Options:
-h Show this help message and exit.
-f Force the enrollment process, no confirmation will be prompted.
EOF
}

get_opts() {
while getopts "fh" opt
do
case $opt in
f)
FORCE=1
;;
h)
usage
exit 0
;;
\?)
usage >&2
exit 1
;;
esac
shift $((OPTIND-1))
done

ZFS=$1
CHALLENGE=$2

if [ -z "${ZFS}" ]
then
usage
fi
}

get_fs_value() {
zfs get -H -o value "$2" "$1" 2>/dev/null
}

check_pool() {
encryption=$(get_fs_value "${ZFS}" "encryption")
if [ "$encryption" = "off" ]
then
echo "${ZFS} is not encrypted." 1>&2
exit 1
fi

keystatus=$(get_fs_value "${ZFS}" "keystatus")
if [ "$keystatus" != "available" ]
then
echo "${ZFS} current key must be loaded." 1>&2
exit 1
fi
}

check_yubikey() {
if ! ykinfo -q -a >/dev/null 2>&1
then
echo "Yubikey not found." 1>&2
exit 1
fi

if [ "$(ykinfo -q -2 2>/dev/null)" -ne 1 ]
then
echo "Yubikey second slot not configured." 1>&2
exit 1
fi
}

enroll() {
if [ -z "${CHALLENGE}" ]; then
if [ -e /run/systemd/system ]
then
CHALLENGE=$(systemd-ask-password --echo=no "Encrypted ZFS challenge for ${ZFS}: ")
else
trap 'stty echo' INT

stty -echo
printf "Encrypted ZFS challenge for %s: " "${ZFS}"
read -r CHALLENGE
stty echo
printf "\n"
fi
fi

if [ -z "${FORCE}" ]
then
echo "This will enroll a new key for ${ZFS}."
echo "The existing key will be overriden!!!"
echo
printf "Do you want to continue? [y/N] "
read -r response
case "${response}" in
[yY][eE][sS]|[yY])
;;
*)
echo "Aborted." 1>&2
exit 1
;;
esac
fi

ENCRYPTIONROOT=$(get_fs_value "${ZFS}" "encryptionroot")
echo "${CHALLENGE}" | ykchalresp -2 -i- | zfs change-key "${ENCRYPTIONROOT}"
}

main() {
get_opts ${1+"$@"}

check_pool
check_yubikey
enroll

exit 0
}

main ${1+"$@"}
14 changes: 14 additions & 0 deletions package/usr/share/doc/yubikey-zfs-initramfs/copyright
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
yubikey-zfs-initramfs

Copyright: 2024 Tobias Schäfer <[email protected]>

2024-03-20

The entire code base may be distributed under the terms of the GNU General
Public License (GPL), which appears immediately below. Alternatively, all
of the source code as any code derived from that code may instead be
distributed under the GNU Lesser General Public License (LGPL), at the
choice of the distributor. The complete text of the LGPL appears at the
bottom of this file.

See /usr/share/common-licenses/(GPL|LGPL)
25 changes: 25 additions & 0 deletions package/usr/share/initramfs-tools/hooks/yubikey-zfs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/sh

set -e

PREREQ="zfs"

prereqs()
{
echo "$PREREQ"
}

case $1 in
prereqs)
prereqs
exit 0
;;
esac

. /usr/share/initramfs-tools/hook-functions

copy_exec /usr/bin/ykchalresp
copy_exec /usr/bin/ykinfo

exit 0

2 changes: 2 additions & 0 deletions package/usr/share/lintian/overrides/yubikey-zfs-initramfs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
yubikey-zfs-initramfs binary: file-in-etc-not-marked-as-conffile [etc/zfs/initramfs-tools-load-key]

48 changes: 48 additions & 0 deletions yubikey-zfs-enroll.8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
% YUBIKEY-ZFS-ENROLL(8) yubikey-zfs-enroll user manual

# NAME

yubikey-zfs-enroll - Enroll a YubiKey as a second factor for unlocking an
encrypted ZFS dataset.

# SYNOPSIS

`yubikey-zfs-enroll` [-f] *ZFS* [*CHALLENGE*]

`yubikey-zfs-enroll` -h

# DESCRIPTION

yubikey-zfs-enroll enrolls a YubiKey as a second factor for unlocking an
encrypted ZFS dataset.

The challenge-response mechanism of the second slot of the YubiKey is used to
generate a response based on a passphrase (challenge). Only the combination
of the challenge and the matching YubiKey will generate the valid key.

yubikey-zfs-enroll requires that the existing key for the dataset is already
loaded. While the enroll process the user will be prompted to enter the
challenge, alternatively the challenge can be passed as an argument. Further
a confirmation is required before the YubiKey is fianlly enrolled.
The confirmation can be skipped with the `-f` option.

# OPTIONS

`-h` Show the help message and exit.

`-f` Force the enrollment process, no confirmation will be prompted.

# SEE ALSO

zfs-change-key(8), ykman(1)

# AUTHOR

Written by Tobias Schäfer <[email protected]>

# COPYRIGHT

Copyright © 2024 Tobias Schäfer <[email protected]> License GPLv3+: GNU GPL
version 3 or later <https://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it. There is
NO WARRANTY, to the extent permitted by law.

0 comments on commit d6217ca

Please sign in to comment.