Date: Fri, 26 Jun 2026 19:09:57 +0000 From: Benedict Reuschling <bcr@FreeBSD.org> To: doc-committers@FreeBSD.org, dev-commits-doc-all@FreeBSD.org Subject: git: d020202567 - main - Revert "handbook/zfs: Add new section about ZFS native encryption" Message-ID: <6a3ece85.43600.18d51852@gitrepo.freebsd.org>
index | next in thread | raw e-mail
The branch main has been updated by bcr: URL: https://cgit.FreeBSD.org/doc/commit/?id=d020202567aa62090adf23d27862749d1f81ce11 commit d020202567aa62090adf23d27862749d1f81ce11 Author: Benedict Reuschling <bcr@FreeBSD.org> AuthorDate: 2026-06-26 19:09:36 +0000 Commit: Benedict Reuschling <bcr@FreeBSD.org> CommitDate: 2026-06-26 19:09:36 +0000 Revert "handbook/zfs: Add new section about ZFS native encryption" This reverts commit 9ddc2f8625bf8d59738c10c1370ba03eac0677af. Not approved yet. --- .../content/en/books/handbook/zfs/_index.adoc | 299 --------------------- 1 file changed, 299 deletions(-) diff --git a/documentation/content/en/books/handbook/zfs/_index.adoc b/documentation/content/en/books/handbook/zfs/_index.adoc index 607d905fb8..e1738f9716 100644 --- a/documentation/content/en/books/handbook/zfs/_index.adoc +++ b/documentation/content/en/books/handbook/zfs/_index.adoc @@ -2645,305 +2645,6 @@ Another restriction aimed at preventing abuse: non-`root` users must own the mou `zfs allow _someuser_ allow _mydataset_` gives the specified user the ability to assign any permission they have on the target dataset, or its children, to other users. If a user has the `snapshot` permission and the `allow` permission, that user can then grant the `snapshot` permission to other users. -[[zfs-native-encryption]] -== ZFS Native Encryption - -ZFS supports native encryption of datasets and the data stored within them. -This was not always the case, as previous solutions relied on FreeBSD's GELI-based encryption. -While this approach is secure, it was not as easily portable to non-FreeBSD systems that lacked GELI support. -With ZFS native encryption, encrypted datasets can be used on other systems that support this pool feature without relying on third-party components or operating system-native encryption. - -Another benefit of ZFS native encryption is that datasets do not need to be decrypted for administrative tasks such as snapshots, replication, or scrub operations. -ZFS data integrity checks work just as well with natively encrypted datasets, and compression also works encrypted datasets. - -Different datasets on the same pool can use separate keys independently. -Consider a central file server where different users store their data in encrypted home datasets. -User A has a different key than User B. -Both users can work side by side and choose to unencrypt their datasets as needed without knowing each other's decryption keys. -The decryption method can also differ completely between users without affecting one another. -This allows sensitive data from different users to be stored on the same pool while remaining protected by separate keys. - -Before using ZFS native encryption, be aware of the following: - -- Encryption is applied at the dataset level, not the pool level. -- Booting from encrypted ZFS pools is not yet supported on FreeBSD. -- Encryption can only be enabled when a dataset is created, not afterward. -- The block cipher, key length, and encryption mode can not be changed after they have been set. -- ZFS does not encrypt metadata. - -The last point may seem like a drawback compared to full-disk encryption. -However, it provides greater flexibility by allowing different keys to protect datasets within the same pool instead of requiring a single key or passphrase to unlock the entire pool. -Specifically, ZFS encrypts the following: - -* file and zvol data, -* file attributes, -* ACLs, -* permission bits, -* directory listings, -* FUID mappings, -* userused/groupused data, and -* deduplicated data - -Some ZFS metadata and information remains unencrypted, including the following: - -* pool structure and name, -* dataset and snapshot names, -* dataset hierarchy, -* properties, -* file size, -* file holes, and -* deduplication tables - -This unencrypted metadata allows ZFS to perform routine maintenance operations, such as `zfs scrub`, without first decrypting the data. -As a result, ZFS can detect and repair corrupted encrypted data that is encrypted data without accessing the unencrypted file contents. - -To encrypt existing unencrypted data, copy it to a dataset with encryption enabled. -This allows data to be migrated to a secure location within the pool, provided the passphrase is supplied to authorize access. -Typically, this is done by loading the encryption key into memory after confirming knowledge of a secret such as a passphrase. -Once the key has been loaded, the dataset contents become accessible for reading and writing. -To re-secure the dataset, unload the key from memory. -ZFS then makes the dataset inaccessible until the key is loaded again. - -When encryption is enabled, some ZFS operations behave differently. -ZFS applies compression before encryption to preserve compression ratios. -While ZFS normally uses 256-bit checksums, encryption replaces them with a 128-bit checksum and a 128-bit Message Authentication Code (MAC) provided by the encryption suite. -This provides additional protection against malicious data modification. - -When deduplication is used together with encryption, ZFS performs deduplication only within the encrypted dataset, its snapshots, and its clones. -This prevents information from leaking between encrypted datasets. -The tradeoff is lower deduplication efficiency because ZFS cannot compare checksums across the entire pool. -Even so, deduplication combined with encryption still reveals which blocks are identical and incurs additional CPU overhead for each block written. - -Other limitations apply when using ZFS encryption. -The `embedded_data` feature cannot be used with encryption. -Datasets with encryption enabled also cannot have the `copies` property set to 3, because the implementation stores encrypted metadata in the location where the third copy would normally reside. - -[[zfs-encrypted-dataset-creation]] -=== Creating an encrypted dataset - -ZFS encryption is enabled by setting the `encryption=on` property when creating a dataset. -Setting this property outside of a `zfs create` command does not enable encryption retroactively, as it only takes effect during dataset creation. -In the following example, a passphrase is used when mounting the encrypted dataset after it has been created. - -[source,shell] -.... -# zfs create -o encryption=on -o keyformat=passphrase -o keylocation=prompt zroot/secretdata -Enter passphrase: -Re-enter passphrase: -.... - -If the passphrase is shorter than eight characters, ZFS rejects it and does not create the dataset. -After the passphrase has been entered correctly twice, ZFS creates and mounts the dataset in the pool. - -Any data stored in the encrypted dataset remains encrypted while it resides there. -Copying data from an encrypted dataset to an unencrypted location decrypts the data during the copy operation. -The newly created dataset can then be mounted at a different location if necessary. - -[source,shell] -.... -# zfs set mountpoint=/secretdata zroot/secretdata -# echo "Hello FreeBSD!" > /secretdata/message -# cat /secretdata/message -Hello FreeBSD! -.... - -As expected, the data is currently available for reading and writing by anyone who has access to the dataset. - -[[zfs-encrypted-dataset-properties]] -=== Properties of encrypted datasets - -Listing the ZFS native encryption properties for a dataset is done with the following command: - -[source,shell] -.... -# zfs get encryption,keylocation,keyformat zroot/secretdata -NAME PROPERTY VALUE SOURCE -mypool/secretdata encryption aes-256-gcm - -mypool/secretdata keylocation prompt local -mypool/secretdata keyformat passphrase - -.... - -The `encryption` property shows `aes-256-gcm`, which is currently the default encryption method used by ZFS. -As indicated by the `SOURCE` column, neither this property nor the `keyformat` property can be changed using `zfs set` after the dataset has been created. -See the crossref:zfs-change-encryption-key[zfs-change-encryption-key, changing the encryption key] section for information on how to modify some of these properties. -The following table lists the encryption-related properties used by ZFS: - -[.informaltable] -[cols="10%,90%"] -|=== - -|[[zfs-term-encryptionroot]]encryptionroot -|The dataset from which the current dataset inherits its encryption key. -Dataset clones share the encryption key of their originating dataset. - -|[[zfs-term-keyformat]]keyformat -a|The format of the encryption key. Possible values are: `raw`, `hex`, and `passphrase`. Both `raw` and `hex` keys must be 32 bytes long and contain random values. -|[[zfs-term-encryption]]encryption -a|The cipher used for encryption, consisting of the block cipher, key length, and encryption mode. Both the `encryption` and `keyformat` properties must be specified when the dataset is created. Possible values for the `encryption` property are: - - * `off` (default), - * `on`, - * `aes-128-ccm`, - * `aes-192-ccm`, - * `aes-256-ccm`, - * `aes-128-gcm`, - * `aes-192-gcm`, and - * `aes-256-gcm` (current standard when `on` is set). - -This property cannot be changed once it has been set. - -|[[zfs-term-keystatus]]keystatus -a|Indicates whether an encryption key has been successfully loaded. Possible values are `none`, `available`, and `unavailable`. - -|[[zfs-term-keylocation]]keylocation -a|Specifies the location from which to load the encryption key. Possible values are: - -* `prompt`, -* `file://path/to/file`, -* `http://some.address`, and -* `https://other.address` - -|[[zfs-term-pbkdf2iters]]pbkdf2iters -a|The number of iterations used when deriving an encryption key from a passphrase. This forces an attacker to perform a large number of computationally expensive hash operations. As computing power increases, this value should also be increased from its current default of 350000. -|=== - -[[zfs-unload-encryption-key]] -=== Unloading the encryption key - -Protecting the data stored in an encrypted dataset requires two steps: first unmount the dataset, then unload the encryption key from memory. -This distinction is important. -An unmounted dataset is not protected if its encryption key remains loaded in memory. -Always run `zfs unload-key` to protect the data. -To access the dataset again, load the key and provide the passphrase as described in the crossref:zfs-load-encryption-key[zfs-load-encryption-key, loading the encryption key] section. -ZFS prevents `zfs unload-key` from running while the dataset is still mounted. - -[source,shell] -.... -# zfs unmount zroot/secretdata -# zfs unload-key zroot/secretdata -.... - -Running `zfs unload-key` multiple times results in an error indicating that the key has already been unloaded. - -[[zfs-load-encryption-key]] -=== Loading the encryption key - -Before an encrypted dataset can be used like any other dataset, its encryption key must be loaded and the passphrase provided. -At this point, the `keystatus` property is still set to `unavailable`, and mounting the dataset fails because the key has not yet been loaded: - -[source,shell] -.... -# zfs get keystatus zroot/secretdata -NAME PROPERTY VALUE SOURCE -zroot/secretdata keystatus unavailable - -# zfs mount zroot/secretdata -cannot mount 'zroot/secretdata': encryption key not loaded -.... - -This indicates that the dataset is encrypted and requires an encryption key. -To mount the dataset, run `zfs load-key` and provide the passphrase when prompted: - -[source,shell] -.... -# zfs load-key zroot/secretdata -Enter passphrase for 'zroot/secretdata': -# zfs get keystatus zroot/secretdata -NAME PROPERTY VALUE SOURCE -zroot/secretdata keystatus available - -.... - -Next, mount the dataset to make it accessible through the filesystem hierarchy: - -[source,shell] -.... -# zfs mount zroot/secretdata -# mount|grep secretdata -zroot/secretdata on /secretdata (zfs, local, noatime, nfsv4acls) -.... - -To load multiple encryption keys recursively, specify the `-r` option with `zfs load-key`. -If a key has already been loaded, ZFS reports this with an error message. - -[source,shell] -.... -# zfs load-key zroot/secretdata -Key load error: Key already loaded for 'zroot/secretdata'. -.... - -The `keystatus` property also confirms that the key has been loaded by reporting the value `available`. -To verify whether a passphrase is correct without loading the key, use the `-n` option to perform a dry run. - -[[zfs-change-encryption-key]] -=== Changing the encryption key - -ZFS also supports changing encryption keys, such as replacing a passphrase. -This operation does not require re-encrypting the dataset. -Run the following command to change the encryption passphrase: - -[source,shell] -.... -# zfs change-key zroot/secretdata -Enter new passphrase for 'zroot/secretdata': -Re-enter new passphrase for 'zroot/secretdata': -.... - -Running `zfs change-key` requires the current key to be loaded. If it is not, -ZFS still prompts for the new key but then displays a warning that the current key has not been loaded. - -The zfs change-key command can also modify the `keylocation`, `keyformat`, and `pbkdf2iters` properties by specifying them with the `-o` option. -Running `zfs change-key` on an encrypted child dataset makes it an encryption root if it is not one already. -To prevent this behavior and continue inheriting the parent's key, specify the `-i` option. - -Be aware that changing the encryption key of a parent dataset also changes the key for child datasets that inherit it. -Consequently, those child datasets continue to use the parent's encryption key. -If a child dataset should use a different key, either specify a different `keyformat` when creating it or run `zfs change-key` on the child dataset. -Doing so creates a new encryption root for the child and breaks its encryption inheritance from the parent. - -ZFS clones of an encrypted dataset always use the encryption key of their origin dataset. -As a result, the `keystatus`, `keyformat`, `keylocation`, and `pbkdf2iters` properties are not inherited like other dataset properties. -Instead, they use the values defined by the encryption root. -To determine the encryption root, use the read-only `encryptionroot` property. - -If an attacker compromises an encryption key, changing the passphrase with `zfs change-key` does not necessarily protect existing or newly written data. -New data continues to be encrypted with the same master key as the existing data. -If an attacker obtains both a user key and its corresponding wrapped master key, running `zfs change-key` does not overwrite the previous master key on disk. -As a result, the old master key may remain available for forensic analysis for an indeterminate period. - -If a master key has been compromised, the preferred solution is to securely erase the underlying storage devices and create a new pool. -Afterwards, restore the data from a backup to the new pool. -Alternatively, create a new encrypted dataset, migrate the data using `zfs send` and `zfs receive`, and then run `zpool trim --secure` to erase the freed space. -If the underlying hardware does not support secure TRIM, use `zpool initialize` instead. - -[[zfs-encrypted-send]] -=== Sending Encrypted Datasets - -ZFS replication is based on sending dataset snapshots, which can also be created from encrypted datasets. -The resulting snapshots remain encrypted. - -[source,shell] -.... -# zfs snapshot zroot/secretdata@snap1 -.... - -In addition to crossref:zfs-load-encryption-key[zfs-send-ssh, sending encrypted backups over SSH], using the `-w` (raw) option with `zfs send` transfers the encrypted data blocks to the target pool. -A raw send provides several advantages: - -* the receiving system never sees plaintext data. -* the receiving system does not require the passphrase since no decryption takes place. -* Backups can be sent without first loading the encryption key. -* an untrusted system can receive the encrypted data but cannot decrypt or modify it without the encryption key. - -To send the snapshot created above as a raw stream to the dataset `secret` in the pool `backup`, enter the following command: - -[source,shell] -.... -# zfs send -w zroot/secretdata@snap1 | zfs recv backup/secret -.... - -Without the `-w` option, `zfs send` transmits the data in unencrypted form. -The receiving system may then re-encrypt the data using a different key. -However, doing so prevents future incremental raw sends to that destination. - [[zfs-advanced]] == Advanced Topicshome | help
Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a3ece85.43600.18d51852>
