Secret Storage and Gateway Delivery Flow
Overview
An authorized owner stores a Namespace-owned Secret before any Agent exists, binds its stable reference in Configuration for gateway delivery, then grants, assigns and deploys a consuming Agent. For these Configuration bindings, OCC admits references and Kubernetes supplies values only to each selected gateway. Harness model authentication uses the shared Agent binding flow. The local installer also grants a new Agent access and verifies a model response. Credential issuance and provider internals are outside this flow.
Entry Points
apps/controller/src/index.ts:createFastifyApp
POST /namespaces/:namespaceId/secrets: a ready Namespace and caller authorization to create the Secret in that Namespace.- Configuration create/update, Agent create/update assignment, and the existing Agent deployment action: authorized exact Secret references, same-Namespace bindings, exact Agent assignment authority, and an approved Harness/Compute selection.
- Local installer:
scripts/first-agent.mjs:mainuses the bootstrap service key. - Source: HTTP handlers, OpenClawController, and KubernetesSecretDriver.
- The console and OCC CLI call these HTTP operations. They initiate OCC-authorized mutations; neither writes directly to SQL, Kubernetes, or credential backends.
Flow
graph TD
subgraph Storage["Protected storage request"]
A["Owner supplies value"] --> B["OCC authorizes Namespace Secret create"]
B --> C["KubernetesSecretDriver stores mutable Secret"]
C --> D["OCC stores metadata and returns stable ref"]
end
subgraph Admission["Configuration and deployment"]
D --> E["Bind source ref to gateway env destination"]
E --> P["Bind Agent identity to exact Secret"]
P --> F["Authorize caller and Agent SP; verify backend"]
F -->|allowed| G["Freeze references in AgentRevision"]
F -->|denied or unavailable| X["No admitted deployment"]
D --> K{"Local v3 state uses<br/>Kubernetes and Sandbox none?"}
K -->|yes| L["Local installer: grant Agent use of this exact Secret"]
K -->|no or OpenShell| X
L --> F
L -->|ownership or IAM denied| X
end
subgraph Runtime["Worker and Kubernetes"]
G --> H["Worker resolves OCC metadata for Compute"]
H --> I["Kubelet injects secretKeyRef into selected gateway"]
I --> J["OpenClaw resolves native env SecretRef"]
I -->|missing material| Y["Gateway cannot become ready"]
G -->|Agent harnessAuth| W["Harness auth flow delivers to model workload"]
W -->|local installer| V["Check model response"]
endExecution Trace
1. Authorize storage without requiring a gateway
packages/occ/src/index.ts:OpenClawController.createSecret
OpenClawController.createSecret validates
bounded, nonempty UTF-8 input and locks the Namespace. The caller needs create
on the Namespace's Secret collection. The Namespace must already be ready; an
Agent record does not need to exist. OCC selects the
Installation SecretDriver, generates the Secret identity, and prevents the
caller from choosing Kubernetes backend identity. The value stays in protected
request/driver memory, never in the reconciliation queue or resource metadata.
2. Store material and commit safe identity
apps/controller/src/drivers/secret/kubernetes/index.ts:KubernetesSecretDriver.create
KubernetesSecretDriver.create
uses Compute-owned tenant control-plane placement. It creates a mutable Opaque Secret with
a Namespace-derived name, exact Namespace ownership metadata, and a fixed
value key. Its result contains only backend identity, including UID. OCC state
persists immutable Namespace, driver, and backend metadata while public metadata
omits the backend locator and returns { kind: "secret", namespaceId, id }.
Known OCC transaction failure can compensate the exact created object. An unknown commit outcome must not trigger destructive compensation. There is no value journal or automatic replay; ambiguous creation can require operator recovery.
3. Bind a source, then admit references
packages/occ/src/index.ts:OpenClawController.deployAgent
The Agent response exposes its immutable servicePrincipalId. An administrator
grants that identity operate on the exact Secret before deployment. OCC checks
Installation administration, Namespace scope, and target access through the
selected IAM Driver; policy and audit commit together.
createConfiguration and updateConfiguration
keep secretBindings in OCC metadata, separate from native values. Each binding
has a Secret source and an env delivery destination; omitted delivery normalizes
to env. Unsupported sources, substitution modes, and reserved environment
variables fail closed. All sources must belong to the same Namespace as the
Configuration. A Configuration create/update whose resulting document contains
bindings requires operate on every selected Secret, including retained bindings
when PATCH omits secretBindings.
createAgent and updateAgent require the normal
Agent mutation permission plus operate on each exact Secret when selecting a
Configuration with bindings.
deployAgent separately authorizes the deploying
caller and consuming Agent service principal to operate every Secret, then
checks live backend identity through the API-side driver. Namespace locking
serializes binding/admission changes against deletion. Admission freezes
normalized refs and the selected SecretDriver identity, not backend locators or
values, in the revision. Enabled native channel environment SecretRefs must have
matching bindings at admission; disabled channel provider blocks do not require
them.
Model-auth environment destinations are reserved for Agent harnessAuth;
Configuration bindings cannot select or override model credentials in either
execution topology.
4. Grant the first local Agent access to its model Secret
scripts/first-agent.mjs:main;
scripts/first-agent-database.mjs:grantFirstAgentSecret
The tool targets the persistent installation
started with ./bin/occ dev up. Before invoking Kubernetes or the OCC API, it
requires the current v3 development marker and state from the same checkout.
The state must select Kubernetes Compute and
sandboxDriver: "none". OpenShell state fails with an explicit unsupported-profile
error because that development profile does not support this model-turn path.
With the bootstrap service key, it creates a
Secret, Configuration, and named Agent through the OCC HTTP API. A new Agent uses
openai/gpt-6-astra unless OPENCLAW_FIRST_AGENT_MODEL selects another authorized
plain model ID; a repeat without an override keeps the recorded model, and a
conflicting override is rejected. Bootstrap already has Secret operate; the
Agent does not.
OCC has no public IAM management endpoint. The tool opens the recorded local
PostgreSQL service. One transaction verifies the Namespace, Agent, and Secret, then
grants the Agent's existing principal operate on that exact Secret. It verifies
the bootstrap identity, honors IAM restrictions, and audits a new grant.
The tool provisions initial runtime credentials and requests deployment through OCC. Once the revision is active, it sends a prompt through the gateway and checks the model response. It leaves the installation and resources in place on exit.
5. Render only the exact gateway's projection
apps/controller/src/worker.ts:ControllerWorker.resolveRevisionSecretContext
ControllerWorker rechecks
consumption authority and resolves revision refs from OCC metadata before each
preparation and activation. It passes an ephemeral ComputeRevisionContext; it
does not add backend metadata to the revision. Its Compute Driver performs
the physical Secret reads and scoped runtime delivery.
KubernetesComputeDriver.prepareRevision
checks the revision, source UIDs, projection identities and verified CP Namespace.
Dedicated Gateways directly reference admitted canonical CP Secrets. It renders env[].valueFrom.secretKeyRef with optional: false only in each
selected consuming gateway. Model-auth projections are prepared separately from
Agent harnessAuth. ConfigMaps retain native references only. A missing
Secret/key prevents startup; normal readiness and cutover rules still control
activation. Dispatch checks OCC metadata; Compute also rejects a replaced source UID before
delivery. Kubernetes environment references themselves bind a name and key, so
Kubernetes administrators remain trusted.
For an embedded replacement, preparation stages its immutable ConfigMap without requiring the old gateway to be healthy. The worker commits the selected revision before activation replaces the gateway Deployment and checks readiness. This lets an explicit corrected deployment recover from a native SecretRef startup failure; preparation alone is not proof that the replacement runtime is ready.
Kubelet obtains the bytes and creates the process environment. OpenClaw resolves
its existing { source: "env", provider, id } reference. This is the handoff to
the native consumer, not a new OpenClaw provider or OCC text-substitution engine.
Native channel credentials follow these same admitted bindings. No legacy
per-Agent channel Secret injects additional values. Dedicated gateways receive
channel bytes; the dedicated Harness receives only its separately admitted model
authentication. Embedded channel credentials remain unsupported.
The trusted worker reads CP sources and manages DP runtime projections; workload ServiceAccounts have no Secret API verbs. A trusted workload writer can still project namespace Secrets, so controller compromise remains outside workload isolation.
6. Update, restart, or remove
packages/occ/src/index.ts:OpenClawController.updateSecret
updateSecret serializes the write and uses Kubernetes concurrency/ownership checks. It changes only the stored value; the response retains the same ref. No revision, binding, or running environment is updated, and no controller automatically restarts the gateway. A successful update means stored, not delivered.
For coordinated channel replacement, stop the Agent and wait for shutdown before updating each Secret. A partial update leaves it stopped until repaired; there is no multi-Secret transaction or rollback of stored bytes.
For model-key replacement, update the OCC Secret and explicitly deploy each
consuming Agent through OCE. The new revision's preparation calls
KubernetesComputeDriver.deliverHarnessAuth, which reads the current CP source
and writes the revision-owned DP Secret before the Harness starts. Wait for
activation and verify a real model request before revoking the old key upstream.
A Harness Pod recreation reads its existing DP projection; it does not deliver
current CP values. This remains true when the Configuration and Secret reference
are unchanged.
Dedicated Gateway infrastructure restarts read canonical CP channel Secrets
directly. Failed cutover does not restore old source values. Revoking operate
blocks new OCC admission, not kubelet process starts or already delivered bytes.
deleteSecret rejects current Configuration, Agent harness-binding draft, active revision, and pending-work dependencies under the same serialization boundary. Once unreferenced, it deletes only the exact Namespace-owned backend and metadata. A partial delete can be retried; missing or foreign objects never become an adoption or recreation path. Gateway replacement does not garbage-collect Secrets, so immediate revocation requires stopping workloads or revoking the credential at its issuer.
Debugging and Verification
- Read public Secret metadata without requesting or dumping values. Inspect safe
ownership/UID metadata separately as an authorized operator; do not print
Secret.data, complete process environments, or credential-bearing requests. - A stored Secret with no ready gateway is valid. Update success does not imply delivery. Compare revision/Pod identities and use noncredential sentinel values for restart assertions.
- On local failure, rerun the tool with the same Agent name. It prints the Agent and revision IDs only after the model responds.
- Source selection, exact Namespace ownership, consumption authorization, missing material, and concurrent backend mutations fail closed. Do not retry a denial against another driver or model-key source.
- Real Agent acceptance requires explicitly selected PostgreSQL/Kubernetes, digest-pinned real runtime images, and an authorized model key. It must prove the native-ref negative control, genuine turn, and env restart behavior; mocked rendering is not that proof.
- Run focused conformance, API, startup, Helm, PostgreSQL Secret-state, real Compute, and real Agent suites when changing this flow's implementation. State skipped credentials, infrastructure, or runtime hooks as verification gaps rather than replacing them with mocked rendering.
