Skip to content

jortsupetterson/root-token-manager

Repository files navigation

Root Token Manager — README

Straight to the point: this Worker rotates two bootstrap secrets on a schedule using a strict 2-slot model: PRIMARY (active) and SECONDARY (previous). No grace windows, no extra slots — deterministic swap only.


What it does

Each scheduled run does the following in order:

  1. Read current PRIMARY bootstrap tokens.
  2. Copy them to SECONDARY.
  3. Create two new tokens in parallel.
  4. Verify both new tokens.
  5. Overwrite PRIMARY with the new tokens.

A short KV lock prevents overlapping runs. All errors are logged and trigger a single email alert.


Quick facts / model

  • Required bootstrap secrets (must exist):
    • PRIMARY_TOKEN_CREATION_TOKEN — token used to create Cloudflare account API tokens.
    • PRIMARY_SECRET_EDIT_TOKEN — token used to PUT/UPDATE Secrets Store entries.
  • Secondary names written by the worker:
    • SECONDARY_TOKEN_CREATION_TOKEN
    • SECONDARY_SECRET_EDIT_TOKEN
  • Lock: KV_CACHE (KV namespace) used as a short-TTL mutex to avoid concurrent runs.
  • Handler: export default { async scheduled(...) }, configured via triggers.crons.
  • Alerting: single mail via configured mailer.send(...) on any failure path.

Grace window / fallback behavior (key point)

This design purposefully removes a separate "grace window" state by relying on token TTL and a deterministic two-slot swap. The important properties are:

  • New tokens are created with a ~2 hour TTL (configurable in code).
  • Rotation runs every hour by default. Because a freshly created token remains valid for ~2 hours, the SECONDARY slot (which holds the previous PRIMARY values) is always a valid fallback if the PRIMARY is unavailable, pending, or otherwise failing during an operation (for example, when the SECRET_EDIT token is used to rotate other secrets).
  • In other words: SECONDARY is guaranteed to work as a fallback for at least the next rotation cycle, avoiding complex grace-window logic. This gives deterministic behavior when consumers try to use a token during a rotate: try PRIMARY; if it fails, fallback to SECONDARY.

This simplifies coordination and reduces edge-case complexity: no separate next/current/grace states — just PRIMARY and a guaranteed working SECONDARY.


Files of interest

  • src/index.ts — TypeScript Worker implementation (scheduled handler + helpers).
  • wrangler.jsonc — bindings (Secrets Store, KV, cron). Populate secret bindings before deploy.
  • worker-configuration.d.ts — generated by npx wrangler types (recommended for editor types).

Pre-deploy checklist (do this, exactly)

  1. Add these Secrets Store entries (binding name → secret name in the store):
    PRIMARY_TOKEN_CREATION_TOKEN, PRIMARY_SECRET_EDIT_TOKEN, SECONDARY_TOKEN_CREATION_TOKEN (can be dummy "1"), SECONDARY_SECRET_EDIT_TOKEN (can be dummy).
  2. Ensure the creation bootstrap token (PRIMARY_TOKEN_CREATION_TOKEN) has rights to create account API tokens.
  3. Ensure the secret-edit bootstrap token (PRIMARY_SECRET_EDIT_TOKEN) can write to Secrets Store for the target store.
  4. Set account_id and KV_CACHE namespace id in wrangler.jsonc.
  5. Generate types for editor support: npx wrangler types.

Bootstrap nuance — secondary secrets must exist

Important operational note: the SECONDARY secret entries must already exist in the Secrets Store at bootstrap time (they can hold any value, including an empty string ""). The worker expects the secondary secret names to be present so the first scheduled run can atomically stage PRIMARY → SECONDARY and then populate PRIMARY with newly-created tokens. The system becomes fully operational only after the first successful rotation when both PRIMARY and SECONDARY contain valid token values.

Commands

  • Generate types (recommended):
npx wrangler types
  • Test scheduled handler locally:
npx wrangler dev --test-scheduled
  • Deploy (use deploy, publish is deprecated):
npx wrangler deploy

Rotation flow (detailed)

  1. Acquire KV lock (TTL ≈ 300s). If lock is held, exit.
  2. Read PRIMARY_TOKEN_CREATION_TOKEN and PRIMARY_SECRET_EDIT_TOKEN.
  3. Stage: PUT current PRIMARY values into SECONDARY_* names (idempotent).
  4. Create: two new tokens in parallel (creation + secret-edit) using the creation bootstrap.
  5. Verify: confirm both tokens via Cloudflare verify endpoint. If verify fails → abort (PRIMARY unchanged, SECONDARY staged).
  6. Promote: PUT new tokens into PRIMARY_* names (overwrite).
  7. Release lock.
  8. On any error: one log + one notification email; scheduled handler swallows (does not rethrow).

Security & ops notes

  • Keep bootstrap tokens in Cloudflare Secrets Store only — do not commit them to source.
  • Scope bootstrap tokens with least privilege. The worker assumes the generated tokens are short-lived (code defaults to ≈2h expiry). Adjust if needed.
  • If rotation fails repeatedly, inspect SECONDARY_* values for last-known-good and logs for failure reasons.
  • For stronger lock guarantees, replace KV lock with a Durable Object coordinator.

TypeScript / editor setup

  1. Run:
npx wrangler types
  1. Include the generated worker-configuration.d.ts in your tsconfig.json via include or compilerOptions.types so your editor recognizes Env and bindings.

TL;DR

  • Two bootstrap bindings only: token-creation + secret-edit.
  • Deterministic 2-slot swap: PRIMARY ← new, SECONDARY ← previous.
  • Because tokens live ~2 hours and rotation runs every hour, SECONDARY is always a valid fallback if PRIMARY fails.
  • KV lock prevents concurrent runs.
  • Single email alert on failure.
  • Use npx wrangler deploy to deploy.

About

Use this template to automatically rotate the Cloudflare secrets required to manage secret rotation.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published