Tinfoil offers two ways to persist data. The buckets sidecar (this page) is object
storage: encrypted objects in S3, reachable from any number of enclaves and clients, encrypted
under keys your end users hold. Encrypted volumes 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 key the deployment owner
holds.
End users hold the keys
You operate the enclave, but the data belongs to your end users, so each user’s data is sealed under a key only that user holds. Keys cannot live inside the enclave: it has no persistent disk, so a key generated and kept there would be lost on the first deploy or update, making everything stored under it unrecoverable. Instead, each end user generates a 32-byte AES-256 key on their own device (or derives one from a passphrase using a key derivation function such as HKDF) and sends it along with each request to your app. Your app authenticates the user, then forwards the key to the sidecar in a per-request header. The key exists inside the enclave only for the lifetime of the request and is never persisted, so neither you as the operator nor Tinfoil can decrypt the stored data.Tutorial
This walks through adding encrypted S3 storage to an existing container deployment. For a complete runnable deployment, see the persistent storage example.1. Create a bucket and IAM credentials
Create an S3 bucket and an IAM user whose credentials the sidecar will use. IAM is what controls which buckets are accessible, so attach a policy scoped to the bucket(s) the sidecar should reach:AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Use tinfoil secret create SECRET_NAME --value-file ./path for organization scope. For repository scope, add them in the repository’s Repository secrets section under Containers → Repositories in the dashboard. These credentials only ever touch ciphertext.
2. Add the sidecar to your config
Run the sidecar alongside your app in multitenant mode and put both on a shared network. The sidecar needs egress to reach S3; your app reaches it athttp://buckets:9000 by container name:
tinfoil-config.yml
3. Have each end user generate a key
Client applications generate 32 random bytes per user, base64-encode them, and store the key durably on the user’s side. The equivalent of:4. Make per-user requests from your app
For each authenticated request, your app forwards two headers to the sidecar: the user’s key, and a tenant id your app derives from the user’s verified identity (never from user input). Any S3 SDK works, configured with the sidecar as the endpoint, path-style addressing, and sequential single-request transfers; credentials can be any throwaway values, since SDKs refuse to send unsigned requests:s3://bucket/key), so one sidecar can serve multiple buckets; reachability is enforced by the IAM policy from step 1. Equivalent Java and AWS CLI setups are in the sidecar’s guides.
How multitenancy works
- Objects are transparently namespaced under
<tenantId>/in the backing bucket, so one tenant can never address another’s objects. Listing and reads within a tenant see plain object keys with the prefix stripped. - The sidecar trusts the tenant ID and key it receives in the headers; your app is the authentication layer. Derive the tenant ID from the user’s verified identity, never from client input.
- Key and tenant id are decoupled, so a user can rotate keys without moving data. The caller tracks which key decrypts which object; the wrong key returns
400 DecryptionFailed.
MULTITENANT and supply one ENCRYPTION_KEY secret instead. See the sidecar README.
Differences from normal S3
Because the sidecar maintains streaming AES-GCM cipher state, a few S3 behaviors differ:
High-level SDK transfer managers satisfy the multipart constraints with the configuration shown above. For objects larger than the buffer cap, the sidecar supports a streaming mode (
DANGEROUS_DELAYED_AUTH) that requires a verifying client; see the design notes before using it.
Relevant repositories
- tinfoil-buckets-sidecar: the sidecar itself, with CLI and SDK guides
- tinfoil-persistent-storage-example: a minimal deployable example

