Encrypted images¶
For privacy reasons you sometimes want to use a disk encryption for the root filesystem. The images support this by using LUKS2 encryption.
To enable encryption, define the variable use_luks
, like make
... DEFINES="use_luks=true"
, or add use_luks: true
to the mpp-vars
section in your image.
When encryption is enabled, the root filesystem partition will be made a dm-crypt partition, using LVM2, and the right dependencies is added to the system to allow this to be unlocked.
The passphrase used for the initial encryption is taken from the
luks_passphrase
variable, which defaults to password
. However,
once the systems is booted, other passphrases can be added and
this one removed as required.
Automatic unlocking with initial passphrase¶
By default, the passphrase must be entered interactively from the
initrd during boot, which is not always possible. So there is support
for automatic unlocking. Enable this by setting the variable
luks_auto_unlock
to true.
If enabled, the initial passphrase (whatever was in the
luks_passphrase
variable) will be copied into the root filesystem as
/usr/.auto-unlock-key
, and then propagated into the initrd. During
boot, this key will be automatically used to unlock the root partition.
It should be noted that this setup on its own is not secure, as the password is visible in plaintext in the initrd which is not encrypted. This feature is meant as an initial step to have an encrypted filesystem that can boot non-interactively from which point you can later add a new secure passphrase.
Hardware TPM based unlocking¶
One option when it comes to unlocking root filesytem is to use the hardware in modern CPUs called the TPM. This allows using tokens specific to the individual hardware instance to unlock the device.
The idea here is that we build an image that is encrypted with a throwaway passphrase, and on the first boot we unlock it using that. Then we run some code that enrolls a hardware-specific key and removes the throwaways passphrase. Then on further boots, the TPM automatically unlocks the filesystem with a key that nobody knows (or can know).
This can be achived using the clevis-luks support in cs9.
Note:
osbuild requires additional packages to support org.osbuild.luks2 and org.osbuild.lvm2
sudo dnf install osbuild-luks2 osbuild-lvm2
To demonstrate how this works, there is an example image called
encrypted.mpp.yml'. In order to try this you need a hardware TPM,
which is possible with qemu, which can be enabled with the
runvm
–tpm2` switch.
To test this, try:
$ make cs9-qemu-encrypted-regular.x86_64.qcow2
$ ./runvm --tpm2 cs9-qemu-encrypted-regular.x86_64.qcow2
This will boot the VM first, auto-unlock using the initial passphrase, and then replace the key with a TPM based one. Once booted you can verify this:
# cryptsetup luksDump /dev/vda3
LUKS header information
Version: 2
Epoch: 6
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: aedd1eef-f24e-425e-a9f3-bb5a1c996a95
Label: luks-rootfs
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
1: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: pbkdf2
Hash: sha256
Iterations: 1000
Salt: 16 1a 97 25 40 5c 13 df 98 03 e4 a9 7f c4 f1 d8
51 44 09 15 ec 5d 8a 8b ab 85 c3 4b a1 d1 29 cc
AF stripes: 4000
AF hash: sha256
Area offset:290816 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
0: clevis
Keyslot: 1
Digests:
0: pbkdf2
Hash: sha256
Iterations: 1000
Salt: 22 2f cc 82 7c 18 d6 27 59 c3 af 70 b0 9a 7e d0
c9 e2 f3 f8 a0 cc a5 a5 38 5e ed 27 3a 7e 07 99
Digest: cd b3 89 8b 33 d9 7b db 9f 73 36 bb 19 28 cc 1b
a4 f1 45 8f c7 7b 19 80 a5 64 62 eb 12 b9 c8 cc
Which is different from what you would see normally:
# cryptsetup luksDump /dev/vda3
LUKS header information
Version: 2
Epoch: 3
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
UUID: aedd1eef-f24e-425e-a9f3-bb5a1c996a95
Label: luks-rootfs
Subsystem: (no subsystem)
Flags: (no flags)
Data segments:
0: crypt
offset: 16777216 [bytes]
length: (whole device)
cipher: aes-xts-plain64
sector: 512 [bytes]
Keyslots:
0: luks2
Key: 512 bits
Priority: normal
Cipher: aes-xts-plain64
Cipher key: 512 bits
PBKDF: argon2i
Time cost: 4
Memory: 32
Threads: 1
Salt: 31 e4 a1 3b df 08 aa d9 71 1c be 26 7c 45 15 0b
22 69 51 35 a4 58 04 09 2b 96 a8 91 c1 3d c6 4e
AF stripes: 4000
AF hash: sha256
Area offset:32768 [bytes]
Area length:258048 [bytes]
Digest ID: 0
Tokens:
Digests:
0: pbkdf2
Hash: sha256
Iterations: 1000
Salt: f7 09 53 c5 8b 7e e6 59 31 ec d7 4e bd ce 81 c1
f6 42 7b ba e4 dc 1e 16 64 e8 67 69 91 a0 9a 81
Digest: bc 5e f2 21 41 6a 7c 10 d6 2f b1 2e 28 01 e0 e9
67 85 53 00 43 49 03 69 a7 39 83 2c a5 55 51 2d
Note how the earlier example uses keyslot 1 instead of keyslot 0 and how there is a token for keyslot 1, and how there is no keyslot 0 anymore.
If at this point you reboot the vm, it will unlock the root filesystem using this token.