Confidential VM Tier

Confidential VMs & Tenant Attestation

A full virtual machine running as an Intel TDX Trust Domain, with root access and a GPU attached. You generate your own attestation quote from inside the VM and verify it offline against Intel's root CA. VoltageGPU is not in the trust path.

Tenant-side TDX quotes
Full root via SSH
GPU attached, nvidia-smi works

VM Tier vs Container Tier

The confidential container tier gives you a hardware-sealed container inside an Intel TDX enclave: your workload is protected, but attestation happens at the infrastructure level and the container does not expose /dev/tdx_guest. You have to trust the platform's attestation reports.

The Confidential VM tier removes that trust requirement. You get a full Ubuntu VM that itself runs as a TDX Trust Domain, with the TDX guest device exposed inside the VM. You generate the signed quote yourself, bind it to your own nonce, and verify the signature chain offline with Intel's open-source tooling. Nothing in the verification path is operated by VoltageGPU.

CapabilityConfidential ContainersConfidential VMs
/dev/tdx_guest exposedNoYes
AttestationInfrastructure-levelTenant-generated TDX quote
Access levelContainer rootFull VM root via sudo
ProvisioningSelf-serve (API, dashboard, CLI)Self-serve (deploy page, since 7 Sept 2026)
Persistent volumesAvailableNot yet, disk is ephemeral

What You Get Inside the VM

Ubuntu 24.04 LTS

Ubuntu 24.04 LTS with kernel 6.8, running as an Intel TDX Trust Domain. Full root via sudo and direct SSH access, install anything you need.

GPU Attached

The GPU is attached to the VM and visible from inside it: nvidia-smi works out of the box for your training and inference workloads.

TDX Guest Interface

The VM exposes /dev/tdx_guest plus the tdx_guest and tsm kernel modules, everything you need to generate signed quotes via configfs TSM.

Request a Confidential VM

Deploy it yourself from your dashboard: pick a tier, give it a name, and it boots in about two minutes with your SSH key already on it. Add an SSH key to your account first, because a Confidential VM binds its keys at creation and can never be given one afterwards. The VM then appears under Your Pods with its SSH command, its live cost and a Release button, so you never wait on us to start or stop it.

1

Add Your SSH Key

Add a public SSH key to your account first. A Confidential VM binds its keys at creation and can never be given one afterwards.

2

Deploy It Yourself

Pick a size on the deploy page and the VM boots in about two and a half minutes as an Intel TDX Trust Domain, with your key on it. Email contact@voltagegpu.com only for a size we do not list.

3

SSH In

Connect with your key, verify the TDX environment, and run your workload. You have full root via sudo.

Fully self-serve. Deploying, managing and releasing a Confidential VM all happen from your own dashboard, with no email and no waiting. Container-tier pods are self-serve too.

Verify the Environment

Once you are in, confirm you are actually inside a TDX guest: the TDX guest device must exist, the kernel modules must be loaded, and the GPU must be visible.

Check the TDX guest device
$ ls -l /dev/tdx_guest
crw------- 1 root root 10, 127 ... /dev/tdx_guest
Check the kernel modules
$ lsmod | grep -E 'tdx_guest|tsm'
tdx_guest              ...
tsm                    ...
Check the GPU
$ nvidia-smi

Generate a TDX Quote

Step 1: Create a Report Entry

Quotes are generated through the kernel's configfs TSM interface. Creating a directory under /sys/kernel/config/tsm/report opens a new report request.

sudo mkdir /sys/kernel/config/tsm/report/r1

Step 2: Write Custom report_data

Write exactly 64 bytes of custom report_data into inblob. Binding a hash of a fresh nonce is the standard way to prove the quote was generated now, for you, and is not a replay. SHA-512 output is exactly 64 bytes, so it fits inblob perfectly.

Fresh nonce, hashed to 64 bytes
head -c 32 /dev/urandom > nonce.bin
openssl dgst -sha512 -binary nonce.bin | \
  sudo tee /sys/kernel/config/tsm/report/r1/inblob > /dev/null

Keep the nonce. The verifier needs nonce.bin later to confirm the quote embeds the SHA-512 of that exact nonce in its report_data field.

Step 3: Read the Signed Quote

Reading outblob triggers quote generation inside the Trust Domain and returns the signed quote. On this tier the output is a TDX quote v4 of 5247 bytes.

sudo cat /sys/kernel/config/tsm/report/r1/outblob > quote.bin
ls -l quote.bin   # 5247 bytes

Step 4: Sanity-Check the Header

Before running full verification, eyeball the first header bytes. A valid quote from this tier starts with 04 00 02 00 81 00.

Expected header
$ xxd -l 6 quote.bin
00000000: 0400 0200 8100                           ......

Header Fields

