containerd doesn’t actually encrypt your container images on disk itself. Instead, it relies on the underlying filesystem or block device to provide encryption.

Here’s how you can make that happen:

Let’s say you’re running containerd on a Linux system. The most straightforward way to encrypt your container images at rest is by encrypting the entire storage device that containerd uses for its data. This is typically /var/lib/containerd.

The kernel module dm-crypt combined with LUKS (Linux Unified Key Setup) is the standard way to achieve this. You’ll be creating an encrypted block device and then mounting a filesystem on top of it, which will house your containerd data.

Setting Up LUKS Encryption

First, you need a dedicated block device. This could be a spare partition, a whole disk, or even a loop device backed by a file for testing. For this example, let’s assume you have a partition at /dev/sdb1.

  1. Create a LUKS container:

    sudo cryptsetup luksFormat /dev/sdb1
    

    This will prompt you to enter a passphrase twice. Choose a strong passphrase! This is the key to your encrypted data.

  2. Open the LUKS container:

    sudo cryptsetup luksOpen /dev/sdb1 encrypted_containerd_storage
    

    You’ll be prompted for the passphrase you just set. This creates a new block device at /dev/mapper/encrypted_containerd_storage.

  3. Format the new block device: Now, format this newly opened device with a filesystem like ext4 or xfs.

    sudo mkfs.ext4 /dev/mapper/encrypted_containerd_storage
    
  4. Mount the encrypted filesystem: Create a mount point and mount the filesystem.

    sudo mkdir /mnt/encrypted_containerd
    sudo mount /dev/mapper/encrypted_containerd_storage /mnt/encrypted_containerd
    

Configuring containerd to Use the Encrypted Storage

