Encryption

From OpenZFS on OS X
Jump to: navigation, search

Encryption is now native to ZFS, and it is recommended to use that for greater flexibility and compatibility. See below. However, the core storage documentation will remain here for those who prefer that method.

Native ZFS Encryption

On a zpool that supports encryption, encryption may be enabled as follows:

# zpool set feature@encryption=enabled [pool]

On an zpool that supports encryption, an encrypted zfs dataset may be created as follows:

# zfs create -o encryption=on -o keylocation=prompt -o keyformat=passphrase [dataset]

This will prompt for the encryption passphrase for this zfs dataset. Other options for the location of the encryption key and its format can be found in the zfs(1M) manpage.

An encrypted zfs dataset may be mounted as follows:

# zfs mount -l [dataset]

This will prompt for the encryption passphrase for this zfs dataset and mount the encrypted dataset; it will not mount any child datasets of the encrypted dataset, but they will be accessible as subdirectories of the encrypted dataset. If the encryption passphrase is stored in the Keychain as a generic password under the name of the dataset, security(1) may be used to retrieve the passphrase as follows:

# security find-generic-password -a [dataset] -w | zfs mount -l [dataset]

One common use case for an encrypted volume is a portable backup drive. Typically the user will create snapshots on the source drive in the computer, and then transmit them to the portable drive using zfs send and receive. In this scenario it is helpful if the destination dataset on the portable drive is read only, since then there is no need to roll back the destination dataset on the fly to the last valid snapshot. To make this work with encryption, place the destination dataset as a child dataset of the encrypted dataset in the zpool of the portable drive; because it is a child of the encrypted dataset it, too, will be encrypted. More importantly, it can be made read-only, whereas it appears that the encrypted parent dataset cannot be read-only (probably so that the key can be stored locally in the parent dataset).

Additional helpful information about zfs encryption can be found in the How-To: Using ZFS Encryption at Rest in OpenZFS (ZFS on Linux, ZFS on FreeBSD, …).

Core Storage (File Vault 2)

Although the upstream OpenZFS project lists platform-agnostic encryption support at the ZFS dataset level as a possible future enhancement, OS X already offers a feature called FileVault 2, which provides built-in support for XTS-AES 128 encryption at the block level as part of Core Storage volume management.

This is the OS X analogue of the following block-level encryption systems on other operating systems that support ZFS:

  • FreeBSD: geli
  • Linux: LUKS

The overall procedure is, as follows: convert an empty HFS+ partition to use Core Storage and apply Core Storage encryption. Then use the Core Storage Logical Volume as a device in your zpool by supplying it to "zpool create," "zpool add," "zpool attach," etc.

Prerequisites

Build ZFS from source, or wait for the next installer, newer than 1.2.0 (for explanation, see original IRC chat).

Caveats

You may receive a pop-up claiming the disk isn't readable by this computer. This leads to one step that can be confusing: when unlocking the disk (e.g., on startup), the "bug" will make OS X believe the disk wasn't unlocked, and thus "wiggle," presenting the prompt again.

Assuming you entered your password correctly, the encrypted volume should now be unlocked, despite the misleading wiggle, and you can safely close the dialog box by clicking "Cancel." You'll know for sure the volume is unlocked when you proceed to import your pool, or you can check directly by looking for Encryption Status: Unlocked in the output of diskutil coreStorage list.

Steps

The initial layout, with disk1 being the external disk (counter-intuitively named "Internal HD") intended as encrypted ZFS device.

# diskutil list
/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *160.0 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            159.7 GB   disk0s2
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk1
   1:                        EFI EFI                     209.7 MB   disk1s1
   2:                  Apple_HFS Internal HD             999.9 GB   disk1s2

We note that disk1s2 is the partition to be encrypted, and we convert it to Core Storage (think LVM), to enable encryption:

#  diskutil coreStorage convert /dev/disk1s2
Started CoreStorage operation on disk1s2 Internal HD
Resizing disk to fit Core Storage headers
Creating Core Storage Logical Volume Group
Attempting to unmount disk1s2
Switching disk1s2 to Core Storage
Waiting for Logical Volume to appear
Mounting Logical Volume
Core Storage LVG UUID: 4690972A-484E-42E2-B72D-933A58E41237
Core Storage PV UUID: 22A1A783-01BA-4ABA-B4A3-2A9146506519
Core Storage LV UUID: F6D16BFE-B6E9-4A9B-BC03-E5CD03772C44
Core Storage disk: disk2
Finished CoreStorage operation on disk1s2 Internal HD

