Krystian Chachuła: 1 Support encrypted root in setup-disk 1 files changed, 96 insertions(+), 24 deletions(-)
Thanks for the review. On Mon Aug 9, 2021 at 1:07 PM CEST, Alex Denes wrote:
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.alpinelinux.org/~alpine/devel/patches/3585/mbox | git am -3Learn more about email & git
Co-authored-by: Drew DeVault <sir@cmpwn.com> --- I rebased Drew's patch onto current master. I had to change two things to make the script work correctly. 1. install_mounted_root: Move adding cryptsetup to initfs_features before generating mkinitfs.conf. 2. init_progs: Add cryptsetup package if using encryption. I have tested the script with syslinux (no EFI). Now there is a question about making it work with GRUB (EFI). This would require: 1. changing luksFormat type to luks1 as GRUB2 does not support luks2;
Alex Denes <caskd@redxen.eu>GRUB has recently added support for luks2 but the mkimage wrapper doesn't include the required modules so the support is not as automated as it should be. I would instead go for a encrypted root with a unencrypted /boot to avoid using luks1 for everything and it would simplify the setup. This is not "full-disk" encryption as one would want but it doesn't have the limitation that luks1 has.Krystian Chachuła <krystian@krystianch.com>Ok, this seems reasonable to me. I'll modify the mount point so that in the case of GRUB with EFI we have unencrypted /boot. It will be similar to current behavior when choosing syslinux. Maybe in the meantime we'll get some more opinions on this issue."LUKS provides a generic key store on the dedicated area on a disk, with the ability to use multiple passphrases to unlock a stored key. LUKS2 extends this concept for more flexible ways of storing metadata, redundant information to provide recovery in the case of corruption in a metadata area, and an interface to store externally managed metadata for integration with other tools." https://gitlab.com/cryptsetup/cryptsetup/blob/master/docs/on-disk-format-luks2.pdf
2. adding a workaround in order for grub-install to succeed (it is not called from a chroot so it complains about GRUB_ENABLE_CRYPTODISK=y not being present in /etc/default/grub, we can temporarily replace /etc/default/grub with "$mnt"/etc/default/grub);
Alex Denes <caskd@redxen.eu>A temporary symlink could work for this instead of making a full copy. Alternatively, a change of root would work as well but that requires setting up the chroot so that grub-install has the required paths.Krystian Chachuła <krystian@krystianch.com>This workaround is not needed if /boot is unencrypted.I have also added some feedback to the patch:
I would appreciate feedback about those two issues before I start working on this again. setup-disk.in | 120 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 96 insertions(+), 24 deletions(-) diff --git a/setup-disk.in b/setup-disk.in index 656b5bc..e617101 100644 --- a/setup-disk.in +++ b/setup-disk.in @@ -82,6 +82,26 @@ enumerate_fstab() { done } +# given an fstab on stdin, determine if any of the mountpoints are encrypted +crypt_required() { + while read devname mountpoint fstype mntops freq passno; do
Alex Denes <caskd@redxen.eu>I would use the '-r' flag for read as fstab has no escapes.
+ if [ -z "$devname" ] || [ "${devname###}" != "$devname" ]; then + continue + fi + uuid="${devname##UUID=}" + if [ "$uuid" != "$devname" ]; then + devname="$(blkid --uuid "$uuid")" + fi + mapname="${devname##/dev/mapper/}" + if [ "$mapname" != "$devname" ]; then + if cryptsetup status "$mapname" >&1 >/dev/null; then + return 0 + fi + fi + done + return 1 +} + is_vmware() { grep -q VMware /proc/scsi/scsi 2>/dev/null \ || grep -q VMware /proc/ide/hd*/model 2>/dev/null @@ -427,7 +447,7 @@ setup_raspberrypi_bootloader() { install_mounted_root() { local mnt="$1" shift 1 - local disks="${@}" mnt_boot= boot_fs= root_fs= + local disks="${@}" mnt_boot= boot_fs= root_fs= use_crypt= local initfs_features="ata base ide scsi usb virtio" local pvs= dev= rootdev= bootdev= extlinux_raidopt= root= modules= local kernel_opts="$KERNELOPTS" @@ -490,7 +510,6 @@ install_mounted_root() { esac done - if [ -n "$VERBOSE" ]; then echo "Root device: $rootdev" echo "Root filesystem: $root_fs" @@ -513,6 +532,28 @@ install_mounted_root() { # we should not try start modloop on sys install rm -f "$mnt"/etc/runlevels/*/modloop + # generate the fstab + if [ -f "$mnt"/etc/fstab ]; then + mv "$mnt"/etc/fstab "$mnt"/etc/fstab.old + fi + enumerate_fstab "$mnt" >> "$mnt"/etc/fstab + if [ -n "$SWAP_DEVICES" ]; then + local swap_dev + for swap_dev in $SWAP_DEVICES; do + echo -e "$(uuid_or_device ${swap_dev})\tswap\tswap\tdefaults\t0 0" \ + >> "$mnt"/etc/fstab + done + fi + cat >>"$mnt"/etc/fstab <<-__EOF__ + /dev/cdrom /media/cdrom iso9660 noauto,ro 0 0 + /dev/usbdisk /media/usb vfat noauto 0 0 + __EOF__ + + if crypt_required <"$mnt"/etc/fstab; then + use_crypt=1 + initfs_features="${initfs_features% cryptsetup} cryptsetup"
Alex Denes <caskd@redxen.eu>Isn't this the only place where cryptsetup can be added to the initfs_features? Wouldn't this duplicate the feature if it wasn't the last appended?
+ fi + # generate mkinitfs.conf mkdir -p "$mnt"/etc/mkinitfs/features.d echo "features=\"$initfs_features\"" > "$mnt"/etc/mkinitfs/mkinitfs.conf @@ -530,24 +571,14 @@ install_mounted_root() { if [ -n "$(get_bootopt nomodeset)" ]; then kernel_opts="nomodeset $kernel_opts" fi + if [ "$use_crypt" ] && cryptsetup status "$rootdev" 2>&1 >/dev/null; then + # Boot to encrypted root + root=$(cryptsetup status "$rootdev" | awk '/device:/ { print $2 }') + kernel_opts="cryptroot=$root cryptdm=root"
Alex Denes <caskd@redxen.eu>cryptsetup returns devices without unique identifiers which means this might fail when the order of devices found by the kernel changes.
+ root=/dev/mapper/root + fi modules="sd-mod,usb-storage,${root_fs}${raidmod}" - # generate the fstab - if [ -f "$mnt"/etc/fstab ]; then - mv "$mnt"/etc/fstab "$mnt"/etc/fstab.old - fi - enumerate_fstab "$mnt" >> "$mnt"/etc/fstab - if [ -n "$SWAP_DEVICES" ]; then - local swap_dev - for swap_dev in $SWAP_DEVICES; do - echo -e "$(uuid_or_device ${swap_dev})\tswap\tswap\tdefaults\t0 0" \ - >> "$mnt"/etc/fstab - done - fi - cat >>"$mnt"/etc/fstab <<-__EOF__ - /dev/cdrom /media/cdrom iso9660 noauto,ro 0 0 - /dev/usbdisk /media/usb vfat noauto 0 0 - __EOF__ # remove the installed db in case its there so we force re-install rm -f "$mnt"/var/lib/apk/installed "$mnt"/lib/apk/db/installed echo "Installing system on $rootdev:" @@ -595,6 +626,10 @@ unmount_partitions() { # unmount the partitions umount $(awk '{print $2}' /proc/mounts | egrep "^$mnt(/|\$)" | sort -r) + + if [ "$USE_CRYPT" ]; then + cryptsetup close /dev/mapper/root + fi } # figure out decent default swap size in mega bytes @@ -697,9 +732,10 @@ select_bootloader_pkg() { # install needed programs init_progs() { - local raidpkg= lvmpkg= fs= fstools= grub= + local raidpkg= lvmpkg= cryptpkg= fs= fstools= grub= [ -n "$USE_RAID" ] && raidpkg="mdadm" [ -n "$USE_LVM" ] && lvmpkg="lvm2" + [ -n "$USE_CRYPT" ] && cryptpkg="cryptsetup" for fs in $BOOTFS $ROOTFS $VARFS; do # we need load btrfs module early to avoid the error message: # 'failed to open /dev/btrfs-control' @@ -714,7 +750,7 @@ init_progs() { vfat) fstools="$fstools dosfstools";; esac done - apk add --quiet sfdisk $lvmpkg $raidpkg $fstools $@ + apk add --quiet sfdisk $cryptpkg $lvmpkg $raidpkg $fstools $@ } show_disk_info() { @@ -1082,6 +1118,18 @@ native_disk_install_lvm() { setup_root $root_dev $BOOT_DEV } +setup_crypt() { + local dev="$1" local dmname="$2" + mkdir -p /run/cryptsetup + echo "Preparing root partition for encryption." >&2 + echo "You will be prompted for your password at boot." >&2 + echo "If you forget your password, your data will be lost." >&2 + cryptsetup luksFormat --type luks2 "$dev" >&2 + echo "Enter password again to unlock disk for installation." >&2 + cryptsetup open "$dev" "$dmname" >&2 + echo "/dev/mapper/$dmname"
Alex Denes <caskd@redxen.eu>I would check that the device is unlocked properly here and if not, prompt for a retry.Krystian Chachuła <krystian@krystianch.com>Is this really needed? cryptsetup open prompts for a retry when it fails.
+} + native_disk_install() { local prep_part_type=$(partition_id prep) local root_part_type=$(partition_id linux) @@ -1156,6 +1204,10 @@ native_disk_install() { root_dev=$(find_nth_non_boot_parts $index "$root_part_type" $@) fi + if [ "$USE_CRYPT" ]; then + root_dev=$(setup_crypt $root_dev root) + fi + [ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev setup_root $root_dev $BOOT_DEV $@ } @@ -1176,7 +1228,7 @@ diskselect_help() { diskmode_help() { cat <<-__EOF__ - You can select between 'sys', 'data', 'lvm', 'lvmsys' or 'lvmdata'. + You can select between 'sys', 'cryptsys', 'data', 'lvm', 'lvmsys' or 'lvmdata'. sys: This mode is a traditional disk install. The following partitions will be @@ -1184,6 +1236,12 @@ diskmode_help() { This mode may be used for development boxes, desktops, virtual servers, etc. + cryptsys: + This mode is equivalent to sys, except that the root filesystem will be + encrypted with cryptsetup. You will be prompted to enter a decryption + password, and will need to use this password to boot up the operating + system after installation. + data: This mode uses your disk(s) for data storage, not for the operating system. The system itself will run from tmpfs (RAM). @@ -1233,7 +1291,7 @@ ask_disk() { usage() { cat <<-__EOF__ - usage: setup-disk [-hLqrv] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE] + usage: setup-disk [-hLqrve] [-k kernelflavor] [-m MODE] [-o apkovl] [-s SWAPSIZE] [MOUNTPOINT | DISKDEV...] Install alpine on harddisk. @@ -1247,6 +1305,7 @@ usage() { options: -h Show this help + -e Encrypt disk -m Use disk for MODE without asking, where MODE is either 'data' or 'sys' -o Restore system from given apkovl file -k Use kernelflavor instead of $KERNEL_FLAVOR @@ -1286,11 +1345,13 @@ case $kver in *) KERNEL_FLAVOR=lts;; esac +USE_CRYPT= DISK_MODE= USE_LVM= # Parse args -while getopts "hk:Lm:o:qrs:v" opt; do +while getopts "hek:Lm:o:qrs:v" opt; do case $opt in + e) USE_CRYPT=1;; m) DISK_MODE="$OPTARG";; k) KERNEL_FLAVOR="$OPTARG";; L) USE_LVM="_lvm";; @@ -1319,6 +1380,12 @@ fi reset_var swapoff -a +if [ $USE_CRYPT -eq 1 ] && [ -n "$USE_LVM" ]; then + echo "cryptsys and lvm are currently mutually incompatible." + echo "Please run $0 again with only one of these options selected." + exit 1 +fi + # stop all volume groups in use vgchange --ignorelockingfailure -a n >/dev/null 2>&1 @@ -1381,9 +1448,14 @@ if [ -n "$diskdevs" ] && [ -z "$DISK_MODE" ]; then echo "The following $disk_is_or_disks_are selected${USE_LVM:+ (with LVM)}:" show_disk_info $diskdevs _lvm=${USE_LVM:-", 'lvm'"} - ask "How would you like to use $it_them? ('sys', 'data'${_lvm#_lvm} or '?' for help)" "?" + ask "How would you like to use $it_them? ('sys', 'cryptsys', 'data'${_lvm#_lvm} or '?' for help)" "?" case "$resp" in '?') diskmode_help;; + cryptsys) + resp=sys + USE_CRYPT=1 + break + ;; sys|data) break;; lvm) USE_LVM="_lvm" ;; nolvm) USE_LVM="";;
Alex Denes <caskd@redxen.eu>-- Alex D. RedXen System & Infrastructure Administration https://redxen.eu/
-- 2.32.0
Alex Denes <caskd@redxen.eu>Hello, Thanks for the patch and contribution. I've added my feedback to everything below.