From e54f58da5a97cd8054c44daca5ab77c5ad008d56 Mon Sep 17 00:00:00 2001 From: Maximilian Friedersdorff Date: Sat, 13 Apr 2019 14:58:59 +0100 Subject: [PATCH] Write content about minimal initfs --- content/minimal_boot_initfs.rst | 252 ++++++++++++++++++++++++++++++++ 1 file changed, 252 insertions(+) create mode 100644 content/minimal_boot_initfs.rst diff --git a/content/minimal_boot_initfs.rst b/content/minimal_boot_initfs.rst new file mode 100644 index 0000000..db1edd8 --- /dev/null +++ b/content/minimal_boot_initfs.rst @@ -0,0 +1,252 @@ +Creating a minimal file system to ease the boot process +======================================================= + +:date: 1970-01-01 00:00 +:category: System Administration +:tags: initramfs, boot, luks, gpg, ssh +:authors: Maximilian Friedersdorff +:summary: Booting a system with full disk encryption can be tricky. +:status: draft + +Context +------- + +My personal systems use full disk encryption according to the scheme +`LVM on LUKS`_. This works great, but obviously requires some way of supplying +(or unlocking) the decryption key during the early boot process. + +Passphrase +__________ + +Using a passhrase to protect the decryption key is easy, provided the user is +sitting in front of the machine. If the machine needs to be started remotely, +then it becomes necessary to install a SSH server like dropbear_, or decrypt the +LUKS partition in some other way. + +Key File +________ + +One can use a key file that either contains the decryption key directly, or just +contains a passphrase that unlocks the decryption key. This requires the key to +be available during the early boot process. + +This is tricky, because if it +exists in plaintext on the machine it is supposed to unlock, then there is not +much point in encrypting in the first place. If instead the key is on a +different machine, the key has to be transmitted accross the network, and the +other machine has to be on and running. Alternatively the key might be stored +on a USB device and carried on one's person at all times, but USB devices can be +unreliable. This is also sensitive to loss. + +Solution +________ + +I use a Yubikey (a USB SmartCard_) to store my GPG key. This enables a +convenient compromise. + +The solution I propose is to store a GPG encrypted key file on the encrypted +machine. When starting the machine remotely, the key can be transmitted to the +remote client, decrypted on the SmartCard_ and transmitted back to the encrypted +machine. Transmission happens over SSH authenticated with a GPG authentication +key stored on the same SmartCard_. + +When starting the machine locally, the decryption takes place directly on the +SmartCard_ itself. + +This has an additional benefit. The SmartCard_ is protected by a passphrase +forcing the use of two different factors to decrypt the drive. + +Required Software +_________________ + +To get all of this to work, several pieces of software need to be available +during the early boot process: + +* GnuPG, preferably V2.1 or above +* pcscd, the PC/SC Smart Card Daemon +* dm-crypt +* LVM, Logical Volume Manager +* SSH server, for instance dropbear_ + +Some of these can be built with static linking. This makes their inclusion in +an initramfs relatively straightforward. However neither pcscd nor recent +version of GnuPG can be built this way. They must be dynamically linked to +at least glibc. Including dynamic executable in an initramfs is substantially +more tedious as all of their library dependencies have to be included also. + +Initramfs vs ? +______________ + +Building an initramfs that can do these things is tedious. Existing automated +tools that build an initramfs would require substantial additions to make this +possible. Doing it manually or building an automated tool from scratch is lots +of work. An initramfs like this will also be fairly large (since it contains +lots of libraries) and has to be loaded in it's entirety at boot time. + +Instead I will build a minimal, self hosted root file system. This way I can +use a proper package manager to manage the file system, I don't have to worry +too much about it's overall size (it doesn't all have to be read at boot +time) and I have easy access to any package included in the distribution I base +this on. I will call this an initfs. + +I use gentoo on all of my personal systems, so I will base the initfs on gentoo +also. An initramfs is typically built from source anyway, so this makes sense. +This is also an opportunity to play with alternative libc's like uClib-ng_ or +musl_ which gentoo has some support for. + +Building the initfs +------------------- + +Minimal Gentoo +______________ + + +I start by building a very minimal Gentoo system. Initially I follow the amd64 +handbook_. All of this is done on a fully installed gentoo system. As such the +network is already set up, the bootloader is installed, the kernel is configured +and compiled and the disk is already partially partitioned. + +First I add an additional small partition that is *outside* the encrypted LUKS +volume, formatting it to ext4 and mounting it somewhere convenient:: + + $ sudo fdisk /dev/sda + Password: + + Welcome to fdisk (util-linux 2.33.1). + Changes will remain in memory only, until you decide to write them. + Be careful before using the write command. + + + Command (m for help): n + Partition number (2-4,7-128, default 2): 2 + First sector (534528-500118158, default 534528): + Last sector, +/-sectors or +/-size{K,M,G,T,P} (534528-83509247, default 83509247): +1G + + Created a new partition 2 of type 'Linux filesystem' and of size 1 GiB. + + Command (m for help): p + Disk /dev/sda: 238.5 GiB, 256060514304 bytes, 500118192 sectors + Disk model: SanDisk SD8SNAT2 + 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: gpt + Disk identifier: 699BC6B3-E694-4D9B-AE65-2C7101253C99 + + Device Start End Sectors Size Type + /dev/sda1 2048 534527 532480 260M EFI System + /dev/sda2 534528 2631679 2097152 1G Linux filesystem + /dev/sda5 83509248 84557823 1048576 512M Linux filesystem + /dev/sda6 84557824 500117503 415559680 198.2G Linux filesystem + + Command (m for help): w + The partition table has been altered. + Syncing disks. + + $ sudo mkfs.ext4 /dev/sda2 + mke2fs 1.45.0 (6-Mar-2019) + Discarding device blocks: done + Creating filesystem with 262144 4k blocks and 65536 inodes + Filesystem UUID: 97904c89-51e3-4a6b-b3f3-24bb5f083f60 + Superblock backups stored on blocks: + 32768, 98304, 163840, 229376 + + Allocating group tables: done + Writing inode tables: done + Creating journal (8192 blocks): done + Writing superblocks and filesystem accounting information: done + + $ sudo mount /dev/sda2 /mnt/initfs + +I then move on to installing a stage3 tarball. The main system will be in a +chroot anyway, so a No-multilib (pure 64-bit) system is appropriate here and will +save some small amount of space. For a first attempt I choose the uclibc stage3 +tarball. I download the file tarball and it's signed DIGESTS file, verify the +DIGESTS file and finally check the hash:: + + # cd /mnt/initfs + # wget http://distfiles.gentoo.org/releases/amd64/autobuilds/20190405/uclibc/stage3-amd64-uclibc-vanilla-20190405.tar.bz2 + . + . + . + # wget http://distfiles.gentoo.org/releases/amd64/autobuilds/current-stage3-amd64-uclibc-vanilla/stage3-amd64-uclibc-v + anilla-20190405.tar.bz2.DIGESTS.asc + . + . + . + # gpg --verify stage3-amd64-uclibc-vanilla-20190405.tar.bz2.DIGESTS.asc + gpg: Signature made Sat 06 Apr 2019 07:13:22 BST + gpg: using RSA key 534E4209AB49EEE1C19D96162C44695DB9F6043D + gpg: Good signature from "Gentoo Linux Release Engineering (Automated Weekly Release Key) " [unknown] + gpg: WARNING: This key is not certified with a trusted signature! + gpg: There is no indication that the signature belongs to the owner. + Primary key fingerprint: 13EB BDBE DE7A 1277 5DFD B1BA BB57 2E0E 2D18 2910 + Subkey fingerprint: 534E 4209 AB49 EEE1 C19D 9616 2C44 695D B9F6 043D + # sha512sum -c ./stage3-amd64-uclibc-vanilla-20190405.tar.bz2.DIGESTS.asc + stage3-amd64-uclibc-vanilla-20190405.tar.bz2: OK + stage3-amd64-uclibc-vanilla-20190405.tar.bz2: FAILED + sha512sum: stage3-amd64-uclibc-vanilla-20190405.tar.bz2.CONTENTS: No such file or directory + stage3-amd64-uclibc-vanilla-20190405.tar.bz2.CONTENTS: FAILED open or read + sha512sum: stage3-amd64-uclibc-vanilla-20190405.tar.bz2.CONTENTS: No such file or directory + stage3-amd64-uclibc-vanilla-20190405.tar.bz2.CONTENTS: FAILED open or read + sha512sum: WARNING: 14 lines are improperly formatted + sha512sum: WARNING: 2 listed files could not be read + sha512sum: WARNING: 1 computed checksum did NOT match + +Some things to note: I verified the fingerprint of the "Gentoo Linux Release +Engineering" GPG key from the official `gentoo website`_, accessed via https. +I can be reasonably confident that that is proper. The error messages in the +output of sha512sum exist because there are some other files listed in the +DIGESTS, because for each file there is also a WHIRLPOOL hash and there is an +inline GPG signature in the file. + +Extracting the tarball:: + + # tar xpf stage3-*.tar.bz2 --xattrs-include='*.*' --numeric-owner + +And editing the ``/etc/portage/make.conf`` to have sensible values:: + + # cat etc/portage/make.conf + +The portage tree is definitely *not* required during boot and is quite large. I +just mount it from the host system and chroot:: + + # mount --types proc /proc proc + # mount --rbind /sys sys + # mount --make-rslave sys + # mount --rbind /dev dev + # mount --make-rslave dev + # mount --rbind /usr/portage usr/ + # mkdir usr/portage + # mount --rbind /usr/portage usr/portage + # mount --make-rslave usr/portage + # chroot /mnt/initfs /bin/bash + # source /etc/profile + # export PS1="(chroot) ${PS1}"k + +Because I am building a *minimal* gentoo system, and because I will be writing +my own init script anyway, I can remove the installed init system:: + + (chroot) # emerge -C openrc virtual/service-manager netifrc + (chroot) # echo 'virtual/service-manager' >> /etc/portage/package.mask + (chroot) # emerge -av --depclean + +Replacing openssh with dropbear:: + + (chroot) # emerge -C openssh + (chroot) # emerge -av dropbear + +Updating the whole system:: + + (chroot) # emerge -avuDN --with-bdeps y world + + + + +.. _`LVM on LUKS`: https://wiki.archlinux.org/index.php/Dm-crypt/Encrypting_an_Entire_System#LVM_on_LUKS +.. _dropbear: https://matt.ucc.asn.au/dropbear/dropbear.html +.. _SmartCard: https://wiki.gnupg.org/SmartCard +.. _UClib-ng: https://uclibc-ng.org/ +.. _musl: https://www.musl-libc.org/ +.. _handbook: https://wiki.gentoo.org/wiki/Handbook:AMD64 +.. _gentoo website: https://www.gentoo.org/downloads/signatures/ -- 2.47.1