# secrets-engine — NetKingdom security layer declaration # # Framework: net-kingdom/canon/standards/security-layer-model_v0.7.md # Companion: net-kingdom/SECURITY-COMPANION.md # Voice: INTENT.md (this repository's own declaration, §11) # Validate: python3 scripts/check_layer_conformance.py # # §11 requires a machine-readable form because prose cannot distinguish a # declaration from a transcribed review. ops-warden offered the layer.yaml # shape estate-wide; this file is that shape adapted for a Lifecycle engine # rather than a Staff repository. # # §5 (Staff never touches Tooling) does not apply to this repository's OpenBao # client. A Lifecycle engine is the deterministic API over Tooling it fronts. # OpenBao contact here is owned, not a §5.3 gap. schema_version: "0.1" framework: netkingdom-security-layer-model standard_version: "0.7" repository: secrets-engine layer: engine role: lifecycle declared_by: INTENT.md declared_at: "2026-08-29" # §3.3: a Lifecycle engine is a deterministic API over Tooling it owns. # OpenBao remains the vault; this engine fronts it. owned_tooling: - id: openbao-lifecycle tooling: OpenBao modules: - src/secrets_engine/openbao.py operations: - "bao policy/auth/kv subprocess adapter" - "CAS-aware KV create/patch via JSON input files, never argv values" - "JWT login via JSON input files; issued engine tokens self-revoke" - "response wrapping via -wrap-ttl; wrap token never in argv evidence" note: >- This is the owned Lifecycle contact, not a Staff §5 shape. A new direct OpenBao client outside the listed modules is a finding. # §6: no repository other than access-engine exposes an authorization decision # surface. secrets-engine consumes and validates a supplied ActionAuthorization # object; it does not evaluate policy. decision_surfaces_exposed: none # §6.4 — apply, provision, exec, handoff, revoke, and lifecycle mutations # cause protected side effects. Being PEP-shaped does not change the layer. pep_shaped: true pep_stance: pep-stance.yaml protected_actions: - apply - provision - verify - exec - handoff - revoke - lifecycle-suspend - lifecycle-deactivate - lifecycle-destroy - session-revoke - wrap # §13 proposed capabilities. Owner status is proposed, not assented, until # the surface exists in this repository's own contract. proposed_capabilities: - id: ssh-ca-signing-surface state: unowned-capability capability: >- Deterministic engine API for OpenBao SSH-CA signing, so a Staff PEP (ops-warden) does not hold a direct VaultCA write. intended_owner: secrets-engine owner_status: proposed contract: docs/ssh-ca-signing-contract.md blocked_on: >- Contract published; ops-warden has not assented. No OpenBao SSH-CA write is added to this CLI until that assent. ops-warden continues to sign through its declared §5.3 gap. This repository accepts the engine surface and declines operational ownership of the SSH access lane. review: "2026-11-28" consequence: >- ops-warden's ssh-ca-signing-write gap remains the production path. - id: secret-use-evidence state: unowned-capability capability: >- Lease, revocation, mount, rotation, and delivery-session metadata exposed as an engine surface for kings-guard secret-abuse posture. intended_owner: secrets-engine owner_status: proposed contract: docs/secret-use-evidence-contract.md blocked_on: >- Surface shipped as `secrets-engine secret-use snapshot`; cadence is the declared 1d heartbeat. kings-guard assented 2026-09-01 (message 75ebd2cc-a166-4676-94aa-deef2791c0c9) and has not yet admitted the snapshot as an observation input. Completeness is not claimed. review: "2026-11-28" consequence: >- kings-guard secret-abuse posture stays fixture-driven. # Contacts that are not Tooling, recorded so the check is total. non_tooling_clients: - id: state-hub-decisions-and-progress target: state-hub layer: not-catalogued modules: - src/secrets_engine/decisions.py - src/secrets_engine/evidence.py operation: "HTTP GET /decisions/{id} and POST /progress/" write: true note: >- Outside §5 by the scope rule: State Hub is not a §4 Tooling row. Decisions consumed from it are a gap relative to access-engine, not a Tooling contact. Progress notes are not a security state plane. - id: access-engine-action-authorization target: access-engine (flex-auth) layer: engine modules: - src/secrets_engine/authorization.py operation: "Local validation of a supplied ActionAuthorization object" write: false note: >- Engine-to-engine consume, not a decision surface. The durable State Hub endpoint that would serve the object is not yet available; production live actions therefore fail closed (see pep-stance.yaml). - id: approval-engine-consume target: approval-engine layer: engine modules: - src/secrets_engine/approval_consume.py operation: "POST /v1/approvals/{id}/consume before a production OpenBao write" write: true note: >- PEP CAS consume under GH-DEC-2026-003. Not a decision surface. Conflict, unavailability, or a missing binding fail closed; OpenBao is not called. Production also remains fail-closed until a durable consume binding is served. - id: key-cape-service-auth-scaffold target: key-cape layer: tooling modules: - src/secrets_engine/service_auth.py - src/secrets_engine/engine_auth.py operation: "HTTPS client_credentials exchange; OpenBao JWT login when the platform contract is present" write: false note: >- key-cape is catalogued Tooling. The consumer exchanges a service JWT and logs in only when SECRETS_ENGINE_OPENBAO_JWT_LOGIN names a published mount/role contract. Failure never falls back to bootstrap or BAO_TOKEN. The platform-owned role remains unpublished, so auto still uses the named bootstrap/env providers. - id: audit-core-outbox-drain target: audit-core layer: engine modules: - src/secrets_engine/evidence.py operation: "Optional POST /v1/events from secrets-engine evidence drain" write: true note: >- Engine-to-engine emit. Never on the mutation path. Empty URL skips delivery and leaves the local outbox in place. Sender binding in audit-core is not yet admitted. # §9.6 — what this repository may claim about evidence it writes today. evidence_bound: classification: evidence-classification.yaml proves: - local JSONL records that were written were not rewritten by this engine - load-bearing records queued in evidence_dir/outbox/ were written does_not_prove: - that a record was ever sent to audit-core - absence of a record as evidence of non-occurrence - completeness of the trail destination_today: "local JSONL; load-bearing also queued locally; attributive State Hub notes" intended_destination: audit-core completeness_claimed: false no_control_branches_on_presence: true