cellos-broker-vault
SecretBroker that fetches secrets from HashiCorp Vault via AppRole
authentication.
What it is
Implements cellos_core::ports::SecretBroker. For each secretRef, the
broker:
- POSTs
{addr}/v1/auth/approle/loginwith the configuredrole_idandsecret_id. - GETs
{addr}/v1/{kv_mount}/data/{kv_path_prefix}/{key}with the freshly-issuedX-Vault-Token. - Extracts
data.data.{key}from the Vault KV v2 envelope and returns it as aSecretView.
By default every resolve performs a fresh AppRole login. Combined
with a use_limit=1 or short-ttl AppRole policy, this yields one-shot
tokens with no persistent state in the supervisor.
When the cell spec opts into runtimeLeasedBroker, the broker performs
a single login per cell, reuses the cached token for on-demand fetches,
and actively calls /v1/auth/token/revoke-self in revoke_for_cell —
the only broker in the family that implements meaningful runtime
revocation.
Selected in cellos-supervisor::composition::build_secret_broker when
CELLOS_BROKER=vault-approle.
What it does NOT do:
- It does not refresh tokens proactively. For classic env delivery, the child process holds the materialized secret already; revocation depends on short Vault TTLs.
- It does not perform any Vault auth method other than AppRole.
Public API surface
| Symbol | Purpose |
|---|---|
VaultAppRoleBroker |
The broker. |
VaultAppRoleBroker::from_env() |
Construct from the env vars below; returns Err if required vars are missing or malformed. |
VaultAppRoleBroker::has_runtime_lease(cell_id) |
Test helper: cached lease for a given cell. |
VaultAppRoleBroker::runtime_lease_count() |
Observability helper: number of cached leases. |
DEFAULT_REQUEST_TIMEOUT_MS / DEFAULT_CONNECT_TIMEOUT_MS |
15 s / 10 s defaults; overridable. |
resolve_timeout_ms(env_var, default_ms) |
Pure helper. |
Source: src/lib.rs.
Configuration
Selection:
CELLOS_BROKER=vault-approle
Required:
| Env var | Description |
|---|---|
CELLOS_VAULT_ADDR |
Vault server URL, e.g. https://vault.example.com |
CELLOS_VAULT_ROLE_ID |
AppRole role_id |
CELLOS_VAULT_SECRET_ID |
AppRole secret_id |
Optional:
| Env var | Default | Description |
|---|---|---|
CELLOS_VAULT_KV_MOUNT |
secret |
KV v2 mount name |
CELLOS_VAULT_KV_PATH_PREFIX |
(none) | Prefix prepended to every key (e.g. cellos/prod) |
CELLOS_VAULT_NAMESPACE |
(none) | Vault Enterprise namespace (X-Vault-Namespace) |
CELLOS_CA_BUNDLE |
(none) | PEM CA bundle path for private Vault PKI |
CELLOS_VAULT_TIMEOUT_MS |
15 000 | Request timeout |
CELLOS_VAULT_CONNECT_TIMEOUT_MS |
10 000 | Connect timeout |
HTTP_PROXY / HTTPS_PROXY / NO_PROXY are honoured automatically by
reqwest. The client is never built without explicit timeouts.
Examples
authority:
secretRefs:
- DB_PASSWORD
# Reads secret/data/cellos/prod/DB_PASSWORD
Testing
Related crates
cellos-broker-env/cellos-broker-file— env / file delivery.cellos-broker-oidc— GitHub Actions OIDC alternative.cellos-supervisor— selects this broker viaCELLOS_BROKER.cellos-core— defines theSecretBrokerport andSecretView.
Operator note: tracing
reqwest can emit X-Vault-Token (and the AppRole login response with
auth.client_token) at TRACE level. Every CellOS binary that
initializes tracing wires cellos_core::observability::redacted_filter
into the fmt layer so RUST_LOG=reqwest=trace cannot leak Vault tokens
to stderr. Do not bypass this filter in custom tracing-init paths.
ADRs
- ADR-0007 — RBAC and
secretRefadmission contract; AppRole is the canonical machine-to-machine path.