Encrypting the Rootfs#

These procedures generate, flash, and boot a Jetson device with an encrypted root file system (rootfs). The same tooling covers internal (eMMC) and external (NVMe) rootfs, the UDA-only variant, and the initrd-level customization required to unlock additional encrypted file systems at boot.

Creating an Encrypted Rootfs on the Host#

The rootfs is generated on the host by l4t_initrd_flash.sh. The following diagram shows the inputs (in green), the utilities used to generate it (in gray), and the output (in blue).

How to Create an Encrypted Rootfs on the Host

The input has two parts: the plain key file of the EKB key used for disk encryption, and a raw rootfs image to be encrypted.

You must generate the rootfs on a secure system; that is, a secure host computer equipped with a Hardware Security Module (HSM). The HSM is used for key generation and management to secure key assets and safe transport to the factory floor. This process is necessary to ensure that the keys cannot be leaked to an unsecure system on the production line. l4t_initrd_flash.sh invokes two helper scripts to generate the passphrase and the disk images:

  • gen_luks_passphrase.py follows the same process as the hwkey-agent and luks-srv TAs to derive the LUKS key, and uses the key to generate the passphrase.

  • disk_encryption.sh outputs the disk images for the initrd, system_boot.img, and system_root_encrypted.img.

The Jetson Linux reference implementation generates only per-device encrypted disk images. Use it as a starting point to develop a script that is suited to your use case and production environment.

Flashing the encrypted rootfs on the host with l4t_initrd_flash.sh for Jetson AGX Orin and Jetson Thor requires an update of Linux_for_Tegra/bootloader/eks_<platform>.img.

  1. Decompress the OP-TEE source package and run example.sh in it to generate a test EKS image. (In a real production scenario, you must generate your own EKS image using your own keys.)

    $ cd optee/samples/hwkey-agent/host/tool/gen_ekb/
    # Take a look at example.sh; you must update all keys accordingly
    $ ./example.sh
    
  2. Copy the eks_<platform>.img generated by example.sh to the Linux_for_Tegra/bootloader folder and overwrite the eks_<platform>.img file.

    For details about EKS image generation, refer to Tool for EKB Generation in OP-TEE.

  3. Use l4t_initrd_flash.sh to generate and flash the encrypted rootfs:

    # The disk encryption key in the EKB partition:
    # This key is defined in example.sh too to generate the EKS image
    $ echo <disk_enc_key> > disk_enc.key
    $ sudo ROOTFS_ENC=1 ./l4t_initrd_flash.sh -i "./disk_enc.key" <board> <rootdev>
    
    • <board> is the value of $(BOARD) for your Jetson module and configuration, as shown in the table in the section Jetson Modules and Configurations in the topic Quick Start.

    • <rootdev> is the partition where the root file system is to be flashed.

The l4t_initrd_flash.sh command line option -i specifies the key to be used for disk encryption. The reference implementation described earlier uses the EKB key. For the sake of security, we recommend that you customize the script to use a different key source. The keys in the preceding example are only for reference and testing purposes, and you should not use them as given. When you change the key, change the EKS partition accordingly, and review the overall key and passphrase generation flow to ensure that everything works correctly.

Flashing an Encrypted Rootfs to an External Storage Device#

To flash an encrypted rootfs to an external storage device, use l4t_initrd_flash.sh (also known as “the initrd flashing tool”). See Flashing with initrd in Flashing Support for details.

The following example uses l4t_initrd_flash.sh to flash an encrypted rootfs to an NVMe SSD attached to a Jetson Orin NX series device:

$ cd Linux_for_Tegra
$ sudo ./l4t_initrd_flash.sh --no-flash jetson-orin-nano-devkit internal
$ sudo ROOTFS_ENC=1 ./l4t_initrd_flash.sh --no-flash -S 16GiB \
        --external-only --append -i ./disk_enc.key jetson-orin-nano-devkit external
$ sudo ./l4t_initrd_flash.sh --flash-only

For the Jetson AGX Thor developer kit, use commands similar to the following:

$ cd Linux_for_Tegra
$ sudo ROOTFS_ENC=1 ./l4t_initrd_flash.sh -i ./disk_enc.key \
        --no-flash jetson-agx-thor-devkit internal
$ sudo ./l4t_initrd_flash.sh --flash-only jetson-agx-thor-devkit internal

