You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
vTPM on KVM does not persist data (ACS 4.20.1.0, Ubuntu 24.04) #11842
after a shutdown, the /var/lib/libvirt/swtpm/ which holds the tpm data is gone. When starting the vm again, the folder is re-created with empty tpm files.
I am using a similar tpm definition in manually configured kvm guests, if those vm are powered off the folder remains.
versions
4.20.1.0
Ubuntu 24.04
The steps to reproduce the bug
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# echo "Hello, TPM!" > datafile
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvwrite -C o -i datafile 0x1500016
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvread -C o 0x1500016
WARN: Reading full size of the NV index
Hello, TPM!
Instance power cycle, and tryi to read our value again from the tpm
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:~# tpm2_nvread -C o 0x1500016
WARN: Reading full size of the NV index
WARNING:esys:src/tss2-esys/api/Esys_NV_ReadPublic.c:309:Esys_NV_ReadPublic_Finish() Received TPM Error
ERROR:esys:src/tss2-esys/esys_tr.c:243:Esys_TR_FromTPMPublic_Finish() Error NV_ReadPublic ErrorCode (0x0000018b)
ERROR:esys:src/tss2-esys/esys_tr.c:398:Esys_TR_FromTPMPublic() Error TR FromTPMPublic ErrorCode (0x0000018b)
ERROR: Esys_TR_FromTPMPublic(0x18B) - tpm:handle(1):the handle is not correct for the use
ERROR: Unable to run tpm2_nvread
root@VM-647bf7bc-bdca-48fa-8329-8b7a103f9ab6:
however, if vm runs on shared storage, when vm is migrated, or started on another host, it will not work, as the tpm file is saved on the original host, for example /var/lib/libvirt/swtpm/<vm uuid>/tpm2/tpm2-00.permall
we could save the tpm file on the same primary pool as ROOT disk, for example <path of ROOT disk>.tpm2, add then create a vm with tpm device (it is supported since libivrt v10.10.0, so it does not work on RHEL 8/9 and ubuntu 22/24, it only works with RHEL 10)
Wouldnt it be possible to add an option which persists a vm on a specific host? From my understanding it would be sufficient to make the libvirt xml persistent.
I gave the Cloudstack source to the AI together with the Bugreport and the initial implementation ticket to see what kind of solutions could be implemented. It seems like there is a flag in Libvirt 7.0+ "persistent_state XML attributes". Adding this to the swtpm part should keep the tpm files, and i think this would help if the instance is fixed to a specific compute node.
I'd like to take this on. I'm planning to do it in two parts.
Part 1: keep the TPM on the same host.
Right now libvirt deletes the TPM data every time the VM stops. Setting persistent_state='yes' on the TPM stops that. Live migration already moves the TPM to the new host, so with this change the TPM survives a stop and start and a live migration. It still resets if the host fails and HA starts the VM somewhere else. This is a small change and I think it could go into 4.22 (if there's more maintenance releases to go), or into 23/24.
One side effect is that a host keeps the TPM data after the VM moves away. For example, a VM that runs on host A, is stopped and then started on host B will get a new TPM on B. Host A still has the old one, so if the VM later starts on A again it would pick that up. To keep this predictable, I'm proposing that the agent only reuse the saved TPM when the VM starts on the host it last ran on, and clear it otherwise. Happy to change this if people would rather keep the old copy.
Part 2: save the TPM on primary storage.
I'd add a small hidden volume for each VM that holds a copy of the TPM. The agent copies the TPM out of it before the VM starts and saves it back while the VM runs and when it stops. The TPM then follows the VM to any host, including after HA. This works on Ceph RBD as well as file-based storage. The copy would be encrypted, and there would be room for UEFI NVRAM too (see #12427). This would be a new feature for main.
I also looked at letting swtpm use the volume directly while the VM runs, which is closer to how Proxmox does it. On Ceph that means mapping the volume on the host as a block device, which the KVM agent doesn't do today. libvirt also resets the TPM file on the destination host during a live migration, so each migration would need extra handling. Copying in and out avoids both of these. The downside is that if a host crashes, the last few seconds of TPM changes could be lost. In practice this should be rare, because the TPM data only changes when something like BitLocker is set up or its keys change, so the saved copy will almost always be current.
I've tested the libvirt side on libvirt 11.10 and swtpm 0.8, and with persistent_state='yes' the TPM kept its identity after the VM was stopped and started again. Restoring a saved copy of the TPM also kept its identity. Let me know if you have any thoughts before I start on the code.
Activity
weizhouapache commentedon Oct 15, 2025
@jgotteswinter
added to 4.20.3.0 milestone
weizhouapache commentedon Oct 15, 2025
if vm runs on local storage, this might work
however, if vm runs on shared storage, when vm is migrated, or started on another host, it will not work, as the tpm file is saved on the original host, for example
/var/lib/libvirt/swtpm/<vm uuid>/tpm2/tpm2-00.permallwe could save the tpm file on the same primary pool as ROOT disk, for example
<path of ROOT disk>.tpm2, add then create a vm with tpm device (it is supported since libivrt v10.10.0, so it does not work on RHEL 8/9 and ubuntu 22/24, it only works with RHEL 10)then we need to handle the migration of the tpm2 file when migrate ROOT disk to another storage pool.
jgotteswinter commentedon Oct 15, 2025
i am using the swtpm together with manually deployed vms, using this tpm definition
the files remain, even after the vm has been powered off
weizhouapache commentedon Oct 15, 2025
it may be because the vms you created are defined and persistent on the kvm host.
when you stop them, you can still find them by
virsh list --allbut the vms created by ACS, are not persistent on the kvm host.
jgotteswinter commentedon Oct 15, 2025
yes, you are absolutely right
jgotteswinter commentedon Oct 15, 2025
i did not yet test moving the tpm files to a different host, but it might be also needed to handle /var/lib/swtpm-localca to get migration working
jgotteswinter commentedon Nov 12, 2025
Is there currently any warning or hint in the docs somewhere that the current implementation is non-persisting? I think this should mentioned.
weizhouapache commentedon Nov 12, 2025
created a doc PR: apache/cloudstack-documentation#598
abh1sar commentedon Jan 5, 2026
@weizhouapache this just needs a documentation update, right?
weizhouapache commentedon Jan 6, 2026
yes.
we can consider it as a known limitation as of now, and improve it in the future release, for example 4.23
abh1sar commentedon Jan 7, 2026
Thanks @weizhouapache
daviftorres commentedon Feb 25, 2026
Dear @abh1sar , is this fix also going to be available on 4.22.1? Regards,
sureshanaparti commentedon Feb 26, 2026
@daviftorres the doc update with known limitation will be available in 4.22.1 as well.
jgotteswinter commentedon Feb 26, 2026
Wouldnt it be possible to add an option which persists a vm on a specific host? From my understanding it would be sufficient to make the libvirt xml persistent.
I gave the Cloudstack source to the AI together with the Bugreport and the initial implementation ticket to see what kind of solutions could be implemented. It seems like there is a flag in Libvirt 7.0+ "persistent_state XML attributes". Adding this to the swtpm part should keep the tpm files, and i think this would help if the instance is fixed to a specific compute node.
weizhouapache commentedon Jul 6, 2026
related issue: #12427
MitchDrage commentedon Nov 12, 2026
I'd like to take this on. I'm planning to do it in two parts.
Part 1: keep the TPM on the same host.
Right now libvirt deletes the TPM data every time the VM stops. Setting persistent_state='yes' on the TPM stops that. Live migration already moves the TPM to the new host, so with this change the TPM survives a stop and start and a live migration. It still resets if the host fails and HA starts the VM somewhere else. This is a small change and I think it could go into 4.22 (if there's more maintenance releases to go), or into 23/24.
One side effect is that a host keeps the TPM data after the VM moves away. For example, a VM that runs on host A, is stopped and then started on host B will get a new TPM on B. Host A still has the old one, so if the VM later starts on A again it would pick that up. To keep this predictable, I'm proposing that the agent only reuse the saved TPM when the VM starts on the host it last ran on, and clear it otherwise. Happy to change this if people would rather keep the old copy.
Part 2: save the TPM on primary storage.
I'd add a small hidden volume for each VM that holds a copy of the TPM. The agent copies the TPM out of it before the VM starts and saves it back while the VM runs and when it stops. The TPM then follows the VM to any host, including after HA. This works on Ceph RBD as well as file-based storage. The copy would be encrypted, and there would be room for UEFI NVRAM too (see #12427). This would be a new feature for main.
I also looked at letting swtpm use the volume directly while the VM runs, which is closer to how Proxmox does it. On Ceph that means mapping the volume on the host as a block device, which the KVM agent doesn't do today. libvirt also resets the TPM file on the destination host during a live migration, so each migration would need extra handling. Copying in and out avoids both of these. The downside is that if a host crashes, the last few seconds of TPM changes could be lost. In practice this should be rare, because the TPM data only changes when something like BitLocker is set up or its keys change, so the saved copy will almost always be current.
I've tested the libvirt side on libvirt 11.10 and swtpm 0.8, and with persistent_state='yes' the TPM kept its identity after the VM was stopped and started again. Restoring a saved copy of the TPM also kept its identity. Let me know if you have any thoughts before I start on the code.