04 00bytes 0-1Quote format version 4
02 00bytes 2-3Attestation key type: ECDSA-P256
81 00 ...bytes 4-7TEE type 0x81: Intel TDX

Generate a GPU Attestation Report

The TDX quote above never covers the GPU. On a single-GPU H200 Confidential VM, the GPU produces its own attestation report, signed by NVIDIA rather than by Intel, and bound to a nonce you choose. That gives you two independent proofs from one session, with two separate roots of trust and VoltageGPU in neither. On the 8x H100 node the same proof exists for all eight GPUs, in NVIDIA's multi-GPU Protected PCIe mode: see the note at the end of this section, the reading differs and the SDK needs one option.

Read the state before anything else. If CC State is not ON, or DevTools Mode is not OFF, stop: a DevTools part produces a report whose measurements will not match NVIDIA reference values.

Step 1: confirm the GPU is in confidential mode
$ nvidia-smi conf-compute -q

    CC State                   : ON
    Multi-GPU Mode             : None
    CPU CC Capabilities        : INTEL TDX
    GPU CC Capabilities        : CC Capable
    CC GPUs Ready State        : Ready

$ nvidia-smi conf-compute -d
DevTools Mode: OFF
Step 2: pull a report bound to your own nonce
sudo apt-get install -y python3-pip python3-venv
python3 -m venv ~/att && . ~/att/bin/activate     # a venv, not --break-system-packages
pip install nvidia-ml-py nv-attestation-sdk cryptography==43.0.1

python3 - <<'PY'
import os, pynvml as n
n.nvmlInit()
h = n.nvmlDeviceGetHandleByIndex(0)
nonce = os.urandom(32)                       # yours, generated here, now
rep = n.nvmlDeviceGetConfComputeGpuAttestationReport(h, nonce)
open("gpu_report.bin","wb").write(bytes(rep.attestationReport[:rep.attestationReportSize]))
print("report", rep.attestationReportSize, "bytes, nonce", nonce.hex())
PY
Step 3: have NVIDIA verify it, not us
python3 - <<'PY'
import secrets, json, base64
from nv_attestation_sdk import attestation
nonce = secrets.token_hex(32)
c = attestation.Attestation()
c.set_name("my-vm"); c.set_nonce(nonce); c.set_claims_version("2.0")
c.add_verifier(attestation.Devices.GPU, attestation.Environment.REMOTE,
    "https://nras.attestation.nvidia.com/v3/attest/gpu", "")
ev = c.get_evidence()          # attest() without evidence raises in 2.7.3
print("attest ->", c.attest(ev))
open("nras_token.json","w").write(c.get_token())
PY

A passing run prints Attestation Successful and writes a signed EAT token. The claims that matter are measres: success, meaning the runtime driver and VBIOS measurements matched NVIDIA's published golden values, and x-nvidia-gpu-attestation-report-nonce-match: true, which is what makes the report impossible to replay from an earlier session. Verified on this SKU on 4 September 2026: driver 595.71.05, VBIOS 96.00.CF.00.02, hwmodel GH100, secboot true, dbgstat disabled.

The deprecated local verifier (python3 -m verifier.cc_admin) currently fails its OCSP request from inside the guest and reaches end of support on 15 September 2026. Use the remote service above, or NVIDIA's C++ SDK.

Multi-GPU nodes read differently. On an 8-GPU node in NVIDIA's Protected PCIe mode, nvidia-smi conf-compute -q reports CC State OFF together with Multi-GPU Mode Protected PCIe: the second line is the one that matters. If CC GPUs Ready State reads Not Ready, run sudo nvidia-smi conf-compute -srs 1. The attestation SDK then needs get_evidence(options={"ppcie_mode": False}) (the option means "standalone mode"; with the default it refuses to run on a PPCIe system). Verified on 10 September 2026 on an 8x H100 VM: NVIDIA's remote service returned Attestation Successful for all eight GPUs, token published at /blog/two-proofs/evidence/ppcie-8x-h100/. NVSwitch attestation is not verified yet. The 8x H200 node reads the same mode (Ready State Not Ready on 4 and 9 September) and its attestation has not been run.

Where this does not work: RTX 6000B VMs read CC OFF, and the container tier gives the tenant no attestation. On those, the Intel TDX quote is the only hardware evidence available. Always run conf-compute -q yourself at first login rather than trusting any page, including this one.

Two Reports Are Never Byte-Identical

If you hash a report today and compare that hash against a fresh report tomorrow, the comparison will fail even on an untouched machine. The report is 4,129 bytes and three regions of it change between calls. Only 3,969 bytes are stable. This catches people on their first day, because the natural way to pin an approved state is to fingerprint the whole blob.

OffsetSizeWhat it isChanges when
[4, 36)32 bytesYour nonce, echoed backYou send a different nonce
[3565, 3597)32 bytesThe GPU's own nonceEvery single call
[4033, 4129)96 bytesECDSA signatureEvery single call

