docs: seed SECRETS-WP-0004 (warden-sign lane); complete SCOPE.md sections

- SECRETS-WP-0004: scoped warden-sign OpenBao token lane for ops-warden, to
  unblock FLEX-WP-0007 T4 joint smoke. First auth-capability (non-KV) lane and
  first lane touching production OpenBao (bao.coulomb.social).
- SCOPE.md: add the standard sections flagged by the repo scope review (Relevant
  When, Not Relevant When, How It Fits, Terminology, Related / Overlapping,
  Provided Capabilities with fenced capability blocks); refresh Current State to
  reflect the delivered MVP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-06-29 12:55:58 +02:00
parent 9a65875bae
commit bcdfc78087
2 changed files with 273 additions and 4 deletions

113
SCOPE.md
View file

@ -39,9 +39,114 @@ roles, safe delivery modes, and non-secret evidence.
- Storing raw secret values in this repo, State Hub, chat, prompts, or logs.
- Broad platform-root or platform-admin automation as a steady-state model.
## Relevant When
- An approved decision needs to become a narrow OpenBao policy/auth-role apply
without platform-root hand-typing.
- A workload or operator command needs a secret delivered **into the command**
without printing or exporting it (e.g. `npm publish`).
- A non-SSH credential need (API key, provider token, npm token, DB password,
scoped OpenBao token) is routed here by ops-warden.
- Build/test/production need different privilege, ceremony, and delivery rules
for the same kind of secret.
- A reviewer needs non-secret evidence of who applied/provisioned/verified what.
## Not Relevant When
- You need an **SSH certificate** (→ ops-warden `warden sign`).
- You need an **authorization decision** (→ flex-auth).
- You need **identity / OIDC / MFA / claim lifecycle** (→ user-engine / key-cape).
- You need a **tunnel** or remote transport (→ ops-bridge).
- You want OpenBao itself replaced as the custody/lease/audit backend (it is not).
- You want a raw secret value moved through Git, State Hub, chat, prompts, or logs
(never — delivery is exec-time or out-of-band only).
## Current State
The repo is in bootstrap. Seed intent, PRD, boundary documentation, and an MVP
workplan are present. The first worker should complete State Hub bootstrap,
validate the generated repo identity files, then begin the whynot-design npm
publish token pilot through the `SECRETS-WP-0002` workplan.
MVP delivered. The Python CLI (`src/secrets_engine/`) proves the
`whynot-design-npm-publish` lane end to end — catalog → decision check →
policy/AppRole apply → provision → positive/negative verify → exec-time npm
delivery → ops-warden routing pointer → revoke — verified live against OpenBao
(44 tests; `scripts/demo-e2e.sh`, `scripts/npm-publish-demo.sh`). The
netkingdom maturity-gated publication-scope policy is in place but dormant
(netkingdom at `maturity-build`), so lanes clamp to repo-scope / `NPM_AUTH_TOKEN`.
Bootstrap workplans `SECRETS-WP-0001` (State Hub integration) and
`SECRETS-WP-0002` (MVP) are finished. Open: `SECRETS-WP-0003` (real pilot
close-out) and `SECRETS-WP-0004` (scoped `warden-sign` token lane for
ops-warden / FLEX-WP-0007 T4), both proposed.
## How It Fits
secrets-engine is the **interaction layer** in the NetKingdom security stack. It
sits between approval/identity systems and the OpenBao backend:
- **OpenBao / railiance-platform** — enforces custody, policy, lease, audit.
secrets-engine drives it through least-privilege stage roles and validated
paths, never as root.
- **flex-auth / State Hub decisions** — authorize. secrets-engine requires and
verifies a decision before privileged action and writes non-secret evidence
back.
- **user-engine / key-cape** — own identity and claims that bind consumers.
- **ops-warden** — routes non-SSH credential needs here (conduit-not-broker) and
issues SSH certs itself; secrets-engine mints and custodies the tokens.
- **ops-bridge** — may consume scoped delivery for remote execution but stores no
secret material.
- **info-tech-canon** — source of canonical terminology and stage/policy concepts.
Canonical cross-system boundary: `net-kingdom/docs/secrets-engine-security-infrastructure-boundary.md`.
## Terminology
| Term | Meaning |
| --- | --- |
| **lane / catalog id** | a non-secret entry describing one secret's OpenBao location, consumers, delivery, approval |
| **stage** | `build` / `test` / `prod` — separate OpenBao privilege contexts |
| **stage role** | `secrets-engine-{build,test,prod}` OpenBao role, confined to its prefix |
| **delivery mode** | how a value leaves OpenBao: `exec-env`, `npm-config`, `read-check`, `wrapped` |
| **org / repo** | Gitea organisation (`coulomb`) / repository (`whynot-design`) — explicit, not the overloaded "project" |
| **npm scope** | the `@`-prefixed npm name (`@whynot`) — distinct from org and repo |
| **maturity** | `maturity-build/test/prod` package tag; feeds the publication-scope policy |
| **bootstrap token** | temporary mode-0600 OpenBao token used during setup, revocable, outside repos |
## Related / Overlapping
- **ops-warden** — front door / SSH cert issuer; routes non-SSH needs here.
- **OpenBao (railiance-platform)** — the custody/policy/lease/audit backend.
- **flex-auth** — authorization decisions secrets-engine depends on.
- **user-engine / key-cape** — identity and claim lifecycle for consumers.
- **ops-bridge** — remote transport; may consume scoped delivery.
- **net-kingdom** — owns the cross-system security-infrastructure boundary doc.
- **info-tech-canon** — canonical terminology source.
## Provided Capabilities
```capability
type: security
title: Decision-aware OpenBao policy/role apply
description: Turns an approved State Hub decision into a narrow, guarded OpenBao apply —
catalog lane to dry-run plan to idempotent ACL policy + AppRole write — through
least-privilege build/test/prod stage roles. Refuses unapproved, superseded, wildcard,
out-of-stage, or broad-admin plans before any backend call. Writes non-secret evidence.
keywords: [secrets, openbao, vault, policy, approle, catalog, decision, stage, least-privilege, netkingdom]
```
```capability
type: security
title: Exec-time secret delivery
description: Delivers a secret into a child process only — never printing, exporting, or
persisting the value. npm-config injects a temporary mode-0600 .npmrc pointing at the
configured registry; exec-env injects a scoped env var. Temp config is cleaned up on
success, failure, and interruption; child output is redacted as a backstop.
keywords: [secrets, delivery, exec, npm, publish, token, injection, redaction, npmrc, openbao]
```
```capability
type: governance
title: Maturity-gated publication-scope policy
description: Binds npm publication scope to package maturity (build to gitea-wide, test to
org-wide, prod to repo-scoped) and gates the graduated table behind the netkingdom domain
reaching production grade. While dormant, every lane clamps to the safest repo-scope —
fail-safe, never fail-open. The injected token env-var name signals the effective blast radius.
keywords: [policy, maturity, publication-scope, governance, least-privilege, npm, gitea, netkingdom]
```

