Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Rewrite luks tpm2 script. #302

Merged
merged 5 commits into from
Jul 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 48 additions & 12 deletions build/ublue-os-luks/luks-disable-tpm2-autounlock
Original file line number Diff line number Diff line change
@@ -1,45 +1,81 @@
#!/bin/bash
## disable auto-unlock LUKS2 encrypted root on Fedora/Silverblue/maybe others
set -u
set -euo pipefail

[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

read -p "This will modify your system and disable TPM2 auto-unlock of your LUKS partition! Are you sure you've read the script and are good with this? " -n 1 -r
echo "This script utilizes systemd-cryptenroll for removing tpm2 auto-unlock."
echo "You can review systemd-cryptenroll's manpage for more information."
read -p "This will modify your system and disable TPM2 auto-unlock of your LUKS partition! Are you sure you are good with this? " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
[[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
fi

DISK_UUID=$(sudo awk '{ print $2 }' /etc/crypttab | cut -d= -f2)
## Inspect Kernel Cmdline for rd.luks.uuid
RD_LUKS_UUID="$(xargs -n1 -a /proc/cmdline | grep rd.luks.uuid | cut -d = -f 2)"

# Check to make sure cmdline rd.luks.uuid exists
if [[ -z ${RD_LUKS_UUID:-} ]]; then
printf "LUKS device not defined on Kernel Commandline.\n"
printf "This is not supported by this script.\n"
printf "Exiting...\n"
exit 1
fi

# Check to make sure that the specified cmdline uuid exists.
if ! grep -q "${RD_LUKS_UUID}" <<< "$(lsblk)" ; then
printf "LUKS device not listed in block devices.\n"
printf "Exiting...\n"
exit 1
fi

# Cut off the luks-
LUKS_PREFIX="luks-"
if grep -q ^${LUKS_PREFIX} <<< "${RD_LUKS_UUID}"; then
DISK_UUID=${RD_LUKS_UUID#"$LUKS_PREFIX"}
else
echo "LUKS UUID format mismatch."
echo "Exiting..."
exit 1
fi

# Specify Crypt Disk by-uuid
CRYPT_DISK="/dev/disk/by-uuid/$DISK_UUID"

# Check to make sure crypt disk exists
if [[ ! -L "$CRYPT_DISK" ]]; then
printf "LUKS device not listed in block devices.\n"
printf "Exiting...\n"
exit 1
fi

bsherman marked this conversation as resolved.
Show resolved Hide resolved
## Restore the crypttab
cp -a /etc/crypttab /etc/crypttab.working-before-disable-tpm2
bsherman marked this conversation as resolved.
Show resolved Hide resolved
if [ -f /etc/crypttab.known-good ]; then
echo "Restoring /etc/crypttab.known-good to original /etc/crypttab"
mv /etc/crypttab.known-good /etc/crypttab
else
echo "No /etc/crypttab.known-good found to restore"
fi

## Wipe luks slot
cryptsetup luksDump $CRYPT_DISK | grep systemd-tpm2 > /dev/null
if [ 0 -eq $? ]; then
if cryptsetup luksDump "$CRYPT_DISK" | grep systemd-tpm2 > /dev/null; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This validation can be more thorough. For example, if the user accidentally enrolled multiple tokens, or has no backup passphrase.

In the latter case, I believe systemd-cryptenroll will throw an error, which would break the script if not handled

Copy link
Contributor

@RoyalOughtness RoyalOughtness Jul 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.



DISK_LUKSDUMP=$(cryptsetup luksDump $CRYPT_DISK)

if echo $DISK_LUKSDUMP | grep fido > /dev/null || ! echo $DISK_LUKSDUMP | {add logic to check for passphrase here}; then
  echo "cryptsetup has been manually configured, exiting..."
  exit 1
fi

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the same logic that we had previously. We can put a warning at the top to make sure you still have a decryption method besides the tpm.

We could have a warning during the enrollment to always ensure that you have a password or recovery key to ensure you have access to the data.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m2Giles I don't see this logic in the previous script, unless you mean the backing up of the previous crypttab?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do like the check.

I think the simple thing will be checking if passphrase is in slot 0. If not it's safe to assume the user manually configured the device.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m2Giles yeah that's a reasonable assumption.

Copy link
Contributor

@RoyalOughtness RoyalOughtness Jul 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@m2Giles I think this script should be as foolproof as possible, so if there's any sign that the user has manually touched cryptsetup, we should fail and say "it looks like you've got this covered :)"

otherwise you open this up to needing to support and/or work around custom configurations

echo "Wiping systemd-tpm2 from LUKS on $CRYPT_DISK"
systemd-cryptenroll --wipe-slot=tpm2 $CRYPT_DISK
systemd-cryptenroll --wipe-slot=tpm2 "$CRYPT_DISK"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming a comment I made elsewhere, systemd-cryptenroll will NOT wipe the tpm2 slot if it's the last remaining slot.

$ systemd-cryptenroll /dev/disk/by-uuid/d4f1e47c-a653-4cd5-a6ae-bfc62c0a6852 --wipe-slot=tpm2 
Wipe operation would leave no valid slots around, can't allow that, sorry.

Granted, if a user is living dangerously if they get to this state, and I think it would have to be by use of having a tpm2 slot and recover-key slot both setup by systemd-cryptenroll, and then having wiped the recovery slot.

Similarly, cryptsetup luksKillSlot prevents removing of a slot using that slot's passphrase.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As an aside, if a user does reach the state of only a tpm2 slot... a passphrase can be re-added:
cryptsetup luksAddKey --token-id 2 --token-type systemd-tpm2 /dev/disk/by-uuid/d4f1e47c-a653-4cd5-a6ae-bfc62c0a6852

else
echo "No systemd-tpm2 found in LUKS to wipe"
fi

## Disable initramfs
rpm-ostree initramfs | grep tpm2 > /dev/null
if [ 0 -eq $? ]; then
if rpm-ostree initramfs | grep tpm2 > /dev/null; then
echo "WARNING: if you configured initramfs for anything other than TPM2, this wipes that too..."
echo "here's a printout:"
rpm-ostree initramfs
echo
echo "Disabling rpm-ostree initramfs..."
rpm-ostree initramfs --disable
else
echo "TPM2 was not found in 'rpm-ostree initramfs'..."
echo "TPM2 is not configured in 'rpm-ostree initramfs'..."
fi

echo "TPM2 auto-unlock disabled..."
echo "To reenroll TPM2 auto unlock please run ujust setup-luks-tpm-unlock..."
81 changes: 50 additions & 31 deletions build/ublue-os-luks/luks-enable-tpm2-autounlock
Original file line number Diff line number Diff line change
@@ -1,57 +1,76 @@
#!/bin/bash
## setup auto-unlock LUKS2 encrypted root on Fedora/Silverblue/maybe others
set -u
set -eou pipefail

[ "$UID" -eq 0 ] || { echo "This script must be run as root."; exit 1;}

read -p "This will modify your system and enable TPM2 auto-unlock of your LUKS partition! Are you sure you've read the script and are good with this? " -n 1 -r
echo "This script uses systemd-cryptenroll to enable TPM2 auto-unlock."
echo "You can review systemd-cryptenroll's manpage for more information."
echo "This script will modify your system."
echo "It will enable TPM2 auto-unlock of your LUKS partition for your root device!"
echo "It will bind to PCR 7 only which is tied to your secureboot state."
read -p "Are you sure are good with this and want to enable TPM2 auto-unlock? " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
[[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1 # handle exits from shell or function but don't exit interactive shell
fi

## Inspect crypttab to find disk info, should look like this
#sudo cat /etc/crypttab
#luks-912462a2-39ce-abcd-1234-89c6c0304cb4 UUID=912462a2-39ce-abcd-1234-89c6c0304cb4 none discard
DISK_UUID=$(sudo awk '{ print $2 }' /etc/crypttab | cut -d= -f2)
CRYPT_DISK="/dev/disk/by-uuid/$DISK_UUID"
## Inspect Kernel Cmdline for rd.luks.uuid
RD_LUKS_UUID="$(xargs -n1 -a /proc/cmdline | grep rd.luks.uuid | cut -d = -f 2)"

## Backup the crypttab
if [ -f /etc/crypttab.known-good ]; then
echo "Our backup already exists at /etc/crypttab.known-good\nExiting..."
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
# Check to make sure cmdline rd.luks.uuid exists
if [[ -z ${RD_LUKS_UUID:-} ]]; then
printf "LUKS device not defined on Kernel Commandline.\n"
printf "This is not supported by this script.\n"
printf "Exiting...\n"
exit 1
fi
cp -a /etc/crypttab /etc/crypttab.known-good

## modify the crypttab
grep tpm2-device /etc/crypttab > /dev/null
if [ 0 -eq $? ]; then
echo "TPM2 already present in /etc/crypttab. Exiting..."
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
# Check to make sure that the specified cmdline uuid exists.
if ! grep -q "${RD_LUKS_UUID}" <<< "$(lsblk)" ; then
printf "LUKS device not listed in block devices.\n"
printf "Exiting...\n"
exit 1
fi
sed -i "s/discard/discard,tpm2-device=auto/" /etc/crypttab

cryptsetup luksDump $CRYPT_DISK | grep systemd-tpm2 > /dev/null
if [ 0 -eq $? ]; then
KEYSLOT=$(cryptsetup luksDump $CRYPT_DISK|grep -A23 systemd-tpm2|grep Keyslot|awk '{print $2}')
echo "TPM2 already present in LUKS Keyslot $KEYSLOT of $CRYPT_DISK. Exiting..."
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
# Cut off the luks-
LUKS_PREFIX="luks-"
if grep -q ^${LUKS_PREFIX} <<< "${RD_LUKS_UUID}"; then
DISK_UUID=${RD_LUKS_UUID#"$LUKS_PREFIX"}
else
echo "LUKS UUID format mismatch."
echo "Exiting..."
exit 1
fi

# Specify Crypt Disk by-uuid
CRYPT_DISK="/dev/disk/by-uuid/$DISK_UUID"

# Check to make sure crypt disk exists
if [[ ! -L "$CRYPT_DISK" ]]; then
printf "LUKS device not listed in block devices.\n"
printf "Exiting...\n"
exit 1
fi

if cryptsetup luksDump "$CRYPT_DISK" | grep systemd-tpm2 > /dev/null; then
KEYSLOT=$(cryptsetup luksDump "$CRYPT_DISK"|grep -A29 systemd-tpm2|grep Keyslot|awk '{print $2}')
echo "TPM2 already present in LUKS Keyslot $KEYSLOT of $CRYPT_DISK."
echo "Remove the existing TPM2 enrollment with ujust remove-luks-tpm2-autounlock"
echo "Exiting..."
[[ "$0" = "${BASH_SOURCE[0]}" ]] && exit 1 || return 1
fi

## Run crypt enroll
echo "Enrolling TPM2 unlock requires your existing LUKS2 unlock password"
echo
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 $CRYPT_DISK
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 "$CRYPT_DISK"


lsinitrd 2>&1 | grep -q tpm2-tss > /dev/null
if [ 1 -eq $? ]; then
if lsinitrd 2>&1 | grep -q tpm2-tss > /dev/null; then
## add tpm2-tss to initramfs
rpm-ostree initramfs | grep tpm2 > /dev/null
if [ 0 -eq $? ]; then
if rpm-ostree initramfs | grep tpm2 > /dev/null; then
echo "TPM2 already present in rpm-ostree initramfs config."
rpm-ostree initramfs
echo
echo "Re-running initramfs to pickup changes above."
fi
rpm-ostree initramfs --enable --arg=--force-add --arg=tpm2-tss
Expand Down
6 changes: 5 additions & 1 deletion build/ublue-os-luks/ublue-os-luks.spec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Name: ublue-os-luks
Packager: ublue-os
Vendor: ublue-os
Version: 0.2
Version: 0.3
Release: 1%{?dist}
Summary: ublue-os scripts for simplified LUKS usage
License: MIT
Expand Down Expand Up @@ -31,6 +31,10 @@ install -Dm644 %{SOURCE2} %{buildroot}/%{_exec_prefix}/lib/dracut/dracut.conf.d
%attr(0644,root,root) %{_exec_prefix}/lib/dracut/dracut.conf.d/90-ublue-luks.conf

%changelog
* Thu Jul 04 2024 m2Giles <[email protected]> - 0.3
- Rewrite enable script to fail out if disk is not found
- LUKs disk is determined from kernel commandline instead of /etc/crypttab

* Sat Jun 29 2024 Benjamin Sherman <[email protected]> - 0.2
- Add tpm, fido2, pkcs11 to dracut config enabling initramfs LUKS unlock options

Expand Down
Loading