Skip to main content
Tinfoil offers two ways to persist data. Encrypted volumes (this page) are block storage: a filesystem attached to one enclave at a time, suited to large working sets such as build trees, datasets, and fine-tuning checkpoints, encrypted under a secret the deployment owner holds. The buckets sidecar is object storage: encrypted objects in S3, reachable from any number of enclaves and clients, encrypted under keys your end users hold.

Overview

A secure enclave encrypts its memory with a key that only the enclave’s own hardware can use. That is what guarantees no operator, including Tinfoil, can read the data being processed inside it. Memory, however, is not persistent, and even if it were, the key protecting it lives in hardware registers that cannot be read out or saved. Everything in the enclave is lost when it stops. Encrypted persistent volumes extend the enclave model to storage. They compose two primitives: private secret delivery and authenticated disk encryption. A volume’s contents are unreadable to anyone who does not hold its volume secret, and that secret never exists outside your infrastructure and the enclave.

Key management

Persistent storage needs a long-term secret to encrypt and authenticate data under. That secret cannot be managed by Tinfoil, since anyone holding it can read or modify the data. It is created and kept on your side. When you first provision a deployment with a volume, your client generates a random 64-byte volume secret and stores it durably, either locally or in a keyserver on your own infrastructure. The enclave never generates or persists this secret. On every boot, the volume secret is delivered to the enclave after attestation, over a connection that terminates inside the enclave. There are two ways to do this:
  • Automatically, by declaring the volume secret as a private secret and letting your keyserver release it once the enclave’s attestation matches your policy.
  • Manually, by sending the secret over the attested connection to the running enclave, which unlocks the volume at runtime.
Inside the enclave, the volume secret is expanded with HKDF into the two keys the disk layer needs: a 64-byte AES-XTS cipher key and a 32-byte HMAC key. You provision one secret; the derived keys exist only in enclave memory.
The volume secret is the confidentiality boundary for everything on the volume. If it is lost, the data cannot be recovered by you, by Tinfoil, or by anyone else.

Disk encryption

Once the enclave holds the derived keys, it opens the volume with two Linux kernel primitives, dm-crypt and dm-integrity, configured for authenticated encryption:
  • Confidentiality: AES-XTS with a fresh random IV for every write, so identical plaintext produces different ciphertext each time it is written, regardless of where it lands on disk.
  • Integrity: an HMAC-SHA256 tag over every 4 KiB sector. The tag and the IV are stored in a journaled dm-integrity layer beneath the encrypted device, and any sector whose tag does not verify is rejected on read.
Your container sees an ordinary writable filesystem. The disk, and anyone with access to it, sees only ciphertext, tags, and IVs.

Threat model

The goal is to give the volume the same guarantees as the enclave’s encrypted memory, and to be explicit about what it does not cover. Protected. An attacker with full access to the disk cannot read its contents, and cannot forge or alter a sector’s contents without the enclave detecting it. Because every write uses a random IV, the attacker also cannot tell whether two sectors hold the same data or whether a sector was rewritten with its previous contents, which rules out ciphertext-comparison attacks. Not protected: rollback. Integrity protection guarantees the ciphertext has not been tampered with, but an attacker who replays an earlier, valid version of a sector, or restores the whole disk to an earlier state, is not detected. This mirrors the memory model, where the hardware protects against modification but not replay. Not protected: access patterns. A privileged attacker can observe which sectors the enclave reads and writes, and when. This side channel can leak information about enclave activity even though the contents are encrypted. It can be closed at the application level by running an Oblivious RAM (ORAM) scheme on top of the volume, at a performance cost that depends on your workload. For an example of such implementation and a detailed study of this tradeoff, see Opal, a private memory system for personal AI built on Tinfoil.

Configuration

Declare volumes at the top level of tinfoil-config.yml and mount them into containers by name. key-secret names the private secret that carries the volume secret; omit it to unlock the volume manually at runtime instead. It must be a private secret released by your keyserver. A Tinfoil-managed secret would give Tinfoil the ability to read the volume.
tinfoil-config.yml
Requires cvm-version 0.14.4 or later.
Volumes persist across restarts and redeploys of the same deployment. Docker’s writable layers, pulled images, and ordinary Docker volumes still live in memory and are lost on restart; only data written to a declared volume is durable.