This is about Network-Bound Disk Encryption (NBDE) not to be confused
of course with NBD! NBDE is where you use disk encryption in your
virtual machines. But instead of having to type a passphrase when the
guest boots, there is a network server which gives out tokens, so as
long as the guest is booted from the trusted network it is able to
boot unattended.
In RHEL[1] we have three pieces of software which help here:
- Clevis: Installed in the guest, it replaces the normal askpass
script with one which goes to the server to get the decryption
token.
- Tang: This is the server component, ie. it must always be running
on the trusted network so your guests can boot unattended.
- JOSE: Something something JSON encryption. Does some JSON
reformatting and is otherwise very opaque.
A disk from a VM which is using LUKS + NBDE will have a Clevis
keyslot, shown in luksDump output:
# cryptsetup luksDump /dev/sda2
...
Tokens:
0: clevis
Keyslot: 1
It will also usually have one or more regular keyslots, since a guest
which uses NBDE can also be booted disconnected from the trusted
network using a regular passphrase at the keyboard.
There's an obscure sequence of commands which can be used (when on the
trusted network of course) to unlock the disk:
Clevis token ID, not keyslot
|
V
# cryptsetup token export --token-id 0 /dev/sda2
{"type":"clevis","keyslots":["1"],"jwe":{"ciphertext":<....>,"encrypted_key":"","iv":<....>,"protected":<....>}}
We then use the JOSE tool to extract the "jwe" field alone. I'm not
clear if JOSE is necessary here, or we could use any other JSON tool.
From casual inspection it appears all this is doing is taking the
"jwe" field and reformatting it as a top-level JSON object in the
output:
# jose fmt -j- -Og jwe -o- < /tmp/token.json
{"ciphertext":"CIPHERTEXT",
"encrypted_key":"",
"iv":"IV",
"protected":"PROTECTED\n"}
I've formatted the output, but in reality it's all in one very long
line of JSON. For me, encrypted_key field was empty, the other fields
had long ASCII strings in some kind of unknown (but printable)
encoding.
The next step takes the four fields and concatenates them with dots:
# jose fmt -j- -Og jwe -o- < /tmp/token | jose jwe fmt -i- -c
PROTECTED..IV.CIPHERTEXT
It's possible that the double dot contains the empty encrypted_key
field. The final string is about 1300 characters long, but printable.
We can use this to get the decryption key. Note networking must be
available for this to work:
# jose fmt -j- -Og jwe -o- < /tmp/token | jose jwe fmt -i- -c > /tmp/key
# clevis decrypt < /tmp/key
<-- prints a plaintext ASCII key here
# cryptsetup open --type luks /dev/sda2 vol
Enter passphrase for /dev/sda2: <-- type the ASCII key here
(I guess there is a way to automatically feed the key from
clevis-decrypt to cryptsetup)
This will unlock the disk.
To integrate this into libguestfs, we will probably need to carry out
the following steps:
(a) Add clevis and jose to the packagelist.
(b) In programs like virt-v2v that want to use NBDE:
(b-1) Increase the memory available to the appliance, see:
https://gitlab.com/cryptsetup/cryptsetup/issues/488
(b-2) Enable network, obviously necessary for NBDE.
(c) Decide how we are going to automate the clevis steps above. Do we
integrate this with the existing common/options/decrypt.c code? Or do
we change appliance/init so that it attempts these steps automatically
if clevis is present, if there are encrypted disks and if the network
is up?
Rich.
[1] RHEL and Fedora, but it's broken at the moment in Fedora:
https://bugzilla.redhat.com/show_bug.cgi?id=1628258
--
Richard Jones, Virtualization Group, Red Hat
http://people.redhat.com/~rjones
Read my programming and virtualization blog:
http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v