Zero-Trust Posture
Status: living document · Owner: SKOPAQ AI Pvt Ltd · Scope: the VELA ground-segment
service (vela/api/), advisory-only.
The core principle: guarantees live in the application, not at the edge
VELA is air-gap / sovereign-deployable. A cloud edge (Cloudflare, a cloud WAF, a managed identity provider) cannot exist in an air-gapped deployment. Therefore every security guarantee VELA relies on is enforced inside the application, so the same posture holds with or without any cloud vendor. Edge layers (Cloudflare in the cloud, an on-prem WAF in a sovereign install) are defense-in-depth only — never a control the safety or isolation case depends on.
This is the load-bearing rule for a reviewer: remove the edge and the guarantees still hold.
Zero-trust tenets → in-app controls
| Tenet | VELA control | Where |
|---|---|---|
| Verify every request explicitly | Every non-probe route resolves an authenticated Principal; no request is trusted by network position. OIDC JWTs are signature-verified against the IdP JWKS with iss/aud/exp checks; API-key auth is the offline alternative. Missing/invalid credentials → 401. |
vela/api/security.py, vela/api/app.py::_principal |
| Least privilege | Three roles — VIEWER (reads) < OPERATOR (launches) < APPROVER (releases). Each route declares the role it requires; releasing a recovery procedure requires APPROVER. |
vela/api/security.py::Role, per-route _require(...) |
| Non-forgeable authority | The recorded approver is the authenticated principal’s subject, never request-body text — an operator cannot self-attribute a senior approval. | vela/api/service.py (approve), audit trail |
| Isolate tenants (assume breach of one) | Two enforcement points, both keyed on Principal.tenant_id: the investigation record (created/read/audited under the caller’s tenant, not a server default) and the KG (TenantScopedGraphStore — a tenant sees only shared reference data plus its own nodes). |
vela/orchestration.py, vela/api/service.py, vela/kg/store.py |
| Assume breach at the boundary | Structured error envelopes leak no stack traces; security headers on every response; a per-request body-size cap and a rate limiter blunt abuse. | vela/api/middleware.py (SecurityHeaders, BodySizeLimit, RateLimit) |
| No standing trust in the model | Reasoning output is gated by release-blocking grounding gates (fabricated value / unsupported citation → INSUFFICIENT/UNGROUNDED); an uncalibrated “high confidence” is never shown (hazard H4). |
vela/audit/, vela/agents/nodes.py::_calibrate_confidence |
Data-plane zero-trust — the structural caps
Beyond request auth, VELA caps the worst outcome structurally, so even a fully-compromised reasoning path cannot cross the safety boundary:
- No commanding (guardrail #1). No code path constructs, formats, or transmits a telecommand —
grep-enforced in CI over
apps/andvela/(scripts/guardrails/no-commanding.sh), now with a regression test on both halves. This is the invariant the entire safety case rests on; it holds regardless of any edge or auth layer. - Read-only, typed MCP boundary (guardrail #4). Agents reach data only through
vela.mcp.client(import-linter-enforced); tools are read-only and whitelisted, with a traversal hop-cap and no free-form queries from the model. - Air-gap egress-free. In
airgapmode the service constructs no network-backed reasoning backend (hard-fails ifreasoning != "deterministic") and performs no egress; the whole pipeline runs offline. - No fabricated data (guardrail #2). All spacecraft data is synthetic reference (VELA-REF-1) or seeded replay; nothing is presented as a real mission.
Deployment-posture edges (defense-in-depth, never core)
| Posture | Identity / secrets | Edge |
|---|---|---|
| Cloud SaaS | OIDC IdP (Auth0/Okta/Keycloak) via the AuthProvider seam; secrets from the platform’s secret store / env. |
Cloudflare (or an equivalent) in front: WAF, Access / Zero-Trust network policy, DDoS, edge mTLS. Optional hardening — the app’s auth/RBAC/tenant isolation still hold if it is removed. |
| Sovereign / air-gap | Keycloak (self-hostable OIDC, air-gap-capable) behind the same AuthProvider seam; Vault (Shamir unseal) for secrets. |
On-prem WAF / reverse proxy + mTLS between services. No internet, so no Cloudflare — the equivalent controls run inside the enclave. |
Secrets in both postures are read from the environment at connect time, never from config files, and OIDC validation is public-key only (the JWKS) — VELA holds no client secret to leak.
Residual gaps / roadmap (honest)
- mTLS between internal services is a deployment concern (service mesh / on-prem proxy), not yet codified in the chart.
- Per-tenant encryption keys / data residency — the audit’s strongest warning is to make isolation a one-way door before a second tenant; record + KG isolation are done, per-tenant keys are the next increment and must not be retrofitted after cross-tenant data lands.
- Vault auto-unseal (connected) vs Shamir (air-gap) wiring is specified but not yet in the Helm chart.
- Compliance certification surface (ITAR/EAR/MTCR, DPDP 2023, MeitY/CERT-In, ISO 27001, SOC 2) is a separate legal/compliance track — this document is the technical posture only.
Review rule
Any change that would make a security guarantee depend on the edge (Cloudflare, a cloud WAF, a managed IdP) rather than the application is a regression of this posture. State the guarantee, show it holds with the edge removed, or don’t ship it.
