23 May 2009

Encrypted FreeBSD 7.2 (and 8.0) system using geli

A BIT OF HISTORY AND CAUTION
==========================


Caution
As of FreeBSD 8.0 "dangerously dedicated" mode has been removed. What does this mean for setups like this? I don't know... seriously. There is a large discussion about this on the FreeBSD mailing lists so I suggest you educate yourself there and decide if this is really what you want to do. You have been cautioned.

Update 2010
This updated guide was originally written in 2009 for FreeBSD 7.2, but now being 2010 and with FreeBSD 8.0 being released I thought I'd touch it up again (Couldn't wait for 8.2). The process is pretty much the same. Any differences are slight and will be pointed out. Keep in mind that the links pointing to the manpages are for the FreeBSD 7.2-RELEASE manuals.

This guide explains how to install an encrypted system using geli (8), with an unencrypted /boot parition placed on a usb-stick, which will also contain a keyfile that, aswell as a password, is required to boot into the system. Additionally a bootable CD can be used which is covered in the previous 6.2 guide (If it still works... That section hasn't been touched for almost 3 years!).

One final note: This is WAY too much effort if you ask me...

SETUP
======

FreeBSD installation DVD (which contains the live fs)
A system/drive to install FreeBSD onto /dev/ad0
A usb-stick /dev/da0

Make sure not to confuse /dev/ad0 with /dev/da0 like I've done in the past!

Boot from the FreeBSD install dvd. At the install screen choose the Fixit option, and select:

Use the "live" filesystem CDROM/DVD

You will see something like:

blah blah blah
more blah blah
even more blah
...
Good Luck!

Fixit#


PREPARING THE DRIVES
====================

Sanitising
This step is optional, as the sanitation process can literally take days depending on how large the drive is. The disk will be wiped with random data to make previous data difficult to recover. I personally prefer to use dban and leave it running overnight, or you could go the BSD route. You can also sanitise the usb-stick here too if you want.

# dd if=/dev/random of=/dev/ad0 bs=1M

Later on when you edit files you'll be presented with vi (8), an extremely powerful editor. Otherwise, for something more user friendly you can use ee (8).

# setenv EDITOR=ee

Creating and editing the partitions on the usb-stick:
Now fdisk (8) and bsdlabel (8) will be used to setup the bootable usb-stick.

# fdisk -BI /dev/da0
# bsdlabel -Bw /dev/da0s1
# bsdlabel -e /dev/da0s1

You will see something like the following:
> # /dev/da0s1
> 8 partitions:
> # size offset fstype [fsize bsize bps/cpg]
> a: 1001936 16 unused 0 0
> c: 1234567 0 unused 0 0 # "raw" part, don't edit
In the a: entry, used for our root partition, change "unused" to "4.2BSD"
> #     size   offset   fstype     [fsize bsize bps/cpg]
> a: 1001936 16 4.2BSD 0 0
Creating the filesystem and keyfile
We are now going to construct a filesystem on the usb-stick using newfs (8), then we will mount (8) it, then using dd (1) we are going to create a 256KB keyfile filled with random data.
# newfs /dev/da0s1a
# mkdir /usb && mount /dev/da0s1a /usb
# dd if=/dev/random of=/usb/ad0.key bs=256K count=1
They keyfile can be any length you want it to be.

MOULDING THE SYSTEM WITH GELI
=============================

Get it? No? Nevermind...

Geli isn't enabled by default with the livefs. So we'll have to create a couple symlinks with ln (1), then load the geom_eli module with kldload (8).

# ln -s /dist/boot/kernel /boot/kernel
# ln -s /dist/lib /lib
# kldload geom_eli

Initialising the drive [8.0 Users note below]
Now we are going to initialise the system drive /dev/ad0 with geli (8).The default encryption algorithm is AES, which was designed to only accept key sizes of 128, 192 or 256 bit. You try and set another keylength and you'll get an error at this stage.

Note the uppercase and lowercase letter k's
# geli init -b -l 256 -s 4096 -K /usb/ad0.key /dev/ad0
Enter new passphrase:
Reenter new passphrase:
# geli attach -k /usb/ad0.key /dev/ad0
Enter passphrase:
On FreeBSD 8.0, geli (8) now contains the "-B" (UPPERCASE) flag to backup the metadata stored in /var/backups/ by default. Therefore you first have to create a /var/backups directory or define where you want the backup to go, if you want one at all, otherwise you'll get a lovely error message.

Creating and editing the partitions and filesystems on the system drive
Now we are going to prepare the system drive as we did the usb-stick
# bsdlabel -w /dev/ad0.eli
# bsdlabel -e /dev/ad0.eli
Like before you'll see something like the following:
> # /dev/ad0s1
> 8 partitions:
> # size offset fstype [fsize bsize bps/cpg]
> a: 1001936 16 unused 0 0
> c: 1234567 0 unused 0 0 # "raw" part, don't edit
I like to add other partitions such as /home, /var, /tmp and /usr so that my partition layout looks something like the following mess:
> # /dev/ad0s1
> 8 partitions:
> # size offset fstype [fsize bsize bps/cpg]
> a: 300M 16 4.2BSD 0 0 # /
> b: 512M * swap
> c: 1234567 0 unused 0 0 # "raw" part, don't edit
> d: 512M * 4.2BSD # /home
> e: 512M * 4.2BSD # /tmp
> f: 2046M * 4.2BSD # /var
> g: * * 4.2BSD # /usr
There's no need to enter in values for fsize, bsize and bps/cpg as they're filled in automatically when you write the partition layout. # bsdlabel -e /dev/ad0.eli again to see what I mean. I wouldn't change the default values anyway as the newfs (8) manpage explains. (And if you can actually understand the explanation then you're a smarter person than I am).

Also, instead of M for Megabytes in the size column you can use G for Gigabytes. What the asterisks * in the offset column do is to tell newfs (8) to automagically determine the offset, where the partition should begin, based on where the previous partition ended. NICE!

Now construct the filesystems:
# newfs /dev/ad0.elia
# newfs /dev/ad0.elid
etc...
Mount, mount, and more mount
Now we are going to create mountpoints for the partitions and re-mount the usb-stick. The reason being, is that later on we are going to create a chroot (8) at /tmp/fixed, and we want the usb-stick accessible within the chroot.
# mkdir /tmp/fixed && cd/tmp/fixed
# mount /dev/ad0.elia .
# mkdir home tmp var usr usb
# mount /dev/ad0.elid home
# mount /dev/ad0.elie tmp
# mount /dev/ad0.elif var
# mount /dev/ad0.elig usr
# umount /usb && mount /dev/da0s1a /tmp/fixed/usb
Installing base and the kernel
Now we are going to actually install something... Can I get a "YAY!" But first we need to setup some variables so that things are installed to the right places.

# export DESTDIR=/tmp/fixed

I prefer to only install base and build a custom kernel. If it all works properly I can just install whatever I want later via sysinstall (8). Obviously for 8.0 users change the numbers accordingly.
# cd /dist/7.2-RELEASE
# cd base && ./install.sh

You are about to extract the base distribution into /tmp/fixed - are you SURE you want to do this over your installed system (y/n)? y

# cd ../src && ./install.sh sys base

Sources for sys and base were installed so that a custom kernel could be compiled. Should you want the GENERIC kernel instead, forget about installing the sources and skip the "Configuring/Compiling the kernel" sections and just install the GENERIC kernel:

# cd /dist/7.2-RELEASE/kernels && ./install.sh GENERIC

[ NOTE: The original reason given for configuring and compiling a custom kernel was that in the 6.2-RELEASE kbdmux (8) would interfere when trying to enter in the passphrase for geli at boot. Whether or not the original problem still exists is unknown, but now its just something I like to do.

Either way, as it states in the handbook, "If you do not plan to use more than one keyboard on the system, you can safely remove that line" from the GENERIC kernel.]

Kernel configuration
We need a devfs in the chroot to enable us to compile everything. Then we're going to chroot /tmp/fixed, edit a custom kernel and compile away.
# mount -t devfs devfs /tmp/fixed/dev
# chroot /tmp/fixed
Perform a # pwd and you'll see that you're at the root directory, which is really /tmp/fixed
# cd /usr/src/sys/i386/conf
# mkdir /root/kernels
# cp GENERIC /root/kernels/CUSTOM
# ln -s /root/kernels/CUSTOM
# vi CUSTOM
Check out the handbook if you never compiled a kernel before, in particular sections 8.5 and 8.6. One thing to note, I always include the following in my custom kernel config file, for inbuilt support for GELI devices:
options GEOM_ELI
device crypto
Compiling the kernel
# export MAKEOBJDIRPREFIX=/usr/obj2 && export DESTDIR=/
# cd /usr/src
# make buildkernel KERNCONF=CUSTOM
# make installkernel KERNCONF=CUSTOM

THE FINAL STAGES
===============

Boot to boot
Now /boot is to be copied to the usb-stick. There's a couple ways of doing this, the convoluted and complicated method (my personal favourite) or the simple method that just takes a little longer to process. Then the fstab (5) files will be configured. Firstly, I like to gzip (1) the kernel as this helps speed up boot time and decreases the file size to copy over.

# cd /boot/kernel && gzip kernel

[ convoluted method 1 ]
If you configured and compiled a kernel and built in support for geom_eli, then you don't need to copy over the geom_eli.ko module, otherwise copy over geom_eli.ko aswell. On my simple system all I needed was the kernel, though YMMV.
[WATCH YOUR SPACING]
# mkdir /usb/boot
NB: I split this command up into two lines as it wasn't completely
showing the whole command otherwise

# (cd /boot && tar --exclude "kernel*" -cf - .) | \
(cd /usb/boot && tar -xf -)
# cd /boot/kernel && mkdir /usb/boot/kernel
# cp geom_eli.ko kernel.gz /usb/boot/kernel
The above uses tar (8) to create an archive of the /boot directory, excluding the kernel directories (kernel and kernel.old) and extracts the contents to the /usb/boot directory. Then you just copy over the required files needed for boot to /usb/boot. All in all, roughly 3MB in total copied over.

[ easy method 2 ]
This method takes longer to process as all the kernel modules are copied over, which on my system totalled more than 100MB

# cp -Rpv /boot /usb

Usb configuration files
Given up yet?

Now for the last part of the last stretch. Configuring the config files.
The geom_eli_load="YES" line may be omitted if you enabled GEOM_ELI support in the CUSTOM kernel, assuming you made one.

# vi /usb/boot/loader.conf
> geom_eli_load="YES"
> geli_ad0_keyfile0_load="YES"
> geli_ad0_keyfile0_type="ad0:geli_keyfile0"
> geli_ad0_keyfile0_name="/ad0.key"

Now for the fstab (5) files. First we need to create an etc/fstab on the usb stick to mount the root partition.

# mkdir /usb/etc && \
echo "/dev/ad0.elia / ufs rw 1 1" >> /usb/etc/fstab

Now we create an etc/fstab on the system-drive, so that once the root partition is loaded the rest of the partitions can be loaded.
# vi /etc/fstab
> # Device Mountpoint FStype Options Dump Pass#
> /dev/ad0.elib none swap sw 0 0
> /dev/ad0.elid /home ufs rw 2 2
> /dev/ad0.elie /tmp ufs rw 2 2
> /dev/ad0.elif /var ufs rw 2 2
> /dev/ad0.elig /usr ufs rw 2 2
And that should be it. If you want to create a bootable cd then have a look at my previous guide. Note that mkisofs isn't included in the base system so you'll need access to another BSD system.

************************
EXTREMELY IMPORTANT
************************

Before you reboot, you MUST unmount everything! So exit the chroot, umount (8) your mounted partitions, and detach the geli (8) device.

# exit
# cd /tmp/fixed
# umount dev home tmp var usr usb
# cd .. && umount fixed
# geli detach /dev/ad0

Now you can reboot. When you reboot into your wonderful newly encrypted system, you can use sysinstall (8) to install other packages and configure your gear. So, happy hunting.

NOTE: When you do finally boot into your system, you may see the normal boot process scroll by and then all of a sudden it'll seem to have stopped when its detected the usb stick (da0). You may be wondering where the password prompt to attach the geli device is... most likely its about 10 or so lines up... yeah, its confusing. But it'll still work.

References
==========

FreeBSD forums
http://forums.freebsd.org/archive/index.php/t-434.html

"Complete Hard Disk Encryption with FreeBSD" - Marc Schiesser
22nd Chaos Communication Congress, 29 December 2005

FreeBSD-Geom Mailing List Archives
http://lists.freebsd.org/pipermail/freebsd-geom/

bootable FreeBSD on USB-Flash-Drive [Solution]
http://lists.freebsd.org/pipermail/freebsd-questions/2006-March/117738.html

FreeBSD Handbook, Chapter 18.6 - Creating and Using Optical Media(CDs)
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/creating-cds.html

FreeBSD Handbook, Configuring the FreeBSD Kernel
http://www.freebsd.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig.html

Marc Fritsche, marc [at] proportion [dot] ch
http://www.proportion.ch/index.php?page=31

And a few people on #freebsd on irc.freenode.net. Sorry, can't remember your names...