Private models and datasets
This page is the supported way to run a model or a dataset that the GPU provider must not see. You rent a Confidential Computing machine, the pod proves from the inside what machine it is on, and only then does a key service you control release a short-lived key that decrypts your data. Nothing secret is stored in the image, the template or your Lium account.
What is guaranteed
This holds on a Confidential Computing machine, once your own verifier has checked the pod's quote as in step 4.
| Guarantee | Holds |
|---|---|
| The GPU provider cannot read the VM's memory, through the host OS, the hypervisor or physical access to RAM | Yes. Intel TDX encrypts it. |
| The GPU provider cannot read the VM's disk | Yes. The disk is encrypted with a key that only a VM with the same measurements can obtain. |
| A process in your pod can obtain a hardware-signed quote that binds a value you choose to the machine's measured software | Yes. See Attesting from inside your pod. |
| The quote identifies your container image | No. It measures the machine: Lium's OS image and node software. Your image is not measured. |
| The quote identifies your pod | No. Any pod on the same machine can ask for a quote. Rent every GPU of the machine so yours is the only pod on it. |
| Lium cannot access the pod | No. Lium's node software runs inside the VM and manages your pod's container. The VM keeps the GPU provider out, not Lium. |
| GPU memory and the CPU-to-GPU link are protected | Not stated by the label. The label is based on the CPU's TDX quote and does not say whether the GPUs run in NVIDIA confidential-computing mode. If you need that, check the GPUs with NVIDIA's attestation tools from your pod before you load anything. |
| Data that leaves the VM is protected | Only by what you do. Backups, network volumes, logs and network traffic leave the VM. Encrypt them yourself and use TLS. |
| The machine stays up | No. The provider can still power it off or cut its network. This is confidentiality, not availability. |
On an ordinary machine none of the "Yes" rows hold: the provider can read the pod's memory, disk and environment (Pod security). The credential lifecycle below still limits how long a leaked credential works and what it opens. It does not hide anything from the host.
The flow
1. Prepare outside Lium
- Encrypt the weights or the dataset with a data key, and upload only the ciphertext to your object store.
- Keep the data key in a key service you control: a cloud KMS, Vault, or a small service of your own. This page calls it the key broker. It releases the key only to a pod that passes step 4.
- Build an image that contains your code and the dstack SDK, and no secrets. Build arguments,
ENVlines and image layers are readable by anyone who can pull the image.
2. Rent a Confidential Computing machine
On Browse Pods, turn on the Confidential Computing filter and pick a machine. Rent all of its GPUs.
From the API, the listing carries the same flag on every node:
curl -s https://lium.io/api/executors \
| jq '[.[] | select(.specs.tdx_attestation_passed == true) | {id, machine_name, gpu_count}]'
Rent the node you picked with its full GPU count, so the rent is refused when another pod already holds part of the machine: Lium.up(executor_id=..., gpu_count=...) in the SDK or lium up <id> -c <gpu_count> in the CLI.
Do not pass secrets in the rent request, the template's environment variables or a startup command. They travel through Lium's control plane.
The label is what Lium last observed for the machine. Your verifier, not the label, decides whether the pod receives a key.
3. Get a quote from inside the pod
Inside the pod, create a key pair that exists only in memory. Ask the broker for a fresh nonce. Bind both into the quote's report_data:
import hashlib
from cryptography.hazmat.primitives.asymmetric.x25519 import X25519PrivateKey
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from dstack_sdk import DstackClient
nonce = get_nonce_from_your_broker() # your code
private_key = X25519PrivateKey.generate()
public_key = private_key.public_key().public_bytes(Encoding.Raw, PublicFormat.Raw)
quote = DstackClient().get_quote(hashlib.sha256(public_key + nonce).digest())
send_to_your_broker(quote.quote, quote.event_log, public_key, nonce) # your code
4. Verify the quote and release the key
The broker releases nothing until every check passes:
- Signature and TCB. The quote verifies against Intel's certificate chain with an Intel DCAP quote verifier or the dstack verifier, and its TCB status is up to date.
- Binding.
report_dataequalssha256(public_key + nonce), and the nonce is one the broker issued in the last few minutes and has not seen before. - Measurements. The OS image measurements (MRTD, RTMR0 to RTMR2) are the ones of the dstack OS image release named in the CVM guide, and the compose hash in RTMR3 is the one published in the "CVM attestation" section of the current executor release notes. Reject any other value, even when the quote itself is genuine.
When all three pass, the broker encrypts the data key, or a short-lived storage credential, to the pod's public key and returns it. It logs the pod, the quote's hash and the time.
5. Load the data
The pod decrypts the key, downloads the ciphertext and decrypts it into memory or into /root. Do not write plaintext to a network volume or to a path you back up.
6. End the run
Terminate the pod. The in-memory key pair goes with it. Revoke any storage credential that has not expired, and rotate the data key when you retire that version of the model or dataset.
Credential lifecycle
| Credential | Where it lives | Lifetime | How it ends |
|---|---|---|---|
| Lium API key | Your laptop or CI, never the pod | Long; set an expiry and a budget | Delete it under Access → API Keys. A read and rent key is enough for this flow. |
| SSH private key | Your laptop | Long | The pod only receives the public key. |
| Pod key pair | Pod memory | The pod's lifetime | Gone when the pod is terminated. |
| Data key | Your key broker | Until you rotate it | Released per attested pod, wrapped to that pod's public key. |
| Storage credential | Pod memory | Minutes to an hour | A pre-signed URL or a temporary token, read-only, limited to the one object or prefix. It expires on its own, or you revoke it. |
Related
- Pod security: what a provider can do on an ordinary machine, and the in-pod quote socket.
- Encrypted local volumes: data at rest, on any machine.
- API keys: scopes and budgets for the key that rents the pod.