Credential Management
What you'll accomplish: Store and manage integration/provider credentials securely — and understand a deliberate security property: the vault has no read-back.
The vault
Hoziron ships a built-in credential vault (hoziron-extensions::secrets::VaultStore) — a SQLite-backed store where every value is AES-256-GCM encrypted per-row (never a single whole-file blob), keyed by a master key generated at <HOZIRON_HOME>/keys/vault.key with 0600 permissions.
# Store a credential — prompts for the value, not echoed to the terminal
# or passed as a CLI argument (never lands in shell history)
hoziron-cli vault set CLAIMCENTER_API_KEY
# List stored keys — names and timestamps only, never values
hoziron-cli vault list
# Remove a credential
hoziron-cli vault remove CLAIMCENTER_API_KEY
hoziron-cli vault init is a no-op today — the vault (database + master key) is created lazily by the daemon on first write. There's nothing to pre-initialize.
No read-back, by design (Issue #475)
There is no GET /vault/{key} and no hoziron-cli vault get — this is a deliberate non-goal, not a missing feature. The vault is write/rotate/delete only from every surface:
// crates/surfaces/hoziron-api/src/routes.rs
// No single-key `GET /vault/{key}` — the vault is write/rotate/delete only
// from the API; there is no read-back of a stored value (see the issue's
// non-goals and acceptance criterion #8). `GET /vault` returns key names and
// timestamps only, never values.
GET /vault (list) requires the vault:read action; PUT/DELETE /vault/{key} (write/remove) require vault:manage. Both are Admin-only — the same bar as API key management, and stricter than most other read actions: even the auditor role (which can read almost everything else, including the audit trail) cannot list vault key names or their values. See RBAC.
| Action | Route | Role required |
|---|---|---|
| List key names + timestamps | GET /vault | admin only |
| Store / overwrite a value | PUT /vault/{key} | admin only |
| Delete | DELETE /vault/{key} | admin only |
Referencing vault/env credentials from config
Provider and registry entries reference a credential by name, never by value:
[[provider]]
id = "big.licence"
driver = "anthropic"
api_key_env = "ANTHROPIC_API_KEY" # the name of an env var, resolved lazily at request time
[[catalog.registries]]
name = "internal"
url = "https://packages.internal.company.com"
auth_token_env = "INTERNAL_REGISTRY_TOKEN"
For registry tokens specifically, resolution checks the vault before the named env var (Issue #475's shared resolve_env_secret chokepoint) — so auth_token_env = "INTERNAL_REGISTRY_TOKEN" is satisfied by either a vault entry named INTERNAL_REGISTRY_TOKEN or a literal environment variable of that name, vault taking priority.
Environment variables
For container deployments, inject credentials via environment variables directly — this is the standard pattern for secrets managed by your container platform:
export ANTHROPIC_API_KEY="sk-ant-..."
How credentials are resolved
Key principles:
- Credentials are resolved lazily at request time, not at daemon startup — adding or removing a value takes effect on the next request, no restart needed.
config.tomland package manifests store only the name of the credential reference — never the value.- Error messages name the env var / vault key, never the secret value.
Security practices
- Never put raw secrets in
config.toml,MANIFEST.toml, oradapter.json— always reference by name (api_key_env,auth_token_env, or a vault key). - The vault encrypts at rest (AES-256-GCM, per-row); plain environment variables rely on OS/container-level security instead.
- Use an external secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.) and inject as environment variables in containerized deployments — Hoziron's own vault is the right choice for bare-metal/persistent secrets where an external manager isn't already in play.
- REST/SOAP adapter contracts declare an
envallowlist (integration.env) for anythingbase_urlmay reference — a var used but not declared there is a hard validation error, closing an ambient-env-var exfiltration path. See APIs § REST/SOAP adapter packages.
Next steps
Related: