OpenClaw EnterpriseDOCSGitHub

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

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"]
  end

Execution 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

Search documentation