Skip to main content

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.

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.

At rest

The CVM’s data disk is encrypted with LUKS2 using the aes-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:
LayerMechanism
Cipheraes-xts-plain64
KDF for the LUKS2 keyslotPBKDF2
Key sourcedstack KMS, delivered to the CVM at boot in the dstack response
Key residenceCVM memory only — never stored in plaintext on disk, in logs, or anywhere the operator can reach
Key derivation primitiveHKDF-SHA256 inside the KMS (salt "RATLS"), bound to the cluster’s attested identity
This protects against a compromised host detaching the disk and reading it elsewhere: without an attested CVM with the matching identity, the LUKS2 keyslot cannot be unlocked. It does not protect against an attacker who has already compromised the running CVM — at that point the key is in memory and the attacker has the same access Postgres does. That is the threat the next two layers are for. Backups use a separate cipher: AES-256-GCM with a 32-byte cluster-shared key derived inside the KMS at the path 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 the aws-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.1 retained as a legacy raw-quote fallback
  • The TLS public key is bound to that quote via the quote’s REPORTDATA field, 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
A standard TLS client that does not understand the OID rejects the cert as untrusted, which is why TeeSQL ships RA-TLS-aware client libraries that verify the quote out-of-band rather than the chain. See SSL & TLS and Remote attestation for the full handshake and verification flow.

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 gdb or virsh dump from 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
TDX is enforced by silicon, not by software policy. It does not protect against side-channel attacks against the CPU, against a complete TDX silicon vulnerability, or against an attacker who has compromised the CVM at the application layer. See Trusted execution environments for the full threat model.

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.
KeyPurposePath / sourceCipher consumed by
Disk encryption keyLUKS2 unlockdstack response field disk_crypt_key at CVM bootLUKS2 (aes-xts-plain64)
Backup encryption keyEncrypted base backups + WAL segmentsKMS path backup/encryption, onboarding envelopeAES-256-GCM
Postgres role passwordsteesql_read, teesql_readwrite, replicatorCluster secret in onboarding envelope; sidecar injects on the wirePostgres SCRAM-SHA-256 (driver-side)
RA-TLS key + certificateServer- and client-side mutual RA-TLSdstack guest agent GetTlsKey(...) per CVM bootTLS 1.2/1.3 + TDX quote binding
Properties that follow from this design:
  • 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_hash produces a different attested identity, which the KMS refuses to unlock against the cluster’s keys.
There is no automatic key rotation today; keys rotate when the cluster’s CVM image is replaced, which produces a new attested identity and therefore a new KMS-derived key set.
Last modified on May 1, 2026