I’ve been a long-time user and supporter of FreeBSD ever since I was exposed to it by Greg Lehey and Ceren Ercen back in the Linuxcare days. I’ve come to enjoy its security, speed and powerful simplicity. The FreeBSD documentation is also unrivaled in the community.
But I also realized that securing the system itself only means so much, if I don’t actually encrypt the data it stores locally on those platters, so I had to do better.
You can lock down externally-facing services, ports and daemons.. but someone who has physical access to your systems can bypass almost everything if they have the tools and the skills. This includes a clueless operations person working in a datacenter (which I’ve been fighting quite a bit lately, as my own hosting provider rooted one of my machines, because I refused to give them the root password. Grr!).
Enter “geli” encryption under FreeBSD!
But getting geli encryption working isn’t quite as straightforward as you’d think. It requires some prior planning and preparation to make sure you’re doing it correctly. We’ll do this in two steps:
- Set up encrypted swap
- Encrypt the secondary drive and mount
/hometo it, encrypted
In a nutshell, here are the steps to set that up to encrypt your data:
- Add a second drive in your system at least equal to the capacity of your primary drive. This drive will be the target of the encrypted filesystems you put on it. If you’re planning on encrypting the entire system including the root partition, you’ll need to make sure it’s the same size or larger. If you’re just encrypting home directories or /var or something smaller, you can use a lesser capacity drive.
- Boot your BSD system so it recognizes that new drive. If you’re using VMware, VirtualBox or similar virtualization product to run your FreeBSD instance, add a second virtual disk to the VM, of equal or larger size. On my system, this is called
- Once booted, edit your kernel config (you have compiled a custom kernel, haven’t you?), and add the following lines to it:
options GEOM_ELI device crypto
- Rebuild your kernel, install it and reboot back into that newly built kernel (which should now have geli support compiled in). If you’re using the
GENERICkernel, add the following line to
- Now you have to create your key for the partition or drive you wish to encrypt. Since we’re going to encrypt swap first, we have to find out which partition is the swap partition. We do that with swapinfo(8):
# swapinfo -hg Device 1G-blocks Used Avail Capacity /dev/da0s1b 1 0B 2.0G 0%
Here we can see that
/dev/da0s1bis our swap partition. Let’s unmount that so we can begin:
# swapoff /dev/da0s1b
- Now let’s randomize and scramble the data on that slice:
# dd if=/dev/random of=/dev/da0s1b bs=1m
- Next, we encrypt that slice and mount it (choose the best algorithm for your needs. AES is fast and efficient, which is why I’m using it here. Blowfish, Camellia and 3DES are other ciphers you can choose from):
# geli onetime -d -e aes /dev/da0s1b # swapon /dev/da0s1b.eli
- We can now verify that it is indeed mounted and encrypted:
# swapinfo -hg Device 1G-blocks Used Avail Capacity /dev/da0s1b.eli 1 0B 2.0G 0%
- We’re not done yet, we still have to update
/etc/fstabto reference the new encrypted slice (ending in
# cat /etc/fstab # Device Mountpoint FStype Options Dump Pass# /dev/da0s1b.eli none swap sw 0 0 /dev/da0s1a / ufs rw 1 1 /dev/da0s1e /tmp ufs rw 2 2 /dev/da0s1f /usr ufs rw 2 2 /dev/da0s1d /var ufs rw 2 2 /dev/da1.eli /home ufs rw 2 2 /dev/acd0 /cdrom cd9660 ro,noauto 0 0
Now we need to start encrypting actual data itself. In this series of steps, we’re going to encrypt home directories on their own partition, secured by geli. Our secondary drive (the one we installed in our machine or attached to our VM in this case), is called “
Your drive lettering and designation may differ, so please make note of it when you boot your machine. Make sure you choose the blank drive when you follow these next steps; you don’t want to wipe out all of your data on your existing drive by accident. Been there, done that. Be careful!
da1designated as the target drive in the system, let’s create an initial key to secure it. For better performance, a key size of 4k or larger is preferred (that’s the
-s 4096option below):
# dd if=/dev/random of=/root/da1.key bs=64 count=1 # geli init -s 4096 -K /root/da1.key /dev/da1 Enter new passphrase: Reenter new passphrase:
- You’ll need to “attach” that new drive to the encryption provider, as follows:
# geli attach -k /root/da1.key /dev/da1 Enter passphrase:
- If that was successful, you’ll now want to completely ‘shred’ or randomize any data that may be on that drive, to ensure that there is nothing deterministic left on it.
# dd if=/dev/random of=/dev/da1.eli bs=1m
This may take awhile, so sit back and relax, but do not skip this step!
- Now let’s create the filesystem on top of that encrypted volume and mount it to a temporary mount point:
# newfs /dev/da1.eli /dev/da1.eli: 30720.0MB (62914552 sectors) block size 16384, fragment size 4096 using 92 cylinder groups of 336.88MB, 21560 blks, 21568 inodes. super-block backups (for fsck -b #) at: ... # mkdir -p /private # mount /dev/da1.eli /private
- You should now be able to see this and verify that it is mounted correctly:
# df Filesystem 1K-blocks Used Avail Capacity Mounted on /dev/da0s1a 507630 298322 168698 64% / devfs 1 1 0 100% /dev /dev/da0s1e 507630 16 467004 0% /tmp /dev/da0s1f 25438226 2477294 20925874 11% /usr /dev/da0s1d 2007598 39942 1807050 2% /var /dev/da1.eli 30958184 8 28481524 0% /private
- Now you can copy data to the partition and be assured that it is secured from prying eyes. My favorite tool to do this is rsync, and I’m a ninja with its hundreds of options. For example, to copy the user’s home directories over to the encrypted partition, simply use the following:
# rsync -avSP /home/. /private
- From here, we now have to change where
/homeis mounted, by updating
/etc/fstabto refer to that location:
# cat /etc/fstab # Device Mountpoint FStype Options Dump Pass# /dev/da0s1b none swap sw 0 0 /dev/da0s1a / ufs rw 1 1 /dev/da0s1e /tmp ufs rw 2 2 /dev/da0s1f /usr ufs rw 2 2 /dev/da0s1d /var ufs rw 2 2 /dev/da1.eli /home ufs rw 2 2 /dev/acd0 /cdrom cd9660 ro,noauto 0 0
- We still need to make sure this partition is set up to mount at boot time, so let’s add that to
/etc/rc.confby adding these two additional lines at the end:
geli_devices="da1" geli_da1 _flags="-k /root/da1 .key"
That should do it. Remember though, this will also mean you will be prompted to enter the passphrase at boot time; you can’t do this headless or remotely.
When the machine boots up, it will prompt you for your passphrase, and then mount /home to /private/home (the encrypted provider). If all goes right, you should see this:
GEOM_ELI: Device da1.eli created. GEOM_ELI: Encryption: AES-CBC 128 GEOM_ELI: Crypto: software
- If you want to unmount the partition, simply do the following:
# umount /home # geli detach da1.eli
- You can also blow away
/private, since we’re no longer using it. It was just a simple “trampoline” to allow us to get the data out of the unencrypted
/hometo the encrypted one:
# rm -Rf /private
That’s it! Pretty simple, but pretty powerful. Once you incorporate that into your overall workflow, you won’t even know it’s there.
Encryption should be 100% transparent to valid users, but 100% opaque to unauthorized users or prying eyes.
Some more references: