Skip to content

core.vault

← Module catalog

keeper-sidesoulstack.secretssecrets

Explicit reading and generation of Vault KV secrets on the Keeper side.

core.vault works with Vault KV on the Keeper itself (both states require on: keeper), not on the host. kv-read reads a secret explicitly and leaves a vault.kv-read audit event, which implicit ${ vault(...) } does not; kv-present idempotently generates missing fields with a crypto-random value per the password policy and does not overwrite existing ones. The generated value is never handed out — not to the output, the audit, or the logs.

Requirements

  • Rootnot required
  • Sidekeeper-side
  • Collectionsoulstack.secrets
  • Categorysecrets
Backend detection

The Vault KV engine version (v1/v2) is determined on the Keeper side automatically (probe) or set by the vault.kv_version override. The module receives an already-flat payload and works the same on both versions; the path is given mount-relative and without the data/ segment.

States

core.vault.kv-read — Explicit read of a secret from Vault KV, recording the vault.kv-read audit event.

Changes when

Never: it is a read operation, the state is not mutated.

Stays unchanged when

Always — kv-read only reads.

Parameters

ParamTypeRequired / defaultDescription
pathstringrequiredVault KV path (mount-relative).
fieldslist<string>optionalWhich keys to extract; empty → the whole secret.

Example — Read DB credentials for the audit event

- name: Read DB credentials from Vault (audit-tracked)
on: keeper
module: core.vault.kv-read
register: db_creds
params:
path: secret/redis/admin
fields: [username, password]

Output

FieldTypeDescription
pathstringecho of the requested path
dataobjectthe extracted key→value pairs (after the fields filter)
fieldsarray<string>the key names in data (sorted)

Reference

Alphabet (charset) presets for generation

kv-present generates a value from a named charset preset or from an explicit allowed_chars (mutually exclusive). The default is ascii-printable-safe: the password must not break the target config.

PresetAlphabet
alphanumericLatin letters of both cases + digits (safe everywhere)
hexlowercase hex digits 0-9a-f
base64urlurl-safe base64 (-/_ instead of +//, no =)
ascii-printable-safe (default)printable ASCII (0x21–0x7E) without the characters that break redis.conf / users.acl / shell substitution: space, double and single quotes, #, backslash, backtick, and $

Notes

  • kv-read exists for the audit trail: implicit ${ vault(...) } is cheap to render but only reads and leaves no separate audit record. kv-read is the explicit form for compliance (PCI-DSS, SOC2); implicit reads remain available for the render phase.
  • kv-present is a write form that CEL resolution does not have at all: the service generates the missing passwords itself at create, and the operator does not need to pre-seed secrets with a manual vault kv put.
  • Multiple targets on the same path (different fields) are merged into a single WriteKV over the existing fields (read-merge-write) — neighboring fields are not lost and no extra KV versions are spawned.
  • destroy does not clean up secrets: a re-create reuses the same passwords. Rotating or deleting a secret is a separate scenario — this state does not do it.
  • kv-present must run before the render phase of tasks that read the same secrets through ${ vault(...) } (staged-render, ADR-056): first generation in Vault, then the read.

Security & defaults

  • The generated value never leaves the system (ADR-010): not in the register output, the audit payload, the logs/OTel/UI, or the error text — only the fact, the path, and the names of the generated fields. The invariant is locked in by a guard test.
  • kv-read: the secret values themselves do not go into the audit payload — only the path and the list of fields are recorded. In the register output the values are present (data.*), but on the write path they are masked (logs / OTel / UI / reports) via MaskSecrets.
  • Generation uses crypto/rand (not math/rand), and each character is chosen uniformly (rejection sampling, no modulo bias).
  • The default charset ascii-printable-safe excludes the characters that break redis.conf / users.acl / shell substitution — a generated password will not break the target config.
  • Requires the Keeper's Vault auth: reads and writes run under the Keeper cluster's account, the module does not accept a token/credentials in params and does not elevate access — it works exactly where the Keeper's policy in Vault allows.
  • A Keeper-side operation (on: keeper): root/capability semantics do not apply, and running a scenario with this step is governed by the operator's RBAC.

See also