swtpm icon indicating copy to clipboard operation
swtpm copied to clipboard

Host access to the Platform and EK certificates for a vTPM instance ?

Open berrange opened this issue 1 year ago • 8 comments

When invoking swtpm_setup to provision a new VTPM instance for a KVM guest, libvirt passes the --create-ek-cert and --create-platform-cert options. While they are on disk temporarily as output from swtpm_cert command, IIUC, these get deleted and the resulting certificates are only stored inside the swtpm state file.

IIUC the swtpm state file is considered an opaque blob from POV of any 3rd party tools. Thus I'm wondering how the host OS can get access to these AK/platform certs ?

My anticipated use case is around remote attestation of a virtual machine's TPM quote.

IIUC, the guest OS TPM PCR quote would typically be signed by an AK (Attestation Key). An AK is generated when required by the TPM and signed by the embedded EK (Endorsement Key) certificate. The remote attestation service needs to validate that the AK is associated with the guest it claims to be, and thus needs to check the signature against the EK cert.

In order to do this there needs to be a trusted entity providing information on the association between a virtual machine and an EK certificate.

My thought here is that libvirt, as the management layer of the virtualization host, should be able to expose a list of virtual machines and associated AK certificate and Platform certificate. The data center management application (like OpenStack, OVirt, etc) can collate the AK/Platform certs for VMs belonging to a tenant across the environment and make them available to the tenants TPM attestation service. This all hinges on libvirt being able to get access to the certs that swtpm_setup created though.

berrange avatar Jul 29 '22 16:07 berrange

When invoking swtpm_setup to provision a new VTPM instance for a KVM guest, libvirt passes the --create-ek-cert and --create-platform-cert options. While they are on disk temporarily as output from swtpm_cert command, IIUC, these get deleted and the resulting certificates are only stored inside the swtpm state file.

Per #455 it is now possible to write the EK certs into files in a given directory using the --write-ek-cert-files option:

$ mkdir -p /tmp/myvtpm/certs
$ swtpm_setup --tpmstate /tmp/myvtpm --tpm2 --create-ek-cert --write-ek-cert-files /tmp/myvtpm/certs
[...]
$ ls -l /tmp/myvtpm/certs/
total 8
-rw-r----- 1 stefanb stefanb 1017 Aug  5 06:29 ek-rsa2048.crt
-rw-r----- 1 stefanb stefanb  843 Aug  5 06:29 ek-secp384r1.crt

From the man page:

       --write-ek-cert-files <directory> (since v0.7)
           This option causes endorsement key (EK) files to be written into the provided directory. The files
           contain the DER-formatted EKs that were written into the NVRAM locations of the TPM 1.2 or TPM 2. The
           EK files have the filename pattern of ek-<key type>.crt. Example for filenames are ek-rsa2048.crt,
           ek-rsa3072.crt, and ek-secp384r1.crt.

           The keys that are written for a TPM 2 may change over time as the default strength of the EK keys
           changes. This means that one should look for all files with the above filename pattern when looking
           for the EKs.

The capability cmdarg-write-ek-cert-files indicates that this is implemented.

$ swtpm_setup --tpm2 --print-capabilities
{ "type": "swtpm_setup", "features": [ "tpm-1.2", "tpm-2.0", "cmdarg-keyfile-fd", "cmdarg-pwdfile-fd", "tpm12-not-need-root", "cmdarg-write-ek-cert-files", "cmdarg-create-config-files", "cmdarg-reconfigure-pcr-banks", "tpm2-rsa-keysize-2048", "tpm2-rsa-keysize-3072", "cmdarg-profile" ], "profiles": [ "default", "null", "fips-2022", "1" ], "version": "0.8.0" }

IIUC, the guest OS TPM PCR quote would typically be signed by an AK (Attestation Key). An AK is generated when required by the TPM and signed by the embedded EK (Endorsement Key) certificate. The remote attestation service needs to validate that the AK is associated with the guest it claims to be, and thus needs to check the signature against the EK cert.

If you are using keylime: In the case of keylime I think it would be sufficient to place the local/datacenter/... CA's certificate bundle into the directory where all the HW vendors' certificates already are. Those CAs are the ones signing the EK certificates and keylime uses them for validation of EKs it receives from the keylime agent.

