TeeSQL composes three independent encryption layers, each with a different cipher and a different threat. This page describes the mechanism for each, where the keys come from, and what the layer does and does not protect.Documentation Index
Fetch the complete documentation index at: https://docs.teesql.com/llms.txt
Use this file to discover all available pages before exploring further.
At rest
The CVM’s data disk is encrypted with LUKS2 using theaes-xts-plain64 cipher and PBKDF2 key derivation. The format is set up at first boot via cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --pbkdf pbkdf2, and the same key is used to open the volume on every subsequent boot.
The disk encryption key is delivered to the CVM by the dstack KMS at startup. The CVM never sees the key on disk — it lands in CVM memory only after the platform produces a TDX quote, the KMS verifies it, and the quote’s measurements match the cluster’s attested identity. The key is then handed to cryptsetup luksOpen to unlock the LUKS2 volume.
Concretely:
| Layer | Mechanism |
|---|---|
| Cipher | aes-xts-plain64 |
| KDF for the LUKS2 keyslot | PBKDF2 |
| Key source | dstack KMS, delivered to the CVM at boot in the dstack response |
| Key residence | CVM memory only — never stored in plaintext on disk, in logs, or anywhere the operator can reach |
| Key derivation primitive | HKDF-SHA256 inside the KMS (salt "RATLS"), bound to the cluster’s attested identity |
backup/encryption. Backups are encrypted inside the CVM before being uploaded to untrusted blob storage. The backup key is part of the cluster’s onboarding envelope and is the same on every cluster member, so any member can produce a backup any other member can restore — but no one outside the TEE ever sees the key.
In transit
External clients reach the cluster on port 5433 only, where the sidecar terminates a mutual RA-TLS handshake using rustls with theaws-lc-rs cryptographic provider. Plain Postgres on port 5432 is bound to localhost inside the CVM and is unreachable from outside.
The sidecar’s TLS configuration uses rustls’s default cipher suite selection (TLS 1.3 preferred, TLS 1.2 supported). The signature-verification paths for both versions are implemented; older TLS versions are not negotiated. No custom cipher restrictions are configured in the sidecar — it relies on rustls’s default safe set.
What makes RA-TLS different from standard TLS is the certificate, not the cipher suites:
- The server’s certificate is self-signed by the dstack guest agent inside the CVM
- A TDX attestation is embedded in a custom X.509 extension at Phala RA-TLS OID
1.3.6.1.4.1.62397.1.8(current SCALE-encoded form), with.1.1retained as a legacy raw-quote fallback - The TLS public key is bound to that quote via the quote’s
REPORTDATAfield, so an attacker who substitutes a different certificate cannot reuse the quote - In production the sidecar requires a client certificate of the same shape — the client must present its own TDX-attested cert, and the sidecar runs full DCAP verification on it after the handshake completes
In use
Intel TDX encrypts the CVM’s RAM at the level of the CPU’s memory controller. Memory pages belonging to the Trust Domain are encrypted with keys held inside the CPU itself; the keys never leave the chip and are not visible to the hypervisor, the host OS, the cloud provider’s management plane, or any other workload on the same physical machine. Practically, this means:- A
gdborvirsh dumpfrom the host produces ciphertext, not Postgres rows - A memory snapshot taken by the cloud provider’s management plane is similarly opaque
- The disk encryption key, the cluster secrets, the KMS-derived password, and Postgres’s buffer cache all live in CVM memory and are protected by this layer for as long as Postgres is running
Key management
All keys derived for a TeeSQL cluster come from the dstack KMS, which itself runs in a separate attested TEE instance. The KMS uses HKDF-SHA256 to derive per-purpose keys from a per-cluster root, with each derived key bound to the cluster’s attested identity.| Key | Purpose | Path / source | Cipher consumed by |
|---|---|---|---|
| Disk encryption key | LUKS2 unlock | dstack response field disk_crypt_key at CVM boot | LUKS2 (aes-xts-plain64) |
| Backup encryption key | Encrypted base backups + WAL segments | KMS path backup/encryption, onboarding envelope | AES-256-GCM |
| Postgres role passwords | teesql_read, teesql_readwrite, replicator | Cluster secret in onboarding envelope; sidecar injects on the wire | Postgres SCRAM-SHA-256 (driver-side) |
| RA-TLS key + certificate | Server- and client-side mutual RA-TLS | dstack guest agent GetTlsKey(...) per CVM boot | TLS 1.2/1.3 + TDX quote binding |
- No human ever holds plaintext keys. Keys exist only inside enclave memory — in the KMS TEE before delivery, in the database CVM after.
- Keys are deterministic. If a CVM moves to different hardware (or restarts), the KMS re-derives the same key after re-attestation. Restart does not require a backup-and-restore.
- Keys are bound to attested identity. A different CVM image, a tampered guest kernel, or an unexpected
compose_hashproduces a different attested identity, which the KMS refuses to unlock against the cluster’s keys.