Krystian Chachuła: 1 Support encrypted root in setup-disk 1 files changed, 106 insertions(+), 29 deletions(-)
Thank you Natanael for the review. On Fri Oct 1, 2021 at 6:40 PM CEST, Natanael Copa wrote:
Copy & paste the following snippet into your terminal to import this patchset into git:
curl -s https://lists.alpinelinux.org/~alpine/devel/patches/3596/mbox | git am -3Learn more about email & git
Co-authored-by: Drew DeVault <sir@cmpwn.com> --- Major changes since v7 are: * setup_grub and setup_root: when using EFI and encryption, the boot partition is unencrypted and mounted to /boot instead of /boot/efi (like current behavior with syslinux); this solves two issues: setting up GRUB with luks2 encrypted /boot is difficult, installing GRUB with encrypted /boot needs chroot or a workaround (see v7 discussion)
I think it would be nice with an explanation in the commit message why it is done this way.
* install_mounted_root: cryptroot kernel param is now set to UUID instead of device name * init_progs: blkid is explicitly installed, because crypt_required needs it I tested sys and cryptsys installation with syslinux/BIOS, GRUB/BIOS and GRUB/EFI on x86_64.
great! thanks!
See https://git.sr.ht/~krystianch/alpine-conf/commit/70aaffca3d4685f3a8d78deaca7b479521b13ab8 for full diff between v7 and v8. I'd appreciate a review / feedback. setup-disk.in | 135 +++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 29 deletions(-) diff --git a/setup-disk.in b/setup-disk.in index 656b5bc..46c8068 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 -r devname mountpoint fstype mntops freq passno; do + 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 @@ -283,19 +303,23 @@ setup_grub() { # install GRUB efi mode if [ -n "$USE_EFI" ]; then local target fwa + local efi_directory="$mnt"/boot/efi case "$ARCH" in x86_64) target=x86_64-efi ; fwa=x64 ;; x86) target=i386-efi ; fwa=ia32 ;; arm*) target=arm-efi ; fwa=arm ;; aarch64) target=arm64-efi ; fwa=aa64 ;; esac + if [ -n "$USE_CRYPT" ]; then + efi_directory="$mnt"/boot + fi # currently disabling nvram so grub doesnt call efibootmgr # installing to alpine directory so other distros dont overwrite it - grub-install --target=$target --efi-directory="$mnt"/boot/efi \ + grub-install --target=$target --efi-directory="$efi_directory" \ --bootloader-id=alpine --boot-directory="$mnt"/boot --no-nvram # fallback mode will use boot/boot${fw arch}.efi - install -D "$mnt"/boot/efi/EFI/alpine/grub$fwa.efi \ - "$mnt"/boot/efi/EFI/boot/boot$fwa.efi + install -D "$efi_directory"/EFI/alpine/grub$fwa.efi \ + "$efi_directory"/EFI/boot/boot$fwa.efi # install GRUB for ppc64le elif [ "$ARCH" = "ppc64le" ]; then shift 5 @@ -427,7 +451,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 +514,6 @@ install_mounted_root() { esac done - if [ -n "$VERBOSE" ]; then echo "Root device: $rootdev" echo "Root filesystem: $root_fs" @@ -513,6 +536,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" + fi + # generate mkinitfs.conf mkdir -p "$mnt"/etc/mkinitfs/features.d echo "features=\"$initfs_features\"" > "$mnt"/etc/mkinitfs/mkinitfs.conf @@ -530,24 +575,15 @@ 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 }') + root=$(uuid_or_device $root) + kernel_opts="cryptroot=$root cryptdm=root" + 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 +631,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 +737,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 blkid" 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 +755,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() { @@ -1018,11 +1059,11 @@ setup_root() { mkfs.$ROOTFS $MKFS_OPTS_ROOT $mkfs_args "$root_dev" mkdir -p "$SYSROOT" mount -t $ROOTFS $root_dev "$SYSROOT" || return 1 - if [ -n "$boot_dev" ] && [ -z "$USE_EFI" ]; then + if [ -n "$boot_dev" ] && ([ -z "$USE_EFI" ] || [ -n "$USE_CRYPT" ]); then mkdir -p "$SYSROOT"/boot mount -t $BOOTFS $boot_dev "$SYSROOT"/boot || return 1 fi - if [ -n "$boot_dev" ] && [ -n "$USE_EFI" ]; then + if [ -n "$boot_dev" ] && [ -n "$USE_EFI" ] && [ -z "$USE_CRYPT" ]; then mkdir -p "$SYSROOT"/boot/efi mount -t $BOOTFS $boot_dev "$SYSROOT"/boot/efi || return 1 fi @@ -1082,6 +1123,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
What happens if user provides wrong password to `cryptsetup open` in setup_crypt? Shouldn't we handle error here?
+ echo "/dev/mapper/$dmname" +} + native_disk_install() { local prep_part_type=$(partition_id prep) local root_part_type=$(partition_id linux) @@ -1156,6 +1209,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)
What should happen here if `cryptsetup open` failed?
+ fi + [ $SWAP_SIZE -gt 0 ] && setup_swap_dev $swap_dev setup_root $root_dev $BOOT_DEV $@ } @@ -1176,7 +1233,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 +1241,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 +1296,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 +1310,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 +1350,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 +1385,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 +
I wonder how much extra work it would be to add support for encrypted disk under lvm?
# stop all volume groups in use vgchange --ignorelockingfailure -a n >/dev/null 2>&1 @@ -1381,9 +1453,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 + ;;
What would be needed to be able to select 'crypt' and then select either 'sys' or 'data'? similar to what we do with lvm. So we could have data on cryptsetup as well.
sys|data) break;; lvm) USE_LVM="_lvm" ;; nolvm) USE_LVM="";; -- 2.32.0
Some feedback from ncopa: From: Natanael Copa <ncopa@alpinelinux.org> To: Krystian Chachu*a <krystian@krystianch.com> Cc: ~alpine/devel@lists.alpinelinux.org, Drew DeVault <sir@cmpwn.com> Subject: Re: [PATCH alpine-conf v8] Support encrypted root in setup-disk Date: Fri, 1 Oct 2021 18:40:51 +0200 X-Mailer: Claws Mail 4.0.0 (GTK+ 3.24.30; x86_64-alpine-linux-musl) Hi! Thank you for working on this. On Sat, 14 Aug 2021 21:11:42 +0200 Krystian Chachuła <krystian@krystianch.com> wrote: