Rotation
Static credentials age into liabilities. ScaiVault has first-class rotation: define a policy once, attach it to a set of secrets, and ScaiVault drives the schedule, keeps an old version readable during cutover, and emits events so your systems can respond.
The model#
A rotation policy is a schedule plus behavior:
- Interval. How often (
90d,7d,24h). - Grace period. How long the previous version stays readable after rotation (
48hby default). - Warn-before. When to emit
rotation.dueevents (["7d", "1d"]). - Auto-generate. Whether ScaiVault generates the new value itself (random string) or just fires an event and waits for you to
PUTa new value. - Webhook IDs. Where to route rotation events.
Attach a rotation policy to one or more secrets. The schedule runs independently per secret, based on its last-rotated timestamp.
1 2 3 4 5 6 7 8 9 10 11 12 13 | |
Lifecycle of a rotation#
Take a secret with a 90-day policy, currently at version 3, last rotated on day 0.
- Day 83 (7 days before rotation). Webhook fires with
rotation.due,warn_before: "7d". Your automation can do anything — prepare the new value, tell a human, open a ticket. - Day 89 (1 day before). Second
rotation.duewebhook,warn_before: "1d". - Day 90. Rotation fires:
- If
auto_generate: true, ScaiVault writes a new version (v4) with a random value. - If
auto_generate: false, ScaiVault emitsrotation.duewithdue_now: trueand waits. Your automation mustPUT /v1/secrets/{path}with the new value. If it doesn't within the grace period,rotation.overduefires.
- If
- Day 90.5.
secret.rotatedwebhook fires withold_version: 3, new_version: 4. Consumers can pick up the new value. - Day 92 (48h grace period ends). Version 3 is no longer reachable; v4 is the only readable version. Rotation complete.
Auto-generate vs event-driven#
auto_generate: true works for secrets whose value is just a random string — database passwords where you also control the database, internal service tokens. ScaiVault generates a cryptographically random value (configurable length and alphabet via a linked secret policy) and writes it as the new version. You then need to propagate the value to the downstream system.
auto_generate: false works when the value comes from somewhere else — an external OAuth provider, a third-party API key you request through a portal, a human picking a value. ScaiVault fires the event; you do the rest. This is the common case for third-party credentials.
The pattern is:
- ScaiVault emits
rotation.due. - Your automation generates (or obtains) the new credential from the source system.
- Your automation writes the new version:
PUT /v1/secrets/{path}. - ScaiVault records the rotation and emits
secret.rotated.
Grace periods#
The grace period keeps the old version readable after rotation. Without grace, a consumer that just loaded v3 and is mid-request might fail with "this credential is invalid" because the underlying resource has already moved to v4.
During grace, a read with no explicit version returns v4. Reads with ?version=3 return v3. After grace, ?version=3 returns the value but consumers treating it as current should use the latest — the audit log will flag reads of stale versions.
Set grace long enough to cover your longest-running job. 24h is usually safe for typical web services; batch pipelines may want 72h or more.
Secrets due for rotation#
Dashboards and automation can ask "what's due soon?":
1 2 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | |
Use this in CI or a scheduled job to surface overdue rotations.
Triggering an immediate rotation#
Sometimes you need to rotate now — a credential leaked, a new hire left, a third party asked.
1 2 3 4 5 6 7 8 | |
grace_period: "1h" overrides the default for this one rotation — you probably don't want 48 hours of grace if you're responding to a compromise. For a policy-triggered emergency rotation across many secrets, POST /v1/rotation/policies/{id}/rotate with optional secret_paths filters.
Rotation history#
Every rotation (successful or failed) is recorded:
1 2 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Failed rotations are retried on a backoff schedule. After the configured retry limit, they stop and require manual intervention.
Enabling and disabling#
POST /v1/rotation/policies/{id}/disable pauses the policy. Attached secrets stop rotating but are not detached. Re-enable with POST /v1/rotation/policies/{id}/enable. Useful during incidents or infrastructure migrations.
Secret policies (value generation)#
A secret policy (different from an access policy) controls how ScaiVault generates random values when auto_generate: true. Specify length, character classes, and constraints:
1 2 3 4 5 6 7 8 9 10 | |
Attach a secret policy to a rotation policy or directly to a secret. POST /v1/secret-policies to create.
What's next#
- Rotation Policies Guide — end-to-end setup.
- Events and Webhooks — consuming rotation events.
- Rotation Reference — endpoints.