From f845a5fa5ac42cd74cd53658b0b2f2cf21aa6648 Mon Sep 17 00:00:00 2001 From: Greg Castle Date: Wed, 28 Oct 2026 21:08:08 +0000 Subject: [PATCH 1/2] docs: redraw the threat model diagrams and add a security boundaries diagram The threat model diagram predated most of the current components (atenet-egress, ate-idp-server, k8s-credential-provider, objectstore plugins, PostgreSQL) and mixed several arrow styles without a legend. Replace it with two diagrams that keep every component in the same place. The first shows how an actor template is prepared: a golden actor is run, snapshotted and kept. The second shows creating an actor from the template and serving a request, through to an egress call with an injected credential. Each numbered arrow says what it does, and a table under each diagram lists what happens at each step and what is checked. Connections outside the journeys are drawn in grey so the full attack surface still shows. Refresh the Key Components list to match. Add a much simpler diagram to security.md that shows only the four boundaries Substrate holds: sandbox, ingress/egress gateways, control plane isolation and snapshot storage. Signed-off-by: Greg Castle --- docs/assets/actor-call-diagram.svg | 208 +++++++++++++++++++++++++ docs/assets/actor-template-diagram.svg | 126 +++++++++++++++ docs/assets/security-boundaries.svg | 84 ++++++++++ docs/assets/threat-model-diagram.svg | 1 - docs/security/security.md | 13 ++ docs/security/threat-model.md | 70 +++++++-- 6 files changed, 489 insertions(+), 13 deletions(-) create mode 100644 docs/assets/actor-call-diagram.svg create mode 100644 docs/assets/actor-template-diagram.svg create mode 100644 docs/assets/security-boundaries.svg delete mode 100644 docs/assets/threat-model-diagram.svg diff --git a/docs/assets/actor-call-diagram.svg b/docs/assets/actor-call-diagram.svg new file mode 100644 index 0000000000..831a3a79df --- /dev/null +++ b/docs/assets/actor-call-diagram.svg @@ -0,0 +1,208 @@ + + Substrate architecture and data flows + + + + + + + + + + + Kubernetes cluster + + ate-system namespace: control plane + + Kubernetes + + Worker node + + Worker Pod, worker namespace + + Sandbox: gVisor or microVM + + Sandbox: gVisor or microVM + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Application layer + agent framework, + end-user auth + + + External relying + parties + + + External services + and tools + + + + Snapshot bucket + + + + MicroVM asset bucket + + + atenet-router + ingress gateway + + + ate-api-server + OpenFGA authz, identity minting, + objectstore-plugin sidecar + + + ate-controller + + + ate-idp-server + OIDC discovery, JWKS + + + + PostgreSQL + + + k8s-credential-provider + egress secrets + + + atenet-egress + egress gateway + + + kube-apiserver + + + podcertcontroller + pod, DNS, DB certs + + + ateworker + atunnel + ingress listener, egress redirect, + DNS relay + + + atelet DaemonSet + objectstore-plugin sidecar + + + Actor A + untrusted code, no credentials + + + Actor B + untrusted code, no credentials + + + Container image + registry + + + A1 + create actor + + A2 + save record + + B1 + send request + + B2 + resume actor + + B3 + restore actor + + B4 + get snapshot + + B5 + start sandbox + + B6 + forward request + + B7 + deliver + + B8 + call a tool + + B9 + forward as this actor + + B10 + get credential + + B11 + call with credential + + A: create an actor + + B: send a request to an actor + + Supporting connection + + Sandbox: untrusted actor code + + Worker Pod: shared by many actors + + Node + + Control plane namespace + + Untrusted + + Node and worker components + + Control plane components + + Outside Substrate + diff --git a/docs/assets/actor-template-diagram.svg b/docs/assets/actor-template-diagram.svg new file mode 100644 index 0000000000..fa3ec6ea6d --- /dev/null +++ b/docs/assets/actor-template-diagram.svg @@ -0,0 +1,126 @@ + + Substrate actor template creation + + + + + + + + + + + Kubernetes cluster + + ate-system namespace: control plane + + Worker node + + Worker Pod, worker namespace + + Sandbox: gVisor or microVM + + + + + + + + + + + + + + + + + Application layer + agent framework, + end-user auth + + + ate-api-server + OpenFGA authz, identity minting, + objectstore-plugin sidecar + + + + PostgreSQL + + + ateworker + atunnel + ingress listener, egress redirect, + DNS relay + + + atelet DaemonSet + objectstore-plugin sidecar + + + Golden actor + built from the template + + + + Snapshot bucket + + + + MicroVM asset bucket + + + Container image + registry + + + T1 + create template + + T10 + template ready + + T2 + run golden actor + + T7 + suspend golden actor + + T3 + pull image + + T4 + start sandbox + + T5 + get actor certificate + + T6 + mint certificate + + T8 + get storage credential + + T9 + upload snapshot + + T: create an actor template + + Other connection + + Sandbox: untrusted actor code + + Worker Pod: shared by many actors + + Node + + Control plane namespace + + Untrusted + + Node and worker components + + Control plane components + + Outside Substrate + diff --git a/docs/assets/security-boundaries.svg b/docs/assets/security-boundaries.svg new file mode 100644 index 0000000000..b5e90c989f --- /dev/null +++ b/docs/assets/security-boundaries.svg @@ -0,0 +1,84 @@ + + Substrate security boundaries + + + + + + + + + + + Substrate + + Control plane + + Worker node + + Sandbox + + Sandbox + + + + + + + + + + + + + Your application + authenticates end users + + + Substrate API + authorization per atespace + + + Ingress gateway + authenticated callers + + + Egress gateway + destination policy, + credential injection + + + Actor A + no credentials + + + Actor B + no credentials + + + Node supervisor + + + External services + and tools + + + + Snapshot storage + + manage actors + per-actor credentials + + 1 + + 1 + + 2 + + 2 + + 3 + + 4 + invoke + diff --git a/docs/assets/threat-model-diagram.svg b/docs/assets/threat-model-diagram.svg deleted file mode 100644 index 9f2682a02e..0000000000 --- a/docs/assets/threat-model-diagram.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/security/security.md b/docs/security/security.md index 8d871097ee..ceb621cd53 100644 --- a/docs/security/security.md +++ b/docs/security/security.md @@ -12,6 +12,19 @@ Substrate delivers zero trust for agents. Every agent has an identity, but no cr Agent Substrate executes untrusted actors at scale in a multi-tenant environment where workloads are dynamic and memory states migrate continuously across physical infrastructure. All security controls operate within Substrate's cold-start and resume latency budget. This document defines the high-level security principles. For identity and credential configuration, see the [Authentication Guide](../guides/authentication.md). Detailed threat scenarios and mitigating invariants are documented [in the threat model](threat-model.md). +## Security Boundaries + +![Substrate security boundaries](../assets/security-boundaries.svg) + +The numbered tags mark the boundaries Substrate holds: + +1. **Sandbox.** Each actor runs in its own gVisor or microVM sandbox, with its own network namespace and storage. Actor code can't reach the node, the worker, or other actors. +2. **Gateways.** Traffic reaches actors only through the ingress gateway, from authenticated callers. Traffic leaves only through the egress gateway, which allows only the destinations in policy and injects credentials, so sandboxes hold none. +3. **Control plane.** Actors and worker pods have no network path to the Substrate API, its database, or the Kubernetes API. API callers are authorized per atespace. +4. **Storage.** Sandboxes never touch snapshot storage. The node supervisor moves an actor's snapshots using credentials scoped to that one actor, and only the control plane copies or deletes them. + +Your application is outside these boundaries: it authenticates end users and decides which actors they can reach. A more detailed diagram is available in the [threat model](threat-model.md#architecture-of-substrate). + ## Security Scope Substrate provides the foundational base for agent security: diff --git a/docs/security/threat-model.md b/docs/security/threat-model.md index 7feec5f1e7..c910e1329d 100644 --- a/docs/security/threat-model.md +++ b/docs/security/threat-model.md @@ -8,7 +8,7 @@ description: > # Substrate Threat Model -Last updated: Oct 14, 2026 +Last updated: Oct 28, 2026 # Overview @@ -24,25 +24,71 @@ This threat model catalogs the security threats inherent to high-density statefu # Architecture of Substrate -![Substrate Architecture Diagram](../assets/threat-model-diagram.svg) +Two diagrams show the same components in the same positions. The first prepares an actor template. The second creates an actor from it and serves a request. + +## Creating an actor template + +![Substrate actor template creation](../assets/actor-template-diagram.svg) + +Creating a template runs a golden actor once, snapshots it, and keeps that snapshot. Actors created from the template start from it. + +| Step | What happens | What's checked | +| :---- | :---- | :---- | +| T1 | The application creates an actor template. `ate-api-server` stores it, and a background reconciler starts building its golden snapshot. | OpenFGA allows the caller to create templates in the atespace. Container images must be pinned by digest. | +| T2 | The reconciler creates a golden actor in the template's atespace, picks a worker, and tells that node's `atelet` to run it. | `atelet` accepts only `ate-api-server`'s identity. | +| T3 | `atelet` pulls the container image into the node's layer cache, which all actors on the node share. MicroVM nodes also fetch the guest kernel and image from the asset bucket. | The image is fetched by digest, with the node's registry credentials. | +| T4 | `atelet` tells `ateworker` to start the sandbox. | The call stays on the node. | +| T5 | `atunnel` asks `atelet` for the actor's certificate. | `atelet` accepts only workers on its own node. | +| T6 | `atelet` asks `ate-api-server` to mint it. | It is minted only for the worker the actor is assigned to. | +| T7 | Once the workload is ready and warmed up, the reconciler suspends the golden actor, and `atelet` checkpoints its memory and disk. | Only `ate-api-server` can order a suspend. | +| T8 | `atelet` trades a JWT for this actor for storage credentials. | The credentials cover only this actor's snapshot location. | +| T9 | `atelet` uploads the golden snapshot. | The sandbox never touches storage. | +| T10 | The reconciler tags the snapshot, deletes the golden actor, and marks the template ready. | The worker's actor directories are wiped before it is reused. | + +The golden actor has no network egress unless the template sets a golden egress policy. + +## Creating an actor and serving a request + +![Substrate architecture and data flows](../assets/actor-call-diagram.svg) + +In **A**, an application creates an actor. In **B**, it sends the actor a request, which resumes the actor on a worker, and the actor then calls an external tool. + +| Step | What happens | What's checked | +| :---- | :---- | :---- | +| A1 | The application asks `ate-api-server` to create an actor from a template. | The caller is authenticated, and OpenFGA allows it to create actors in the atespace and use the template. | +| A2 | `ate-api-server` saves the actor as suspended. It points at the template's golden snapshot without copying it, and nothing runs until its first request. | Only `ate-api-server` can reach the database, with a client certificate. | +| B1 | The application sends a request for `/` to `atenet-router`. | The caller's mTLS identity must be on the router's allowlist. | +| B2 | The router asks `ate-api-server` to resume the actor and return its worker. | Only the router's identity can resume actors this way. | +| B3 | `ate-api-server` tells the `atelet` on the chosen node to restore the actor. | `atelet` accepts only `ate-api-server`'s identity. | +| B4 | `atelet` downloads the actor's snapshot. | The storage credentials are scoped to this one actor. | +| B5 | `atelet` tells `ateworker` to start a sandbox from the snapshot. If the node hasn't cached the image, `atelet` pulls it first. | The call stays on the node. | +| B6 | The router forwards the request to `atunnel` in the actor's Worker Pod. | `atunnel` accepts only the router's identity, and NetworkPolicy admits only the router. | +| B7 | `atunnel` delivers the request to the actor's sandbox. | It goes only to the actor named in the request. | +| B8 | The actor calls a tool. nftables outside the sandbox send the connection to `atunnel`. | DNS answers only names in the actor's egress policy. Other protocols are dropped. | +| B9 | `atunnel` forwards the call to `atenet-egress` with a certificate for this actor. | The certificate is issued only to the worker the actor is assigned to. | +| B10 | `atenet-egress` fetches the credential the egress rule names. | Only `atenet-egress` can reach the credential provider. | +| B11 | `atenet-egress` calls the external service and injects the credential. | Destinations not in the actor's egress policy are refused. The credential never enters the sandbox. | # Key Components -* **ate-api-server:** Control plane server managing actor lifecycle, scheduling, OpenFGA authorization, and credential issuance. -* **ate-controller:** Kubernetes controller managing worker pool deployments and network policies. -* **podcertcontroller:** Kubernetes controller issuing short-lived mTLS certificates for pod identity, service DNS, and database access. -* **atelet:** Per-node supervisor daemon coordinating sandbox lifecycle, checkpoint/restore, and node-attested credentials. -* **ateworker:** Per-worker Pod runtime daemon managing interior sandboxes (`gVisor` or `Cloud Hypervisor` microVMs). -* **Worker:** Pre-provisioned Pods that host active actors. * **Actor:** The core stateful compute primitive, grouped into atespaces and scheduled onto workers via Run or Resume. -* **Actor Network:** Private per-actor network namespace and point-to-point veth link behind `atunnel`'s authenticated listener on port 443. +* **Actor Network:** Private per-actor network namespace with a point-to-point veth (gVisor) or tap device (microVM). nftables rules outside the sandbox send all of its traffic to `atunnel`. * **Actor Routing:** Ingress requests identify the target actor via `ate-target-actor: /`. -* **atenet-router:** Envoy ingress proxy with an `ext_proc` processor that authenticates callers over mTLS, resolves worker assignments, and routes to `atunnel`. +* **ate-api-server:** Control plane API that manages actor lifecycle, scheduling, OpenFGA authorization, and actor credential minting. Its `objectstore-plugin` sidecar copies and deletes snapshots and issues per-actor storage credentials. +* **ate-controller:** Kubernetes controller that turns WorkerPools into worker Deployments and their NetworkPolicies. +* **ate-idp-server:** Serves the public OIDC discovery document and JWKS that relying parties use to verify actor JWTs. +* **atelet:** Per-node supervisor (DaemonSet) that coordinates sandbox lifecycle and checkpoint/restore, and brokers credentials for the actors on its node. Its `objectstore-plugin` sidecar moves snapshots. * **atenet-egress:** Multi-tenant Envoy egress forward proxy that enforces declarative egress policies and injects credentials. -* **Object Storage:** Stores partitioned actor snapshots, accessed through the out-of-process `objectstore-plugin`. +* **atenet-router:** Envoy ingress proxy with an `ext_proc` processor that authenticates callers over mTLS, resolves worker assignments, and routes to `atunnel`. +* **ateworker:** Runtime daemon in each Worker Pod. It runs the sandboxes (`gVisor` or `Cloud Hypervisor` microVMs) and includes `atunnel`. +* **atunnel:** Terminates mTLS ingress from `atenet-router`, tunnels each actor's redirected outbound TCP to `atenet-egress`, and relays DNS filtered by egress policy. * **Filesystem Support:** Container rootfs overlays and working directories captured in snapshots and wiped on actor teardown. -* **Substrate Database:** PostgreSQL (or Cloud SQL on GCP), accessed over TLS by `ate-api-server`. +* **k8s-credential-provider:** Gives `atenet-egress` the Kubernetes Secrets that egress rules reference. * **Kubernetes:** The underlying cluster infrastructure providing node isolation and network policies. +* **Object Storage:** A snapshot bucket, partitioned by atespace and actor and reached only with per-actor credentials, and a separate read-only bucket of microVM assets. +* **podcertcontroller:** Kubernetes controller that issues short-lived mTLS certificates for pod identity, service DNS, and database access. +* **Substrate Database:** PostgreSQL (or a managed PostgreSQL service). Only `ate-api-server` can reach it. +* **Worker Pod:** Pre-provisioned Pod that hosts many actors, each in its own sandbox. # Threats and Mitigations From f39108b62316b2f91093355232ccc6111e9ed9bc Mon Sep 17 00:00:00 2001 From: Greg Castle Date: Thu, 29 Oct 2026 19:24:02 +0000 Subject: [PATCH 2/2] docs: address review feedback on security diagrams and boundaries Signed-off-by: Greg Castle --- docs/assets/actor-call-diagram.svg | 18 ++++---- docs/assets/actor-template-diagram.svg | 58 ++++++++++++++------------ docs/assets/security-boundaries.svg | 3 +- docs/security/security.md | 8 ++-- docs/security/threat-model.md | 34 +++++++-------- 5 files changed, 65 insertions(+), 56 deletions(-) diff --git a/docs/assets/actor-call-diagram.svg b/docs/assets/actor-call-diagram.svg index 831a3a79df..6412874636 100644 --- a/docs/assets/actor-call-diagram.svg +++ b/docs/assets/actor-call-diagram.svg @@ -5,6 +5,7 @@ + @@ -13,8 +14,10 @@ Kubernetes cluster ate-system namespace: control plane - + Kubernetes + + Cert namespace Worker node @@ -60,7 +63,7 @@ - + @@ -83,10 +86,11 @@ Snapshot bucket - + - MicroVM asset bucket + Sandbox assets + (SandboxConfig) atenet-router @@ -119,9 +123,9 @@ kube-apiserver - - podcertcontroller - pod, DNS, DB certs + + podcertcontroller + pod, DNS, DB certs ateworker + atunnel diff --git a/docs/assets/actor-template-diagram.svg b/docs/assets/actor-template-diagram.svg index fa3ec6ea6d..c670499f8e 100644 --- a/docs/assets/actor-template-diagram.svg +++ b/docs/assets/actor-template-diagram.svg @@ -5,6 +5,7 @@ + @@ -20,17 +21,19 @@ Sandbox: gVisor or microVM - - - - - - - - + + + + + + + + + + - + @@ -64,47 +67,48 @@ Snapshot bucket - + - MicroVM asset bucket + Sandbox assets + (SandboxConfig) Container image registry - T1 + P1 create template - - T10 - template ready - T2 + P2 run golden actor - - T7 - suspend golden actor - T3 + P3 pull image - T4 + P4 start sandbox - T5 + P5 get actor certificate - T6 + P6 mint certificate + + P7 + suspend golden actor - T8 + P8 get storage credential - T9 + P9 upload snapshot - - T: create an actor template + + P10 + copy tag snapshot + + P: prepare an actor template Other connection diff --git a/docs/assets/security-boundaries.svg b/docs/assets/security-boundaries.svg index b5e90c989f..6030a8010f 100644 --- a/docs/assets/security-boundaries.svg +++ b/docs/assets/security-boundaries.svg @@ -5,6 +5,7 @@ + @@ -67,7 +68,7 @@ Snapshot storage manage actors - per-actor credentials + per-actor credentials (GCS) 1 diff --git a/docs/security/security.md b/docs/security/security.md index ceb621cd53..0d2a9a8281 100644 --- a/docs/security/security.md +++ b/docs/security/security.md @@ -18,10 +18,10 @@ Agent Substrate executes untrusted actors at scale in a multi-tenant environment The numbered tags mark the boundaries Substrate holds: -1. **Sandbox.** Each actor runs in its own gVisor or microVM sandbox, with its own network namespace and storage. Actor code can't reach the node, the worker, or other actors. -2. **Gateways.** Traffic reaches actors only through the ingress gateway, from authenticated callers. Traffic leaves only through the egress gateway, which allows only the destinations in policy and injects credentials, so sandboxes hold none. -3. **Control plane.** Actors and worker pods have no network path to the Substrate API, its database, or the Kubernetes API. API callers are authorized per atespace. -4. **Storage.** Sandboxes never touch snapshot storage. The node supervisor moves an actor's snapshots using credentials scoped to that one actor, and only the control plane copies or deletes them. +1. **Sandbox.** Each actor runs in its own gVisor or microVM sandbox, with its own network namespace and storage. Actor code cannot reach the node or other actors; it can only talk through its gateway path and DNS relay, where policy applies. +2. **Gateways.** Traffic reaches actors only through the ingress gateway, from authenticated callers. Outbound traffic leaves only through the egress gateway and DNS relay. The gateway enforces destination allowlists and injects credentials, so sandboxes hold none. +3. **Control plane.** Actors have no network path to the Substrate API, its database, or the Kubernetes API. Worker pods cannot reach the Substrate API or database. API callers are authorized per atespace. +4. **Storage.** Sandboxes never touch snapshot storage. On GCS, the node supervisor moves an actor's snapshots using credentials scoped to that one actor (S3 per-actor scoping is planned), and only the control plane copies or deletes them. Your application is outside these boundaries: it authenticates end users and decides which actors they can reach. A more detailed diagram is available in the [threat model](threat-model.md#architecture-of-substrate). diff --git a/docs/security/threat-model.md b/docs/security/threat-model.md index c910e1329d..d4d2e67b78 100644 --- a/docs/security/threat-model.md +++ b/docs/security/threat-model.md @@ -24,7 +24,7 @@ This threat model catalogs the security threats inherent to high-density statefu # Architecture of Substrate -Two diagrams show the same components in the same positions. The first prepares an actor template. The second creates an actor from it and serves a request. +Two diagrams coordinate component layouts so components both diagrams show are in the same positions. The first prepares an actor template. The second creates an actor from it and serves a request. ## Creating an actor template @@ -34,16 +34,16 @@ Creating a template runs a golden actor once, snapshots it, and keeps that snaps | Step | What happens | What's checked | | :---- | :---- | :---- | -| T1 | The application creates an actor template. `ate-api-server` stores it, and a background reconciler starts building its golden snapshot. | OpenFGA allows the caller to create templates in the atespace. Container images must be pinned by digest. | -| T2 | The reconciler creates a golden actor in the template's atespace, picks a worker, and tells that node's `atelet` to run it. | `atelet` accepts only `ate-api-server`'s identity. | -| T3 | `atelet` pulls the container image into the node's layer cache, which all actors on the node share. MicroVM nodes also fetch the guest kernel and image from the asset bucket. | The image is fetched by digest, with the node's registry credentials. | -| T4 | `atelet` tells `ateworker` to start the sandbox. | The call stays on the node. | -| T5 | `atunnel` asks `atelet` for the actor's certificate. | `atelet` accepts only workers on its own node. | -| T6 | `atelet` asks `ate-api-server` to mint it. | It is minted only for the worker the actor is assigned to. | -| T7 | Once the workload is ready and warmed up, the reconciler suspends the golden actor, and `atelet` checkpoints its memory and disk. | Only `ate-api-server` can order a suspend. | -| T8 | `atelet` trades a JWT for this actor for storage credentials. | The credentials cover only this actor's snapshot location. | -| T9 | `atelet` uploads the golden snapshot. | The sandbox never touches storage. | -| T10 | The reconciler tags the snapshot, deletes the golden actor, and marks the template ready. | The worker's actor directories are wiped before it is reused. | +| P1 | The application creates an actor template. `ate-api-server` stores it, and a background reconciler starts building its golden snapshot. | OpenFGA allows the caller to create templates in the atespace. Container images must be pinned by digest. | +| P2 | The reconciler creates a golden actor in the template's atespace, picks a worker, and tells that node's `atelet` to run it. | `atelet` accepts only `ate-api-server`'s identity. | +| P3 | `atelet` pulls the container image into the node's layer cache, which all actors on the node share. Nodes also fetch sandbox assets (such as runsc or guest kernel and rootfs) specified by the SandboxConfig. | The image is fetched by digest, using credentials from the node's credential provider config when available. | +| P4 | `atelet` tells `ateworker` to start the sandbox. | The call stays on the node. | +| P5 | `atunnel` asks `atelet` for the actor's certificate. | `atelet` accepts only workers on its own node. | +| P6 | `atelet` asks `ate-api-server` to mint it. | It is minted only for the worker the actor is assigned to. | +| P7 | Once the workload is ready and warmed up, the reconciler suspends the golden actor, and `atelet` checkpoints its memory and disk. | Only `ate-api-server` can order a suspend. | +| P8 | `atelet` trades a JWT for this actor for storage credentials. | On GCS, the credentials cover only this actor's snapshot location (S3 uses node credentials). | +| P9 | `atelet` uploads the golden snapshot. | The sandbox never touches storage. | +| P10 | The reconciler tags the snapshot, deletes the golden actor, and marks the template ready. | The golden actor's local directories are removed when it is deleted. | The golden actor has no network egress unless the template sets a golden egress policy. @@ -56,11 +56,11 @@ In **A**, an application creates an actor. In **B**, it sends the actor a reques | Step | What happens | What's checked | | :---- | :---- | :---- | | A1 | The application asks `ate-api-server` to create an actor from a template. | The caller is authenticated, and OpenFGA allows it to create actors in the atespace and use the template. | -| A2 | `ate-api-server` saves the actor as suspended. It points at the template's golden snapshot without copying it, and nothing runs until its first request. | Only `ate-api-server` can reach the database, with a client certificate. | +| A2 | `ate-api-server` saves the actor as suspended. It points at the template's golden snapshot without copying it, and nothing runs until its first request. | For bundled PostgreSQL, NetworkPolicy restricts access to `ate-api-server` with a client certificate; managed databases use provider network and IAM/TLS controls. | | B1 | The application sends a request for `/` to `atenet-router`. | The caller's mTLS identity must be on the router's allowlist. | -| B2 | The router asks `ate-api-server` to resume the actor and return its worker. | Only the router's identity can resume actors this way. | +| B2 | The router asks `ate-api-server` to resume the actor and return its worker. | OpenFGA allows the router (or an authorized user/editor) to resume actors in the atespace. | | B3 | `ate-api-server` tells the `atelet` on the chosen node to restore the actor. | `atelet` accepts only `ate-api-server`'s identity. | -| B4 | `atelet` downloads the actor's snapshot. | The storage credentials are scoped to this one actor. | +| B4 | `atelet` downloads the actor's snapshot. | On GCS, credentials grant read/write access to this actor's snapshot prefix and read-only access to the template's source tag prefix (S3 uses node credentials). | | B5 | `atelet` tells `ateworker` to start a sandbox from the snapshot. If the node hasn't cached the image, `atelet` pulls it first. | The call stays on the node. | | B6 | The router forwards the request to `atunnel` in the actor's Worker Pod. | `atunnel` accepts only the router's identity, and NetworkPolicy admits only the router. | | B7 | `atunnel` delivers the request to the actor's sandbox. | It goes only to the actor named in the request. | @@ -85,9 +85,9 @@ In **A**, an application creates an actor. In **B**, it sends the actor a reques * **Filesystem Support:** Container rootfs overlays and working directories captured in snapshots and wiped on actor teardown. * **k8s-credential-provider:** Gives `atenet-egress` the Kubernetes Secrets that egress rules reference. * **Kubernetes:** The underlying cluster infrastructure providing node isolation and network policies. -* **Object Storage:** A snapshot bucket, partitioned by atespace and actor and reached only with per-actor credentials, and a separate read-only bucket of microVM assets. -* **podcertcontroller:** Kubernetes controller that issues short-lived mTLS certificates for pod identity, service DNS, and database access. -* **Substrate Database:** PostgreSQL (or a managed PostgreSQL service). Only `ate-api-server` can reach it. +* **Object Storage:** A snapshot bucket, partitioned by atespace and actor (scoped per actor on GCS), and storage locations for sandbox assets specified by the SandboxConfig. +* **podcertcontroller:** Substrate's Kubernetes controller, in the `podcertificate-controller-system` namespace, that issues short-lived mTLS certificates for pod identity, service DNS, and database access. +* **Substrate Database:** PostgreSQL (or a managed PostgreSQL service). Bundled installs restrict network access to `ate-api-server` over TLS with a client certificate; managed installs use provider network and IAM controls. * **Worker Pod:** Pre-provisioned Pod that hosts many actors, each in its own sandbox. # Threats and Mitigations