Skip to content

JIT escalation substrate

Default credentials for high-blast-radius systems (infrastructure state, secret stores, production IAM, application databases) are read-only. Write operations require a pull request that requests time-boxed elevation, declaring target, scope, TTL, risk tier, justification, and rollback plan. A human reviewer approves the request; on merge, an adapter mints a scoped short-lived credential; the apply runs; the credential is revoked on TTL expiry or explicit destroy. The PR, the reviewer approval, the issuance event, the apply outcome, and the revocation event all land in a joinable audit record.

The substrate is the provider-independent scaffolding that makes the pattern mechanical: a PR metadata schema, a declarative tier-policy config, a CI validator that gates merges on policy, a reusable tier-router workflow that gates applies on environment reviewers, and an audit-event schema that adapters emit against. No credential minting, no revocation mechanics, no provider-specific scope validation — those belong to adapters, separate features per provider (Cloudflare, GitHub App PEM, AWS STS, GCP WIF, Vault, database role).

This is the abstract pattern. The canon’s own wired instance is documented separately at internal/integrations/canon-jit-escalation-substrate.md; the substrate instantiates the gitops-jit-privilege-elevation recipe.

The substrate carries three concerns. Adapters carry everything else.

  • Request surface. A PR whose body leads with a YAML frontmatter block declaring schema: v1, target_adapter, scope, ttl, risk_tier, justification, and rollback_plan. See schemas for the full shape. The PR is the request; no separate issue, no workflow_dispatch wizard as the primary path, no PR label that a reviewer could flip to skip the gate. Frontmatter-inside-the-diff is authored content — editing it re-runs the validator.
  • Approval gate. Two-layer: PR review (always, for every elevation PR) and GitHub Actions environment reviewers (for medium and high tiers, consumed via the tier-router workflow). The PR-review gate approves the request; the environment-reviewer gate approves the act of applying. An author cannot self-approve either layer.
  • Audit schema. Orphan git branch audit with per-event JSON records at YYYY/MM/DD/<pr-number>-<short-sha>/<event>-<sequence>.json. Events (issued, applied, revoked) carry a correlation ID of shape canon-elevation-pr-<N>-<short_sha> embedded in provider credential name fields so provider-side audit logs corroborate without a sidecar lookup table. The substrate specifies the schema and the join shape; each adapter emits its own events into that shape.

The separation from adapter features is load-bearing. The substrate ships once; adapters ship per provider. Keep these concerns out of the substrate:

  • Credential issuance. Minting a scoped token, assuming an IAM role, requesting a Vault lease, creating a GitHub App installation token — all adapter responsibilities. The substrate’s target_adapter enum records which adapters are known; a tier’s allowed_adapters list records which are callable.
  • Revocation. Platform expires_on enforcement, explicit destroy calls, lease expiry, token deletion — adapter-side. The substrate knows that revoked is a lifecycle event; the mechanism is the adapter’s.
  • Adapter-specific scope validation. The scope field is an opaque map or list from the substrate’s perspective. Each adapter validates its own scope shape (e.g. a Cloudflare adapter maps scope payloads to CF permission-group IDs; a Vault adapter maps to policy paths). A substrate-level “must be non-empty” check is the only scope constraint the substrate enforces.
  • Provider audit log correlation mechanics. The substrate specifies the correlation-ID format. Adapters embed that ID in provider-side credential names or tags so provider audit logs are joinable back.

A typical elevation cycle, start to finish:

  1. Author opens a PR from the elevation template, fills the YAML frontmatter declaring target adapter, scope, TTL, tier, justification, and rollback plan.
  2. Validator (CI status check) parses the frontmatter, applies schema + policy checks. Violations fail the required status check and block merge; structured errors name the specific violation (missing field, bad enum, TTL over tier max, adapter not in tier allowed list, etc.).
  3. Reviewer approves the PR. For low-tier elevations this is the only human gate. For medium/high, the environment-reviewer gate follows at apply time.
  4. Merge triggers the adapter’s apply workflow. The workflow invokes the reusable tier-router to resolve the tier’s environment; medium/high runs pause at the environment’s reviewers gate until a listed reviewer clicks approve (low runs proceed without the pause).
  5. Adapter mints the credential — scoped to the declared scope, with expires_on at now + min(requested_ttl, tier.max_ttl), named with the correlation ID. Emits issued to the audit branch.
  6. Apply runs against the target system. Emits applied with result: success | failure.
  7. Adapter revokes the credential post-apply: explicit destroy plus platform-side expiry as belt-and-braces. Emits revoked.
  8. Audit-join (on demand) combines the PR metadata (author, reviewers, merge state) with the branch’s event records, surfaces any missing_phases to the caller.

Rejected elevations produce no audit-branch records — the PR object itself (closed, unmerged, with review decisions) is the artefact.

  • Schemas — field-by-field reference for the elevation PR frontmatter, the policy config, and the audit-event record.
  • Authoring an adapter — the 30-minute-sketch guide. What an adapter provides, what it consumes, what it emits, and a skeleton for a new adapter feature doc.