mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-09 15:59:30 +00:00
Add Vault SecretRef plugin (#89255)
* Add Vault SecretRef plugin Signed-off-by: sallyom <somalley@redhat.com> * expand Vault setup to registered SecretRef targets Signed-off-by: sallyom <somalley@redhat.com> * fix(vault): use sdk secret target seam * fix(vault): preserve auth profile target paths * docs(vault): document plugin enable step * fix(vault): make status provider-alias aware * fix(vault): reject noncanonical secret ids * fix(vault): separate resolver timeout deadlines * fix(vault): forward private CA trust settings * fix(secrets): preserve plugin policy boundaries --------- Signed-off-by: sallyom <somalley@redhat.com> Co-authored-by: joshavant <830519+joshavant@users.noreply.github.com>
This commit is contained in:
parent
6a6aba0d5a
commit
e595a8c0ac
30 changed files with 2677 additions and 8 deletions
|
|
@ -1,2 +1,2 @@
|
|||
d23999706f07d7e3ad75a2d642d9d3df9aa9d9eccfd162e90ee03745af79d788 plugin-sdk-api-baseline.json
|
||||
dd8db488da6b6a09f1873834fea1b84c95c61ebeba99c347760d767ea6ee0a79 plugin-sdk-api-baseline.jsonl
|
||||
52c7a8b045ee89b62266910d1d2db6a379c696ed514aeaa7ca3c6f0dbcc3ff67 plugin-sdk-api-baseline.json
|
||||
a703333cefbf3b36cc826965592a8de3542ac91cfe9cd8c5447cb748407fece3 plugin-sdk-api-baseline.jsonl
|
||||
|
|
|
|||
|
|
@ -155,3 +155,4 @@ If `audit --check` still reports plaintext findings, update the remaining report
|
|||
|
||||
- [CLI reference](/cli)
|
||||
- [Secrets management](/gateway/secrets)
|
||||
- [Vault SecretRefs](/plugins/vault)
|
||||
|
|
|
|||
|
|
@ -1280,6 +1280,7 @@
|
|||
"plugins/webhooks",
|
||||
"plugins/admin-http-rpc",
|
||||
"plugins/voice-call",
|
||||
"plugins/vault",
|
||||
"plugins/memory-wiki",
|
||||
"plugins/llama-cpp",
|
||||
"plugins/memory-lancedb",
|
||||
|
|
|
|||
|
|
@ -6783,6 +6783,15 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
|||
- H2: Surface
|
||||
- H2: Related docs
|
||||
|
||||
## plugins/reference/vault.md
|
||||
|
||||
- Route: /plugins/reference/vault
|
||||
- Headings:
|
||||
- H1: Vault plugin
|
||||
- H2: Distribution
|
||||
- H2: Surface
|
||||
- H2: Related docs
|
||||
|
||||
## plugins/reference/venice.md
|
||||
|
||||
- Route: /plugins/reference/venice
|
||||
|
|
@ -7157,6 +7166,21 @@ Do not edit it by hand; run `pnpm docs:map:gen`.
|
|||
- H3: Tool does not appear after install
|
||||
- H2: See also
|
||||
|
||||
## plugins/vault.md
|
||||
|
||||
- Route: /plugins/vault
|
||||
- Headings:
|
||||
- H1: Vault SecretRefs
|
||||
- H2: Before you begin
|
||||
- H2: Store a provider key in Vault
|
||||
- H2: Make Vault visible to the Gateway
|
||||
- H2: Generate and apply a SecretRef plan
|
||||
- H2: Configure more provider keys
|
||||
- H2: SecretRef id format
|
||||
- H2: What OpenClaw stores
|
||||
- H2: Containers and managed deployments
|
||||
- H2: Related
|
||||
|
||||
## plugins/voice-call.md
|
||||
|
||||
- Route: /plugins/voice-call
|
||||
|
|
|
|||
|
|
@ -741,6 +741,7 @@ Some SecretInput unions are easier to configure in raw editor mode than in form
|
|||
|
||||
- [Authentication](/gateway/authentication) - auth setup
|
||||
- [CLI: secrets](/cli/secrets) - CLI commands
|
||||
- [Vault SecretRefs](/plugins/vault) - HashiCorp Vault provider setup
|
||||
- [Environment Variables](/help/environment) - environment precedence
|
||||
- [SecretRef Credential Surface](/reference/secretref-credential-surface) - credential surface
|
||||
- [Secrets Apply Plan Contract](/gateway/secrets-plan-contract) - plan contract details
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ Each entry lists the package, distribution route, and description.
|
|||
|
||||
## Core npm package
|
||||
|
||||
61 plugins
|
||||
62 plugins
|
||||
|
||||
- **[admin-http-rpc](/plugins/reference/admin-http-rpc)** (`@openclaw/admin-http-rpc`) - included in OpenClaw. OpenClaw admin HTTP RPC endpoint.
|
||||
|
||||
|
|
@ -157,6 +157,8 @@ Each entry lists the package, distribution route, and description.
|
|||
|
||||
- **[tts-local-cli](/plugins/reference/tts-local-cli)** (`@openclaw/tts-local-cli`) - included in OpenClaw. Adds text-to-speech provider support.
|
||||
|
||||
- **[vault](/plugins/reference/vault)** (`@openclaw/vault`) - included in OpenClaw. HashiCorp Vault SecretRef provider integration.
|
||||
|
||||
- **[vllm](/plugins/reference/vllm)** (`@openclaw/vllm-provider`) - included in OpenClaw. Adds vLLM model provider support to OpenClaw.
|
||||
|
||||
- **[volcengine](/plugins/reference/volcengine)** (`@openclaw/volcengine-provider`) - included in OpenClaw. Adds Volcengine, Volcengine Plan model provider support to OpenClaw.
|
||||
|
|
|
|||
|
|
@ -15,5 +15,5 @@ This page is generated from `extensions/*/package.json` and
|
|||
pnpm plugins:inventory:gen
|
||||
```
|
||||
|
||||
Use [Plugin inventory](/plugins/plugin-inventory) to browse all 133
|
||||
Use [Plugin inventory](/plugins/plugin-inventory) to browse all 134
|
||||
generated plugin reference pages by distribution, package, and description.
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ Adds the iMessage channel surface for sending and receiving OpenClaw messages.
|
|||
|
||||
## Surface
|
||||
|
||||
channels: imessage
|
||||
channels: imessage; skills
|
||||
|
||||
## Related docs
|
||||
|
||||
|
|
|
|||
23
docs/plugins/reference/vault.md
Normal file
23
docs/plugins/reference/vault.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
---
|
||||
summary: "HashiCorp Vault SecretRef provider integration."
|
||||
read_when:
|
||||
- You are installing, configuring, or auditing the vault plugin
|
||||
title: "Vault plugin"
|
||||
---
|
||||
|
||||
# Vault plugin
|
||||
|
||||
HashiCorp Vault SecretRef provider integration.
|
||||
|
||||
## Distribution
|
||||
|
||||
- Package: `@openclaw/vault`
|
||||
- Install route: included in OpenClaw
|
||||
|
||||
## Surface
|
||||
|
||||
plugin
|
||||
|
||||
## Related docs
|
||||
|
||||
- [vault](/plugins/vault)
|
||||
|
|
@ -227,7 +227,7 @@ usage endpoint failed or returned no usable usage data.
|
|||
| `plugin-sdk/channel-secret-runtime` | Deprecated broad secret-contract surface (`collectSimpleChannelFieldAssignments`, `getChannelSurface`, `pushAssignment`, secret target types); prefer the focused subpaths below |
|
||||
| `plugin-sdk/channel-secret-basic-runtime` | Narrow secret-contract exports for non-TTS channel/plugin secret surfaces |
|
||||
| `plugin-sdk/channel-secret-tts-runtime` | Narrow nested channel TTS secret assignment helpers |
|
||||
| `plugin-sdk/secret-ref-runtime` | Narrow `coerceSecretRef` and SecretRef typing helpers for secret-contract/config parsing |
|
||||
| `plugin-sdk/secret-ref-runtime` | Narrow SecretRef typing, resolution, and plan-target path lookup for secret-contract/config parsing |
|
||||
| `plugin-sdk/secret-provider-integration` | Type-only SecretRef provider integration manifest and preset contracts for plugins that publish external secret provider presets |
|
||||
| `plugin-sdk/security-runtime` | Deprecated broad barrel for trust, DM gating, root-bounded file/path helpers including create-only writes, sync/async atomic file replacement, sibling temp writes, cross-device move fallback, private file-store helpers, symlink-parent guards, external-content, sensitive text redaction, constant-time secret comparison, and secret-collection helpers; prefer focused security/SSRF/secret subpaths |
|
||||
| `plugin-sdk/ssrf-policy` | Host allowlist and private-network SSRF policy helpers |
|
||||
|
|
|
|||
332
docs/plugins/vault.md
Normal file
332
docs/plugins/vault.md
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
---
|
||||
summary: "Use the bundled Vault plugin to resolve SecretRefs from HashiCorp Vault"
|
||||
read_when:
|
||||
- You want OpenClaw to read API keys from HashiCorp Vault
|
||||
- You are setting up SecretRefs on a local machine or server
|
||||
- You need to configure Vault-backed model provider credentials
|
||||
title: "Vault SecretRefs"
|
||||
---
|
||||
|
||||
# Vault SecretRefs
|
||||
|
||||
The bundled Vault plugin lets OpenClaw resolve `exec` SecretRefs from
|
||||
HashiCorp Vault at Gateway startup and reload time. OpenClaw stores Vault
|
||||
references in config, keeps resolved values in the in-memory secrets snapshot,
|
||||
and does not write the resolved API keys back to `openclaw.json`.
|
||||
|
||||
Use this when you already run Vault or want model provider keys to live outside
|
||||
OpenClaw config files. For the SecretRef runtime model, see
|
||||
[Secrets management](/gateway/secrets).
|
||||
|
||||
## Before you begin
|
||||
|
||||
You need:
|
||||
|
||||
- OpenClaw with the bundled `vault` plugin available
|
||||
- a reachable Vault server
|
||||
- Vault auth that can produce a client token with read access to the secret
|
||||
paths OpenClaw should resolve
|
||||
- the environment that starts the Gateway must include `VAULT_ADDR` and either
|
||||
`VAULT_TOKEN`, `OPENCLAW_VAULT_AUTH_METHOD=token_file` with `VAULT_TOKEN_FILE`,
|
||||
or a configured JWT/Kubernetes login
|
||||
|
||||
The resolver talks to Vault over HTTP from Node. The Gateway does not need the
|
||||
Vault CLI to resolve SecretRefs.
|
||||
|
||||
Enable the bundled plugin before running the `openclaw vault` commands:
|
||||
|
||||
```bash
|
||||
openclaw plugins enable vault
|
||||
```
|
||||
|
||||
## Store a provider key in Vault
|
||||
|
||||
OpenClaw defaults to KV v2 mounted at `secret`, matching Vault dev-server
|
||||
examples. For production Vault, set `OPENCLAW_VAULT_KV_MOUNT` to your actual KV
|
||||
mount path before creating SecretRef ids. With the OpenClaw defaults, this
|
||||
SecretRef id:
|
||||
|
||||
```text
|
||||
providers/openrouter/apiKey
|
||||
```
|
||||
|
||||
reads this Vault field:
|
||||
|
||||
```text
|
||||
secret/data/providers/openrouter -> apiKey
|
||||
```
|
||||
|
||||
One way to create it with the Vault CLI is:
|
||||
|
||||
```bash
|
||||
export OPENROUTER_API_KEY=<openrouter-api-key>
|
||||
vault kv put secret/providers/openrouter apiKey="$OPENROUTER_API_KEY"
|
||||
```
|
||||
|
||||
Use a scoped client token for OpenClaw, not a root token. For the default KV v2
|
||||
layout, a minimal policy for model provider keys looks like:
|
||||
|
||||
```hcl
|
||||
path "secret/data/providers/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
```
|
||||
|
||||
## Make Vault visible to the Gateway
|
||||
|
||||
For an uncontainerized local Gateway, export Vault settings in the same shell
|
||||
that starts OpenClaw. The default auth method reads a Vault client token from
|
||||
`VAULT_TOKEN`:
|
||||
|
||||
```bash
|
||||
export VAULT_ADDR=https://vault.example.com
|
||||
export VAULT_TOKEN=<vault-client-token>
|
||||
```
|
||||
|
||||
If Vault Agent writes a token sink file, use token-file auth:
|
||||
|
||||
```bash
|
||||
export VAULT_ADDR=https://vault.example.com
|
||||
export OPENCLAW_VAULT_AUTH_METHOD=token_file
|
||||
export VAULT_TOKEN_FILE=/vault/secrets/token
|
||||
```
|
||||
|
||||
For a Vault server signed by a private CA, either install that CA in the host
|
||||
trust store and enable Node system trust:
|
||||
|
||||
```bash
|
||||
export NODE_USE_SYSTEM_CA=1
|
||||
```
|
||||
|
||||
Or provide a PEM bundle directly:
|
||||
|
||||
```bash
|
||||
export NODE_EXTRA_CA_CERTS=/path/to/vault-ca.pem
|
||||
```
|
||||
|
||||
These variables must be present when OpenClaw starts. The Vault plugin forwards
|
||||
them to its resolver process.
|
||||
|
||||
For non-interactive JWT auth, use a workload JWT file and a Vault role of type
|
||||
`jwt`:
|
||||
|
||||
```bash
|
||||
export VAULT_ADDR=https://vault.example.com
|
||||
export OPENCLAW_VAULT_AUTH_METHOD=jwt
|
||||
export OPENCLAW_VAULT_AUTH_MOUNT=jwt
|
||||
export OPENCLAW_VAULT_AUTH_ROLE=openclaw
|
||||
export OPENCLAW_VAULT_JWT_FILE=/var/run/secrets/tokens/vault
|
||||
```
|
||||
|
||||
The JWT file should be a projected workload token, such as a Kubernetes service account
|
||||
token with an audience accepted by the Vault role.
|
||||
Interactive OIDC browser login is useful for humans, but Gateway runtime needs
|
||||
non-interactive JWT login or a token file.
|
||||
|
||||
For Vault's Kubernetes auth method, use `kubernetes`. This is intended for
|
||||
Gateways running as Pods; the default mount is `kubernetes`, and the default JWT
|
||||
file is the standard service account token path:
|
||||
|
||||
```bash
|
||||
export VAULT_ADDR=https://vault.example.com
|
||||
export OPENCLAW_VAULT_AUTH_METHOD=kubernetes
|
||||
export OPENCLAW_VAULT_AUTH_ROLE=openclaw
|
||||
```
|
||||
|
||||
Set `OPENCLAW_VAULT_AUTH_MOUNT` only when Vault mounted Kubernetes auth somewhere
|
||||
other than `auth/kubernetes`. Set `OPENCLAW_VAULT_JWT_FILE` only when the service
|
||||
account token is projected at a custom path.
|
||||
|
||||
Optional settings:
|
||||
|
||||
```bash
|
||||
export VAULT_NAMESPACE=<namespace-name>
|
||||
export OPENCLAW_VAULT_KV_MOUNT=secret
|
||||
export OPENCLAW_VAULT_KV_VERSION=2
|
||||
```
|
||||
|
||||
Check what the current shell can see:
|
||||
|
||||
```bash
|
||||
openclaw vault status
|
||||
```
|
||||
|
||||
When more than one Vault-backed secret provider is configured, select one by
|
||||
alias:
|
||||
|
||||
```bash
|
||||
openclaw vault status --provider-alias corp-vault
|
||||
```
|
||||
|
||||
`openclaw vault status` never prints `VAULT_TOKEN`; it reports only whether the
|
||||
token, token file, and JWT file are set.
|
||||
|
||||
<Warning>
|
||||
If the Gateway runs as a service, LaunchAgent, systemd unit, scheduled task, or
|
||||
container, that runtime environment must receive the same Vault variables.
|
||||
Setting variables in an interactive shell only proves that shell, not the
|
||||
already-running Gateway.
|
||||
</Warning>
|
||||
|
||||
## Generate and apply a SecretRef plan
|
||||
|
||||
Create a plan that maps OpenRouter's model provider API key to Vault:
|
||||
|
||||
```bash
|
||||
openclaw vault setup \
|
||||
--plan-out ./vault-secrets-plan.json \
|
||||
--openrouter-id providers/openrouter/apiKey
|
||||
```
|
||||
|
||||
Apply and verify the plan:
|
||||
|
||||
```bash
|
||||
openclaw secrets apply --from ./vault-secrets-plan.json --dry-run --allow-exec
|
||||
openclaw secrets apply --from ./vault-secrets-plan.json --allow-exec
|
||||
openclaw secrets audit --check --allow-exec
|
||||
openclaw secrets reload
|
||||
```
|
||||
|
||||
Use `--allow-exec` because the Vault plugin resolves through an OpenClaw-managed
|
||||
exec SecretRef provider.
|
||||
|
||||
If the Gateway is not running yet, start it normally after applying the plan
|
||||
instead of running `openclaw secrets reload`.
|
||||
|
||||
## Configure more provider keys
|
||||
|
||||
Built-in shortcuts:
|
||||
|
||||
```bash
|
||||
openclaw vault setup --openai-id providers/openai/apiKey
|
||||
openclaw vault setup --anthropic-id providers/anthropic/apiKey
|
||||
openclaw vault setup --openrouter-id providers/openrouter/apiKey
|
||||
```
|
||||
|
||||
Multiple provider keys in one plan:
|
||||
|
||||
```bash
|
||||
openclaw vault setup \
|
||||
--plan-out ./vault-secrets-plan.json \
|
||||
--openai-id providers/openai/apiKey \
|
||||
--anthropic-id providers/anthropic/apiKey \
|
||||
--openrouter-id providers/openrouter/apiKey
|
||||
```
|
||||
|
||||
Bundled providers without shortcuts, or already-configured OpenAI-compatible and
|
||||
custom model providers, use `--provider-key`:
|
||||
|
||||
```bash
|
||||
openclaw vault setup \
|
||||
--plan-out ./vault-secrets-plan.json \
|
||||
--provider-key local-openai=providers/local-openai/apiKey \
|
||||
--provider-key groq=providers/groq/apiKey
|
||||
```
|
||||
|
||||
Each `--provider-key <provider=id>` writes a SecretRef to
|
||||
`models.providers.<provider>.apiKey`. For custom providers, it does not create
|
||||
the provider's `baseUrl`, `api`, or `models` settings; configure those first.
|
||||
|
||||
Use `--target <path=id>` for any known SecretRef target path:
|
||||
|
||||
```bash
|
||||
openclaw vault setup \
|
||||
--target channels.telegram.botToken=channels/telegram/botToken \
|
||||
--target models.providers.openai.headers.x-api-key=providers/openai/proxyKey \
|
||||
--target auth-profiles:main:profiles.openai.key=providers/openai/apiKey
|
||||
```
|
||||
|
||||
Bare target paths apply to `openclaw.json`. Use
|
||||
`auth-profiles:<agentId>:<path>` for existing `auth-profiles.json` targets.
|
||||
The target path must be a registered OpenClaw SecretRef target. The setup
|
||||
command does not create arbitrary named secrets in OpenClaw; Vault remains the
|
||||
secret store, and OpenClaw stores SecretRefs only on supported config fields.
|
||||
|
||||
## SecretRef id format
|
||||
|
||||
Vault SecretRef ids use this convention:
|
||||
|
||||
```text
|
||||
<vault-secret-path>/<field>
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
| SecretRef id | Default KV v2 Vault read | Returned field |
|
||||
| ----------------------------- | ---------------------------------- | -------------- |
|
||||
| `providers/openrouter/apiKey` | `secret/data/providers/openrouter` | `apiKey` |
|
||||
| `providers/openai/apiKey` | `secret/data/providers/openai` | `apiKey` |
|
||||
| `teams/agent-prod/openrouter` | `secret/data/teams/agent-prod` | `openrouter` |
|
||||
|
||||
The returned Vault field must be a string.
|
||||
|
||||
For KV v1, set:
|
||||
|
||||
```bash
|
||||
export OPENCLAW_VAULT_KV_VERSION=1
|
||||
```
|
||||
|
||||
Then `providers/openrouter/apiKey` reads:
|
||||
|
||||
```text
|
||||
secret/providers/openrouter -> apiKey
|
||||
```
|
||||
|
||||
## What OpenClaw stores
|
||||
|
||||
Applying a Vault setup plan stores a plugin-managed provider:
|
||||
|
||||
```json
|
||||
{
|
||||
"source": "exec",
|
||||
"pluginIntegration": {
|
||||
"pluginId": "vault",
|
||||
"integrationId": "vault"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Credential fields point at that provider:
|
||||
|
||||
```json
|
||||
{ "source": "exec", "provider": "vault", "id": "providers/openrouter/apiKey" }
|
||||
```
|
||||
|
||||
The resolved value lives only in the active runtime secrets snapshot.
|
||||
|
||||
## Containers and managed deployments
|
||||
|
||||
Containerized Gateways still use the same plugin and SecretRef config. The
|
||||
container must receive:
|
||||
|
||||
- `VAULT_ADDR`
|
||||
- one auth source:
|
||||
- `VAULT_TOKEN`
|
||||
- `OPENCLAW_VAULT_AUTH_METHOD=token_file` plus `VAULT_TOKEN_FILE`
|
||||
- `OPENCLAW_VAULT_AUTH_METHOD=jwt` plus `OPENCLAW_VAULT_AUTH_MOUNT`,
|
||||
`OPENCLAW_VAULT_AUTH_ROLE`, and `OPENCLAW_VAULT_JWT_FILE`
|
||||
- `OPENCLAW_VAULT_AUTH_METHOD=kubernetes` plus `OPENCLAW_VAULT_AUTH_ROLE`; optionally
|
||||
override `OPENCLAW_VAULT_AUTH_MOUNT` or `OPENCLAW_VAULT_JWT_FILE`
|
||||
- optional `VAULT_NAMESPACE`, `OPENCLAW_VAULT_KV_MOUNT`, and
|
||||
`OPENCLAW_VAULT_KV_VERSION`
|
||||
|
||||
When using Kubernetes, prefer `OPENCLAW_VAULT_AUTH_METHOD=kubernetes`
|
||||
when Vault has Kubernetes auth configured for the cluster. Use
|
||||
`OPENCLAW_VAULT_AUTH_METHOD=jwt` only when Vault is configured to treat the cluster
|
||||
as a generic JWT/OIDC issuer. Either option is better than a long-lived Vault
|
||||
token in a Kubernetes Secret. Vault Agent sidecar or injector deployments can
|
||||
use `token_file` instead.
|
||||
|
||||
For multi-tenant Vault setups, keep tenant routing in Vault policy and
|
||||
deployment config. OpenClaw does not require a fixed mount, role, or path: each
|
||||
Gateway environment can set its own `OPENCLAW_VAULT_KV_MOUNT`,
|
||||
`OPENCLAW_VAULT_AUTH_ROLE`, and SecretRef ids. If one shared Gateway must resolve
|
||||
different Vault users at the same time, use manually configured exec providers
|
||||
that wrap distinct auth environments, or split tenants across Gateway
|
||||
environments with separate Vault env.
|
||||
|
||||
## Related
|
||||
|
||||
- [Secrets management](/gateway/secrets)
|
||||
- [`openclaw secrets`](/cli/secrets)
|
||||
- [Plugin inventory](/plugins/plugin-inventory)
|
||||
Loading…
Add table
Add a link
Reference in a new issue