View file

@ -0,0 +1,164 @@
---
id: SECRETS-WP-0004
type: workplan
title: "Provision a scoped warden-sign token lane (ops-warden / FLEX-WP-0007 T4)"
domain: infotech
repo: secrets-engine
status: proposed
owner: codex
topic_slug: custodian
created: "2026-06-29"
updated: "2026-06-29"
---
# SECRETS-WP-0004 - Provision a scoped warden-sign token lane
## Goal
Give ops-warden a scoped OpenBao credential that can run `warden sign` over the
HTTP API, minted and custodied by secrets-engine. Model it as a first-class
secrets-engine **auth-capability lane** (an OpenBao policy + AppRole granting a
narrow capability), not a KV value. Post the non-secret pointers to State Hub and
hand the token/secret_id to the operator out-of-band.
This unblocks FLEX-WP-0007 T4 (the joint OpenBao + policy-gate production smoke),
after which `policy.enabled: true` can go live on CoulombCore.
## Context
ops-warden raised this on State Hub (msg 077ac90d, 2026-06-28). warden's vault
backend signs over the HTTP API (`X-Vault-Token`) and holds no standing OpenBao
token (conduit-not-broker), so token custody/minting is squarely secrets-engine's
lane. The operator cannot mint one interactively: the `bao` CLI is not installed
on CoulombCore and `bao login -method=oidc` is therefore unavailable — hence the
preference for an AppRole the operator can use non-interactively.
Target backend is the **production** OpenBao at `https://bao.coulomb.social`,
mount `ssh`. Actors in scope: `agt-state-hub-bridge` (primary),
`agt-codex-interhub-bootstrap`, `adm-example`, `atm-backup-daily`. The signing
roles are `agt-role`, `adm-role`, `atm-role`.
This is the first non-KV, non-npm lane and the first lane that touches production
OpenBao, so it also exercises parts of the engine the npm pilot did not.
## Design Constraints
- No token value or AppRole `secret_id` in Git, State Hub, chat, prompts,
workplans, or normal logs — pointers only on the hub, value out-of-band.
- The `warden-sign` policy must be narrow: `update` on `ssh/sign/<role>` for the
allowlisted roles only. No broader `ssh/*`, no `sys/`, `auth/token/`,
`identity/`, no root/sudo.
- Production apply uses a mode-0600 bootstrap token outside any repo, revocable,
recorded in `docs/hardening-backlog.md` H0.
- ops-warden takes no custody; secrets-engine owns minting and revocation.
## Tasks
## T01 - Extend the catalog for auth-capability (non-KV) lanes
```task
id: SECRETS-WP-0004-T01
status: todo
priority: high
```
Add a lane kind that represents an OpenBao auth credential (AppRole + policy)
granting a capability on a mount, rather than a KV value. The current schema
assumes a KV `mount/path/fields` value and `provision --from-file`; an
auth-capability lane has no stored value — the deliverable is the minted token /
`secret_id`.
Acceptance:
- The schema validates a `warden-sign` auth-capability lane (kind explicit).
- KV-only assumptions (`kv_data_path`, from-file provisioning, value verification)
are bypassed for this kind without weakening the npm KV path.
- `plan`/`apply` produce a policy + AppRole for the lane.
## T02 - Define the warden-sign policy and AppRole
```task
id: SECRETS-WP-0004-T02
status: todo
priority: high
```
Author the `warden-sign` ACL policy and AppRole. Policy: `update` on
`ssh/sign/agt-role` (plus `adm-role`, `atm-role`) on the `ssh` mount; nothing
else. AppRole `warden-sign` bound to that policy with a short token TTL, usable
non-interactively via `role_id` + `secret_id` (no `bao` CLI needed).
Acceptance:
- The policy lists exact allowed/denied paths; the guards in `roles.py` refuse any
broader variant (`ssh/*`, `sys/`, `auth/token/`, `identity/`, wildcards, root).
- Negative check: a token from this AppRole can `sign` only the allowlisted roles
and is denied elsewhere on the `ssh` mount.
- The AppRole issues a scoped token carrying only the sign capability.
## T03 - Apply against production OpenBao via bootstrap token
```task
id: SECRETS-WP-0004-T03
status: todo
priority: high
```
Apply the policy + AppRole on `https://bao.coulomb.social` using a mode-0600
bootstrap token stored outside any repo. Idempotent re-apply.
Acceptance:
- The `warden-sign` policy and AppRole exist on the production OpenBao.
- The bootstrap token file is recorded in `docs/hardening-backlog.md` H0 with an
explicit revocation task and TTL.
- Apply evidence is non-secret (policy/role names, mount, addr, status — no value).
## T04 - Out-of-band handoff and non-secret pointers
```task
id: SECRETS-WP-0004-T04
status: todo
priority: high
```
Define and execute the handoff: mint a fresh `secret_id`, deliver it (with the
`role_id`) to the operator out-of-band; warden does `approle login` to obtain a
`VAULT_TOKEN`. Post the non-secret pointers on the ops-warden thread (policy name,
AppRole name, mount `ssh`, addr `https://bao.coulomb.social`, token TTL, status).
Acceptance:
- Pointers are posted to State Hub; no token value or `secret_id` appears there or
in Git/logs.
- The operator can run, on CoulombCore:
`FLEX_AUTH_EXTERNAL=1 SMOKE_VAULT=1 VAULT_TOKEN=<scoped> ~/ops-warden/scripts/policy_gate_production_smoke.sh`.
## T05 - Confirm the joint smoke and signal ops-warden
```task
id: SECRETS-WP-0004-T05
status: todo
priority: medium
```
Confirm the unblock end to end, then reply to ops-warden (msg 077ac90d) with the
pointers and runbook alignment. The reply is the explicit "we will signal
ops-warden when done" step.
Acceptance:
- Allow path resolves to `backend: vault` + a `policy_decision_id`; deny path
(ttl 999) is rejected by flex-auth before OpenBao.
- ops-warden is replied to on State Hub with the non-secret pointers.
- A revocation/rotation task exists for the minted credential.
## Exit Criteria
- A narrow `warden-sign` policy + AppRole exist on production OpenBao, minted and
custodied by secrets-engine, granting only `ssh/sign/<allowlisted-role>` update.
- The operator can obtain a scoped `VAULT_TOKEN` non-interactively without `bao`.
- FLEX-WP-0007 T4 joint smoke is unblocked (or blocked only on an explicit
external condition).
- ops-warden has the non-secret pointers; no secret value crossed State Hub.
- The bootstrap token and the minted credential have revocation tasks.