Note that we converted the existing unencrypted HFS+ partition.

Next, we encrypt the logical volume, our Core Storage disk, disk2:

Note: If you choose to use diskutil to do the encryption, it will default to the most secure option, which will take a VERY long time with large disks, optionally use the Disk Util UI and set it up as an encrypted HFS+ volume and under advanced change to least secure (good for new disks)
# diskutil coreStorage encryptVolume /dev/disk2
New passphrase for existing volume:
Confirm new passphrase:
The Core Storage Logical Volume UUID is F6D16BFE-B6E9-4A9B-BC03-E5CD03772C44
Started CoreStorage operation on disk2 Internal HD
Scheduling encryption of Core Storage Logical Volume
Core Storage LV UUID: F6D16BFE-B6E9-4A9B-BC03-E5CD03772C44
Finished CoreStorage operation on disk2 Internal HD

Note that we used disk2, the logical volume, not disk1s2.

This can and will take a while to complete. You can check the status by issuing:

# diskutil coreStorage list | grep Conversion

Until it's done:

Conversion Status:  Complete
Conversion Progress: -none-

Your partition layout should now look like:

# diskutil list
/dev/disk0
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *160.0 GB   disk0
   1:                        EFI EFI                     209.7 MB   disk0s1
   2:                  Apple_HFS Macintosh HD            159.7 GB   disk0s2
/dev/disk1
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *1.0 TB     disk1
   1:                        EFI EFI                     209.7 MB   disk1s1
   2:          Apple_CoreStorage                         999.9 GB   disk1s2
   3:                 Apple_Boot Boot OS X               134.2 MB   disk1s3
/dev/disk2
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:                  Apple_HFS                        *999.5 GB   disk2

disk2 being our encrypted, unlocked HFS+ device. If you have yet to be prompted for the passphrase by OS X, now would be a good time to restart your Mac and try it out.

Lastly, we'll prepare the volume for ZFS, by unmounting /dev/disk2:

# mount
...
/dev/disk2 on /Volumes/Internal HD (hfs, local, journaled)
# diskutil unmount "/Volumes/Internal HD"

You can now follow the article on creating a pool. As a simple example, you might

 # zpool list
 no pools available
 # zpool create -f -o ashift=12 ZFS_VOLUME /dev/disk2
 # zpool list
 ZFS_VOLUME    928G  20.8G   907G     2%  1.00x  ONLINE  -

Also note that you don't need to worry about changing the partition type in this case to ZFS as described in the Suppressing the annoying pop-up wiki page.

Reason to "use latest"

<ilovezfs> If you want encryption you have a few options
<ilovezfs> https://github.com/zfsrogue/osx-zfs-crypto
<lundman> :)
<ilovezfs> or you can do what cbreak said, and use an encrypted sparsebundle
<ilovezfs> (I'd give it its own ZFS file system)
<ilovezfs> or you can create a ZVOL, and put an encrypted Core Storage/Filevault 2 HFS+
           file system on it
<ilovezfs> or you can put the pool itself on top of Core Storage.
<ilovezfs> The last option you should not do with the installer version.
<ilovezfs> But wait for the next installer if that's the route you want to go
<ilovezfs> or build from source.
<aandy>    Ah, interesting. Does FileVault 2 require HFS+? Not that it'd surprise me.
<ilovezfs> No it does not.
<ilovezfs> But it is not possible to set other Content Hints
<ilovezfs> so it will always say HFS+ even if you do put ZFS on your logical volumes.
<ilovezfs> So basically the procedure is to format the volume HFS+.
<ilovezfs> Then run 'diskutil coreStorage convert' on it.
<ilovezfs> Then you can encrypt it.
<ilovezfs> Then you unmount the HFS+
<ilovezfs> and zpool create on the logical volume.
<ilovezfs> And you should be good to go.
<aandy>    On the original HFS+ partition, right?
<ilovezfs> Right.
<ilovezfs> But I'd encrypt first
<ilovezfs> then put ZFS on it.
<aandy>    Right. Perfect.
<ilovezfs> diskutil coreStorage convert ...
<ilovezfs> diskutil coreStorage encryptVolume ...
<ilovezfs> etc.
<ilovezfs> The reason not to use the installer version, is that it will attempt to
           partition the Core Storage Logical Volume.
<ilovezfs> But since 10.8.5 and after, Apple doesn't like that
<ilovezfs> so we added new code to detect Core Storage and not partition if it sees it's
           Core Storage.