Full Encrypted Btrfs/Native System Root Guide
Basically this article is an extension to Btrfs/Native System Root Guide which adds Dm-crypt and uses Dracut to create the initramfs rather then dealing with the Early Userspace Mounting approach. As the root partition, which also includes /boot, will end up encrypted, we'll store the keyfile to unlock the btrfs raid partitions within the initramfs. This may be a bit unsafer on runtime as the keyfile ends up in memory but we gain a faster boot process without the need to input the password 4 times (2 x grub and 2 x btrfs raid1). I also have an btrs raid6 with 6 full encrypted disks and this would lead me to enter my password 10 times to have a fully working system. so i'm happy with embedding the keyfile within the initramfs.
As i didn't find a way to get a working system with the initramfs generated by genkernel I've decided to use dracut.
We'll migrate an existing MD software raid1 to an btrfs raid1 without adding extra disks. So better make backups of your data! I assume the raid members of /dev/md1 to be /dev/sda and /dev/sdb.
The whole procedure is straight forward but you have to double check a few things i'll mention later. Please carefully read the whole post and pay extra attention to grub2 and dracut.
There may be better ways to accomplish this setup but after nights of research and testing within a virtual machine this procedure has worked for me.
Required packages
First add the required use flags for the packages.
root #
echo "sys-apps/systemd cryptsetup" >> /etc/portage/package.use
root #
echo "sys-boot/grub device-mapper" >> /etc/portage/package.use
root #
echo "sys-fs/cryptsetup static kernel -gcrypt" >> /etc/portage/package.use
root #
echo "sys-kernel/dracut systemd device-mapper" >> /etc/portage/package.use
Next unmask the packages (Please change the keyword as needed for your system). We'll use the latest available versions.
root #
echo "sys-fs/btrfs-progs ~amd64" >> /etc/portage/package.accept_keywords
root #
echo "sys-boot/grub:2 ~amd64" >> /etc/portage/package.accept_keywords
root #
echo "sys-fs/cryptsetup ~amd64" >> /etc/portage/package.accept_keywords
root #
echo "sys-kernel/gentoo-sources ~amd64" >> /etc/portage/package.accept_keywords
Install the required packages
root #
emerge --ask systemd grub:2 cryptsetup btrfs-progs dracut gentoo-sources
If this installs newer kernel sources, please change the symlink either using eselect kernel or do it manually, build the kernel and reboot. After that proceed from here.
Preparing for encryption
As we'll use a keyfile to unlock the partitions we'll now create one (paranoid settings).
root #
dd if=/dev/random of=/root/secretkey bs=1 count=4096
root #
chmod 0400 /root/secretkey
Preparing the first disk
Dealing with the software raid
Remove /dev/sda drive from md array
root #
mdadm --manage /dev/md1 --fail /dev/sda
root #
mdadm --manage /dev/md1 --remove /dev/sda
root #
mdadm --zero-superblock /dev/sda
Partition the drive
We create a bios boot partition and use the remaining space for the root partition.
root #
gdisk /dev/sda
Number Start (sector) End (sector) Size Code Name 1 2048 8191 3.0 MiB EF02 BIOS boot partition 2 8192 250069679 119.2 GiB 8300 Linux filesystem
Encrypt partition
First we'll format the partitions
root #
cryptsetup luksFormat -s 512 -c aes-xts-plain64 /dev/sda2
Next we add the keyfile to the root partition
root #
cryptsetup luksAddKey /dev/sda2 /root/secretkey
Finally we open the root partition
root #
cryptsetup open -d /root/secretkey /dev/sda2 luks-1
Create filesystem, mountpoints and subvolumes
Now we format the mapped partition.
root #
mkfs.btrfs -L BTROOT /dev/mapper/luks-1
Next we create the mountpoints, mount the filesystems and create subvolumes
root #
mkdir /mnt/btrfsmirror
root #
mount -t btrfs -o defaults,noatime,compress=lzo,autodefrag /dev/mapper/luks-1 /mnt/btrfsmirror
root #
mkdir /mnt/newroot
root #
btrfs subvol create /mnt/btrfsmirror/activeroot
root #
mount -t btrfs -o defaults,noatime,compress=lzo,autodefrag,subvol=activeroot /dev/mapper/luks-1 /mnt/newroot
root #
mkdir /mnt/newroot/home
root #
mkdir /mnt/newroot/boot
root #
btrfs subvol create /mnt/btrfsmirror/home
root #
btrfs subvol create /mnt/btrfsmirror/boot
root #
mount -t btrfs -o defaults,noatime,compress=lzo,autodefrag,subvol=home /dev/mapper/luks-1 /mnt/newroot/home
root #
mount -t btrfs -o defaults,noatime,subvol=boot /dev/mapper/luks-1 /mnt/newroot/boot
Hot copy /
We'll now mount our running system onto /mnt/rawroot and copy everything over.
root #
mkdir /mnt/rawroot
root #
mount --bind / /mnt/rawroot
root #
cd /mnt/rawroot
root #
tar cvpf - . | (cd /mnt/newroot; tar xpf -)
Chroot
Enter the chroot
We now need to chroot into /mnt/newroot and do the usual chroot stuff.
root #
cp -L /etc/resolv.conf /mnt/newroot/etc/
root #
mount -t proc proc /mnt/newroot/proc
root #
mount --rbind /sys /mnt/newroot/sys
root #
mount --rbind /dev /mnt/newroot/dev
root #
mount --make-rslave /mnt/newroot/sys
root #
mount --make-rslave /mnt/newroot/dev
root #
chroot /mnt/newroot /bin/bash
root #
env-update && source /etc/profile
root #
export PS1="(chroot) $PS1"
mtab/fstab
Check that /etc/mtab contains the following lines and if not, add them:
/dev/mapper/luks-1 / btrfs rw,noatime,compress=lzo,autodefrag,subvol=activeroot 0 0
/dev/mapper/luks-1 /home btrfs rw,noatime,compress=lzo,autodefrag,subvol=home 0 0
/dev/mapper/luks-1 /boot btrfs rw,noatime,compress=lzo,autodefrag,subvol=boot 0 0
Next change /etc/fstab to this:
LABEL=BTROOT /mnt/btrfsmirror btrfs defaults,noatime,compress=lzo,autodefrag 0 0
LABEL=BTROOT / btrfs defaults,noatime,compress=lzo,autodefrag,subvol=activeroot 0 0
LABEL=BTROOT /home btrfs defaults,noatime,compress=lzo,autodefrag,subvol=home 0 0
LABEL=BTROOT /boot btrfs defaults,noatime,subvol=boot 0 0
Remove md array configuration
Edit /etc/mdadm.conf and remove your array from it.
Build kernel and initramfs
Now we'll create the kernel with the required configuration.
root #
genkernel --luks --btrfs --oldconfig --save-config --menuconfig --install --bootloader=grub2 --udev all
[*] Enable loadable module support
Device Drivers --->
[*] Multiple devices driver support (RAID and LVM) --->
<*> Device mapper support
<*> Crypt target support
[*] Cryptographic API --->
<*> SHA224 and SHA256 digest algorithm
<*> XTS support
<*> AES cipher algorithms
<*> AES cipher algorithms (x86_64)
General setup --->
[*] Initial RAM filesystem and RAM disk (initramfs/initrd) support
Dracut
Next step is to create a new intitramfs
root #
dracut -f -I /root/secretkey
and we just replace the initramfs create by genkernel with the one from dracut.
Grub2
Customize grub2
We'll change /etc/default/grub to fit our needs.
For that we'll add rd.luks, rd.luks.key and rd.luks.uuid to GRUB_CMDLINE_LUNUX and add GRUB_ENABLE_CRYPTODISK=y as new line somewhere.
The rd.luks.uuid is the uuid of the encrypted (!!) partition in this case /dev/sda2.
Now /etc/default/grub should look like this (i use systemd!):
...
GRUB_ENABLE_CRYPTODISK=y
GRUB_CMDLINE_LINUX_DEFAULT="real_init=/usr/lib/systemd/systemd rd.luks=1 rd.luks.key=/root/secretkey rd.luks.uuid=luks-e57c4e30-7b2e-457a-af9b-3270d085aae2"
...
Generate grub.cfg
We'll use grub2-mkconfig to generate the grub.cfg
root #
grub2-mkconfig -o /boot/grub/grub.cfg
Install grub2 into MBR
root #
grub2-install /dev/sda
Finishing first disk
That's it for the first drive. Now we leave the chroot.
Install grub2 into MBR of /dev/sdb if not already done to be able to reboot into the old system in case of problems.
Now reboot.
Booting from encrypted disk
Make sure you boot from /dev/sda !!
You'll be asked for the password to unlock the boot partition and after that it should boot up as normal (without further password request!)
Preparing second disk
Dealing with the software raid - Part 2
We'll now completely stop and destroy the MD array.
root #
mdadm --stop /dev/md1
root #
mdadm --zero-superblock /dev/sdb
Partition the drive
We create a bios boot partition and use the remaining space for the root partition.
root #
gdisk /dev/sdb
Number Start (sector) End (sector) Size Code Name 1 2048 8191 3.0 MiB EF02 BIOS boot partition 2 8192 250069679 119.2 GiB 8300 Linux filesystem
Encrypt partition
First we'll format the partitions
root #
cryptsetup luksFormat -s 512 -c aes-xts-plain64 /dev/sdb2
Next we add the keyfile to the root partition
root #
cryptsetup luksAddKey /dev/sdb2 /root/secretkey
Finally we open the root partition
root #
cryptsetup open -d /root/secretkey /dev/sdb2 luks-2
BTRFS Raid 1
Now we add the second disk to the btrfs filesystem and convert it to raid1.
root #
btrfs device add /dev/mapper/luks-2 /mnt/btrfsmirror
root #
btrfs balance start -dconvert=raid1 -mconvert=raid1 /mnt/btrfsmirror
Dracut
Recreate the intitramfs with dracut and replace the old one.
root #
dracut -f -I /root/secretkey
Grub2
Customize grub2
Append rd.luks.uuid for /dev/sdb2 to GRUB_CMDLINE_LINUX_DEFAULT in /etc/default/grub
...
GRUB_ENABLE_CRYPTODISK=y
GRUB_CMDLINE_LINUX_DEFAULT="real_init=/usr/lib/systemd/systemd rd.luks=1 rd.luks.key=/root/secretkey rd.luks.uuid=luks-e57c4e30-7b2e-457a-af9b-3270d085aae2 rd.luks.uuid=luks-26ab8aed-7c84-4993-bfe4-579c83c96b05"
...
Generate grub.cfg
Recreate the grub.cfg
root #
grub2-mkconfig -o /boot/grub/grub.cfg
The current grub2-mkconfig (time of writing) creates an invalid grub.cfg. There is a bug which cannot handle multiple boot devices (see https://www.mail-archive.com/bug-grub@gnu.org/msg15384.html and https://bugzilla.redhat.com/show_bug.cgi?id=1177470).
grub2-mkconfig will generate the following broken lines in different places:
cryptomount -u 26ab8aed7c844993bfe4579c83c96b05
a044adcaa23b400bad6ca256a9509c75
set root='cryptouuid/26ab8aed7c844993bfe4579c83c96b05
cryptouuid/a044adcaa23b400bad6ca256a9509c75'
You've to search and fix them.
I'm not sure how they should look like, but this is how they look on my working system:
cryptomount -u 26ab8aed7c844993bfe4579c83c96b05
cryptomount -u a044adcaa23b400bad6ca256a9509c75
set root='cryptouuid/26ab8aed7c844993bfe4579c83c96b05'
set root='cryptouuid/a044adcaa23b400bad6ca256a9509c75'
Also check the UUIDs are correct!
Install grub2 into MBR
Reinstall on /dev/sda
root #
grub2-install /dev/sda
Install on /dev/sdb
root #
grub2-install /dev/sdb
Finishing up
Cleanup
Remove obsolete mountpoints
root #
rm -rf /mnt/newroot /mnt/rawroot
Backup LUKS headers
You definitely should make a backup of your LUKS headers as you'll not be able to rescue the data if the header gets damaged for some reason.
root #
cryptsetup luksHeaderBackup /dev/sda2 --header-backup-file /mnt/usb/luks-header/<UUID of /dev/sda2>.img
root #
cryptsetup luksHeaderBackup /dev/sdb2 --header-backup-file /mnt/usb/luks-header/<UUID of /dev/sdb2>.img
Or use this dirty script to find and save all LUKS headers.
#!/bin/bash
DEST=$1
if [ -z "$1" ]; then
echo "Usage:"
echo $(basename $0) " <destination path>"
exit 1
fi
for DISK in `ls /dev/sd*`; do
TYPE=$(blkid -o value -s TYPE $DISK)
if [ -n "$TYPE" ] && [ "crypto_LUKS" == "$TYPE" ]; then
UUID=$(blkid -o value -s UUID $DISK)
cryptsetup luksHeaderBackup "${DISK}" --header-backup-file "${DEST}/${UUID}.img"
fi
done
Reboot
At this point you should have a full encrypted and working system.
You should now reboot. Grub will ask you for the password twice as it needs to unlock both disks.
After that you should not be prompted for password input anymore.
That's it. Have fun with your encrypted system!
Troubleshooting
Systemd asks for password on wall
If systemd asks for the password on wall while your system is already booted up, you should check /etc/crypttab and make sure your root partitions are not listed there. This is because they are already unlocked by dracut and systemd simply doesn't check that and thus tries to unlock them again which fails as the mapping device already exists.
Mapping names are build from uuid
After a reboot your root partitions mapping devices will look like /dev/mapper/<UUID>. If you prefer clean names (i do) like /dev/mapper/luks-1.1 and /dev/mapper/luks1.2 you can achieve this by adding the partitions to /etc/crypttab and include it into the initramfs. But make sure to comment the lines in /etc/crypttab after you have created the initramfs!
Example of /etc/crypttab
luks-1.1 UUID=e57c4e30-7b2e-457a-af9b-3270d085aae2 /root/secretkey luks
luks-1.2 UUID=26ab8aed-7c84-4993-bfe4-579c83c96b05 /root/secretkey luks
Now include it into the initramfs.
root #
dracut -f -I /root/secretkey -I /etc/crypttab