Skip to main content
Version: v5.7.0

Azure Key Vault provider (packs:secrets-azure)

packs:secrets-azure

Azure Key Vault is a SecretsProvider kind: azure-key-vault. It is additive on the open kind set — the same connection object, CRUD verbs, test verb, health recording, audit events and admin RBAC gate as the vault kinds, with Azure-shaped configuration. Everything on this page requires the packs:secrets-azure licence entitlement (see entitlements): creating an azure-key-vault provider, or enabling a disabled one, refuses with the typed entitlement error naming the pack. Already-enabled providers keep resolving on licence lapse — only the create/enable writes gate (the polite-lapse posture), and disabling stays open for lapse cleanup.

Configuration​

FieldMeaning for this kind
kindazure-key-vault
addressRequired. The vault URL (https://<name>.vault.azure.net).
tenant_idRequired. The Microsoft Entra ID tenant the client credentials authenticate against.
auth_methodclient-secret (the kind's only method, and its default): an Entra ID app registration's client credentials.
usernameThe application (client) id — the non-secret identity half, exactly as userpass auth carries its username.
credentialThe client secret — encrypted at rest, write-only (reads serve credential_set), rotated by the update verb with an audit event that never carries the value.
mount_pathOptional secret-name prefix: every OpsChain path is stored under it, scoping the provider to one corner of the vault's namespace.
ssl_verify / ssl_ca_certThe same TLS options the vault kinds carry — for proxied endpoints.
cipher_stacking / password_lengthAs for every provider: whether /api/secrets/store cipher-stacks written values, and the generated-secret length.

kv_version, role_id and region belong to the other kinds and are refused on this one.

The adapter speaks the Key Vault secrets REST surface (api-version 7.4) and the OAuth2 client-credentials grant directly — the server carries no Azure SDK, exactly as the vault kinds speak their HTTP API with no vendor client. Tokens are requested from the public-cloud authority (login.microsoftonline.com) with the public Key Vault scope; the signing identity is always a client-credential pair — ambient mechanisms (managed identity, workload identity) are not consulted, so the provider behaves identically wherever the server runs. Sovereign-cloud authorities are not configurable on the connection object yet; that is the kind's recorded configuration gap.

How secrets map​

One Key Vault secret holds one OpsChain secret node: the secret's value is a JSON object of key/value pairs, and a secret-vault://<path>/<key> reference reads key <key> from it. A secret whose value is not a JSON object reads as the single key value, so a portal-created plain secret is reachable as secret-vault://<path>/value.

Key Vault secret names allow only letters, digits and dashes, so the adapter encodes the path separator as a double dash: OpsChain path app/db is the secret named app--db (the mount_path prefix joins the same way). Path segments are therefore restricted to [0-9A-Za-z-] on this kind — a segment the name alphabet cannot carry (an underscore, a dot) refuses loudly naming the segment. Listings (the vault browser, the audit/migrate walkers) decode the names back into the directory view.

The test verb​

TestSecretsProvider (CLI: opschain admin secrets providers test <code>) acquires a client-credentials token and performs a single-page secrets listing — proving the tenant, the credential pair, the vault URL and the data-plane list permission. The typed outcome is recorded as the connection's health (last_test_*), and the failure reason never carries credential material. The app registration needs Key Vault data-plane permissions (RBAC: Key Vault Secrets User for reads and the browser, Key Vault Secrets Officer where /api/secrets/store writes; or the equivalent access-policy grants: get/list, plus set for writes).

Resolution lanes​

  • Server-side resolution — secret-vault:// references in properties, the /api/secrets read/write seam and the vault browser all resolve through the provider object, routed by the declared scope bindings exactly as the vault kinds are. Resolved values join the log mask set.
  • Interactive reads use the USER's own credential (the posture): each user stores their own Entra ID client credentials in preferences (username the client id, the credential the client secret; auth method client-secret), and Azure's own authorisation for that principal governs what the reveal/browser shows them. No stored personal credential → the typed configure-your-credential refusal, never a silent fall-back to the platform credential. Note the shape honestly: Azure has no per-human client-credential analogue of a vault token, so "per-user" here means one app registration (service principal) per user — organisations that cannot provision those should treat the interactive lane as unavailable on this kind and rely on the vault's own portal/CLI for human reads.
  • No runner environment, no step lease. The OPSCHAIN_VAULT_* projection and the response-wrapped step lease speak the vault wire protocol, which opschain-core inside the runner expects — an Azure-backed provider projects neither. Step properties still resolve (server-side, before dispatch, masked in logs); what an Azure-backed estate does not get is in-runner secret-vault:// resolution by MintPress action code reading OPSCHAIN_VAULT_* directly (only applicable to existing MintPress customers and those using the MintPress SDK or the packs:mintpress feature). That lane needs a coordinated opschain-core release and is recorded as the kind's follow-on gap.

Pack gating end to end​

  • CreateSecretsProvider with kind: azure-key-vault → permission_denied, ERROR_REASON_FEATURE_ENTITLEMENT_REQUIRED, metadata feature: packs:secrets-azure — unless the licence grants the pack.
  • UpdateSecretsProvider enabling a disabled Azure provider → the same typed refusal.
  • The secrets:multi-vault gate composes independently: a second enabled provider still needs it, whatever the kinds.