~alpine/devel

Support encrypted root in setup-disk v7 PROPOSED

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:
Next
Export patchset (mbox)
How do I use this?

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 -3
Learn more about email & git

[PATCH v7] Support encrypted root in setup-disk Export this patch

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;
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);
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
		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"
	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"
		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"
}

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="";;
-- 
2.32.0
Hello,

Thanks for the patch and contribution. I've added my feedback to everything below.