Secret stores
The runner reads your service credentials from your secret manager, at boot, and keeps them in memory only. Nothing is written to disk, and nothing is custodied outside your infrastructure.
RUNNER_SECRET_STORE_MODE=env # default, developmentRUNNER_SECRET_STORE_MODE=aws # AWS Secrets ManagerRUNNER_SECRET_STORE_MODE=vault # HashiCorp Vault (KV v2 or v1)All three backends implement the same minimal interface, get(name), so switching between them
changes nothing else in the runner.
env: development
Section titled “env: development”Reads from the process environment. It’s the default, and Compose feeds it through pass-through: the
value comes from the shell, injected by your secret manager or by runner.secrets.env via
npm run dev:runner:file.
Fine for local development. In production, prefer one of the two below.
aws: AWS Secrets Manager
Section titled “aws: AWS Secrets Manager”RUNNER_SECRET_STORE_MODE=aws# RUNNER_SECRETS_MANAGER_REGION=us-east-1 # absent ⇒ SDK default resolution# RUNNER_SECRETS_MANAGER_PREFIX=rootpilot/ # prefixes the SecretIdResolves through the SDK’s default credential chain (IAM role, workload identity, IRSA) with no static keys. It’s the natural path for a runner on EKS or ECS.
PREFIX prefixes the SecretId, so a secret named DD_API_KEY with prefix rootpilot/ is fetched
as rootpilot/DD_API_KEY.
vault: HashiCorp Vault (KV v2 and v1)
Section titled “vault: HashiCorp Vault (KV v2 and v1)”RUNNER_SECRET_STORE_MODE=vaultRUNNER_VAULT_ADDR=https://vault.example.com
# token authRUNNER_VAULT_AUTH=tokenRUNNER_VAULT_TOKEN=…
# or AppRole authRUNNER_VAULT_AUTH=approleRUNNER_VAULT_ROLE_ID=…RUNNER_VAULT_SECRET_ID=…
# or Kubernetes auth — the method that belongs in a clusterRUNNER_VAULT_AUTH=kubernetesRUNNER_VAULT_K8S_ROLE=rootpilot# optional; default belowRUNNER_VAULT_K8S_TOKEN_PATH=/var/run/secrets/tokens/vault/tokenHTTP access to the KV API. The mount version (v2 or v1) is detected on the first read — a v1 mount is no longer mistaken for a missing secret. Additional options:
| Variable | Default | What for |
|---|---|---|
RUNNER_VAULT_NAMESPACE |
none | Vault Enterprise. |
RUNNER_VAULT_KV_MOUNT |
secret |
KV mount. v2 and v1 are detected automatically. |
RUNNER_VAULT_KV_FIELD |
value |
Which field of the secret to return. |
RUNNER_VAULT_PREFIX |
'' |
Prefixes the logical path. |
The schema refuses incomplete configuration at boot:
RUNNER_SECRET_STORE_MODE=vault requires RUNNER_VAULT_ADDRvault auth requires RUNNER_VAULT_TOKEN (token), RUNNER_VAULT_ROLE_ID+RUNNER_VAULT_SECRET_ID (approle) or RUNNER_VAULT_K8S_ROLE (kubernetes)A missing secret is not an error
Section titled “A missing secret is not an error”In both remote backends, “not found” (ResourceNotFoundException on AWS, 404 on Vault) resolves to
undefined, not an exception.
That’s what makes the lazy model work: you configure only the connectors you use, and the rest simply drop out of the served set. A missing secret does not bring down the boot.
The signal is in the boot log:
connector not served {connectorId: "azion", missing: ["AZION_TOKEN"]}Per-connector scoping
Section titled “Per-connector scoping”The runtime scopes the secret store per connector: each one sees only the secrets it declared in its own manifest. A connector cannot read another’s credential, even running in the same process. It’s the first of the runtime’s four guarantees.