THIS PAGE NEEDS AN UPDATE BECAUSE the fs ramdisk-cgdroot.fs
in boot.cfg(5) obviates the need for a custom kernel module with the ramdisk embedded
It is possible to run NetBSD with complete root filesystem encryption, thanks to the cgdroot.kmod
kernel module. It really is a memory disk (also knows as RAM disk) that is expected to be loaded in the kernel while booting. It is named after CGD, the "cryptographic device driver", which implements encryption for storage in the NetBSD kernel.
The mechanism described here still requires one unencrypted partition to boot from (typically wd0a
). Full disk encryption would make it more difficult for an attacker to modify the unencrypted part of the disk to plant a backdoor. With only partial encryption, the original cgdconfig(8) binary may be modified to send the passphrase away, allowing an attacker with a disk dump to recover the data.
The NetBSD Guide contains an entire section about CGD.
The boot process
Instead of booting the GENERIC kernel normally and using the root filesystem directly as usual, a special kernel module containing a memory disk is loaded at boot-time. This minimal filesystem image will then be the actual root filesystem, where the decryption process takes place.
The boot partition on disk needs to contain:
- boot(8), the second-stage bootloader
- boot.cfg(5), the configuration file for the bootloader (optional)
- a GENERIC kernel
- the
cgdroot.kmod
kernel module - the configuration file for CGD,
cgd.conf
- the CGD parameters file for the volume, named after its partition (like
wd0f
), which determines how the encryption key is derived and verified
Once loaded the memory disk mounts the wd0a
partition onto /etc/cgd
, and asks for the encryption passphrase as usual (with cgdconfig(8)). If successful, the cgd0a
volume configured is mounted on /altroot
, and init(8) is told via sysctl(7) to chroot into this volume before actually booting. The system then starts normally.
In practice the memory disk remains the real root, and the regular system is
really ran from a chroot in /altroot
.
Obtaining the kernel module
The cgdroot.kmod
kernel module is part of the regular NetBSD releases since NetBSD 7.0. It can be found in the <arch>/installation/miniroot
folder from the release. For instance, for the amd64 architecture of the 7.0.1 release, download it at cdn.netbsd.org/pub/NetBSD/NetBSD-7.0.1/amd64/installation/miniroot/cgdroot.kmod.
Configuring the kernel module
The kernel module needs to be available in the boot partition, alongside the desired kernel. The bootloader configuration in /boot.cfg
should be modified to load the module, as in this example:
Building the kernel module
The kernel module can be compiled in two steps from within the source tree for the NetBSD base system, once the distribution has been built. Change to the distrib/<arch>/ramdisks/ramdisk-cgdroot
and use nbmake-<arch>
to build:
src/distrib/amd64/ramdisks/ramdisk-cgdroot$ /path/to/tooldir/bin/nbmake-amd64 [...] create ramdisk-cgdroot/ramdisk-cgdroot.fs Calculated size of `ramdisk-cgdroot.fs.tmp': 5120000 bytes, 85 inodes Extent size set to 4096 ramdisk-cgdroot.fs.tmp: 4.9MB (10000 sectors) block size 4096, fragment size 512 using 1 cylinder groups of 4.88MB, 1250 blks, 96 inodes. super-block backups (for fsck -b #) at: 32, Populating `ramdisk-cgdroot.fs.tmp' Image `ramdisk-cgdroot.fs.tmp' complete
Then the kernel module can be built:
src/distrib/amd64/kmod-cgdroot$ /path/to/tooldir/bin/nbmake-amd64
It will be found in /path/to/objdir/distrib/amd64/kmod-cgdroot/cgdroot.kmod
.
Caveats
The biggest (known) issue with this setup occurs when firmware needs to be loaded early in the boot process (such as graphics drivers for the console). At the moment they need to be provided as part of the memory disk. Some network interfaces, of which some wireless devices in particular, also require loading firmware to work properly.
Firmware that can be loaded later (e.g. microcode in sysutils/intel-microcode-netbsd
package) can be found only if the corresponding paths in the hw.firmware.path
sysctl variable are adjusted to start with /altroot
.
This setup is not entirely safe against physical attacks. An attacker can modify the boot process to store the passphrase for later retrieval, or insert a backdoor while booting. To defend against such attacks, the bootloader, kernel and ramdisk all need to be signed and their integrity checked before booting (e.g. with tpm(4)). Alternatively, it is possible to boot from a removable medium (e.g. USB stick), which can be protected against tampering attacks (e.g. secure storage, read-only volume...).
It is also possible to boot a Xen DOM0 system with root filesystem encryption. However, Xen-enabled NetBSD kernels currently do not support loading modules at boot-time. The memory disk has to be placed directly inside the kernel instead (with mdconfig(8) or a new kernel configuration).
It should really be possible to install NetBSD this way with sysinst(8). Unfortunately this is not supported yet.
Customized Boot and unlocking via pkgsrc tools
It is relatively straight forward to customize the memory root disk contents and set up a different process to unlock the cgd root via for example tools form pkgsrc and a fido key.
References
- Full Disk Encryption with cgd (well, almost)
- The cryptographic device driver (CGD)
- Creating a custom CGD ramdisk