Security and data flow
This page is for the security reviewer. It says where a request goes, what is kept and where, which controls exist today, and which do not exist yet. Section references such as "platform spec §6.3" point to TerraFlow's design specification, which Altius can share on request.
The boundary, stated plainly
The preview is not inside your boundary. It runs on one server in AWS ap-south-1 (Mumbai), operated by Altius. Your prompts and the answers to them are sent to Anthropic, Microsoft Azure OpenAI and Google under Altius's provider accounts and terms. Use synthetic or public data only. TerraFlow's own promise, that your data never leaves your boundary, holds only in a Pilot installed inside it, with your models, your keys and your identity provider. Real customer data belongs only there.
How a request flows
Your code (OpenAI or Anthropic SDK)
| HTTPS to your workspace's own host
v
Edge (Caddy): TLS; only /v1, /api and /console are forwarded; security headers;
| per-IP rate limits; 2 MB body cap; client IP logged for 14 days
v
Your workspace's TerraFlow plane (its own container, database, cache and keys)
| 1 identify the key, the workload and its contract
| 2 classify the data: declared class, then a scan of everything a model would receive
| 3 Cedar policy over every model: which may receive this request?
| 4 cache, then choose a permitted model and its fallbacks
| 5 reserve budget; the spend guard reserves the call's worst-case cost
| 6 call the model ---> provider (prompt leaves the server)
| 7 check the answer; settle cost; append evidence <--- answer
v
Response with x-terraflow-* headers; evidence in your workspace's ledger
A request that is refused at steps 1 to 5 never reaches a provider. Every outcome, refused or answered, is recorded in the evidence ledger, and the routing decision is committed to it before any model is called.
Where data is held
| Where | What is held | Prompt or answer text? |
|---|---|---|
| Edge (Caddy) | TLS termination; an access log, kept 14 days, with these fields per request: time, client IP and port, protocol, method, host, path (any query string is replaced by ?REDACTED), TLS version, cipher and server name, bytes read, response size, status and duration |
No. Bodies, request headers (so API keys and cookies) and response headers are never logged, and the invite token travels in the URL fragment, which browsers never send |
| Workspace plane, in memory | The request while it runs | Yes, while it runs |
| Workspace cache (Redis, no persistence) | Cached answers, kept no longer than the contract's retention allows | Yes, in memory only, never written to disk |
| Workspace database (PostgreSQL) | The organisation name (as the workspace tenant's name), evidence (hash-chained, without text), contracts, users (scrypt password hashes), API keys (SHA-256 hashes), cost records, semantic-cache vectors | No. Semantic-cache vectors are numbers computed from prompts, not the prompts. Answers held for human review would be stored encrypted; no starter workload uses review |
| Workspace plane logs | JSON lines that carry request ids, and errors by type and code location only. A preview plane keeps no per-request access log of its own: the edge's is the only one | No |
| Telemetry | No telemetry export is configured in the preview | None leaves the server |
| Spend guard (Redis) | Spend counters per workspace and per month, in micro-dollars | No |
| Model providers | The prompt and the answer, under Altius's provider terms, for the retention period each model's data terms in the preview catalogue record (see the models table) | Yes. This is why the preview is for synthetic data only |
| Backups | A nightly dump of each workspace database and an archive of its signing keys, kept 7 days on the server. The key archives are kept in a directory that is not mounted into the PostgreSQL server, so the database server cannot read them | No text, except encrypted held answers if any |
Controls that exist
| Control | What it does | Reference |
|---|---|---|
| Data classification and data gates | Every field a model would receive is scanned for personal data, card numbers, health data and credentials. The effective class is the more sensitive of what you declared and what was detected; an undeclared request is treated as the most sensitive class its workload accepts. Images, audio and files cannot be scanned, so they are treated as restricted | Platform spec §6.3 |
| Preview model limits | Every external model accepts internal data at most and no detected sensitive type, so confidential data and anything with detected personal or card data never reaches a provider. The detection is pattern-based: it is a safety net, not a licence to send real data | HP spec §5 |
| Cedar policy before optimisation | Each candidate model is checked for egress, jurisdiction, data class, model family, lifecycle, consequence tier, data terms and shared prompt caches before any routing or caching decision. A request with no permitted model is denied | Platform spec §6.5 |
| Signed configuration bundles | Contracts, policy and the model catalogue reach the engine only as an Ed25519-signed bundle. An invalid or expired bundle fails closed | Platform spec §6.6 |
| Separation of duties | A contract is approved by someone other than its author before it runs | Platform spec §6.2 |
| Tamper-evident evidence | Every outcome is appended to a SHA-256 hash chain with Ed25519-signed checkpoints, without prompt or answer text. The console and terraflow ledger verify recompute the chain and check the signatures |
Platform spec §6.16 |
| Budgets | Integer micro-dollar reservations of each request's worst case, reconciled to actual cost, at tenant, business-unit and workload level | Platform spec §6.11 |
| The spend guard | See below | HP spec §7.2 |
| One plane per workspace | Each workspace has its own containers, database and login role, Redis, signing key, ledger and session secret. A key or session from one workspace is rejected by another | HP spec §4.2 |
| Edge path allow-list and headers | Only /v1, /api and /console reach a workspace; everything else, including metrics and health endpoints, is a 404. HSTS, a Content-Security-Policy, nosniff, no-referrer and a restrictive permissions policy on every response |
HP spec §8.3 |
| Rate limits | Per client IP at the edge (sign-in and invite redemption 10 a minute, /v1 120 a minute); per workload in the plane; per workspace for provider calls in the guard |
HP spec §7.4, §8.3 |
| Invites | 256-bit single-use tokens, stored only as SHA-256 hashes, expiring after 7 days; one error for every failure; at most 10 failed redemption attempts per client address per 15 minutes | HP spec §6.3 |
| Sessions and passwords | Passwords of at least 12 characters, hashed with scrypt; host-only, Secure, HttpOnly session cookies named __Host-; a CSRF header check on the console API |
HP spec §8.2 |
| Host | Only ports 80 and 443 are open to the internet. SSH (port 22) is allowed through the server's own firewall (ufw) and is filtered to the operator's address by the AWS security group in front of the server. Automatic security updates; secrets in owner-only files, never in the image. The preview's containers are blocked from the cloud instance-metadata endpoint by a firewall rule, so a workspace cannot read the server's cloud metadata or obtain its cloud identity; the block is checked from inside a container before the preview opens | HP spec §8.1 |
The spend guard
Every call to a paid provider, including health probes, cache verification, shadow comparisons and quality checks,
first reserves its worst-case cost with a spend guard that runs outside the workspaces. A call is made only if it fits
the workspace's lifetime allowance ($5), the preview's monthly ceiling ($100 across all workspaces) and the
workspace's provider calls per minute. If the guard cannot answer within 250 milliseconds the call is refused
(SPEND_GUARD_UNAVAILABLE, fail closed). No setting in a workspace can raise these limits.
Known limit, stated in full. Each workspace reaches the guard with its own credentials. Redis's access control confines it to its own counters, plus adding to (never setting or deleting) the shared monthly counter, but Redis checks every command the guard runs against the caller's own rights, so a workspace must itself be able to write those counters. Access control alone therefore cannot confine a compromised plane. A workspace plane taken over by an attacker able to run code could:
- falsify its own counters, and so lift its own allowance;
- add to the shared monthly counter, and so push the whole preview to its ceiling for everyone;
- fill the guard's memory, or slow it, with its own reservation records. The guard never evicts data (an evicted
counter would silently reset spend), so when its memory is full every workspace's paid calls fail closed with
SPEND_GUARD_UNAVAILABLE.
Prospects have no path to run code in a plane. A check of the monthly counter against the workspaces' shares finds bookkeeping faults, not a compromised plane, which can move both together. The backstops are outside TerraFlow, and they are not all hard stops:
| Provider | Backstop |
|---|---|
| Anthropic | A spend limit on the preview's own Anthropic workspace, which would be a hard stop. To be confirmed by the operator before the preview opens |
| Azure OpenAI | An Azure budget, which alerts but does not stop spending |
| Google Gemini | To be confirmed by the operator before the preview opens |
and the operator's monthly check of the provider bills. A broker that alone may write the counters is planned for Phase 5.
What is shared
Workspaces are separate TerraFlow planes, but they share:
- the server, its Docker daemon and its operating system;
- one PostgreSQL server, with a separate database and login role per workspace;
- the spend-guard Redis, with a separate access-controlled user per workspace;
- the on-server embedding model (Ollama);
- the edge (Caddy) and its access log;
- Altius's provider accounts and keys, and so the providers' rate limits and account-scoped prompt caches. Because of those caches, confidential data is kept off every external model.
Residual risk: the shared provider prompt cache. Every external model in the preview is marked as sharing its
provider's prompt cache across all workspaces, because the cache belongs to Altius's provider account, not to your
workspace. Providers cache long prompt prefixes on their own (Azure OpenAI does so automatically for prompts of 1,024
tokens or more), and TerraFlow passes the provider's cached-token count back in the usage it returns
(cached_tokens, cache_read_input_tokens) and records it in the evidence. So a prospect who sends a long prompt can
tell, from the response time or from that count, whether someone, possibly another prospect, sent the same prefix
shortly before. It does not reveal the
other prompt's text or who sent it, and the preview bills every cached token at the full input price. This is one more
reason the preview is for synthetic or public data only; in a Pilot the provider accounts, and so their caches, are
your own.
Controls that do not exist yet
| Not yet built | Planned for |
|---|---|
| Single sign-on (OIDC, SAML) and multi-factor sign-in; today it is a username and password | Phase 5 |
| A separate admin listener: today the console API and the model API share one listener behind the edge | Phase 5 |
| Key custody in a KMS or HSM, an external secrets manager, and encryption of the database by TerraFlow itself | Phase 5 |
| mTLS between components and an egress proxy | Phase 5 |
| Penetration test, formal threat model and a SOC report | Phase 5 |
| High availability; today there is one server and one replica per workspace, with no uptime commitment | Phase 5 |
| Reconciliation of costs against provider invoices | Phase 5 |
| Tenant administration and tenant-scoped console roles within one plane | Phase 4D |
| Retention runs, erasure and legal hold | Phase 4D |
| A Policies screen for authoring Cedar policy in the console | Phase 4C |
TerraFlow holds no security certification, and this preview is not production software.