In a typical cloud setting I would also expected that there's only one CA whose private key is being used by all local CA installations (swtpm_localca creates the certs and is invoked by swtpm_setup). This can be setup via the config file swtpm_localca.conf:

statedir = /var/lib/swtpm-localca
signingkey = /var/lib/swtpm-localca/signkey.pem   <------ CA's signing key
issuercert = /var/lib/swtpm-localca/issuercert.pem  <------ CA's cert
certserial = /var/lib/swtpm-localca/certserial

To create the CA bundle for keylime to use for verification this should work if the certificate was auto-created by swtpm_setup and then harvested on one cloud host and replicated to all other host: https://github.com/stefanberger/swtpm/wiki/Certificates-created-by-swtpm_setup#verifying-your-ek-cert-against-the-ca

Also, in case of keylime I think storing the EKs in a directory would not be necessary since the keylime_agent pulls them out of the TPM's NVRAM storage and passes them to keylime server which verifies them when the EK and AIK are passed.

I didn't implement storing the platform cert since in the keylime use case at least it's not even being looked at (and may not be available for all TPM 2's [my guess])

stefanberger avatar Aug 05 '22 10:08 stefanberger

So what is needed for this issue? At least when using keylime I think we wouldn't need anything.

stefanberger avatar Aug 12 '22 19:08 stefanberger

Per #455 it is now possible to write the EK certs into files in a given directory using the --write-ek-cert-files option:

$ mkdir -p /tmp/myvtpm/certs
$ swtpm_setup --tpmstate /tmp/myvtpm --tpm2 --create-ek-cert --write-ek-cert-files /tmp/myvtpm/certs
[...]
$ ls -l /tmp/myvtpm/certs/
total 8
-rw-r----- 1 stefanb stefanb 1017 Aug  5 06:29 ek-rsa2048.crt
-rw-r----- 1 stefanb stefanb  843 Aug  5 06:29 ek-secp384r1.crt

The swtpm_setup --write-ek-cert-files option can be used if provisioning a new VM, but what equivalent do we have if that's not the case ? For example, on an incoming migration, IIUC, the state file will simply be written out by swtpm when it receives the data over QEMU's wire connection, with no use of swtpm_setup. Can we extract the certs from the state file alone (given the suitable encryption key from the libvirt secret) ? There's also the risk that the separate .crt files may get out of sync with the real state if we store them separately

If you are using keylime: In the case of keylime I think it would be sufficient to place the local/datacenter/... CA's certificate bundle into the directory where all the HW vendors' certificates already are. Those CAs are the ones signing the EK certificates and keylime uses them for validation of EKs it receives from the keylime agent.

IIUC, in a common public cloud environment the CA cert used for signing the vTPM certs is going to common across every VM the cloud creates. IOW, different tenants all have their vTPM signed by the same key. If a tenant deploys keylime and points it at the cloud vendors' CA cert, then keylime is merely verifying that the vTPM is one associated with that public cloud - it could still belong to a completely different tenant though. Checking the main CA cert feels OK if using a private cloud deployment where all VMs belong to the same org, but not fine grained enough for a public cloud with multiple tenants.

One option could be for clouds to have multiple levels of CA, the top level CA signs a cert for the tenant, and then all VMs created for that tenant get their vTPM signed by the per-tenant CA. That wouldn't be possible with current swtpm_setup usage in libvirt which relies on the single global swtpm_localca.conf default config file though

berrange avatar Aug 22 '22 17:08 berrange

The swtpm_setup --write-ek-cert-files option can be used if provisioning a new VM, but what equivalent do we have if that's not the case ? For example, on an incoming migration, IIUC, the state file will simply be written out by swtpm when it receives the data over QEMU's wire connection, with no use of swtpm_setup. Can we extract the certs from the state file alone (given the suitable encryption key from the libvirt secret) ? There's also the risk that the separate .crt files may get out of sync with the real state if we store them separately

The only way of doing this is to run swtpm and query for the various NVRAM locations where the certs may be stored.

https://github.com/stefanberger/swtpm/wiki/Certificates-created-by-swtpm_setup#tpm-2-certificates

If it's necessary to do this why is a problem to extract them when swtpm_setup has been run? It would be possible to write them into the vTPM state directory or some sort of shared storage to make them available later on.

IIUC, in a common public cloud environment the CA cert used for signing the vTPM certs is going to common across every VM the cloud creates. IOW, different tenants all have their vTPM signed by the same key. If a tenant deploys keylime and points it at the cloud vendors' CA cert, then keylime is merely verifying that the vTPM is one associated with that public cloud - it could still belong to a completely different tenant though. Checking the main CA cert feels OK if using a private cloud deployment where all VMs belong to the same org, but not fine grained enough for a public cloud with multiple tenants.

A manufacturer's hardware TPMs are also all signed with a common key and cert (chain). So that problem exists in the physical world as well.

The only way to differentiate between groups of tenants would be to run each VM under a separate user account on the various hosts and setup a different key on each host for swtpm_setup to use.

stefanberger avatar Aug 22 '22 19:08 stefanberger

IIUC, in a common public cloud environment the CA cert used for signing the vTPM certs is going to common across every VM the cloud creates. IOW, different tenants all have their vTPM signed by the same key. If a tenant deploys keylime and points it at the cloud vendors' CA cert, then keylime is merely verifying that the vTPM is one associated with that public cloud - it could still belong to a completely different tenant though. Checking the main CA cert feels OK if using a private cloud deployment where all VMs belong to the same org, but not fine grained enough for a public cloud with multiple tenants.

So what's the advantage of this ? Is this trying to address some protocol issue of some sort or a trustworthiness issue? What advantage does it have that I know that the cert comes from tentant A but I wouldn't be able to then say which one of the hundreds of VMs it comes from? Where does the potential mix-up of certs come into play between tenants that couldn't occur between VMs of the same tenant?

stefanberger avatar Aug 22 '22 19:08 stefanberger

IIUC, in a common public cloud environment the CA cert used for signing the vTPM certs is going to common across every VM the cloud creates. IOW, different tenants all have their vTPM signed by the same key. If a tenant deploys keylime and points it at the cloud vendors' CA cert, then keylime is merely verifying that the vTPM is one associated with that public cloud - it could still belong to a completely different tenant though. Checking the main CA cert feels OK if using a private cloud deployment where all VMs belong to the same org, but not fine grained enough for a public cloud with multiple tenants.

So what's the advantage of this ? Is this trying to address some protocol issue of some sort or a trustworthiness issue? What advantage does it have that I know that the cert comes from tentant A but I wouldn't be able to then say which one of the hundreds of VMs it comes from? Where does the potential mix-up of certs come into play between tenants that couldn't occur between VMs of the same tenant?

Yes, consider the organization wants to have strict control over what "devices" connect to their internal network. If they have a private cloud deployment, their IT admins have visibility into what VMs are launched and by whom, so verifying the CA used for vTPMs in their private cloud is sufficient assurance that the (virtual machine) "device" is auditable/traceable. This is distinct from a VM launched by an employee on a random laptop where their IT admins have no visibility into the VM config.

In a public cloud similarly the IT admins want to have confidence that the device connecting to their attestation service is one that is running under their cloud account, and not associated with some 3rd parties' cloud account. This could be done with usage of separate CA cert per account/tenant at some point in the chain. Or, but having the cloud admin API be able to report a discrete list of EKs associated with VMs in their account, and of course a means to acquire updates to this list whenever a new VM is provisioning...

A manufacturer's hardware TPMs are also all signed with a common key and cert (chain). So that problem exists in the physical world as well.

In the physical world when receiving a device, the IT staff have the opportunity to record the EK associated with the asset, before deploying the device on their network. They don't need to rely on the device / TPM vendor's public CA cert, they can instead build a discrete list of every EK their organization owns. I'm interested in how to facilitate an equivalent option in the virtual world, where provisioning of VMs is typically self-service without involvement of the IT staff. It could be handled if the cloud had a way to publish the list of EKs for VMs in an organization.

Another use case is where the organization has certain very sensitive services that they want to control access to. They only want to allow logins to the services, if the remote user is running on known good remote (virtual) hardware and software. In this case the IT org would want to setup policies tied to a small finite set of known EKs, to prevent an employee attempting to login from some less trustworthy device.

FYI much of my thought here is influenced by this talk about how Google uses TPMs to control access https://www.youtube.com/watch?v=EmEymlA5Q5Q I don't have a personal need to do this, but I'd like to see if we can make it possible for people to build these kind of setups for themselves when using KVM guests and swtpm.

berrange avatar Aug 23 '22 11:08 berrange

IIUC, in a common public cloud environment the CA cert used for signing the vTPM certs is going to common across every VM the cloud creates. IOW, different tenants all have their vTPM signed by the same key. If a tenant deploys keylime and points it at the cloud vendors' CA cert, then keylime is merely verifying that the vTPM is one associated with that public cloud - it could still belong to a completely different tenant though. Checking the main CA cert feels OK if using a private cloud deployment where all VMs belong to the same org, but not fine grained enough for a public cloud with multiple tenants.

So what's the advantage of this ? Is this trying to address some protocol issue of some sort or a trustworthiness issue? What advantage does it have that I know that the cert comes from tentant A but I wouldn't be able to then say which one of the hundreds of VMs it comes from? Where does the potential mix-up of certs come into play between tenants that couldn't occur between VMs of the same tenant?

Yes, consider the organization wants to have strict control over what "devices" connect to their internal network. If they have a private cloud deployment, their IT admins have visibility into what VMs are launched and by whom, so verifying the CA used for vTPMs in their private cloud is sufficient assurance that the (virtual machine) "device" is auditable/traceable. This is distinct from a VM launched by an employee on a random laptop where their IT admins have no visibility into the VM config.

In a public cloud similarly the IT admins want to have confidence that the device connecting to their attestation service is one that is running under their cloud account, and not associated with some 3rd parties' cloud account. This could be done with usage of separate CA cert per account/tenant at some point in the chain. Or, but having the cloud admin API be able to report a discrete list of EKs associated with VMs in their account, and of course a means to acquire updates to this list whenever a new VM is provisioning...

Well, EKs are unique per TPM and per machine. CAs of hardware TPMs are not unique to a company's laptops but span across all the machines equipped with the same type of TPM from a specific manufacturer. So EKs, if anything, is better suited for 'uniqueness' to be able to identify a subset of machines that is given special access privileges.

Also, I don't think that it should be necessary to create a CA per tenant of a public cloud for multiple reasons:

  1. It opens the flood gates for certificates from a public cloud along with the issues of having to manage the CAs for each tenant, to set them up for each host where a tenant's VMs can be started, and to secure the private keys needed for signing the certificates, along with removal of these when a tenant leaves. A single certificate (bundle) for a public cloud should be able to achieve it. The CA's private key can be secured via a pkcs11-enabled HSM and the certificate made available to cloud tenants via a simple wget on a URL so that it can be added to the list of trusted CAs. That's all it should take.

  2. If there's any uncertainty about where a TPM certificate is coming from, whether it comes from tenant B while it should come from tenant A would hint a more serious issue that cannot be solved with a CA for each tentant where the problem then could become that it's not clear whether the TPM certificate is coming from machine 1 versus any of the other machines.

  3. Point 2) really shouldn't be an issue since things are tied together via signatures, certificates, and certificate contents: the certificates of the TPM are tied to the CA of cloud via the CA's signature and the EK and platform certificates can be verified to be tied to a specific VM:

