SCOPE.md is the capability boundary other agents read, and three of its claims had gone stale — one of them describing checks that were deliberately removed months of decisions ago. - It said the engine "builds and validates the flex-auth ActionAuthorization profile", including State Hub authority and an independently required distinct-approver threshold. All three are wrong: ActionAuthorization is deferred and never ratified (FLEX-DEC-2026-006) and nothing validates it, the State Hub authority constant was removed because State Hub is a read model with no runtime approval authority, and the approver threshold is folded into valid_now by the issuer rather than re-checked here. Replaced with the actual two-artifact split from GH-DEC-2026-005, including the reduction in what this engine verifies alone, stated rather than buried. - It said the access-engine serving endpoint does not exist. It does, and step 2 is proven against it. Step 1 is the unserved half. - The layer-model table row repeated the ActionAuthorization framing. Also records the structured-correspondence rule and the tenant requirement in the capability list, and adds responder authentication to Not Implemented — it is a real gap in what this engine can promise, not merely flex-auth's open work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E4tNMAYcSQmZWUE4wqP4ij Assistant: claude-code Assistant-Model: opus Assistant-Process: 715726@bnt-lap001 Assistant-Session: 80a42b32-cba6-4b23-8be0-68819b1a6092
21 KiB
SCOPE
Implemented capability boundary for agents and contributors. Aspirational direction belongs in
INTENT.md; current work and operational gates belong inworkplans/.Layer declaration (accepted model v0.7): Engine / Lifecycle. Machine-readable form:
layer.yaml. PEP stance:pep-stance.yaml. This file states what the implementation currently does inside that layer; it does not restate doctrine.
One-liner
secrets-engine is the Lifecycle engine for cataloged credential work: a decision-gated Python CLI that validates non-secret lane metadata and orchestrates narrowly scoped OpenBao policy, AppRole, provisioning, verification, delivery, routing, handoff, and revocation actions.
It is a deterministic API over OpenBao, not a vault, not a policy decision point, not an identity provider, and not a general secrets API.
Implemented Capabilities
Catalog and validation
- Loads YAML catalog entries for
kvandauth-capabilitylanes. - Models
build,test, andprodstages, exact mounts/paths/fields, consumers, approvals, delivery modes, verification, lifecycle ownership, workload-delivery metadata, andstandard/highrisk. - Distinguishes engine-managed and existing KV mounts, and engine-managed, existing, or absent native delivery auth.
- Rejects malformed entries, inline secret-looking values, wildcard paths, unsupported modes, bootstrap-only approval for high-risk lanes, and high-risk entries without rotation/deactivation owners.
- Records existing ESO/Kubernetes/OIDC workload delivery as metadata only; it does not operate those delivery systems.
Decision-gated planning and OpenBao metadata apply
- Resolves a catalog lane by catalog id or
approval.decision_ref. - Resolves legacy lane decisions from State Hub by id, with tracked local YAML mirrors retained only for non-production and explicit throwaway demos. This is not an access-engine decision record.
- Fails every production live command closed while the two-artifact chain
cannot be completed — today because approval-engine does not serve the
approval-claim endpoint. That fail-closed row is the published
unreachable-engine stance for
prodinpep-stance.yaml. A local mirror can unlock a prod-labeled lane only when an explicit unsafe-demo switch, disabled Hub URL, and loopback OpenBao target are all present. Plans andapply --dry-runremain usable. - Validates the two-artifact authorization chain, split by owning layer per
GH-DEC-2026-005. The approval-engine approval-claim supplies the approval fact: issuer,valid_now, consumption state, freshness,reason_code, a requiredbinding.pdp_pathdeclaration, and thepdp_digesttie to this exact action. The flex-auth DecisionEnvelope supplies the decision: effect, structured binding correspondence to the proposed action, canonical request digest, lifetime, and the accepted policy package/version pin. Neither layer republishes the other's data, and validation is consume-only; this process does not evaluate policy. - Compares the decision binding by structured correspondence rather than
byte-equality, per flex-auth's published normalization rule: everything the
engine proposed must survive unchanged, registry enrichment may add only
type/tenant/attributes, and an enriched tenant must be the request tenant. The request digest is verified against the tuple the binding carries. The CheckRequest carries the package'sknown_tenant; an absent tenant is awrong_tenantdenial, not an ignored field. - The
ActionAuthorizationobject is deferred and never ratified (FLEX-DEC-2026-006); nothing validates it. There is no State Hub authority constant — State Hub is a read model and holds no runtime approval authority. The distinct-approver threshold is folded intovalid_nowby the issuer and is no longer an independent consumer-side check, which is correct on layering and a real reduction in what this engine verifies alone. - Renders guarded OpenBao plans for exact consumer ACL policies and AppRoles.
- Applies policy and AppRole metadata idempotently. Existing mounts render a non-mutating check and are never created by apply.
- Rejects stage mismatches, wildcard paths, broad-admin names, forbidden
sys/, token, identity, root, or sudo semantics, and auth-capability paths outside an exact allowlist.
KV provisioning
- Imports one declared field from a mode-0600 file outside Git worktrees.
- Generates random values only for non-production lanes.
- Keeps values out of CLI output and evidence records.
- Uses a CAS-aware create/patch primitive. Secret data is passed through a
mode-0600 temporary JSON input reference that is removed in a
finallypath, never as a raw subprocess argument. Existing-path updates preserve unmentioned sibling fields and stale-version writes fail closed.
Verification
- KV positive verification logs in through the lane AppRole and reports field
presence without printing values. With no
--field, it checks every declared field; an explicit--fieldnarrows the check. - KV negative verification requires a real unrelated token supplied through a mode-0600 file outside Git and checks that it cannot read the path. Missing unrelated identity material fails closed without a backend probe.
- Auth-capability verification checks the AppRole token's capabilities on exact allowlisted and denial-probe paths.
These are bounded policy/presence probes. A throwaway OpenBao integration test proves an overlapping unrelated policy is detected. Production still needs a reviewed owner/source for each unrelated identity; the engine does not mint or select that identity itself. Verification does not yet exercise a provider operation or produce OpenBao audit-request correlation.
Exec-time delivery
exec-envfetches one declared field through the lane AppRole and injects it into a child process environment.npm-configcreates a temporary mode-0600 npm config containing an environment reference rather than the token, injects the value only into the child, and deletes the config afterward.- Child stdout and stderr are combined and streamed through token-pattern and exact-value redaction.
- Undeclared fields and undeclared/unsupported exec modes are rejected before value fetch.
The OpenBao KV response is parsed in the parent process, so every field stored
at the path crosses that process boundary even though only the selected field is
injected. Exec and verification use scoped AppRole sessions that explicitly
self-revoke in a finally path. Non-secret evidence contains only an accessor
fingerprint and establishment/revocation outcome; TTL/use limits remain cleanup
backstops.
Auth-capability handoff
- Models narrow non-KV AppRole grants such as exact
ssh/sign/<role>update capability. - Mints
role_id/secret_idmaterial only after approval and writes it to distinct mode-0600 files outside Git worktrees without printing thesecret_id.
The cataloged standalone warden-sign AppRole is currently parked by governance
and must not be applied as a break-glass or recovery path. OpenBao being sealed
cannot be recovered through that AppRole.
Routing and evidence
routereturns a non-secret pointer containing lane ownership, decision status, metadata/value-presence booleans, missing declared field names, readiness, and a safe next command. Every declared field must be present.- Records scrubbed local JSONL evidence and posts a minimal State Hub progress
event on a best-effort basis. Posts carry stable idempotency/source headers.
Each requested State Hub delivery receives an append-only local
delivered,queued,failed, orskipped-no-topiccompanion record; edge-relay queued receipts retain only the non-secret outbox id. This trail is attributive: completeness is not claimed, and it is notaudit-core. - Every live privileged CLI handler records an attempt before lane-approval resolution and a terminal success, verification failure, rejection, interruption, or typed backend/input failure. Failure evidence contains the exception class and approval state, never exception prose.
auditsummarizes allowlisted local lane evidence: action/result counts, canonical decision references, session cleanup outcomes, and State Hub delivery outcomes. It never re-emits arbitrary evidence detail.- Keeps OpenBao audit logs as the backend source of truth.
The engine recognizes edge-relay queued receipts but does not own or initiate outbox replay. Direct State Hub failure remains locally visible. Route and audit do not replace exact-action authorization or OpenBao audit logs.
Steady-state service-auth scaffold
- Implements an explicit KeyCape
client_credentialsexchange for the acceptedsecrets-engine-openbaoservice identity. - Reads the confidential-client secret only from a mode-0600 file outside Git, sends it through HTTP Basic authentication, and rejects ID/refresh tokens.
- Preflights the exact issuer, subject, audience, principal type, tenant, role, scope, assurance, RS256 algorithm, and 15-minute lifetime. The in-memory JWT is excluded from object representations and is renewed at the three-minute boundary.
- Never retries into or falls back to bootstrap, operator, or AppRole auth.
The CLI now has a named service-jwt provider that logs in through that
scaffold when the platform JWT mount/role contract is present, then
self-revokes the issued OpenBao token. Signature verification and token
issuance remain with the platform-owned exact-bound OpenBao JWT role, whose
mount/role contract is still outstanding. Until it is published, --auth auto
keeps named bootstrap/env providers and never treats them as a fallback from
service-jwt failure.
Treat their output as operational guidance, not complete attestation for
high-risk lanes.
Revocation currently available
- For engine-managed native auth, live
revokedeletes the AppRole and policy. - For KV lanes, ordinary revoke explicitly preserves all KV metadata/versions.
- Externally managed delivery auth and workload delivery are reported as preserved and are not mutated.
lifecycle suspendremoves only the managed AppRole and preserves its policy for reviewed re-apply.lifecycle deactivateremoves managed native AppRole/policy objects while preserving KV custody.lifecycle destroy --dry-runrenders managed-auth removal plus irreversible KV metadata deletion. Live destroy is currently disabled even with exact catalog-id confirmation; it will remain closed until the canonical exact-action approval contract inSECRETS-WP-0007-T04is enforced.
These operations do not manage external workload delivery. session revoke
revokes an already-issued token accessor or lease id the operator already
holds; evidence is fingerprint-only. rotate replaces one declared KV field
through the merge-safe write path. Persistent overlay states
(active/suspended/deactivated/compromised) live under the evidence
directory; they do not recreate OpenBao objects and do not rotate provider
credentials.
CLI Surface
secrets-engine catalog list|show
secrets-engine decision inspect
secrets-engine plan
secrets-engine apply [--dry-run]
secrets-engine provision
secrets-engine verify
secrets-engine handoff
secrets-engine exec
secrets-engine policy publication
secrets-engine route
secrets-engine revoke [--dry-run]
secrets-engine lifecycle suspend|deactivate|destroy
secrets-engine audit <catalog-id> [--json]
secrets-engine evidence heartbeat|drain|classify
The implemented exec adapters are exec-env, npm-config, and exec-file.
read-check is verification and approle-login is auth-capability handoff
metadata. secrets-engine wrap implements response-wrapped operator handoff.
Proven Operationally
- The whynot-design npm pilot completed a real publish through native
secrets-engine execwithout placing the token in the parent shell. - Throwaway OpenBao integration tests exercise plan, apply, provisioning, positive/negative verification, exec delivery, routing, revocation, and idempotent metadata apply.
- Five existing high-risk
platformmount lanes have reviewed catalog metadata and guarded dry-run plans. Their native AppRoles are not live: workplanSECRETS-WP-0006waits on per-lane approval, production authority, live positive/negative verification, and routing cutover.
Not Implemented
- A service API, daemon, UI, queue, scheduler, or remote multi-user service.
- Platform JWT mount/role materialization for the implemented KeyCape
service-auth /
service-jwtprovider. - Provider-side / workload consumer rotation. Overlay lane state is local and non-secret only; it is not an OpenBao-side state machine.
- Protocol step 1 in production: approval-engine does not yet serve the
approval-claim endpoint (
APPROVAL-WP-0002-T03), soresolve_consume_bindingreturns no binding and live production remains fail-closed. Step 2 is served and proven — a real CheckRequest against the deployedflex-auth-secrets-enginepin returns a validated v2 decision over the owner-documented access path (docs/pdp-access-path.md). - Responder authentication for the decision channel.
flex-auth.decision-record.v1carries no signature and pins serve plain HTTP, so a responder knowing the published package and version could return a well-formed allow. Fail-closed protects against a PDP that is absent, not one that lies (FLEX-DEC-2026-010). The enforced loopback address shape stands in for this untilFLEX-WP-0024ships detached signatures. - Direct access-engine evaluation, JWT signature verification, or identity authentication. KeyCape claims receive only a consumer preflight; OpenBao is responsible for cryptographic JWT validation.
- Runtime tenancy isolation;
org,repo, consumers, and stages are catalog metadata plus local path/policy guards, not a tenant control plane. - Management or health verification of ESO, Kubernetes Secrets, deployments, provider accounts, SSH issuance, tunnels, or remote transport.
- Any backend other than the local
bao/vaultCLI speaking to OpenBao. - An SSH-CA signing engine API. The contract is
docs/ssh-ca-signing-contract.md; ops-warden still signs through its declared OpenBao gap. - A secret-use evidence engine API for kings-guard. The contract is
docs/secret-use-evidence-contract.md.routeandauditare operator summaries over local JSONL, not that observation surface. - Emission to
audit-core. Load-bearing records are queued locally; drain requires a sender binding that does not exist yet. Completeness is not claimed. - Security-zone membership as a request claim. PEP scope is catalog stage.
- Drain of the load-bearing outbox into a live
audit-coresender binding.
System Boundary
- OpenBao / railiance-platform (Tooling) owns custody, policy enforcement, leases, and backend audit. secrets-engine is the Lifecycle API over it.
- access-engine (
flex-auth) owns authorization decisions. secrets-engine consumes a decision record or applies its published unreachable-engine stance; it does not evaluate policy. - approval-engine owns the durable approval object. secrets-engine may consume an approval as an input claim and must not store or mutate one.
- gate-house owns security doctrine. Doctrine reaches this engine only as it already reached the decision, never as a side channel.
- audit-core owns evidence custody and integrity. Local JSONL and State Hub notes are not that archive.
- user-engine / key-cape own identity, OIDC, MFA, and claims.
- ops-warden issues SSH certificates (Staff PEP) and routes non-SSH credential needs here; it does not vend their values. The SSH-CA write surface is a proposed engine API, not a transferred lane.
- ops-bridge owns tunnels and remote execution transport and may consume a scoped delivery path.
- workload/platform repositories own ESO/Kubernetes delivery, provider rotation, and application health.
- info-tech-canon / net-kingdom own canonical terminology and the cross-system security boundary. gate-house owns the layer model.
Canonical boundary:
net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md.
Layer model: net-kingdom/canon/standards/security-layer-model_v0.7.md.
Working companion: net-kingdom/SECURITY-COMPANION.md.
Security Rules
- Never place raw secret values in Git, State Hub, chat, prompts, workplans, normal logs, or evidence.
- Never render or cache an authorization decision. Catalog admission, a dry-run, an old workload CCR, or a local fixture is not an access-engine allow.
- Never treat silence from
access-engineas permission. Production live actions fail closed; any unreachable-engine residue must be the published stance, recorded, never implicit. - Never mutate an existing shared mount or replace workload delivery by implication.
- Never add KV destruction back to ordinary
revoke; irreversible custody destruction requireslifecycle destroy, exact confirmation, and a distinct approved action. The live path remains disabled until that approval contract exists. - Keep bootstrap and handoff material outside repositories with mode 0600 and explicit expiry/revocation handling. Bootstrap is not an implicit fallback from service identity.
- Never claim that local evidence or a missing record proves occurrence or non-occurrence. Completeness is not claimed.
Layer-model obligations (current vs intended)
| Obligation | Current | Intended |
|---|---|---|
| Layer declaration | INTENT.md frontmatter + layer.yaml |
Keep in this repository's own voice |
| One decision point | Two-artifact consumer validation (approval-claim + DecisionEnvelope); step 2 proven against the deployed pin, step 1 unserved so production live stays fail-closed from pep-stance.yaml |
Consume an access-engine decision record before every protected side effect |
| PEP stance | Runtime loads pep-stance.yaml; named stance fields on privileged evidence |
Unchanged map; T02 replaces fail-open residue with a decision record |
| Evidence bound | evidence-classification.yaml; load-bearing local outbox; heartbeat command |
Drain to audit-core once that sender is admitted |
| SSH-CA surface | Contract at docs/ssh-ca-signing-contract.md; not shipped |
Engine API after ops-warden assent |
| Secret-use evidence | Contract at docs/secret-use-evidence-contract.md; not shipped |
Engine surface after kings-guard assent |
| Agent credential | Bootstrap token file still accepted; KeyCape scaffold unwired to OpenBao | Per-task, time-bounded service identity; no standing engine credential |
Where Current Work Lives
workplans/is the source of truth for open work and operational gates.docs/hardening-backlog.mdtracks exit from bootstrap mode.history/contains dated capability and intent assessments.INTENT.mdremains the stable aspirational direction.layer.yaml,pep-stance.yaml, andevidence-classification.yamlare the layer-model declaration surface.
Provided Capabilities
type: security
title: Guarded OpenBao lane planning and metadata apply
description: Validates cataloged KV and auth-capability lanes, renders exact policy/AppRole plans,
and applies approved metadata while rejecting missing decisions, stage mismatches, wildcards,
broad-admin names, and forbidden capability paths. Existing mounts are check-only.
keywords: [secrets, openbao, policy, approle, catalog, decision, stage, least-privilege]
type: security
title: AppRole-scoped exec delivery
description: Fetches one declared KV field through a lane AppRole and injects it into a child
process using exec-env or a temporary npm config, with output redaction, explicit scoped-token
self-revocation, and non-secret cleanup evidence. This is CLI-local delivery; exec-file, wrapping,
and service delivery are absent.
keywords: [secrets, delivery, exec, npm, injection, redaction, openbao]
type: security
title: Scoped OpenBao auth-capability handoff
description: Generates an exact-path policy/AppRole plan and writes role-id/secret-id material to
strict out-of-repo files after approval. Operational use remains subject to lane-specific governance.
keywords: [openbao, approle, auth-capability, handoff, least-privilege]
type: governance
title: Non-secret routing and evidence pointers
description: Reports decision/readiness metadata and records scrubbed local and best-effort State Hub
evidence without returning secret values. Append-only delivery receipts expose State Hub failures,
and an allowlisted audit command summarizes lane operations and cleanup. KV verification can attest a
supplied real unrelated identity, but the engine does not own identity selection. This is attributive
local evidence, not audit-core and not a secret-use observation API.
keywords: [routing, evidence, state-hub, audit, secrets]