Skip to main content
Version: v5.7.0

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.