Confidential agent memory with polign_db on Phala Cloud
You can now run polign_db inside an Intel TDX confidential VM using the Phala Cloud template. The database searches in protected memory and encrypts its contents before writing to disk or your own S3 or GCS bucket.
An agent's memory accumulates what people tell it: conversations, documents, preferences and decisions. Keeping that history makes the agent useful. It also gives the database a growing collection of information its users expect to stay private.
I wanted to keep that memory in a bucket I control and choose the machine that searches it, while limiting what the infrastructure operator can read. That requires protecting the data during a query as well as between queries.
This deployment combines hardware isolation, encryption inside the database and attestation. Each covers a different part of the path from an agent's request to the stored record.
Protect memory and storage together
TLS protects a request on the network. Storage encryption protects persisted data. During a search, though, the database needs readable vectors, indexes and records in memory. Intel TDX isolates that guest memory from the host operating system and hypervisor. The database and other software inside the guest can still read it.
Storage needs its own protection. With bucket-side encryption, the storage service handles plaintext on uploads and downloads. polign_db encrypts inside the database process, before the bytes reach storage. The bucket can store and return the data without possessing the database keys.
The write log, segments, vector and text indexes, manifests and local disk-cache entries use AES-256-GCM. Encryption works in 16 KiB frames, so a search can fetch and decrypt the ranges it needs without downloading an entire object. That preserves the ability to serve an index that is larger than the VM's memory.
Object names, sizes and access patterns remain visible to storage, along with a plaintext
.encryption marker identifying the store as encrypted. Authenticated encryption detects
altered ciphertext; it does not establish that storage returned the latest version. The
encryption documentation describes the format and its limits.
Follow a request through the system
Phala's dstack runs the template's Docker Compose application inside a confidential VM (CVM). On the public HTTPS path, TLS terminates in a separate gateway trusted execution environment (TEE). The gateway and application CVM mutually attest before establishing an encrypted tunnel, as described in Phala's network security documentation.
Inside the application CVM, Caddy checks a shared bearer token and forwards requests to
polign-server. Public port 23000 reaches this proxy; the database's gRPC listener
stays on localhost inside its container. Only GET /healthz is open without a token.
Anyone with the token can read, write and delete data through the API.
The client, gateway TEE and application CVM all handle plaintext. If your agent sends retrieved context to an external model API, that provider receives it too. Your application decides which user may retrieve which records; the template's shared token grants database access.
Verify the code that gets the keys
Hardware isolation makes the software inside the VM more consequential: that software can read the data and keys. You still trust Intel's TDX implementation, the guest OS, container images, proxy, database binary and Phala's key-delivery infrastructure.
Attestation supplies signed evidence about the environment. A verifier outside the CVM needs to
validate the quote, compare platform measurements and application configuration with approved
values, and replay the configuration event log against the quoted RTMR3 register.
Freshness and binding to the endpoint or key receiving your data also matter. Phala's
application verification guide describes these checks.
The template currently downloads polign_db v0.5.0 on first start and checks it against
the release's SHA-256 checksum file. Its container images use version tags. That setup still
trusts the release source and mutable image tags: the attested configuration alone does not
identify the downloaded executable.
For a deployment that must prove which executable handles secrets, package the approved binary in an image, pin both application and proxy images by digest, and verify the resulting measurements. The template does not implement this client verification policy or expose the example attestation endpoints in Phala's guide. Retrieving a dashboard quote is an initial inspection step, not complete application verification.
Keep the database when compute changes
With POLIGN_STORE pointed at S3 or GCS, the bucket holds the durable records and
indexes. The CVM keeps hot data in memory and uses an encrypted disk cache, with a default
budget of 4 GiB. A replacement VM with the same store configuration, bucket access and keyring
can open the database and warm its cache as requests arrive.
This matters for agent memory that is retained for months but queried intermittently. You can change the serving machine without copying the index, or remove an idle CVM and keep its bucket. Starting again takes time and begins with a cold cache. The agent memory cost post measures that tradeoff on EC2; we have not measured the equivalent throughput or latency under TDX.
For a starting cost, Phala lists tdx.small at $0.06 an hour for 1 vCPU and 2 GB of
memory. At 730 hours, that is $43.80 for compute, plus about $2.03 for a 20 GB volume at
$0.000139 per GB-hour: about $45.83 a month before bucket storage, requests and
network transfer. Disk charges continue while the CVM is stopped. These
list prices were checked
September 8, 2026. This is a cost example; the workload still needs a capacity test.
What the deployment test established
We tested the template on a tdx.small in Phala's US-WEST-1 region, first with the
CVM volume and then with an S3 store accessed through an IAM role. The test used a small vector
collection and checked deployment, authentication and data access.
| Check | Observed result |
|---|---|
| Startup | The release checksum passed on both stores. The server logged encryption on and created the store marker. |
| API access | Health checks answered without a token. Protected requests returned 401 for missing or incorrect tokens. An authenticated write could be queried back on both stores. |
| S3 and keyring reuse | The CVM read a vector previously written from a laptop using the same keyring. Logs showed the configured IAM role being assumed. |
| Attestation evidence | The running application's quote was retrieved from the dashboard. The test did not verify a pinned binary identity or an automated client policy. |
Switching the configuration to S3 took about a minute and opened the data already in that bucket. It did not migrate the volume's contents. The test resources were deleted afterwards. These observations establish that the tested setup could serve encrypted data; they do not measure search performance or constitute a security audit. GCS is supported by the template but was not part of this deployment test.
Try it with a small collection
The template README contains the full configuration, bucket policies and upgrade instructions. Start with sample data to check the deployment before connecting an agent.
1. Generate and save the secrets
printf '1=%s\n' "$(openssl rand -base64 32)" # POLIGN_STORE_ENCRYPTION_KEYS
openssl rand -hex 32 # BEARER_TOKEN
The first command produces a keyring entry: a numeric ID and a base64-encoded 32-byte key. The second produces the API token. Save both in your secret manager, and keep a recoverable keyring backup separate from the database. Losing the keyring makes the encrypted data unreadable.
Enter both values through Phala's Encrypted Secrets interface. It encrypts values on the client before upload and decrypts them inside the CVM at boot. This also puts the machine where you generate and enter the secrets within your security boundary. Secret updates replace the full set of variables, so include every value when redeploying.
2. Choose the store and deploy
The default POLIGN_STORE=fs:/data/store keeps the database on the CVM volume.
Deleting that volume deletes the database. For storage independent of the VM, use
s3://BUCKET_NAME/polign or gcs://BUCKET_NAME/polign and configure the
credentials described in the README.
The S3 instructions use a bootstrap IAM key to assume a role with access scoped to your bucket and prefix. The bootstrap key still needs management and rotation. GCS uses a base64-encoded service-account key, supplied as an encrypted secret and decoded into RAM inside the CVM. Bucket credentials authorize storage access; the database keyring decrypts its contents.
Open the template,
enter the configuration, expose port 23000 and deploy. The keyring is required.
Check the startup logs for store encryption: on and the write-key ID.
Changing the store URL opens a different store; it does not move data or encrypt an existing
plaintext database. Import existing data into a new encrypted store.
3. Check authentication, then write and search
Set APP_HOST to the hostname Phala gives you and TOKEN to your bearer
token. The first request below should succeed; the second should return HTTP 401.
The authenticated requests then write a vector and search for it.
curl "https://$APP_HOST/healthz"
curl -i "https://$APP_HOST/v1/collections/docs/vectors/a"
curl -X PUT "https://$APP_HOST/v1/collections/docs/vectors/a" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"values":[1,0,0],"metadata":{"label":"first"}}'
curl -X POST "https://$APP_HOST/v1/collections/docs/query" \
-H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
-d '{"values":[0.9,0.1,0],"k":5}'
The collection is created on the first write. The Python SDK uses
the same bearer token as its api_key.
Before using sensitive data, implement the verification policy described above, restrict API and bucket access, keep retrieved content and secrets out of logs, and test backup recovery. To rotate the store key, add a higher key ID and redeploy; new writes use it. Keep older keys for existing objects and backups. Hardware isolation cannot prevent a stolen API token from authorizing requests or bucket credentials from being used to delete data.
The template's polign_db v0.5.0 release is free to self-host under the
v0.x terms; Phala and storage costs are separate. Try it with a
small collection, then size and verify the deployment for the memory your agent needs to keep.