Skip to content

Security & Tenant Isolation

A synthesis page. Security in Starform is not one feature — it's the sum of four mechanisms, each owned by a canonical section elsewhere. This page ties them together; the linked sections remain authoritative.

The four pillars:

  1. Network isolation — namespace-per-project + label-selector NetworkPolicies (§20.4).
  2. Query isolation — a server-side tenant filter on all telemetry the client cannot override (§35.2 / FR-065).
  3. Encryption at rest — AES-256-GCM on all sensitive Postgres fields (FR-060), and Cloudflare Origin Certs in transit with no cert-manager (§5).
  4. Ingress auth — per-cluster bearer tokens on telemetry ingress, even over private VPC peering (FR-066 / FR-071).

Network isolation — namespace + NetworkPolicy

Tenant isolation is namespace-per-project plus label-selector NetworkPoliciesnot the VPC. Clusters in a region share one /16 VPC (§4.4); isolation is enforced inside the cluster, so sharing the regional VPC is safe.

K8s NetworkPolicies support podSelector.matchLabels — policies reference pods by label rather than by namespace. For each environment, Shuttle creates a policy in the project namespace (§20.4):

Environment-isolation NetworkPolicy · proj-<project_slug> namespace (§20.4)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: env-isolation-production
  namespace: proj-acme-api
spec:
  podSelector:
    matchLabels:
      starform.io/environment: production
  policyTypes: [Ingress, Egress]
  ingress:
    - from:
        - podSelector:
            matchLabels:
              starform.io/environment: production   # same env only
    - from:
        - namespaceSelector:
            matchLabels:
              starform.io/namespace-role: gateway   # Envoy Gateway namespace
  egress:
    - to:
        - podSelector:
            matchLabels:
              starform.io/environment: production
    - to: []   # all external traffic allowed (egress policing is at Gateway)
      ports:
        - protocol: TCP
          port: 443

This enforces production pods can only reach production pods, and staging pods cannot reach production pods, within the same namespace. The starform.io/environment label is therefore load-bearing for isolation — see the label catalog §24.1.

Failure mode → loud, not silent (pre-launch-blocking)

If Shuttle fails to apply the correct starform.io/environment label on a pod, that pod loses its NetworkPolicy protection. Mitigation: a Kyverno admission policy (post-MVP) rejects any pod without the required label set, turning a silent failure into a loud one (§20.4; enforcement tracked in §39.2).

Query isolation — the server-side telemetry filter

Every customer metric and log query is scoped by a tenant filter injected server-side from the authenticated session. The client cannot supply or override it. Starbase acts as the telemetry-query broker: it routes each query to the project's region and injects the filter before the store ever sees the request (§35.2).

  • FR-065 — all customer metric/log queries MUST be scoped by a server-side tenant filter; the client MUST NOT supply or override it.
  • SC-016 — customer queries never return another tenant's data (verified by an isolation test in CI).

The filter keys off the tenant tuple — project_id + environment + service_id, with workspace_id as the billing boundary — the same identity every series and log line is attributed to (§24.1).

Encryption — at rest and in transit

At rest (AES-256-GCM). All sensitive data in Postgres is encrypted with AES-256-GCM using a single key from the ENCRYPTION_KEY env var; key rotation is a post-MVP batch job. The encryption-at-rest catalog (§39.1 item 18) covers every encrypted field:

Encrypted field Requirement
Var Group entry values (§38.2) FR-036
Database credentials FR-028
Storage (bucket) credentials FR-033
GitHub installation tokens FR-060
Cloud-provider credentials / kubeconfigs Starform holds for its own clusters FR-060

FR-060 mandates AES-256-GCM for all sensitive data at rest; SC-011 requires those credentials never appear in logs or API responses.

In transit (Cloudflare, no cert-manager). TLS terminates at the Cloudflare edge; Cloudflare → origin is encrypted with a free Cloudflare Origin Certificate (15-year validity, stored as a K8s Secret on the Gateway listener). *.starform.app subdomains use Cloudflare's wildcard edge cert. No cert-manager is needed at MVP — see Networking › Traffic & TLS §5. (cert-manager arrives post-MVP only when customer-domain Let's Encrypt issuance lands, §39.)

Ingress auth — per-cluster bearer tokens

Customer telemetry ships over the private network (DO VPC peering), authenticated with a per-cluster bearer token at the metrics ingress (vmauth) and the logs ingress (the Vector aggregator's fluent source) — even over the private link. This is defense in depth: a single compromised cluster cannot spoof another's data.

The telemetry stores are VPC-private (no public IPs). Starbase reads them only through the authenticated front door — vmauth (VictoriaMetrics) + a read-only ClickHouse user — over the peered link, and always injects the server-side tenant filter on that read path.

  • FR-066 — ship customer telemetry over the private network, authenticated with a per-cluster bearer token at the metrics and logs ingress (§35.4).
  • FR-071 — serve cross-region telemetry reads over the private network through an authenticated store front-door (vmauth + read-only ClickHouse user), never a public endpoint, applying the server-side tenant filter on that read path.

Authentication & authorization (who can act)

Dashboard login is SSO via GitHub + Google at MVP — distinct from the deferred customer auth primitive (a feature Starform offers customers' apps, out of scope at MVP). Authorization within the dashboard is the two-tier RBAC model §15: workspace roles + project roles + the environment-protection flag.


Cross-references

Network isolation → §20.4 · isolation labels → §24.1 · server-side query filter → §35.2 / FR-065 / SC-016 · encryption-at-rest catalog → §39.1 #18 / FR-060 · TLS / Origin Certs → §5 · ingress + cross-region read auth → FR-066 / FR-071 (§35.4) · RBAC → §15. Canonical map: Canonical Sources.