]> git.friedersdorff.com Git - max/notes.git/commitdiff
Write content about minimal initfs
authorMaximilian Friedersdorff <max@friedersdorff.com>
Sat, 13 Apr 2019 13:58:59 +0000 (14:58 +0100)
committerMaximilian Friedersdorff <max@friedersdorff.com>
Sat, 13 Apr 2019 13:58:59 +0000 (14:58 +0100)
content/minimal_boot_initfs.rst [new file with mode: 0644]

diff --git a/content/minimal_boot_initfs.rst b/content/minimal_boot_initfs.rst
new file mode 100644 (file)
index 0000000..db1edd8
--- /dev/null
@@ -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) <releng@gentoo.org>" [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/