Secrets providers — vaults, bindings and multi-vault
Included from Basic tiersecrets:multi-vaultpacks:secrets-awspacks:secrets-azure
Secret values never live in properties or workflow definitions: work
references them (secret-vault://<path>/<key>) and the server resolves
the reference at execution time. A secrets provider is the
connection the server resolves those references through — this guide is
how to register, route and operate them.
The provider record
A provider is a first-class connection object managed from the admin
plane (GUI: Administration → Secrets providers; CLI below): a code, a
kind (openbao | hashicorp-vault | aws-secrets-manager |
azure-key-vault), KV engine version, address, auth method (token |
userpass | approle for the vault kinds; access-key for AWS, the
IAM access key id and secret access key; client-secret for Azure, the
Entra ID tenant id, client id and client secret) with an encrypted,
write-only credential, TLS options and an enabled flag — audited
writes, and a test verb that probes with the stored credential and
records the outcome as the provider's health. The GUI list and dialogs
also carry the provider's resolution (server, the default, or
runner): choosing runner drops the credential fields because the
server stores none for such a provider — each runner carries it in its
own secrets_providers configuration — and moving a provider back to
server asks for the credential in the same save (see "Where references
resolve" in opschain docs secrets-providers). The GUI dialog shows the
field set of the kind you pick — the region and access key pair for AWS
Secrets Manager, the vault URL, tenant id and client credentials for
Azure Key Vault — and the provider's rate limit (reads per second
and token mints per minute), each lane a choice of inheriting the estate
default (shown resolved, e.g. "Estate default: 50 reads/s" or "Estate
default: unlimited"), unlimited at this provider, or a custom budget; the
list shows the result per provider. The estate default itself is set on
Administration → Settings → Global config under Rate limits.
opschain admin secrets providers list # kind, address, auth, enabled, health
opschain admin secrets providers show <code>
opschain admin secrets providers create <code> # credential via env/prompt, never argv
opschain admin secrets providers update <code> # a supplied credential rotates the stored one
opschain admin secrets providers test <code> # probe and record health
opschain admin secrets providers delete <code>
The cloud kinds are pack-gated: aws-secrets-manager requires
packs:secrets-aws, azure-key-vault requires packs:secrets-azure
(each pack's own reference page: opschain docs packs-secrets-aws,
opschain docs packs-secrets-azure). With no provider registered, a
development server resolves references best-effort from its local AGE
dev store; with every provider disabled, resolution refuses loudly
rather than silently falling back.
Multi-vault, and scope bindings
The first enabled provider is base platform. Enabling a second
requires the secrets:multi-vault entitlement (the typed refusal names
it). With several providers enabled, scope bindings route
resolution between them — declared and auditable, never inferred:
opschain admin secrets bindings list
opschain admin secrets bindings set / # the estate default
opschain admin secrets bindings set /projects/payments # override down the tree
opschain admin secrets bindings resolve <node-path> # which provider governs, and why
The deepest covering scope wins, exactly like the properties overlay.
Which node's binding an unprefixed secret-vault:// reference resolves
through follows where the value came from: a reference committed in the
template's repository (or supplied as a per-run override) resolves
through the binding of the node resolving it — the step's run target,
a refresh task's node, a reveal's owner — while a reference entered in
a project's, environment's or asset's own properties resolves through
the binding of the node it was entered on. secret-vault://origin@…
pins a reference to the node whose properties supplied it,
secret-vault://here@… to the resolving node, and the
provider-qualified form secret-vault://<code>@<path>/<key> is the
explicit cross-provider escape hatch that wins over every rule
(origin and here are reserved — no provider may take either code).
resolve <node-path> --origin <node-path> shows what each form
resolves through for a pair of nodes. Three guard rails: with several
providers enabled and no root binding, default resolution refuses by
name rather than guessing; a value whose supplying node no binding
covers while no default is named refuses by name, naming the property
and the node; and a provider referenced by bindings cannot be deleted
until its bindings are removed (delete on a binding is deliberately
ungated, so a lapsed estate can always unwind).
Day-to-day secrets work
Storing and referencing values is lesson 3.5
(opschain learn 3.5): opschain vault store|store-file|encrypt|global,
no-echo entry, secret-typed run inputs, and the local secret store on
the --local lane. The division of labour: that runbook is writing
and using secrets; this guide is operating the backends they live in.
Where next
opschain docs cli/admin-secrets-providers— the full command manual.opschain docs cli/admin-secrets-bindings— binding semantics.opschain docs packs-secrets-aws/packs-secrets-azure— the cloud kinds' configuration detail.