libvirt's domain XML shows VM name and UUID:

<domain type='kvm' id='99'>
  <name>TestVM</name>
  <uuid>776bf756-e801-431a-8d26-998e1567c1e9</uuid>

The EK and platform certificates of the TPM show the same name and UUID:

# openssl x509 -inform der -in platcert.der -text -noout
Certificate:
    Data:
        [...]
        Subject: CN = TestVM:776bf756-e801-431a-8d26-998e1567c1e9
        Subject Public Key Info:

dmidecode inside an x86_64 VM shows the UUID also:

# dmidecode 3.3
Getting SMBIOS data from sysfs.
SMBIOS 2.8 present.
[...]
System Information
        Manufacturer: QEMU
        Product Name: Standard PC (Q35 + ICH9, 2009)
        Version: pc-q35-4.2
        Serial Number: Not Specified
        UUID: 776bf756-e801-431a-8d26-998e1567c1e9

So things are pretty well tied together via a CA signature and a VM's UUID on top of having the certificate stored in a TPM2 NVRAM location that is protected.

A manufacturer's hardware TPMs are also all signed with a common key and cert (chain). So that problem exists in the physical world as well.

In the physical world when receiving a device, the IT staff have the opportunity to record the EK associated with the asset, before deploying the device on their network. They don't need to rely on the device / TPM vendor's public CA cert, they can instead build a discrete list of every EK their organization owns. I'm interested in how to facilitate an equivalent option in the virtual world, where provisioning of VMs is typically self-service without involvement of the IT staff. It could be handled if the cloud had a way to publish the list of EKs for VMs in an organization.

