Secrets
The secret is the primary object in ScaiVault. Everything else — policies, rotation, audit — exists in service of reading and writing secrets safely.
Shape#
A secret has:
- Path — slash-separated address, e.g.
environments/production/salesforce/api-credentials. Tenant-scoped by default. - Secret type — how the value should be interpreted. One of
kv,json,certificate,ssh_key,api_key. - Data — the actual payload, a JSON object with arbitrary fields.
{"password": "..."},{"client_id": "...", "client_secret": "..."},{"key": "sk_live_..."}— anything. - Version — an integer. Each write creates a new version; the old versions stay readable until aged out.
- Metadata — description, tags, owner, custom key-values. Not secret; searchable.
- Timestamps —
created_at,updated_at,expires_at,last_accessed_at. - Links —
rotation_policy_id,secret_policy_id.
Example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Paths#
Paths are /-separated. They have meaning to you — the service at environments/production/salesforce/ probably knows what secrets live under that prefix. ScaiVault just matches strings.
Rules:
- Maximum depth: 10 levels.
- Maximum length: 512 characters total.
- Allowed characters:
a-z,0-9,-,_,/. - Case-sensitive.
- No leading/trailing slashes.
- No empty segments (
//).
Paths encouraged, not required, to follow a pattern:
1 | |
For example:
1 2 3 4 | |
This is convention, not enforcement. ScaiVault doesn't care about your path scheme as long as it's consistent — your policy patterns will match what you write.
Secret types#
The secret_type field is a hint to consumers and to the UI. It doesn't change storage behavior.
| Type | Typical shape | Use when |
|---|---|---|
kv |
{"key": "value"} |
Single credentials, simple config |
json |
Arbitrary nested JSON | Multi-field credentials, OAuth clients, config blobs |
certificate |
{"cert_pem": "...", "key_pem": "...", "chain_pem": "..."} |
TLS certificates stored by hand. For ScaiVault-issued certs, use the PKI API. |
ssh_key |
{"public_key": "...", "private_key": "..."} |
SSH host or user keys |
api_key |
{"key": "sk_live_..."} |
Single-value API tokens |
Rendering, masking, and search filters in the admin UI key off the type. Your code can ignore it if all you need is .data.
Versioning#
Every write creates a new version. The old versions stay readable and count against the secret's max_versions setting (default: 10).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
When max_versions is exceeded, ScaiVault deletes the oldest versions first (keeping the current always). Set max_versions higher if you need longer history for compliance.
Why not overwrite?#
Two reasons:
- Grace during rotation. A client that read v2 thirty seconds before rotation can still fetch v2 explicitly if the caller is allowed. Gives long-running jobs a window to finish.
- Forensics. "What was the value of this secret on Monday?" is answerable.
You can delete a specific version if it contained something that shouldn't have been stored:
1 | |
Expiration#
Set expires_at (absolute) or expires_in (duration) on write:
1 2 3 4 5 6 | |
Expired secrets return 410 secret_expired on read. Depending on configuration, they can be auto-deleted or kept in a read-only state.
Use expiration for secrets that genuinely have a known lifetime (short-term test credentials, one-off access tokens). For recurring rotation, use a rotation policy instead.
Metadata#
Metadata is searchable and non-secret:
1 2 3 4 5 6 7 8 9 | |
List endpoints accept tag= filters. Custom fields are indexed for prefix search.
Updating metadata does not create a new version:
1 | |
Deletion#
Two flavors:
Soft delete (default): the secret is marked deleted and unreadable, but stays in the database for a recoverable retention period (30 days by default).
1 | |
Response includes recoverable_until. A soft-deleted secret can be restored with POST /v1/secrets/{path}/restore.
Hard delete (requires admin): removes the row permanently.
1 | |
Hard-deleted paths can be reused. Soft-deleted paths cannot — if you try to write to a soft-deleted path, you get 409 secret_exists. Restore or wait out the retention, or use a different path.
What's next#
- Managing Secrets — the full CRUD API.
- Rotation — automated rotation.
- Policies and Permissions — who can read what.