From c55ce46084635c188abb4516ba6ee6eee38dd11d Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sat, 24 Jan 2026 05:33:13 -0600 Subject: Phase 2.8: Add LUKS encryption for btrfs - Add LUKS functions to btrfs.sh (create/open/close container) - Add crypttab configuration for boot - Add encrypt hook to mkinitcpio HOOKS - Add cryptdevice parameter to GRUB cmdline - Add get_btrfs_encryption_choice and get_luks_passphrase prompts - Add LUKS_PASSPHRASE to config variables - Update show_summary and print_btrfs_summary for encryption status - Add btrfs-luks.conf test config VM test pending. --- custom/archangel | 103 +++++++++++++++++++++++++++++++++++++++++++++++---- custom/lib/btrfs.sh | 90 +++++++++++++++++++++++++++++++++++++++++++- custom/lib/config.sh | 1 + 3 files changed, 186 insertions(+), 8 deletions(-) (limited to 'custom') diff --git a/custom/archangel b/custom/archangel index c887a4d..ba0c94e 100755 --- a/custom/archangel +++ b/custom/archangel @@ -117,6 +117,13 @@ gather_input() { fi fi + # Btrfs-specific validation + if [[ "$FILESYSTEM" == "btrfs" ]]; then + if [[ "$NO_ENCRYPT" != "yes" && -z "$LUKS_PASSPHRASE" ]]; then + error "Config missing required: LUKS_PASSPHRASE (or set NO_ENCRYPT=yes)" + fi + fi + # Validate filesystem choice if [[ "$FILESYSTEM" != "zfs" && "$FILESYSTEM" != "btrfs" ]]; then error "Invalid FILESYSTEM: $FILESYSTEM (must be 'zfs' or 'btrfs')" @@ -165,9 +172,8 @@ gather_input() { get_encryption_choice [[ "$NO_ENCRYPT" != "yes" ]] && get_zfs_passphrase elif [[ "$FILESYSTEM" == "btrfs" ]]; then - # Btrfs encryption (LUKS) not yet implemented - Phase 2.8 - info "Note: Btrfs encryption (LUKS) will be available in a future update." - NO_ENCRYPT="yes" + get_btrfs_encryption_choice + [[ "$NO_ENCRYPT" != "yes" ]] && get_luks_passphrase fi get_root_password @@ -545,6 +551,58 @@ get_wifi() { fi } +get_btrfs_encryption_choice() { + step "Btrfs Encryption (LUKS)" + + echo "" + echo "LUKS encryption protects your data at rest." + echo "You'll need to enter a passphrase at each boot." + echo "" + + prompt "Enable LUKS encryption? [Y/n]:" + read -p "> " encrypt_choice + + if [[ "$encrypt_choice" =~ ^[Nn]$ ]]; then + NO_ENCRYPT="yes" + warn "Encryption DISABLED - data will not be encrypted at rest" + else + NO_ENCRYPT="no" + info "LUKS encryption enabled - you'll set a passphrase next" + fi +} + +get_luks_passphrase() { + step "LUKS Encryption Passphrase" + + echo "" + echo "Choose a strong passphrase for disk encryption." + echo "You'll need this passphrase every time you boot." + echo "" + echo "IMPORTANT: If you forget this passphrase, your data is UNRECOVERABLE!" + echo "" + + while true; do + prompt "Enter LUKS encryption passphrase:" + read -rs LUKS_PASSPHRASE + echo "" + + prompt "Confirm passphrase:" + read -rs confirm + echo "" + + if [[ "$LUKS_PASSPHRASE" == "$confirm" ]]; then + if [[ ${#LUKS_PASSPHRASE} -lt 8 ]]; then + warn "Passphrase should be at least 8 characters. Try again." + else + info "Passphrase confirmed." + break + fi + else + warn "Passphrases don't match. Try again." + fi + done +} + get_encryption_choice() { step "ZFS Encryption" echo "" @@ -667,6 +725,11 @@ show_summary() { fi echo " Boot: ZFSBootMenu on all disks (redundant)" else + if [[ "$NO_ENCRYPT" == "yes" ]]; then + echo " Encryption: None" + else + echo " Encryption: LUKS2" + fi echo " Boot: GRUB + grub-btrfs (snapshot boot)" fi echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" @@ -1452,6 +1515,11 @@ print_btrfs_summary() { echo " Hostname: $HOSTNAME" echo " Timezone: $TIMEZONE" echo " Filesystem: Btrfs" + if [[ "$NO_ENCRYPT" == "yes" ]]; then + echo " Encryption: None" + else + echo " Encryption: LUKS2" + fi echo "" echo "Btrfs Snapshot Features:" echo " - Boot from any snapshot via GRUB menu" @@ -1531,15 +1599,25 @@ install_btrfs() { # Get partition references local root_part=$(get_root_partition "${SELECTED_DISKS[0]}") local efi_part=$(get_efi_partition "${SELECTED_DISKS[0]}") + local btrfs_device="$root_part" # Partition and format partition_disk "${SELECTED_DISKS[0]}" format_efi "$efi_part" - create_btrfs_volume "$root_part" + + # LUKS encryption (if enabled) + if [[ "$NO_ENCRYPT" != "yes" ]]; then + create_luks_container "$root_part" "$LUKS_PASSPHRASE" + open_luks_container "$root_part" "$LUKS_PASSPHRASE" + btrfs_device="/dev/mapper/$LUKS_MAPPER_NAME" + fi + + # Create btrfs on the device (raw partition or LUKS mapper) + create_btrfs_volume "$btrfs_device" # Create and mount subvolumes - create_btrfs_subvolumes "$root_part" - mount_btrfs_subvolumes "$root_part" + create_btrfs_subvolumes "$btrfs_device" + mount_btrfs_subvolumes "$btrfs_device" # Mount EFI mkdir -p /mnt/efi @@ -1552,7 +1630,15 @@ install_btrfs() { configure_system configure_wifi configure_ssh - generate_btrfs_fstab "$root_part" "$efi_part" + + # Configure encryption if enabled + if [[ "$NO_ENCRYPT" != "yes" ]]; then + configure_crypttab "$root_part" + configure_luks_grub "$root_part" + configure_luks_initramfs + fi + + generate_btrfs_fstab "$btrfs_device" "$efi_part" configure_btrfs_initramfs configure_grub "$efi_part" configure_snapper @@ -1565,6 +1651,9 @@ install_btrfs() { # Cleanup btrfs_cleanup + if [[ "$NO_ENCRYPT" != "yes" ]]; then + close_luks_container + fi print_btrfs_summary } diff --git a/custom/lib/btrfs.sh b/custom/lib/btrfs.sh index 7da0851..47c6f42 100644 --- a/custom/lib/btrfs.sh +++ b/custom/lib/btrfs.sh @@ -3,9 +3,12 @@ # Source this file after common.sh, config.sh, disk.sh ############################# -# Btrfs Constants +# Btrfs/LUKS Constants ############################# +# LUKS settings +LUKS_MAPPER_NAME="cryptroot" + # Mount options for btrfs subvolumes BTRFS_OPTS="noatime,compress=zstd,space_cache=v2,discard=async" @@ -24,6 +27,91 @@ BTRFS_SUBVOLS=( "@var_lib_docker:/var/lib/docker::" ) +############################# +# LUKS Functions +############################# + +create_luks_container() { + local partition="$1" + local passphrase="$2" + + step "Creating LUKS Encrypted Container" + + info "Setting up LUKS encryption on $partition..." + + # Create LUKS container + echo -n "$passphrase" | cryptsetup luksFormat --type luks2 \ + --cipher aes-xts-plain64 --key-size 512 --hash sha512 \ + --iter-time 2000 --pbkdf argon2id \ + "$partition" - \ + || error "Failed to create LUKS container" + + info "LUKS container created." +} + +open_luks_container() { + local partition="$1" + local passphrase="$2" + local name="${3:-$LUKS_MAPPER_NAME}" + + info "Opening LUKS container..." + + echo -n "$passphrase" | cryptsetup open "$partition" "$name" - \ + || error "Failed to open LUKS container" + + info "LUKS container opened as /dev/mapper/$name" +} + +close_luks_container() { + local name="${1:-$LUKS_MAPPER_NAME}" + + cryptsetup close "$name" 2>/dev/null || true +} + +configure_crypttab() { + local partition="$1" + + step "Configuring crypttab" + + local uuid + uuid=$(blkid -s UUID -o value "$partition") + + # Create crypttab entry + echo "# LUKS encrypted root" > /mnt/etc/crypttab + echo "$LUKS_MAPPER_NAME UUID=$uuid none luks,discard" >> /mnt/etc/crypttab + + info "crypttab configured for $LUKS_MAPPER_NAME" +} + +configure_luks_initramfs() { + step "Configuring Initramfs for LUKS" + + # Backup original + cp /mnt/etc/mkinitcpio.conf /mnt/etc/mkinitcpio.conf.bak + + # Add encrypt hook before filesystems + # Hooks: base udev ... keyboard keymap ... encrypt filesystems ... + sed -i 's/^HOOKS=.*/HOOKS=(base udev microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)/' \ + /mnt/etc/mkinitcpio.conf + + info "Added encrypt hook to initramfs." +} + +configure_luks_grub() { + local partition="$1" + + step "Configuring GRUB for LUKS" + + local uuid + uuid=$(blkid -s UUID -o value "$partition") + + # Add cryptdevice to GRUB cmdline + sed -i "s|^GRUB_CMDLINE_LINUX=\"|GRUB_CMDLINE_LINUX=\"cryptdevice=UUID=$uuid:$LUKS_MAPPER_NAME:allow-discards |" \ + /mnt/etc/default/grub + + info "GRUB configured with cryptdevice parameter." +} + ############################# # Btrfs Pre-flight ############################# diff --git a/custom/lib/config.sh b/custom/lib/config.sh index 38811fa..358a5f4 100644 --- a/custom/lib/config.sh +++ b/custom/lib/config.sh @@ -21,6 +21,7 @@ WIFI_SSID="" WIFI_PASSWORD="" ENCRYPTION_ENABLED=false ZFS_PASSPHRASE="" +LUKS_PASSPHRASE="" ROOT_PASSWORD="" SSH_ENABLED=false SSH_KEY="" -- cgit v1.2.3