Tools and instructions for flashing an encrypted rootfs with initrd are in the directory Linux_for_Tegra/tools/kernel_flash/. For more detailed information, see README_initrd_flash.txt in that directory.

Enabling Disk Encryption Only for UDA#

To enable disk encryption only for the UDA partition, disable rootfs disk encryption.

To disable disk encryption on rootfs:

  1. In the layout configuration file, set the encrypted attribute of APP_ENC to false.

    For an example of a layout configuration, refer to Layout of an Encrypted Disk.

  2. To complete the process, complete the steps in Creating an Encrypted Rootfs on the Host.

Note

  • To enable disk encryption, set ROOTFS_ENC=1.

  • To enable or disable disk encryption for a partition, set the encrypted attribute of that partition in the layout configuration file.

Enhancing initrd to Unlock an Encrypted Rootfs#

To boot from an encrypted root file system, you need an initrd image that includes the necessary utilities (such as cryptsetup) and scripts to set up the root device after the kernel is initialized, but before the rest of the operating system is booted. The flashing images must contain the APP partition, which contains the /boot branch of the rootfs (unencrypted), and the APP_ENC partition, which contains the rest of the rootfs (encrypted).

The boot configuration must also do the following:

  • Specify the LUKS device UUID—the UUID of the encrypted LUKS container, as reported by blkid—in the bootarg kernel command line’s root parameter, rather than the GPT partition GUID (APPUUID or APP_ENC_UUID) defined in the partition layout. For details about obtaining this UUID, refer to the blkid example in Modifying initrd to Unlock Additional Encrypted File Systems.

  • List the encrypted root device in the initrd’s /etc/crypttab so that initrd can unlock it at boot. For the entry format and an example, refer to Modifying initrd to Unlock Additional Encrypted File Systems.

  • List the /boot directory on the APP partition in the rootfs fstab so that the automount process can mount it at boot time.

The init script in the initrd uses the following steps to check the encrypted root device, unlock it, and mount it:

  1. Verify that the root parameter specifies the same device as the root device setting in /etc/crypttab.

  2. Verify that the root device is a LUKS device.

  3. Unlock the encrypted root device with the per-device unique passphrase.

  4. Mount the root device.

  5. Command the luks-srv TA not to respond to further passphrase requests until reboot.

Modifying initrd to Unlock Additional Encrypted File Systems#

The file /etc/crypttab, kept in initrd, describes encrypted block devices that are set up during system boot. Each line of this file has the following form:

<volume-name> UUID=<uuid>
  • <volume-name> is the name of a volume in which decrypted data is to be placed. Its block device is set up in /dev/mapper/. <volume-name> must be unique across all lines in the file.

  • <uuid> is the UUID of the underlying block device containing encrypted data.

The following are two examples of entries in /etc/crypttab:

crypt_root UUID=b5600ed6-69e7-42b8-bee3-ecfdd12649d1
crypt_UDA UUID=cf6fa01d-1127-4612-9992-2f6db77385e0

If your device has several encrypted file systems, you must add a line to /etc/crypttab for each one that you want the bootloader to unlock.

The following example demonstrates how to unlock an encrypted file system:

  1. To find the UUID of the encrypted file system, enter the following command:

    $ sudo blkid | grep TYPE="crypto_LUKS"
    

    For each encrypted disk, this command displays a line of output that includes the disk’s UUID, similar to the following example:

    /dev/mmcblk0p43: UUID="5096aa4d-6590-429b-9295-a1fe041b8fa3"
    TYPE="crypto_LUKS" PARTLABEL="UDA"
    PARTUUID="2b23da7f-2f18-44bf-9e1d-6e3a3a39ad21"
    
  2. Unpack the initrd. For instructions, refer to Modifying Jetson RAM Disk in Flashing Support.

  3. For each encrypted file system that you want to unlock during subsequent reboots, add a line to /etc/crypttab that specifies the UUID of the file system to be unlocked, as in the following example:

    crypt_fs UUID="5096aa4d-6590-429b-9295-a1fe041b8fa3"
    
  4. Repackage the initrd and store it in /boot, replacing the original initrd.

  5. Create a subdirectory in /mnt in which initrd can mount each unlocked file system during the initialization process. For simplicity, we recommend giving each subdirectory the same name as the volume to be mounted there. For the volume in the preceding /etc/crypttab example, the subdirectory would be named crypt_fs:

    $ mkdir -p /mnt/crypt_fs
    

The bootloader unlocks the encrypted file system at each subsequent reboot.