How to manually set up self-encrypted drives (SED)

Hello Everyone.

New user here. I would like to set up a pair on NVME SSDs in RAID-1 with drive based encryption. They do support Opal 2.0.
TrueNAS has, somewhat recently, gated the GUI-based setup to enterprise users. The documentation says:

UI management of Self-Encrypting Drives (SED) is an Enterprise-licensed feature in TrueNAS 25.04 (and later). SED configuration options are not visible in the TrueNAS Community Edition. Community users wishing to implement SEDs can continue to do so using the command line sedutil-cli utility.

Note: Additional changes to SED management options in the TrueNAS UI ahead of the 25.04.0 release version, with documentation updates to follow.

Question: Does anyone know how to manually configure this? Is there a tutorial somewhere? Thanks!

1 Like

Out of interest why wouldn’t you use ZFS encryption? Just curious.

This pool is for running VMs. Hardware based encryption is more performant.
I am aware of the pros and cons of hardware vs software based encryption.

I would like this thread to remain on topic of how to configure SEDs in TrueNAS community edition.

1 Like

Sure. There were indeed some tutorials, but trying to simplify:

Step 0: before you install your drive, record the PSID (Physical Security ID) number on the drive’s label (sometimes/typically, you need it to initialize the drive, and also if one day, you ever need it (to reset/erase a lost password drive), you won’t have to take your machine apart to get it.)

Then, assuming properly identifying your SED drive, e.g. via:
sedutil-cli --scan
and then a few environment variables set:
export PSID_NO_DASHES=<your_PSID_from_the_drive_label>
export SEDPassword=<your_password> # probably keep long/random, but avoid symbols
export SEDDevice=/dev/<your_SED_drive>

Step 1: “Factory reset” the drive (assume this will erase the drive – you should be starting with a empty drive) with this command:
sedutil-cli --PSIDrevert $PSID_NO_DASHES $SEDDevice
Step 2: Initialize the drive with a password with this command:
sedutil-cli --initialsetup $SEDPassword $SEDDevice
Step 3: Enable the “locking range” - (0 is the whole drive)
sedutil-cli --enablelockingrange 0 $SEDPassword $SEDDevice

Now, your drive is setup with your chosen password, for full drive encryption. As such, you can now LOCK and UNLOCK the drive – by setting the locking range 0 as either “lk” (lock) or “rw” (read/write):
sedutil-cli --setlockingrange 0 lk $SEDPassword $SEDDevice
sedutil-cli --setlockingrange 0 rw $SEDPassword $SEDDevice

As you Lock/Unlock, you can see the status of your drives locking with this command:
sedutil-cli --query $SEDDevice |grep "$SEDDevice\|Lock"
which will show either
Locked = Y
or
Locked = N

Of course, by design, at power off/power interuption, it will automatically lock, so you’ll really only need the unlock command:
sedutil-cli --setlockingrange 0 rw $SEDPassword $SEDDevice

However, “implementing SEDs with the sedutil-cli utility” isn’t much of an elegant solution.

There currently isn’t a UI option to set the application environment to not start automatically:

So, when you boot up, and the app service/Docker looks for its drive, the drive will still be encrypted, thus missing, and the service start will bomb out, e.g.:

So, you’ll have to manually unlock your drives, then restart the app service (hopefully) to get everything up and running. I suppose a systemctl disable docker.service is possible here, but I haven’t experimented this far yet. Needless to say, the UX here isn’t the typical TrueNAS ease of use.

What I have seen so far is that Electric Eel still supports the UI adding the SED passwords, and when I did a test upgrade of a system already set to use SEDs to Fangtooth, the SED passwords were still in the UI – so I’m not sure the functionality is really “disabled”.
Likewise, the config database has table/fields for:
storage_disk | disk_password
and
system_advanced | adv_sed_password
and I’m not sure if those got set/config restored in Fangtooth+, if the SED passwords would return to the UI as well. Again, I haven’t experimented this far yet.
Also, per the Jira ticket initiating the SED change, supposedly the “api will still be allowed so this is not removing the feature from the community”, although I’m not sure what that means. Maybe there is still a cli/api way to set
storage_disk | disk_password
and/or
system_advanced | adv_sed_password
… which will also keep the functionality.

So far, I’m just stuck on Electric Eel over this, which is sad, as I’d like to try out Instances. But, in the meantime, the Docker apps in Electric Eel will keep me busy.

Overall, I think nerfing SED was a mistake, and I hope for its reversion. There is a lot of unwarranted bias again SEDs, but even LUKS/Cryptsetup, with 2.7.0, now supports Opal – despite some initial “this will never happen” – so the biases seem to be dying. Even the TrueNAS Jira “issues” related to SEDs seemed unfair, namely dinging SEDs for not being fault tolerant to sketchy power (e.g., NAS-129366, NAS-132518), which is a feature not a bug. Sketchy power is a potential security event – it shouldn’t be tolerated for convenience/fault resilience.

I’m not sure about the “sharp edges” alluded to in NAS-133442, but if it means a power loss locks an SED, or abusing your system by repeatedly turning it off and on again has erratic results, I’d close those tickets with “works as designed”.

1 Like