The first and the third surprise nobody. The middle one does: it changes even when you send the same nonce twice, so you only find it by fetching twice with an identical nonce and diffing the results. The report is a DMTF SPDM 1.1 MEASUREMENTS response, and SPDM has the responder contribute 32 random bytes of its own alongside yours. The signature covers both, which is why the signature moves with it. Neither field is a defect, and neither weakens the proof: the nonce you chose is still in there, still signed, still yours to check.

What to pin instead. Compare the parsed measurement blocks, or the claims in the verified EAT token (measres, driver version, VBIOS version, secboot, dbgstat). Those are the values that must not drift. If you insist on a raw-byte fingerprint, exclude the three ranges above, and be aware that the offsets are specific to this report version rather than guaranteed by NVIDIA.
Reproduce it: same nonce, two reports, diff
python3 - <<'PY'
import pynvml as n
n.nvmlInit()
h = n.nvmlDeviceGetHandleByIndex(0)
nonce = bytes(range(32))                     # deliberately fixed, not random
def pull():
    r = n.nvmlDeviceGetConfComputeGpuAttestationReport(h, nonce)
    return bytes(r.attestationReport[:r.attestationReportSize])
a, b = pull(), pull()
runs, start = [], None
for i, (x, y) in enumerate(zip(a, b)):
    if x != y and start is None: start = i
    if x == y and start is not None: runs.append((start, i)); start = None
if start is not None: runs.append((start, len(a)))
print("size", len(a), "differing ranges", runs)
print("stable bytes", len(a) - sum(e - s for s, e in runs))
PY

Found and reported by Mohammed Zoheb Shaik, who paid for the machine that produced it, ran the diff nobody else had run, and sent us the result. Published with his permission.

Artifacts You Can Verify Without a VM

The raw files from the 4 September 2026 run on a single-GPU H200 VM are published, unchanged since capture, with SHA-256 checksums. They let an auditor check NVIDIA's signature and Intel's quote format before spending anything on a machine. They do not replace a run on your own VM: only your own nonce proves your own session.

FileSizeWhat it isHow to check it
nras_token.json3,055 bytesNVIDIA's verdict: two JWTs signed ES384 by nras.attestation.nvidia.com, nonce 6154dbb2…, issued 2026-09-04 12:31:05 UTCVerify the signatures against NVIDIA's JWKS, then read the claims (measres, driver, VBIOS, secboot, dbgstat)
gpu_report.bin + nonce.txt4,129 bytesA raw SPDM measurement report from a second round with a different nonce (4206…)Confirm the nonce at bytes [4, 36); use it to read the layout above. Not submitted to NRAS, cert chain not included
quote.bin + report_data.bin5,243 bytesTDX v4 quote (header 04 00 02 00 81 00) with the tenant's 64-byte report_data at byte 568Intel DCAP QVL against Intel's root CA, then compare bytes [568, 632) with report_data.bin
SHA256SUMS, README.txtChecksums and a plain-text description of each file, including what the set does not provesha256sum -c SHA256SUMS

Concurrent Quotes: Retry on EINVAL, and Only on EINVAL

One quote at a time works every time. Several at once do not. Mohammed Zoheb Shaik, who is building Custodian, a key broker for model weights, reported on 9 September 2026 that with six quote requests in flight, roughly one in six came back with [Errno 22] Invalid argument from the kernel's configfs TSM interface (Ubuntu 24.04, kernel 6.8). The failure is in the kernel's TSM object as one entry is torn down while the next is created, not in the hardware and not in the quote itself. It fails closed: you get an error, never a quote bound to someone else's report_data.

What to do. Serialise quote generation inside your process, and retry on EINVAL only. A permission error or a missing /dev/tdx_guest means something else is wrong and must fail immediately; a blanket retry would hide it. With that rule the tenant's broker ran twelve unattended renewals and two batches of eight parallel releases without a single crossed quote.
The shape of the retry
import errno, time
def get_quote(report_data, attempts=5):
    for i in range(attempts):
        try:
            return tsm_quote(report_data)        # your configfs TSM call
        except OSError as e:
            if e.errno != errno.EINVAL or i == attempts - 1:
                raise                            # EACCES, ENOENT and the rest: stop here
            time.sleep(0.05 * (i + 1))

Verify Offline with Intel DCAP

Verification is fully offline and uses Intel's open-source DCAP stack (SGXDataCenterAttestationPrimitives). The quote's ECDSA signature chains through the platform's PCK certificate up to Intel's root CA. VoltageGPU operates nothing in that chain: if the quote verifies, the guarantee comes from Intel silicon, not from us.

On your own machine, not the VM
git clone https://github.com/intel/SGXDataCenterAttestationPrimitives
# Build the Quote Verification Library (QVL) sample and run it
# against quote.bin. It validates the signature chain up to the
# Intel root CA, entirely offline.