In the VM world the IT staff also has the possibility to collect the EK certificates from protected NVRAM locations of the TPM as shown here. This can be done on first boot with a prepared VM image or also later on. Presumably the same scripts can be run inside these VMs and the EK certs be submitted to a database. I don't see why this would not be possible.

Further, as shown above, swtpm_setup can write the EK certificates upon creation of a swtpm instance to files and some cloud-specific scripts, that run immediately after the creation of a VM, can then be used to write them to a cloud database from which the tenant can also retrieve them. Again, also this should be possible for a cloud to do but requires cloud-specific support whereas the scripts run inside the VM are just generic.

Another use case is where the organization has certain very sensitive services that they want to control access to. They only want to allow logins to the services, if the remote user is running on known good remote (virtual) hardware and software. In this case the IT org would want to setup policies tied to a small finite set of known EKs, to prevent an employee attempting to login from some less trustworthy device.

Yes, EKs can be used for distinction, not CAs.

FYI much of my thought here is influenced by this talk about how Google uses TPMs to control access https://www.youtube.com/watch?v=EmEymlA5Q5Q I don't have a personal need to do this, but I'd like to see if we can make it possible for people to build these kind of setups for themselves when using KVM guests and swtpm.

I don't see why it shouldn't be possible with the way things are setup now.

