Work is ongoing in nova to provide support for attaching virtual Trusted Platform Modules (vTPMs) to instances. The below guide demonstrates how you can go about testing this feature for yourself. This work was conducted on a Fedora 31 VM (with nested virt, though that’s not relevant) using DevStack master.
Initial Steps
We’re going to use DevStack on Fedora 31 to test this. Fedora 31 is necessary since Ubuntu 18.04 (Bionic) does not provide new enough versions of libvirt or QEMU, while Ubuntu 20.04 (Focal) is not supported by DevStack at the time of writing and was affected by a bug in barbican. With a Fedora 31 installation at the ready, let’s update and get DevStack:
$ sudo dnf upgrade -y
$ git clone https://opendev.org/openstack/devstack
$ cd devstack
The DevStack installation is pretty bog standard with the key differences being
that you need to enable the OpenStack Key Manager service, barbican, for
storing secrets along with the virt preview repo to get new versions of libvirt
and QEMU. Here’s a sample local.conf
, to be placed into the devstack
directory:
[[local|localrc]]
RECLONE=True
## Passwords
ADMIN_PASSWORD=password
DATABASE_PASSWORD=password
RABBIT_PASSWORD=password
HORIZON_PASSWORD=password
SERVICE_PASSWORD=password
SERVICE_TOKEN=no-token-password
## Additional plugins and configuration
enable_plugin barbican https://opendev.org/openstack/barbican
enable_service rabbit mysql key
ENABLE_FEDORA_VIRT_PREVIEW_REPO=true
There’s also a minor tweak necessary to work around pip 10 refusing to uninstall system-provided Python packages:
diff --git inc/python inc/python
index dd772960..63a3dc19 100644
--- inc/python
+++ inc/python
@@ -196,7 +196,7 @@ function pip_install {
no_proxy="${no_proxy:-}" \
PIP_FIND_LINKS=$PIP_FIND_LINKS \
SETUPTOOLS_SYS_PATH_TECHNIQUE=rewrite \
- $cmd_pip $upgrade \
+ $cmd_pip --ignore-installed $upgrade \
$@
result=$?
We also need to install the swtpm
and swtpm_setup
binaries. These are
provided in the Fedora repos (yay!):
$ sudo dnf install swtpm swtpm-tools
Finally, crudini
makes working with INI files a breeze. Let’s install that
too:
$ sudo dnf install crudini
With all this done, you can stack:
./stack.sh
Now go make a cup of tea. ☕
Configuring nova
With the stack (hopefully) complete, we need to configure nova appropriately.
This is a simple, single-node “can I boot an instance” test so we don’t need to
do too much. The key steps are to check out the correct code, given that it’s
not yet merged, add some nova.conf
configuration options and create a new
flavor. First up, let’s checkout the correct nova code. You can use the
checkout link from the Gerrit review for this purpose:
$ cd /opt/stack/nova
# checkout using the "Checkout" link in the "Download" dropdown on the review,
# which I'm not providing here since it won't age well
Now, let’s modify the nova.conf
file the nova-compute
service. We’ll use
crudini
for this:
$ crudini --set /etc/nova/nova-cpu.conf libvirt swtpm_enabled True
Let’s restart the various nova services to load both the correct code and the configuration changes:
$ sudo systemctl restart devstack@n-*
With everything restarted, we should be able to see the relevant
COMPUTE_SECURITY_TPM_*
traits reported by our sole compute node:
$ openstack --os-placement-api-version 1.20 resource provider trait list \
--format value $RP_UUID | grep TPM
(where $RP_UUID
is the UUID of the resource provider of the compute node,
which can be found via openstack resource provider list
)
This should return the following:
COMPUTE_SECURITY_TPM_1_2
COMPUTE_SECURITY_TPM_2_0
With that done, let’s create a suitable flavor. The key feature here is the
configuration of the hw:tpm_version
and hw:tpm_model
extra specs.
hw:tpm_model
is optional but hw:tpm_version
is required to enable the
feature:
$ openstack flavor create test.vtpm \
--ram 512 --disk 1 --vcpus 1 --wait \
--property hw:tpm_version=1.2 \
--property hw:tpm_model=tpm-tis
Create an instance with vTPM
With configuration complete, we can finally proceed to creating an instance. Nothing to funky here: simply create an instance using the flavor we created previously.
$ openstack --os-compute-api-version 2.latest server create test.server \
--image cirros-0.5.1-x86_64-disk --flavor test.vtpm \
--nic none --wait test.server
Once booted, let’s check if the generated XML includes the <tpm>
device
as expected:
$ sudo virsh list
Id Name State
-----------------------------------
10 instance-0000000d running
$ sudo virsh dumpxml instance-0000000d | xmllint --xpath '/domain/devices/tpm' -
<tpm model="tpm-tis">
<backend type="emulator" version="1.2">
<encryption secret="8cc4e70c-d805-4d48-9302-e3c970d1217b"/>
</backend>
<alias name="tpm0"/>
</tpm>
We can also query barbican to see if nova correctly stored keys as expected:
$ openstack secret list --format yaml
- Algorithm: null
Bit length: null
Content types:
default: application/octet-stream
Created: '2020-05-28T15:41:05+00:00'
Expiration: null
Mode: null
Name: vTPM secret for instance bbe8bc62-8403-490b-bce3-bd9c8267147e
Secret href: http://172.20.4.203/key-manager/v1/secrets/8cc4e70c-d805-4d48-9302-e3c970d1217b
Secret type: passphrase
Status: ACTIVE
We can also validate that the rebuild operation works as expected:
$ openstack server rebuild --wait test.server
Finally, we can ensure that things are properly cleaned up once we’re finished:
$ openstack server delete test.server
$ openstack secret list --format yaml
[]
QED. 🎉
Further reading
The spec and WIP code are well worth a read and contain background information on most of the topics discussed here.
Package versions
The following software versions were used. In summary, these correspond to the master versions of various OpenStack projects and latest Fedora package versions on the day of test:
- Distro: Fedora 31 (with virt preview repo via DevStack)
- Kernel:
5.3.7-301.fc31.x86_64
- Libvirt: 6.3.0
- QEMU: 5.0.0
- DevStack:
9a6ae3419c6412a55456aa87b7a790c255f01028
(master) - Nova:
de42f9e983cb4d4e94977697f86abf0a05e61cb4
(master) (before checking out in-progress vTPM changes) - Barbican:
1ad43597352b225b6f3a21ef6c4186330cadf660
(master)