How to create an encrypted secondary storage to lock/encrypt individual qubes

QubesOS 4.2.4

What:
Using a second hard drive as an encrypted secondary storage to host qubes which can only be accessed when the storage is unlocked.
In my example I create two different encrypted LMV storage areas with each an own password.

Why:

  1. Making use of a second hard drive to add new storage space.
  2. Having the ability to lock whole qubes.
  3. Adding an additional layer of encryption.

For example you use QubesOS as your main OS but you live with family (parents, partner, kids etc.) and want to lock some stuff away just to be safe… Or another example you travel a lot and work in trains, cafes, hotels etc. and even when you are careful maybe someone gets a look at your password or snatches your unlocked laptop. You should anyways protect your data with additional measures but why not keep part of the hard drive with whole qubes encrypted when you don’t need then at this moment?

Note: A compromised dom0 can expose passwords. Therefore keep dom0 secure.

This is a step-by-step guide based on secondary-storage with added encryption.

How to:

Do all these steps in dom0.

Step 1: Double check if you pick the right hard drive with:

lsblk -o NAME,SIZE,TYPE,MOUNTPOINT

I use /dev/sdb in this example.

Step 2 (optional): Delete all data on that hard drive:

sudo dd if=/dev/zero of=/dev/sdb bs=1M status=progress

This step takes time. It is not essential and step 3 also overwrites the hard drive but does not erase the old data. However if you want to be diligent you can start with a clean disk.

Step 3: Partition the disk.
In my example I want to have one partition with 60% disk space and one with the other 40%.
Probably not necessary but I make sure the boot flag is off.

   sudo parted /dev/sdb -- \
     mklabel gpt \
     mkpart primary 1MiB 60% \
     mkpart primary 60% 100% \
     set 1 boot off set 2 boot off \
     print

We should now have “/dev/sdb1” and “/dev/sdb2”.

Step 4: Encrypt each partition with LUKS

I call the partitions “storage1” and “storage2”.
For each partition, pick a passphrase when prompted and then unlock each partition:

   # Partition 1 → “storage1”
   sudo cryptsetup luksFormat /dev/sdb1
   sudo cryptsetup open    /dev/sdb1 storage1

   # Partition 2 → “storage2”
   sudo cryptsetup luksFormat /dev/sdb2
   sudo cryptsetup open    /dev/sdb2 storage2

Step 5: Create LVM on top of the unlocked devices

Make Pvs:

sudo pvcreate /dev/mapper/storage1
sudo pvcreate /dev/mapper/storage2

Create two separate volume groups (here named “sec1” and “sec2”):

sudo vgcreate vg_sec1 /dev/mapper/storage1
sudo vgcreate vg_sec2 /dev/mapper/storage2

Step 6: Within each VG, carve out a thin-pool (here named “thinpool1” and “thinpool2”)

   sudo lvcreate -n thinpool1 --type thin-pool -l 100%FREE vg_sec1
   sudo lvcreate -n thinpool2 --type thin-pool -l 100%FREE vg_sec2

note:
I got the warning here: “Pool zeroing and 512.00 KiB large chunk size slows down thin provisioning. Consider disabling zeroing (-Zn) or using small chunk size (<512.00KiB)”
I continued with the default setting anyways. In my understanding zeroing is essential for security when you reuse disk space with different VMs. The old data is wiped (zeroing) by LVM before handing over the disk space to a VM. Otherwise a compromised VM might be able to recover old data from the hard drive. Maybe I am overly paranoid and maybe QubesOS takes additional steps to prevent data leakage from happening but I take the slow down for additional security anytime.
About the chunk size if you wanna run a lot of small VMs that might be worth considering but I left it like that.

Step 7. Tell QubesOS about your new pools

I call the pools “secondary1” and “secondary2”

   sudo qvm-pool --add secondary1 lvm_thin \
     -o volume_group=vg_sec1,thin_pool=thinpool1,revisions_to_keep=2

   sudo qvm-pool --add secondary2 lvm_thin \
     -o volume_group=vg_sec2,thin_pool=thinpool2,revisions_to_keep=2

You can list pools with qvm-pool –list

The pools are now available when you create a new qube or want to move a qube to a new storage area.

Unlocking storage:
In this example storage 1

sudo cryptsetup open /dev/sdb1 storage1

Locking storage 1:
Close all running qubes on this storage. Either manual or with:
qvm-shutdown --all --pool secondary1

It seems like even without running qube the mapping still prevents the storage from locking.
Deactivate the LVM layer backing the mapping:
sudo lvchange -an vg_sec1

You can also close the VG itself but it seems not necessary.
sudo vgchange -an vg_sec1

Then you can finally lock your storage with:
sudo cryptsetup close storage1

You can use a script if you want:

qvm-shutdown --all --pool secondary1
sudo lvchange -an vg_sec1
sudo vgchange -an vg_sec1
sudo cryptsetup close storage1

I’m not an expert with QubesOS but I still want to share this because maybe someone finds it helpful. And if someone find some weaknesses or improvements I am happy for some feedback!

4 Likes

Actually, this could be done using default lvm in qubes os, create a LUKS partition on a LVM volume for that, and apply the rest of your guide, should work without requiring an additional drive.

3 Likes

I dont understand this part:

  1. As you said, it’s already possible (and @solene says it’s unnecessary)
  2. There are other solutions to “lock” qubes
  3. It seems like it’s the main purpose of this guide, but what is the usecase here?

True thx for the advice! :slight_smile: well I had a second hard drive anyways…

  1. Well this was my personal motivation. As @solene absolutely correctly points out don’t need a second hard drive for it to work but I had it built in anyways and wanted to add it to QubesOS.
  2. That’s nice! Can you share some options? I saw this build suggested in a discussion in the forum and it fits my needs. But if there are better options I’m happy to learn!
  3. Well for excample you use QubesOS as your main OS but you life with family (parents, partner, kids etc.) and want to lock some stuff away just to be safe… Or another example you travel a lot and work in trains, cafes, hotels etc. and even when you are careful maybe someone gets a look at your pw or snatches your laptop. You should anyways protect your data with additional measures but why not keep part of the hard dive with whole qubes encrypted when you don’t need then at this moment?
    I’m not claiming this is the perfect way to do it but it works for me and maybe someone finds it helpful…
1 Like

Now I understand, thanks!

I don’t really lock my qubes but some of them won’t start if a certain condition is not provided (the check is made by a script in rc.local). You can also use a libxl hook. But in any situation, I won’t feel more safe, as you said:

Anyway, I was wrong? Locking the qubes is one of the goals of this guide. Maybe add the following to the guide, in order to make it more clear?

And thanks for sharing even if I won’t use this :slight_smile:

1 Like

Yes that’s a good idea to make it more clear :slight_smile: thx

1 Like