Suppose that we have installed a fresh Fedora Core 26 with the default settings. Then we have:
[root@localhost ~]# fdisk -l /dev/vda Disk /dev/vda: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xdefe279a Device Boot Start End Sectors Size Id Type /dev/vda1 * 2048 2099199 2097152 1G 83 Linux /dev/vda2 2099200 16777215 14678016 7G 8e Linux LVM [root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/vda2 fedora lvm2 a-- 7.00g 0 [root@localhost ~]# lvs LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert root fedora -wi-ao---- 6.20g swap fedora -wi-ao---- 820.00m [root@localhost ~]# df / /boot Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/fedora-root 6486016 1192916 5293100 19% / /dev/vda1 999320 119000 811508 13% /boot
This is a fairly standard partitioning scheme. We will add another disk of the same size (8g), which will be completely encrypted, and will transfer all the data to it.
[root@localhost ~]# grep vd /proc/partitions 252 0 8388608 vda 252 1 1048576 vda1 252 2 7339008 vda2 252 16 8388608 vdb
The whole procedure will be performed in several stages, first we will encrypt our operating system, then we will encrypt the /boot partition.
Let's create a partition on the added disk, leaving a some space before it.
Disk /dev/vdb: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xb6d5aab9 Device Boot Start End Sectors Size Id Type /dev/vdb1 512000 16777215 16265216 7.8G 8e Linux LVM
As you can see, I left 512m of free space before the data partition, we use it later. Now we format the data partition as a encrypted volume:
[root@localhost ~]# cryptsetup luksFormat /dev/vdb1 WARNING! ======== This will overwrite data on /dev/vdb1 irrevocably. Are you sure? (Type uppercase yes): YES Enter passphrase: Verify passphrase: [root@localhost ~]# cryptsetup isLuks /dev/vdb1 && echo Success Success [root@localhost ~]# cryptsetup luksDump /dev/vdb1
According to the dump, Key Slot 0 is used by the passphrase you entered when setting up encryption. Start (open) the encrypted volume:
[root@localhost ~]# cryptsetup luksOpen /dev/vdb1 pv_fedora Enter passphrase for /dev/vdb1: [root@localhost ~]# ls -l /dev/mapper/pv_fedora lrwxrwxrwx. 1 root root 7 Jan 16 13:31 /dev/mapper/pv_fedora -> ../dm-2 [root@localhost ~]# dmsetup table | grep pv_fedora pv_fedora: 0 16261120 crypt aes-xts-plain64 0000000000000000000000000000000000000000000000000000000000000000 0 252:17 4096
You can save the key in a file, avoiding entering the passphrase manually at each boot. Since this key will be stored on the encrypted volume (/boot will be encrypted somewhat later), this can be harmless.
Generate random garbage in a file:
[root@localhost ~]# dd if=/dev/urandom of=/root/.passphrase bs=32 count=1 [root@localhost ~]# chmod 600 /root/.passphrase [root@localhost ~]# cryptsetup luksAddKey /dev/vdb1 /root/.passphrase Enter any existing passphrase: [root@localhost ~]# cryptsetup luksDump /dev/vdb1
Now luksDump shows the second slot in use.
Create /etc/crypttab file.
[root@localhost ~]# blkid /dev/vdb1 /dev/vdb1: UUID="0cf9ef49-aa24-43a7-98a3-46e693ac315c" TYPE="crypto_LUKS" PARTUUID="b6d5aab9-01" [root@localhost ~]# cat /etc/crypttab pv_fedora UUID=0cf9ef49-aa24-43a7-98a3-46e693ac315c /root/.passphrase discard [root@localhost ~]# chmod 400 /etc/crypttab
The initrd image must be able to run the encrypted volume before initializing the root LV. So the next step is to build such an initrd before we actually move the data.
Edit /boot/grub2/grub.cfg, replacing rhgb quiet with rd.break. This keyword will launch the bash prompt immediately after mounting the root volume and help us debug the initrd.
Use the following commands to create the initrd and then inspect it. Check the contents of the etc/crypttab file in the initrd. If it's not empty, you've done a good job.
[root@localhost ~]# mkdir /tmp/i [root@localhost ~]# cd /tmp/i [root@localhost i]# mv /boot/initramfs-$(uname -r).img /boot/initramfs-$(uname -r).img.old [root@localhost i]# dracut --install /root/.passphrase --force -a "crypt lvm bash" --add-device /dev/mapper/pv_fedora /boot/initramfs-$(uname -r).img [root@localhost i]# gzip -dc /boot/initramfs-$(uname -r).img | cpio -i 89652 blocks [root@localhost i]# cat etc/crypttab pv_fedora /dev/disk/by-uuid/0cf9ef49-aa24-43a7-98a3-46e693ac315c none discard [root@localhost i]# ll root/.passphrase -rw-------. 1 root root 32 Jan 29 17:44 root/.passphrase
NOTE: The UUID should not be quoted in the /etc/crypttab file, otherwise the dracut will ignore it. (Bug ?)
The familiar mkinird command is now the shell wrapper for the dracut command and is less flexible in its options than dracut itself, so the dracut command is used directly without a wrapper. Here, the --add-device option is required, otherwise dracut will not include our device in the initrd as it detects that device still not used by the system yet and does not required for boot process. The --install option will add our key to the initrd.
Restart the server now. Because of the "rd.break" option added to grub.cfg, you can verify that the initrd has successfully activated our encrypted volume. Use "exit" to exit the debug shell and continue the download.
Once everything works as it should, move the data to encrypted volume:
[root@localhost ~]# pvcreate /dev/mapper/pv_fedora Physical volume "/dev/mapper/pv_fedora" successfully created. [root@localhost ~]# vgextend fedora /dev/mapper/pv_fedora Volume group "fedora" successfully extended [root@localhost ~]# pvs PV VG Fmt Attr PSize PFree /dev/mapper/pv_fedora fedora lvm2 a-- 7.75g 7.75g /dev/vda2 fedora lvm2 a-- 7.00g 0 [root@localhost ~]# pvmove /dev/vda2 .. /dev/vda2: Moved: 100.00% [root@localhost ~]# vgreduce fedora /dev/vda2 Removed "/dev/vda2" from volume group "fedora" [root@localhost ~]# pvremove /dev/vda2 Labels on physical volume "/dev/vda2" successfully wiped.
Now the data had migrated to encrypted volume and you can recheck whole procedure by rebooting the server.
Add another partition in reserved space on disk vdb:
Disk /dev/vdb: 8 GiB, 8589934592 bytes, 16777216 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0xb6d5aab9 Device Boot Start End Sectors Size Id Type /dev/vdb1 512000 16777215 16265216 7.8G 8e Linux LVM /dev/vdb2 2048 511999 509952 249M 83 Linux Partition table entries are not in disk order. Command (m for help): w The partition table has been altered. Calling ioctl() to re-read partition table. Re-reading the partition table failed.: Device or resource busy The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8). [root@localhost ~]# partprobe /dev/vdb [root@localhost ~]# grep vdb /proc/partitions 252 16 8388608 vdb 252 17 8132608 vdb1 252 18 254976 vdb2
Make the partition encrypted, format it as EXT4 and copy everything from /boot there:
[root@localhost ~]# cryptsetup luksFormat /dev/vdb2 WARNING! ======== This will overwrite data on /dev/vdb2 irrevocably. Are you sure? (Type uppercase yes): YES Enter passphrase: Verify passphrase: [root@localhost ~]# cryptsetup luksOpen /dev/vdb2 boot Enter passphrase for /dev/vdb2: [root@localhost ~]# mkfs.ext4 -j -m0 /dev/mapper/boot mke2fs 1.43.4 (31-Jan-2017) Creating filesystem with 252928 1k blocks and 63240 inodes Filesystem UUID: 886ffdba-ec1a-47c1-8e9e-92ee2679fc40 Superblock backups stored on blocks: 8193, 24577, 40961, 57345, 73729, 204801, 221185 Allocating group tables: done Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done [root@localhost ~]# mount /dev/mapper/boot /mnt [root@localhost ~]# rsync -av /boot/ /mnt/
Fix /etc/fstab to mount new encrypted volume on /boot instead of original:
[root@localhost ~]# blkid /dev/mapper/boot /dev/mapper/boot: UUID="886ffdba-ec1a-47c1-8e9e-92ee2679fc40" TYPE="ext4" [root@localhost ~]# grep /boot /etc/fstab UUID=886ffdba-ec1a-47c1-8e9e-92ee2679fc40 /boot ext4 defaults 1 2 [root@localhost ~]# umount /boot /mnt [root@localhost ~]# mount /boot [root@localhost ~]# df /boot Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/boot 240840 138988 97756 59% /boot
Meanwhile, lets add an encrypted volume to /etc/crypttab:
[root@localhost ~]# cryptsetup luksAddKey /dev/vdb2 /root/.passphrase Enter any existing passphrase: [root@localhost ~]# blkid /dev/vdb2 /dev/vdb2: UUID="603a3e1e-d86b-41de-8b61-96cf3926b468" TYPE="crypto_LUKS" PARTUUID="b6d5aab9-02" [root@localhost ~]# cat /etc/crypttab pv_fedora UUID=0cf9ef49-aa24-43a7-98a3-46e693ac315c /root/.passphrase discard boot UUID=603a3e1e-d86b-41de-8b61-96cf3926b468 /root/.passphrase discard
Note that fstab uses the UUID of the file system, and crypttab uses the UUID of the physical block device.
Fix /etc/default/grub as following:
[root@localhost ~]# vi /etc/default/grub [root@localhost ~]# cat !$ cat /etc/default/grub GRUB_TIMEOUT=5 GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)" GRUB_DEFAULT=saved GRUB_DISABLE_SUBMENU=true GRUB_TERMINAL_OUTPUT="console" GRUB_DISABLE_RECOVERY="true" GRUB_CMDLINE_LINUX="rd.lvm.lv=fedora/root rd.lvm.lv=fedora/swap rd.luks=1 rd.shell" GRUB_ENABLE_CRYPTODISK=y
And rebuild grub.cfg:
[root@localhost ~]# grub2-mkconfig > /boot/grub2/grub.cfg Generating grub configuration file ... Found linux image: /boot/vmlinuz-4.11.8-300.fc26.x86_64 Found initrd image: /boot/initramfs-4.11.8-300.fc26.x86_64.img Found linux image: /boot/vmlinuz-0-rescue-d91bc70d6778494dafacaebdc6b03e73 Found initrd image: /boot/initramfs-0-rescue-d91bc70d6778494dafacaebdc6b03e73.img done [root@localhost ~]# grep crypt /boot/grub2/grub.cfg ..
Check that some lines related to cryptodisk were added to cfg file. Now, install grub on vdb:
[root@localhost ~]# grub2-install /dev/vdb Installing for i386-pc platform. Installation finished. No error reported.
Shutdown server, disconnect vda and config server to boot from vdb. Boot it.
Now our server runs on a fully encrypted disk, but GRUB requests a password to decrypt /boot at the boot time. It's not so convenient. The server should be booted automatically and without human intervention. A promising project is the johnlane GRUB cryptomount extention, which allows you to hide the key for the GRUB. However, the configuration file still open and allows reverse decryption.
In addition, this is not a solution for creating a closed packed embedded system, because you must provide at least a key for GRUB, and the rest can be decrypted in reverse order.