stefanberger avatar Aug 24 '22 15:08 stefanberger

3. Point 2) really shouldn't be an issue since things are tied together via signatures, certificates, and certificate contents: the certificates of the TPM are tied to the CA of cloud via the CA's signature and the EK and platform certificates can be verified to be tied to a specific VM:

libvirt's domain XML shows VM name and UUID:

<domain type='kvm' id='99'>
  <name>TestVM</name>
  <uuid>776bf756-e801-431a-8d26-998e1567c1e9</uuid>

The EK and platform certificates of the TPM show the same name and UUID:

# openssl x509 -inform der -in platcert.der -text -noout
Certificate:
    Data:
        [...]
        Subject: CN = TestVM:776bf756-e801-431a-8d26-998e1567c1e9
        Subject Public Key Info:

Ok, I hadn't noticed that the Subject CN mapped to the libvirt name/UUID previously. The name isn't unique beyond the host, but generally we'd expect the UUID to be globally unique. So the UUID can be used to associate the EK cert with the VM instance belonging to a tenant provided the cloud provider correctly ensures UUID uniqueness amongst all VMs whose vTPM EKs are generated from the same CA. That's likely a reasonable assumption.

The swtpm_setup --write-ek-cert-files option can be used if provisioning a new VM, but what equivalent do we have if that's not the case ? For example, on an incoming migration, IIUC, the state file will simply be written out by swtpm when it receives the data over QEMU's wire connection, with no use of swtpm_setup. Can we extract the certs from the state file alone (given the suitable encryption key from the libvirt secret) ? There's also the risk that the separate .crt files may get out of sync with the real state if we store them separately

The only way of doing this is to run swtpm and query for the various NVRAM locations where the certs may be stored.

https://github.com/stefanberger/swtpm/wiki/Certificates-created-by-swtpm_setup#tpm-2-certificates

Yikes, that's kind of complex ! At the time that the incoming migration has written out the new state, QEMU's swtpm instance already has the state file open, so no other process like libvirt can access it to extract the certs.

If it's necessary to do this why is a problem to extract them when swtpm_setup has been run? It would be possible to write them into the vTPM state directory or some sort of shared storage to make them available later on.

There's no problem extracting the certs when swtpm_setup is run. The --write-ek-cert-files option works fine for initial provisioning. The swtpm state is usually local to the host though, so if live migrated the question is ho to get the same certs on the target machine since they're not part of the migrated state. Possibly libvirt could copy the files across out of band from QEMU, since extracting them from the swtpm state file looks hairy.

I'll have to think about whether we really need to expose the certs or not. My gut feeling though is that its still useful to expose this identity information. While you could verify the identity by mapping the VM UUID to the cert CN UUID, this would mean the attestation service is relying on specific behaviour of swtpm/libvirt setup. That may be ok, or may be not. Users might have a more general attestation service that simply wants to have an inventory database recording the EKs for every device.

berrange avatar Aug 26 '22 16:08 berrange