Now, you need to tell containerd to use this new, encrypted directory for its data.

  1. Stop containerd:

    sudo systemctl stop containerd
    
  2. Move existing data (if any): If you have existing container images, you’ll want to move them to the new location.

    sudo rsync -avP /var/lib/containerd/ /mnt/encrypted_containerd/
    

    Important: Ensure rsync completes successfully before proceeding.

  3. Update containerd’s configuration: The containerd configuration file is typically located at /etc/containerd/config.toml. You need to change the root directory. Find the [root] section and modify it:

    [root]
      path = "/mnt/encrypted_containerd"
      # ... other options
    

    If the [root] section doesn’t exist, you can add it.

  4. Automate mounting on boot: To ensure your encrypted storage is mounted every time the system boots, you need to add an entry to /etc/crypttab and /etc/fstab.

    • /etc/crypttab: This file tells the system how to set up encrypted devices. Add this line:

      encrypted_containerd_storage /dev/sdb1 /etc/cryptsetup-keys/containerd.key luks
      

      Note: For true automation without manual passphrase entry on boot, you’d typically use a key file. This example uses a key file for demonstration, but be extremely careful about securing this key file. A more secure approach for production might involve TPM-backed keys or manual passphrase entry.

      To create a key file (for testing, ensure it’s kept secure!):

      sudo mkdir /etc/cryptsetup-keys
      sudo dd if=/dev/urandom of=/etc/cryptsetup-keys/containerd.key bs=512 count=4
      sudo chmod 0400 /etc/cryptsetup-keys/containerd.key
      sudo cryptsetup luksAddKey /dev/sdb1 /etc/cryptsetup-keys/containerd.key
      

      You’ll be prompted for your LUKS passphrase to add the key.

    • /etc/fstab: This file tells the system how to mount filesystems. Add this line:

      /dev/mapper/encrypted_containerd_storage /var/lib/containerd ext4 defaults 0 2
      

      Self-correction: The previous step mounted to /mnt/encrypted_containerd. It’s more conventional to mount the final filesystem directly to /var/lib/containerd after the encrypted device is opened. Let’s adjust.

      Revised Steps:

      1. Create a LUKS container:

        sudo cryptsetup luksFormat /dev/sdb1
        

        Enter passphrase.

      2. Add a key file (secure it!):

        sudo mkdir /etc/cryptsetup-keys
        sudo dd if=/dev/urandom of=/etc/cryptsetup-keys/containerd.key bs=512 count=4
        sudo chmod 0400 /etc/cryptsetup-keys/containerd.key
        sudo cryptsetup luksAddKey /dev/sdb1 /etc/cryptsetup-keys/containerd.key
        

        Enter LUKS passphrase.

      3. Update /etc/crypttab:

        encrypted_containerd_storage /dev/sdb1 /etc/cryptsetup-keys/containerd.key luks
        
      4. Update /etc/fstab:

        /dev/mapper/encrypted_containerd_storage /var/lib/containerd ext4 defaults 0 2
        
      5. Stop containerd:

        sudo systemctl stop containerd
        
      6. Move existing data:

        sudo mv /var/lib/containerd/* /mnt/encrypted_containerd/ # Temporary mount point
        

        Wait, this is getting complicated. Let’s simplify the flow. The goal is for /var/lib/containerd to be the encrypted path.

      Let’s try this again, focusing on /var/lib/containerd as the final destination:

      1. Prepare a block device: /dev/sdb1 (or a file for testing: dd if=/dev/zero of=containerd.img bs=1G count=10)

      2. Format with LUKS:

        sudo cryptsetup luksFormat /dev/sdb1
        

        Enter passphrase.

      3. Create an encryption key file (optional but recommended for automation):

        sudo mkdir -p /etc/cryptsetup-keys
        sudo dd if=/dev/urandom of=/etc/cryptsetup-keys/containerd.key bs=512 count=4
        sudo chmod 0400 /etc/cryptsetup-keys/containerd.key
        sudo cryptsetup luksAddKey /dev/sdb1 /etc/cryptsetup-keys/containerd.key
        

        Enter LUKS passphrase.

      4. Add to /etc/crypttab:

        containerd_data UUID=$(blkid -s UUID -o value /dev/sdb1) /etc/cryptsetup-keys/containerd.key luks
        

        (Using UUID is more robust than device names)

      5. Add to /etc/fstab:

        /dev/mapper/containerd_data /var/lib/containerd ext4 defaults 0 2
        
      6. Stop containerd:

        sudo systemctl stop containerd
        
      7. Prepare the mount point:

        • If /var/lib/containerd already exists and has data, you need to move it before mounting the new encrypted volume.
        • If /var/lib/containerd is empty or doesn’t exist, you can proceed.
        • Let’s assume it has data and we need to move it temporarily.
        sudo mkdir /mnt/containerd_backup
        sudo mv /var/lib/containerd/* /mnt/containerd_backup/
        
      8. Mount the encrypted volume:

        sudo systemctl daemon-reload # Reload systemd units after crypttab changes
        sudo systemctl start systemd-cryptsetup@containerd_data.service # Manually open encrypted device
        sudo mount /var/lib/containerd # Mount the filesystem
        
      9. Restore data:

        sudo mv /mnt/containerd_backup/* /var/lib/containerd/
        sudo rmdir /mnt/containerd_backup # Clean up
        
      10. Update containerd config (if not using default): Ensure /etc/containerd/config.toml points to /var/lib/containerd for its root path. If you’re using the default, you don’t need to change this.

      11. Start containerd:

        sudo systemctl start containerd
        
      12. Reboot and verify: Reboot your system and check if containerd starts correctly and if your images are accessible.

        sudo systemctl status containerd
        sudo cryptsetup status containerd_data
        

This setup encrypts the block device containing your containerd images. When the system boots, systemd-cryptsetup (triggered by crypttab) will prompt for the passphrase (or use the key file if configured) to unlock the device, and then fstab will mount the decrypted filesystem at /var/lib/containerd. Any data written to /var/lib/containerd by containerd will be automatically encrypted by dm-crypt/LUKS before being written to disk.

The next error you’ll likely encounter is a "Permission denied" error when containerd tries to access its data directory if the LUKS volume isn’t unlocked or mounted correctly during system startup.

Want structured learning?

Take the full Containerd course →