My goal is to install FreeBSD on a system with 2 disks, keeping the mirroring of the disks for data security. You can find several tutorials on how to install with one encrypted ZFS pool, and in 11.0-RELEASE, the BSDinstall partitionner can do this for you. However I wanted to use a more complex setting, that I will explain below.
Hardware used
I use a Dell server (bare metal) with two 1 To disks, for disk encryption, the CPU has the AES-NI instruction set.
Rational
This server is located in a datacenter (I rent it) and I have no physical access to it.[1] But I want that my data be encrypted so that if a disk is removed from the server (disk failure, seizure or error) the data is protected. So I need to be able to boot a minimal system, which allows me a remote access (through ssh), then allows me to enter the decryption password, mount the encrypted volume(s) and start the remaining services. For this I will partition my disks and use those partitions to directly define a root ZFS pool or (through geli) an encrypted ZFS pool.
Installation
I do the installation through the IDRac remote console, mounting the
FreeBSD ISO image in the virtual CD. I use the standard installer, but
at the partitionning stage I choose the "Shell Partitionning". This
gives me a shell, and (in order for the installer to work) I must
setup things so that system filetree is found under /mnt
and necessary
config files are defined in /tmp/bsd_install_etc
.
In this directory we set up the following files:
Base partitioning
I use gpart
for this partitioning and I based it on
Ollivier Robert’s
Documentation. My two disks are seen as /dev/ada0
and /dev/ada1
by
the installer.
-
First step is to reset the disks partition table
dd if=/dev/zero of=/dev/ada0 bs=512 count=10 dd if=/dev/zero of=/dev/ada1 bs=512 count=10
-
Then create a gpt partition table
gpart create -s gpt ada0 gpart create -s gpt ada1
-
We then create our partitions. We need a small partition for the boot code, one for the system (root) pool, one for swap and the rest for data (which will be encrypted). Since we want to mirror the partitions, we need to use the same partitioning scheme on both disks. The leads to
gpart add -s 100K -a 4k -t freebsd-boot ada0 gpart add -s 70G -a 4k -t freebsd-zfs -l sys0 ada0 gpart add -s 32G -a 4k -t freebsd-swap -l swap0 ada0 gpart add -a 4k -t freebsd-zfs -l data0 ada0
gpart add -s 100K -a 4k -t freebsd-boot ada1 gpart add -s 70G -a 4k -t freebsd-zfs -l sys1 ada1 gpart add -s 32G -a 4k -t freebsd-swap -l swap1 ada1 gpart add -a 4k -t freebsd-zfs -l data1 ada1
We can now see the partitions
#ls /dev/gpt data0 data1 swap0 swap1 sys0 sys1
Giving their role to the partitions
We first define both disks as bootable, to be able to boot when any of the disks is down.
gpart set -a bootme -i 2 ada0 gpart set -a bootme -i 2 ada1
Now we manually load the necessary modules to continue
kldload zfs kldload geom_mirror kldload geom_eli kldload crypto kldload aesni
Then we create the system pool, that we chroot on /mnt for the installer, and the datasets ins this pool
zpool create -R /mnt -O mountpoint=none system mirror gpt/sys0 gpt/sys1 zfs set compression=lz4 system zfs set checksum=fletcher4 system zfs create -o mountpoint=/ system/root zfs create system/root/usr zfs create system/root/usr/src zfs create system/root/usr/obj zfs create system/root/usr/local zfs create system/root/tmp zfs create system/root/var zpool set bootfs=system/root system
Now that we have the basic tree, we add the boot code in the first partition of the disks
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0 gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
The partitioning is now the following one :
# gpart show => 40 1953525088 ada0 GPT (932G) 40 200 1 freebsd-boot (100K) 240 146800640 2 freebsd-zfs [bootme] (70G) 146800880 67108864 3 freebsd-swap (32G) 213909744 1739615376 4 freebsd-zfs (830G) 1953525120 8 - free - (4.0K) => 40 1953525088 ada1 GPT (932G) 40 200 1 freebsd-boot (100K) 240 146800640 2 freebsd-zfs [bootme] (70G) 146800880 67108864 3 freebsd-swap (32G) 213909744 1739615376 4 freebsd-zfs (830G) 1953525120 8 - free - (4.0K)
The data partition (number 4) will be configured after the system is installed, as base for the encrypted pool.
Defining swap
We use a standard geom mirror for the swap, defined by
gmirror label swap gpt/swap0 gpt/swap1
The line we put in /tmp/bsdinstall_etc/fstab
will define an
encrypted partition over this mirror as the swap of our system.
We can now exit the shell, let the installer do its job and reboot the system.
The encrypted pool
After reboot we have (hopefully) a working system on which we can ssh to define our new encrypted pool that we will use for our sensitive data.
This a quite standard setting
-
First create the key file :
root@tgv:~ # mkdir /root/keys root@tgv:~ # dd if=/dev/random of=/root/keys/data.key bs=128k count=1
-
Then we encrypt the partitions
root@tgv:~ # geli init -K /root/keys/data.key -s 4096 -l 256 /dev/gpt/dataO root@tgv:~ # geli init -K /root/keys/data.key -s 4096 -l 256 /dev/gpt/data1
-
We now attach them to the system
root@tgv:~ # geli attach -k /root/keys/data.key /dev/gpt/data0 root@tgv:~ # geli attach -k /root/keys/data.key /dev/gpt/data1
-
And now we create the pool
root@tgv:~ # zpool create data mirror gpt/data0.eli gpt/data1.eli
Usage
After this we use the data pool creating datasets with their mountpoints inside, setting the compression, and all the standard zfs parameters. In my case I also use ezjail and I defined the jails in the data zpool, so my script simply starts the jail after mounting :