From a working Ubuntu 16.04, I succeeded in post-installation root partition encryption, with the root partition containing everything except /boot. I put /boot on a separate removable usb. Notably I did this before upgrading to Ubuntu 18, and the upgrade worked fine on the encrypted disk version.
The encryption was not done "in place", which was fine with me because I didn't want to overwrite the working version until the new setup was working, anyway.
Performing the correct procedure is extremely simple and fast. (Although figuring out the correct procedure was extremely time consuming because I followed some false leads.)
OUTLINE
- Create a live linux USB disk - it is convenient to have persistence enabled. Boot in on that live USB disk.
- Create a luks encrypted volume group on an empty partition. (In my case it was on the same disk as the original linux, but it could be another disk.) Create / (root) and swap logical volumes on that encrypted partition. These will act as virtual partitions as far as the copied linux is concerned.
- Copy the files from the old root to the new root.
- Set up and partition another USB to act as the removable boot disk.
- Set up some files in the new root, do some magic, and chroot into the new root and then install grub onto the boot disk from the chroot'd new root environment.
DETAILS
1 - Boot with a live linux USB disk - it is convenient to have persistence enabled.
Installed Ubuntu 16 on a usb with unetbootin. The GUI allow "persistence" to be specified, but another step is also required to get the persistence to work - modify /boot/grub/grub.cfg
to add --- persistent
as follows:
menuentry "Try Ubuntu without installing" {
set gfxpayload=keep
linux /casper/vmlinuz file=/cdrom/preseed/ubuntu.seed boot=casper quiet splash --- persistent
initrd /casper/initrd
}
Boot in with the live USB
2- Create a luks encrypted volume group on an empty partition. Create / (root) and swap logical volumes on that encrypted partition.
Assume the unused partition to be encrypted is /dev/nvme0n1p4
.
Optionally, if you have old data on the partition you want to hide before encryption and formatting, you might random wipe the partition. See discussion here.
dd if=/dev/urandom of=/dev/nvme0n1p4 bs=4096 status=progress
Set up the encryption.
cryptsetup -y -v luksFormat /dev/nvme0n1p4
You'll be asked to set a password.
cryptsetup luksOpen /dev/nvme0n1p4 crypt1
You'll be asked to enter the password. Note that crypt1
is an arbitrary user decided name. Now create the volumes and format.
pvcreate /dev/mapper/crypt1
vgcreate crypt1-vg /dev/mapper/crypt1
lvcreate -L 8G crypt1-vg -n swap
mkswap /dev/crypt1-vg/swap
lvcreate -l 100%FREE crypt1-vg -n root
mkfs.ext4 /dev/crypt1-vg/root
Use these utilities to view the volumes and understand the hierarchy.
pvscan
vgscan
lvscan
ls -l /dev/mapper
ls -l /dev/crypt1
3- Copy files from old root to new root
mkdir /tmp/old-root
mount /dev/ubuntu-vg/root /tmp/old-root/
mkdir /tmp/new-root
mount /dev/crypt1-vg/root /tmp/new-root/
cp -a /tmp/old-root/. /tmp/new-root/
umount /tmp/old-root
umount /tmp/new-root
cp -a ...
copies in archive mode, preserving all file modes and flags.
4- Set up and partition another USB to act as the removable boot disk.
I used gparted for this. Set up two partitions. The first partition is vfat
, the second ext2
. Each was 512 MB, you might get away with less. Assume device /dev/sdf
.
# The first partition: (will be /dev/sdf1)
Free space preceding (leave default value)
New size 512 MiB
Free space following (leave default value)
Create as: Primary Partition
Partition Name: (leave)
File System: fat32
Label: (leave)
# The second partition: (will be /dev/sdf2)
Free space preceding (leave default value)
New size 512 MiB
Free space following (leave default value)
Create as: Primary Partition
Partition Name: (leave)
File System: ext4
Label: (leave)
5- Set up some files in the new root, do some magic, and chroot into the new root and then install grub onto the boot disk from the chroot'd new root environment.
Find some UUIDs for later use. Note the outputs from the following commands:
blkid /dev/sdf1
blkid /dev/sdf2
blkid /dev/nvme0n1p4
Mount the root partition and boot partitions
sudo mount /dev/mapper/crypt1--vg-root /mnt
sudo mount /dev/sdf2 /mnt/boot
sudo mount /dev/sdf1 /mnt/boot/efi
Setup the file /mnt/etc/fstab
/dev/mapper/crypt1--vg-root / ext4 errors=remount-ro 0 1
/dev/mapper/crypt1--vg-swap none swap sw 0 0
UUID=[uuid of /dev/sdf2] /boot ext2 defaults 0 2
UUID=[uuid of /dev/sdf1] /boot/efi vfat umask=0077 0 1
where "[uuid of ...]" is just a letter-number-hyphen combination.
Create the file /mnt/etc/cryptab
# <target name> <source device> <key file> <options>
crypt1 UUID=[uuid of /dev/nvme0n1p4] none luks,discard,lvm=crypt1--vg-root
Some magic required to enter the root directory environment:
sudo mount --bind /dev /mnt/dev
sudo mount --bind /proc /mnt/proc
sudo mount --bind /sys /mnt/sys
chroot /mnt
Now set up the boot USB disk with grub
:
apt install --reinstall grub-efi-amd64
grub-install --efi-directory=/boot/efi --boot-directory=/boot --removable
update-initramfs -k all -c
update-grub
Now you should be able to reboot and bootup using the newly created USB boot disk.
Toubleshooting-
(a) The network must be connected for the apt install --reinstall grub-efi-amd64
command. If the network is connected but DNS is failing, try
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf > /dev/null
(b) Before calling initramfs
, the current vmlinuz...
file used in the original linux must be present in the new root directory. If it isn't, find it and place it there.
(c) The grub-install
command will by default search all other linux disks it can find even if they are not mount
ed, and put them in the boot menu on the new boot USB. Usually this is not desired, so it can be avoided by adding this line to /boot/default/grub.cfg
:
GRUB_DISABLE_OS_PROBER=true
NOTE:
A text file with the encryption key can be added to the removable boot USB.