DEV Community

Achyuta Das
Achyuta Das

Posted on • Edited on

Full Disk Encryption (FDE) with Ubuntu Autoinstall

🔍 Context

As system administrators and security-conscious developers, encrypting data at rest is a fundamental best practice—especially for laptops, servers in untrusted environments, or sensitive workloads. Full Disk Encryption (FDE) ensures that all data on the disk is encrypted, and can only be accessed after providing a unlocking key, thus safeguarding data even if physical access to the disk is obtained.

By leveraging cloud-init's autoinstall YAML, we can fully automate the provisioning process—including LUKS encryption, LVM setup, and embedding a drive unlocking key into the initramfs.

🛠️ Implementation Overview

Here’s a high-level overview of what we will be doing:

  • Use LUKS to encrypt the main data partition.
  • Inside the encrypted container, create a LVM volume group to manage the logical volumes.
  • Generate a random key file early in the installation process, which is used to unlock the encrypted volume.
  • Ensured this key is securely copied into the target system and embedded into the initramfs so the system can boot without manual passphrase entry.

đź§Ş Workflow

  • Early Commands: Generate a 4KB random keyfile (root.key) under /etc/cryptsetup-keys.d, with appropriate permissions.
early-commands:
    - mkdir -p /etc/cryptsetup-keys.d
    - dd if=/dev/urandom of=/etc/cryptsetup-keys.d/root.key bs=1024 count=4
    - chmod 600 /etc/cryptsetup-keys.d/root.key
Enter fullscreen mode Exit fullscreen mode
  • Storage config: The disk was partitioned into:
    • An EFI system partition (/boot/efi)
    • An unencrypted /boot partition
    • A third partition for encrypted data.

Create a LUKS-encrypted volume on the third partition using the key file. On top of that, create a LVM volume group (VolGroup) and allocate a root logical volume (lv_root).

  storage:
    config:
      - ptable: gpt
        match:
          size: smallest
        wipe: superblock-recursive
        preserve: false
        name: ''
        grub_device: true
        id: disk-sda
        type: disk

      - device: disk-sda
        size: 536870912  # 512MB
        wipe: superblock
        flag: boot
        number: 1
        preserve: false
        grub_device: true
        id: partition-0
        type: partition

      - fstype: fat32
        volume: partition-0
        preserve: false
        id: format-0
        type: format

      - path: /boot/efi
        device: format-0
        id: mount-0
        type: mount

      - device: disk-sda
        size: 1073741824  # 1GB
        wipe: superblock
        number: 2
        preserve: false
        grub_device: false
        id: partition-1
        type: partition

      - fstype: ext4
        volume: partition-1
        preserve: false
        id: format-1
        type: format

      - path: /boot
        device: format-1
        id: mount-1
        type: mount

      - device: disk-sda
        size: -1
        wipe: superblock
        number: 3
        preserve: false
        grub_device: false
        id: partition-2
        type: partition

      - name: cryptlvm
        volume: partition-2
        preserve: false
        keyfile: /etc/cryptsetup-keys.d/root.key
        id: dm_crypt-lvm
        type: dm_crypt

      - name: VolGroup
        devices:
          - dm_crypt-lvm
        preserve: false
        id: lvm_volgroup-0
        type: lvm_volgroup

      - name: lv_root
        volgroup: lvm_volgroup-0
        size: -1
        wipe: superblock
        preserve: false
        id: lvm_partition-root
        type: lvm_partition

      - fstype: ext4
        volume: lvm_partition-root
        preserve: false
        id: format-root
        type: format

      - path: /
        device: format-root
        id: mount-root
        type: mount
Enter fullscreen mode Exit fullscreen mode
  • Late Commands:
    • Extract the UUID of the LUKS volume and copy the key file into /etc/cryptsetup-keys.d inside the target filesystem, renaming it to match the UUID.
    • Update /etc/crypttab to ensure the system knows how to unlock the encrypted volume during boot.
    • Add the appropriate hook configuration for cryptsetup-initramfs and rebuilt the initramfs so the key file will be included and accessible early in the boot process.
  late-commands:
    - mkdir -p /target/etc/cryptsetup-keys.d /target/etc/cryptsetup-initramfs
    - bash -c '
        luks_uuid=$(blkid -t TYPE=crypto_LUKS -s UUID -o value);
        cp /etc/cryptsetup-keys.d/root.key "/target/etc/cryptsetup-keys.d/${luks_uuid}.key";
        chmod 600 "/target/etc/cryptsetup-keys.d/${luks_uuid}.key";
        echo "dm_crypt-lvm UUID=${luks_uuid} /etc/cryptsetup-keys.d/${luks_uuid}.key luks" > /target/etc/crypttab;
        echo "KEYFILE_PATTERN=/etc/cryptsetup-keys.d/*.key" >> /target/etc/cryptsetup-initramfs/conf-hook;
      '
    - curtin in-target --target=/target -- update-initramfs -c -k all
Enter fullscreen mode Exit fullscreen mode

âś… Conclusion

With this setup, we successfully created a secure, automated Ubuntu installation with full disk encryption using LUKS and LVM. The system boots without requiring a passphrase, thanks to the securely handled key file integrated into the initramfs.
This makes the setup highly suitable for hands-off provisioning in secure environments.

Looking ahead, this foundation can be extended to further enhance security by:

  • Binding the LUKS key to a TPM after installation to enable secure, passphrase-free unlocks based on hardware identity.
  • Integrating with Secure Boot and measured boot for a trusted boot chain.

Top comments (0)