So, after playing with this a bit, and falling into a crash course in working with the API, I can now attest to the fact that setting SED passwords in the TrueNAS middleware via the API is actually pretty simple – rendering the UI change for SEDs, IMO, not a big deal.

Setting system_advanced | adv_sed_password – i.e. the Global SED password – via the API is as simple as, dropping to a shell, and using these commands:

midclt call system.advanced.sed_global_password_is_set
midclt call system.advanced.sed_global_password
midclt call system.advanced.update '{"sed_passwd": "<your_SED_password_string>"}' |jq

The first command returns true/false if a SED global password is set.
The second command returns the set SED global password, if it exists.
The third command will set the SED global password (to the string you put in place of <your_SED_password_string>).
Once set, you can check it with the second command.

Setting individual disk SED passwords, is only slightly more complex – because you have to call the command with a ‘disk identifier’ (NOT simply the disk name, like nmve0, sda, etc.) that you must collect with an additional step. Essentially, the below command at the shell will set an individual drive’s SED password:

midclt call disk.update "<your_disk_identifer>" '{"passwd": "<your_SED_password_string>"}'

… with the disk identifier taking a form like:
{serial_lunid}JQF4XMMRF5TT726_3d84f39adff29c457

You can collect the appropriate identifier for your SED drives thusly:

First, get the names of your SED (Opal “2”, Enterprise “E”) drives with
sedutil-cli --scan, e.g.:

root@TrueNAS[~]# sedutil-cli --scan
Scanning for Opal compliant disks
/dev/nvme0  2      Samsung SSD 970 EVO Plus 2TB
/dev/sda   No
/dev/sdb   No
/dev/sdc    2      Samsung SSD 870 EVO 500GB 
/dev/sdd   No

So, in this example, I’m looking for the disk identifiers for nvme0 and sdc. Once I know that, I can query disk information for those drives from the command line like this:

midclt call disk.query \
        '[["name","~","nvme0|sdc"]]' \
        '{  "extra":{"pools":true,"passwords":true},
            "select":["pool","name","identifier","subsystem","bus","type","model","serial","passwd"],
            "order_by":["bus","name"]
         }' \
|jq

(For any who need the explanation, the second line is a regex query filter putting the targeted disk names delimited by a pipe character, as regex match alterations – so you would modify for the particular needs of your own disk collection – e.g., “nvme0|sdc”, “nvme0|nvme1|sda|sdb”, etc. )

This will output formatted JSON of your SED drive details, giving an easy read of the “identifier” to use for the individual disk SED password setting command:

midclt call disk.update "<your_disk_identifer>" '{"passwd": "<your_SED_password_string>"}'

Of course, once set, you can repeat the earlier disk.query command and see the password in the individual drives details now that it’s set.

2 Likes

Thank you very much for looking into this.
I wasn’t super detailed in my initial question, but you are correct that this is not just a matter of the single commands to encrypt and decrypt the drive.

Important questions are:

  1. Where and how is PWD stored when the drives are unlocked.
  2. How does the system behave when the drives are encrypted.

Actually these questions are not specific to SED drives, They are applicable to ZFS encrypted ones too. I feel there should be a clean way to provide the PWD, unlock the drives and start the related services.

1 Like

When you download a TrueNAS config, with the seed option, you get a tar file with a:
freenas-v1.db
and a
pwenc_secret
file.

The *.db file is an SQLLite database that has these SED related values:
storage_disk | disk_password
and
system_advanced | adv_sed_password

e.g.:


and

The SED password field in the database is encrypted – I’d assume with the pwenc_secret file content. I’d likewise guess that all of these config items are stored somewhere on the boot_pool, since they boot up and unlock without user intervention – I’d assume the same goes for the ZFS encryption as well.

That is, I’d guess that the decryption keys are stored in cipher-text on the boot partition, along with the secret that decrypts the cipher-text. This is probably a security model that assume a data center with physical security over the host (protecting the boot_pool), and the encryption on the data drives are more for assuring data destruction at drive retirement, or in the rare event of data drives being stolen.

In a different model, where you couldn’t assure physical security (or where authorities/hostiles/spies might physically seize/covertly access your equipment, you’d probably want unlocking keys not stored on disk nor stored in memory – but that compromises ease-of-use and fault-tolerance/uptime.

I’m kind of interested in playing with the Opal support in LUKS 2.7.0+, which doesn’t yet seem to be in TrueNAS:

root@TrueNAS[~]# midclt call system.info | jq '.version'
"25.04.1"

root@TrueNAS[~]# cryptsetup --version
cryptsetup 2.6.1 flags: UDEV BLKID KEYRING KERNEL_CAPI

and see if I can get TrueNAS running off a boot_pool enclosed in a LUKS partition that just does Opal pass-through, and prompts for a password (and/or other authenticators, e.g., yubikey, fingerprint, etc.) at boot up before unlocking the boot drive.

Moreover, if enclosing a ZFS partition in a LUKS Opal structure doesn’t have any impact on ZFS operations, once the drive/partition is unlocked, it might even be a better approach for TrueNAS to do SED – rather than rolling their own solution with sedutil-cli under the hood, they could just rely upon the upstream LUKS SED solution. Just spitballing here though.