You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Paths in the tables are relative to /api/v1/vault, except the service probes
explicitly marked as root paths. Authentication is via
Authorization: Bearer rh_... for token-protected routes, except where noted.
The interactive Swagger / ReDoc UIs and the OpenAPI schema are
disabled by default: docs_url, redoc_url, and openapi_url
are all gated by the enable_docs setting (RH_ENABLE_DOCS,
default false). When enabled, the schema is served unauthenticated
at /openapi.json (root path) - put it behind SSO or a reverse proxy
in production, and leave it off otherwise.
Service probes
These paths are served at the API root, without the /api/v1/vault prefix.
Method
Path
Auth
Purpose
GET
/health
none
Liveness; returns 200 while the process is running, including while sealed
GET
/readiness
none
Load-balancer readiness; returns 200 only when this worker may serve vault traffic
GET
/internal/ha/status
none
Process-local HA state that remains available during a PostgreSQL outage
GET
/internal/ha/peer-status
cached cluster mTLS member
The same DB-free HA state, restricted to known cluster peers
List entries from the checkpointed read log (vault_audit_lite) - bulk read traffic
GET
/audit/stream
audit:r
SSE live tail of the chained log
GET
/audit/verify
audit:r or sealed CIDR
Verify the full chain synchronously (compatibility path)
GET
/audit/verify/incremental
audit:r or sealed CIDR
Verify evidence added after the newest signed full-verification anchor
POST
/audit/verify/preflight
audit:r or sealed CIDR
Check the incremental state; queue a full job when its anchor is missing or stale
POST
/audit/verify/jobs
audit:r or sealed CIDR
Queue or join the cluster-wide full-verification job
GET
/audit/verify/jobs/{job_id}
audit:r or sealed CIDR
Poll durable job status and result
POST
/audit/verify/legacy-adopt
admin:w
Explicitly adopt the exact unsigned legacy checkpoint rows committed by a signed full-job candidate
POST
/audit/export
audit:r
Download one signed .tar.gz evidence bundle for an optional since/until range
GET
/audit/files
audit:r
List daily JSONL files
GET
/audit/files/{date}
audit:r
Read one day
DELETE
/audit/files/{date}
admin:w
Delete (only beyond retention)
POST
/audit/mcp
token
Append an MCP tool-call event to the dedicated signed chain
GET
/audit/mcp
audit:r
List MCP tool-call audit entries
GET
/audit/mcp/verify
audit:r
Verify the MCP audit chain
The chained log (/audit/) is Ed25519-signed by default, with an HMAC fallback,
and every row signs the previous row. It records mutations (write, delete,
seal, unseal, token mint, ...). High-volume reads go to the unchained
vault_audit_lite table so the request path stays cheap. Signed Merkle
checkpoints protect completed read windows; /audit/verify reports the newest
uncheckpointed tail separately. Both logs share the same listing fields. Use
the durable job endpoints for retained production evidence:
only one pending/running verifier is allowed cluster-wide, and a different
unsealed worker reclaims the job if its owner stops heartbeating.
Checkpointed audit-lite prefixes older than RH_AUDIT_DB_RETENTION_DAYS are
exported as canonical gzip JSONL beside the main audit archives, sealed through
the signed main chain, and then removed from PostgreSQL. Full verification
checks their content digest, Merkle root, seal lineage, and linked prune anchor.
A clean full run writes an independently Ed25519-signed anchor containing the
main, read-log and archive high-water marks. Incremental verification checks
that signature, the mutation suffix, new Merkle windows, the current tail and
archive seals. It reports verification_scope: incremental because historical
rows are trusted from the anchor rather than read again. Preflight first closes
the current read-log tail; if a fresh anchor is unavailable it returns the
durable full-job id instead of holding the HTTP request open for an O(N) scan.
POST /audit/export accepts optional ISO-8601 since (inclusive) and until
(exclusive) fields. Its only output format is a portable .tar.gz. The bundle
contains live mutation and read rows, overlapping sealed archives, signer
public keys, verification anchors, both archive-seal lineages, and an
Ed25519-signed manifest committing every member's byte length and SHA-256
digest. Export generation uses a repeatable database snapshot and the retention
lock, so pruning cannot move a row between the database and an archive midway
through the export. Ordinary writes remain concurrent. The completed export is
itself recorded as audit_evidence_export in the mutation chain.
The endpoint first runs the bounded preflight. It refuses to sign an export if
the evidence is not intact. When the full anchor is missing or stale, the 409
message includes the durable full-verification job that was queued; retry after
that job succeeds. Only one export runs cluster-wide at a time.
2FA
Method
Path
Auth
Purpose
PUT
/2fa?mode=...
admin
Set mode (none, totp, yubikey, any)
POST
/yubikey
admin
Register a YubiKey HMAC secret
GET
/yubikey
admin
List
DELETE
/yubikey/{serial}
admin
Remove (auto-fallback if last)
POST
/totp/setup
admin
Generate secret + URI
POST
/totp/enable
admin
Activate (after code verification)
DELETE
/totp
admin
Disable (auto-fallback)
WebAuthn / FIDO2
Method
Path
Auth
Purpose
POST
/webauthn/register/begin
admin
Get credential creation options
POST
/webauthn/register/complete
admin
Save the credential
POST
/webauthn/auth/begin
none
Get authentication options
GET
/webauthn/
admin
List registered credentials
DELETE
/webauthn/{id}
admin
Remove
External auth (LDAP + SSO proxy)
Method
Path
Auth
Purpose
POST
/auth/ldap
LDAP bind
Login -> session token
POST
/auth/ldap/config
admin
Configure LDAP (encrypted bind password)
GET
/auth/ldap/config
admin
Read config (password masked)
PUT
/auth/ldap/mappings
admin
Map groups -> permissions
GET
/auth/ldap/mappings
admin
Read mappings
POST
/auth/proxy
trusted IP
SSO proxy login
GET
/auth/proxy/config
admin
Read config
POST
/auth/proxy/config
admin:w
Store the trusted proxy authentication configuration
Remove the typed membership by UUID returned by list/add
Notification channels
Method
Path
Auth
Purpose
POST
/notifications/
admin:w
Create (Matrix, webhook, email)
GET
/notifications/
admin:r
List
PUT
/notifications/{id}
admin:w
Update
DELETE
/notifications/{id}
admin:w
Remove
POST
/notifications/{id}/test
admin:w
Emit a test message
Backup / restore
Method
Path
Auth
Purpose
POST
/backup/create
admin:w
Create age-encrypted logical backup
POST
/backup/restore
admin:w
Restore from age archive
Oneshot
Method
Path
Auth
Purpose
POST
/oneshot
password + 2FA + secret name
Unseal -> read 1 -> re-seal
Dynamic secrets
Method
Path
Auth
Purpose
POST
/dynamic/engines
admin:w
Create an enabled PostgreSQL, MySQL/MariaDB, LDAP, Redis, or Cassandra engine
GET
/dynamic/engines
admin:r
List engines
GET
/dynamic/engines/compatibility
admin:r
List drivers and validated engine targets
POST
/dynamic/engines/test-connection
admin:w
Read-only bind/version probe; unknown versions are reported, not blocked
PUT
/dynamic/modules/{engine_type}
admin:w
Schedule fine-grained cluster module enable/disable; all API nodes must restart
DELETE
/dynamic/engines/{id}
admin:w
Delete engine
POST
/dynamic/engines/{id}/roles
admin:w
Define backend creation/revocation templates and TTL
GET
/dynamic/engines/{id}/roles
admin:r
List roles
POST
/dynamic/engines/{id}/creds/{role_name}
secrets:w
Issue credentials
GET
/dynamic/leases
admin:r
Active leases
POST
/dynamic/leases/{id}/revoke
admin:w
Manual revoke
POST
/dynamic/leases/{id}/renew
admin:w
Extend a lease, capped by its role TTL
PKI
Method
Path
Auth
Purpose
POST
/pki/init
admin:w
Initialise a namespace CA
GET
/pki/cas
secrets:r
List visible namespaces with an initialised CA
GET
/pki/ca
secrets:r
Read a namespace CA certificate and metadata
POST
/pki/issue
secrets:w
Issue a certificate from a namespace CA
POST
/pki/kem/issue
secrets:w
Issue an ML-KEM subject certificate
POST
/pki/revoke
admin:w
Revoke a certificate
POST
/pki/rotate
admin:w
Rotate a namespace CA
GET
/pki/certs
secrets:r
List issued certificates
Observability - Prometheus metrics
GET /metrics (Prometheus exposition format, on the API port).
Access is IP-allow-listed - the endpoint reads the direct peer IP
(NOT X-Forwarded-For) and matches it against
metrics_allowed_cidrs. An empty allow-list refuses everyone.
Disabled entirely if metrics_enabled = false. Routinely
disabled in schema (include_in_schema=False) so it does not appear
in the OpenAPI export.
Live snapshot for the UI
Method
Path
Auth
Purpose
GET
/observability
audit:r
Return the live counters and gauges used by the Nova dashboard
Token-authed (scope audit:r) JSON view over the same registry, for the in-app
Nova dashboard (the browser cannot use the IP-allow-listed /metrics).
Returns reads_total, writes_total, http_total, http_https,
auth_failures_total, active_tokens, active_connections, decrypt_p95_ms,
sealed. Route-layer only: reads already-computed metric values, never touches
keys or crypto. Counters are monotonic totals; the client diffs successive polls
into per-second rates.
Failed background cleanup cycles; each failure is retried after five minutes
DEK lifecycle
Metric
Type
Labels
Meaning
rhorizon_dek_key_stale
gauge
-
1 = the dek_key exceeds its SLO or its rotation timestamp cannot be trusted
rhorizon_dek_key_age_seconds
gauge
-
Age of the current dek_key; -1 means its rotation timestamp is missing or invalid
Cluster
Metric
Type
Labels
Meaning
rhorizon_master_rpc_inflight
gauge
-
RPC calls currently in flight on the master
rhorizon_master_rpc_duration_seconds
histogram
op
RPC dispatch time (master-side)
rhorizon_master_rpc_errors_total
counter
op
RPC errors (non-vault failures)
rhorizon_cluster_failover_total
counter
result (success/quorum_missing/failure)
Master failover events
See howto/observability-alerts.md
for the recommended Prometheus alerting rules ranked by severity
(critical / serious / capacity) and Matrix routing per channel.
Rate limiting
The vault enforces a global rate limit per source IP on auth-failures
(via vault_rate_limits table). Limits:
10 failures / 60s -> 60s lockout
50 failures / 5min -> 1h lockout
100 failures / 1h -> 24h lockout
Plus per-actor rate-limit on namespace mutations
(namespace_mutation_rate_per_hour, default 10).
Error format
FastAPI's standard:
{"detail": "Missing scope: secrets"}
Status codes follow REST conventions:
401 - invalid / missing token
403 - token valid but lacks the required scope or namespace
404 - resource not found (or hidden via deletion)
409 - duplicate name / archived target
423 - set-once flag rejected (one-way ratchet violated)