JIT escalation substrate
What this is
Section titled “What this is”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.
Three concerns, one substrate
Section titled “Three concerns, one substrate”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, androllback_plan. See schemas for the full shape. The PR is the request; no separate issue, noworkflow_dispatchwizard 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
mediumandhightiers, 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
auditwith per-event JSON records atYYYY/MM/DD/<pr-number>-<short-sha>/<event>-<sequence>.json. Events (issued,applied,revoked) carry a correlation ID of shapecanon-elevation-pr-<N>-<short_sha>embedded in provider credentialnamefields 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.
What the substrate does NOT do
Section titled “What the substrate does NOT do”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_adapterenum records which adapters are known; a tier’sallowed_adapterslist records which are callable. - Revocation. Platform
expires_onenforcement, explicit destroy calls, lease expiry, token deletion — adapter-side. The substrate knows thatrevokedis a lifecycle event; the mechanism is the adapter’s. - Adapter-specific scope validation. The
scopefield is an opaque map or list from the substrate’s perspective. Each adapter validates its own scope shape (e.g. a Cloudflare adapter mapsscopepayloads 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.
Lifecycle
Section titled “Lifecycle”A typical elevation cycle, start to finish:
- Author opens a PR from the elevation template, fills the YAML frontmatter declaring target adapter, scope, TTL, tier, justification, and rollback plan.
- 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.).
- 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.
- 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
reviewersgate until a listed reviewer clicks approve (low runs proceed without the pause). - Adapter mints the credential — scoped to the declared
scope, withexpires_onatnow + min(requested_ttl, tier.max_ttl), named with the correlation ID. Emitsissuedto the audit branch. - Apply runs against the target system. Emits
appliedwithresult: success | failure. - Adapter revokes the credential post-apply: explicit destroy plus platform-side expiry as belt-and-braces. Emits
revoked. - Audit-join (on demand) combines the PR metadata (author, reviewers, merge state) with the branch’s event records, surfaces any
missing_phasesto 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.