Check report_data Freshness

A valid signature is not enough: also confirm the quote embeds your report_data. Recompute sha512(nonce.bin) and compare it with the 64-byte report_data field inside the quote body. A match proves the quote was generated after you wrote your nonce, inside that specific Trust Domain.

Full walkthrough. The complete step-by-step guide, including the exact DCAP build commands and the report_data offset inside the quote body, is published at voltagegpu.com/blog/tenant-tdx-attestation-guide.

Or bind both proofs to your workload with voltage-verify

voltage-verify is a small open-source tool (MIT, Python 3.10+) that folds the five steps above and the NVIDIA attestation into one flow, bound to a manifest you write: the image digest, the digests of your model or files, and a random challenge. The TDX quote carries SHA-512 of that manifest as report_data, NVIDIA's service signs the GPU claims over SHA-256 of it, and the verifier on your machine checks Intel's chain to the pinned root, TCB status, Quoting Enclave identity, revocation, NVIDIA's ES384 signatures and claims, then runs six negative tests.

Three commands
# your machine
pip install voltage-verify
voltage-verify manifest --image ghcr.io/you/app:1.4.2 --artifact model.safetensors -o manifest.json
# inside the VM, as root
sudo -E python -m voltage_verify attest --manifest manifest.json -o bundle.json
# your machine
voltage-verify verify bundle.json --challenge <challenge printed by manifest>
voltage-verify selftest bundle.json

Source and issues: github.com/Jabsama/voltage-verify; package on PyPI; wheel, reference bundle and documentation mirrored with SHA-256 sums at voltagegpu.com/blog/two-proofs/voltage-verify. It proves that both hardware proofs were issued for your manifest after your challenge. It does not prove that the GPU executed the named image; that needs a measured launcher, and the tool says so.

Honest Limits

Confidential computing claims are only worth something when the boundaries are stated plainly. Here is exactly what this tier does and does not attest.

The container tier has no tenant attestation

Confidential container pods do not expose /dev/tdx_guest. On that tier, attestation is infrastructure-level only: you cannot generate your own quote from inside a container. If tenant-side attestation is a requirement, use the VM tier documented on this page.

The quote attests the CPU TEE boundary, not the GPU

NVIDIA GPU attestation is verified on single-GPU H200 VMs (September 4, 2026, CC State ON, remote attestation successful) and on the 8x H100 node (September 10, 2026, multi-GPU Protected PCIe mode, all eight GPUs attested; NVSwitch not yet). The 8x H200 reads the same mode but is not attested yet, RTX 6000B VMs read CC OFF, and the container tier gives no tenant-side attestation. The TDX quote never attests the GPU: for GPU evidence, fetch the NVIDIA attestation report (nvmlDeviceGetConfComputeGpuAttestationReport or the NVIDIA attestation SDK) and verify it with NVIDIA's service.

No persistent volumes

The VM disk is ephemeral: when the VM is released, the disk is gone. Persistent volumes are not available on the VM tier yet, so copy models, checkpoints, and results off the box (e.g. via scp or rsync) before tearing it down. Deploying and releasing are both self-serve from Your Pods.

Running It, Stopping It, Paying For It

The single most expensive misunderstanding on this tier is what stops the meter. It is worth two minutes now.

Halting the guest does not stop the rental. sudo poweroff and sudo shutdown stop the operating system, but the machine stays rented and keeps costing. A powered-off VM is the worst of both: it does no work and still bills. The only thing that stops billing is releasing the VM.
1

Release it yourself, from your dashboard

Your VM appears under Your Pods like any other machine. Open it and press Release VM. Billing stops at that moment, and the unused part of the prepaid hour is credited back to your balance automatically.

2

Copy your work off first

Releasing destroys the disk. There is no snapshot and no resume. Pull results down with scp -P <port> ubuntu@<ip>:~/results ./ before you press it.

3

Ask for an automatic stop if you want a hard limit

If you are running a fixed window, ask us to arm an automatic release at the end of it. It runs whether or not anyone is awake, so an overnight finish cannot bill you until morning. It is optional, and you can have it cancelled at any time.

What survives a reboot, and what does not

ActionMachineDisk contentsBilling
sudo rebootRestartsKeptKeeps running
sudo poweroffStays offKeptKeeps running
Release VMDestroyedDestroyedStops, unused prepay refunded

One consequence worth planning for: a reboot re-runs attestation from scratch. Your TDX quote and GPU attestation report are per boot, so a report you captured before a reboot no longer describes the machine you are on. Take a fresh one after any restart, the same way you took the first.

There is no web terminal on this tier, and that is deliberate. The machine carries your public key and nothing else. We hold no key for it, so we cannot open a shell on your VM, and we do not offer a button that pretends otherwise. Connect with your own SSH client, from your own machine.