Skip to content

Instantly share code, notes, and snippets.

@casebeer
Last active March 21, 2024 22:19
Show Gist options
  • Save casebeer/b6ef86bd7531995d7f9b69af3749dfef to your computer and use it in GitHub Desktop.
Save casebeer/b6ef86bd7531995d7f9b69af3749dfef to your computer and use it in GitHub Desktop.
Script to unlock Ubuntu LUKS encrypted volume from initramfs during boot using a keyfile stored on a USB thumb drive with fallback to manual passphrase entry.
#!/bin/sh
# https://tqdev.com/2022-luks-with-usb-unlock
#
# Script to unlock Ubuntu LUKS encrypted volume from initramfs during boot using
# a keyfile stored on a USB thumb drive with fallback to manual passphrase entry.
#
# Runs in Busybox shell environment in initramfs
# After updates to this script or crypttab, update initramfs:
#
# update-initramfs -u
#
set -x
# see man 5 crypttab
crypttabKeyfileArg="${CRYPTTAB_KEY}"
usbDiskUuid="$(echo "${crypttabKeyfileArg}" | cut -d ':' -f 1)"
keyFile="$(echo "${crypttabKeyfileArg}" | cut -d ':' -f 2 )"
mountPoint="/mnt"
keyFilePath="${mountPoint}/${keyFile}"
# Mount USB by UUID to avoid ambiguity
# Alternative considered: Use disk label so we can swap out the USB drive as needed.
# use by-uuid device because Busybox mount doesn't support -U {UUID} option
mkdir -p "${mountPoint}"
mount "/dev/disk/by-uuid/${usbDiskUuid}" "${mountPoint}"
# Print debugging variables
set +x
ls -l "${keyFilePath}" >&2
echo "CRYPTTAB_NAME=${CRYPTTAB_NAME}" >&2
echo "CRYPTTAB_SOURCE=${CRYPTTAB_SOURCE}" >&2
echo "CRYPTTAB_KEY=${CRYPTTAB_KEY}" >&2
echo "CRYPTTAB_TRIED=${CRYPTTAB_TRIED}" >&2
echo "CRYPTTAB_TRIES=${CRYPTTAB_TRIES}" >&2
echo "CRYPTTAB_OPTIONS=${CRYPTTAB_OPTIONS}" >&2
# Pause for a few seconds in case of errors etc.
read -p "Press ENTER to continue..." -t 5 discard
set -x
tryKeyFile() {
if [ -z "${keyFile}" -o -z "${usbDiskUuid}" ] ; then
echo "ERROR: No keyfile or USB disk configured. Specify in /etc/crypttab as {uuid}:{keyfile}" >&2
#exit 1
return 2
fi
if [ -f "${keyFilePath}" ]; then
# we've located the keyfile (by name)
# dump its contents to stdout
# note that if the keyfile is bad, we need to identify that and fail over to passphrase collection
if [ "${CRYPTTAB_TRIED}" -gt "0" ] ; then
echo "Found keyfile, but previously failed to unlock. Skipping to passphrase collection." >&2
return 3
fi
cat "${keyFilePath}"
return 0
fi
echo "ERROR: Unable to find keyfile." >&2
return 1
}
if tryKeyFile ; then
echo "Found keyfile." >&2
else
# collect passphrase manually since we can't find or can't use the keyfile
/lib/cryptsetup/askpass "Enter LUKS passphrase for ${CRYPTTAB_SOURCE}: "
fi
umount "${mountPoint}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment