diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index 6cb227d..c35418f 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -771,6 +771,24 @@ vendor guidance on the "utility nodes" DC-to-DC configuration) -- executes at next-deployment design time; feeds the sub-4 ruling with the LP outcome. +9. D-137 -- credential mint-and-consolidate pipeline (PROPOSED + 2026-07-25, operator-requested: "a durable rule to make sure when + accounts are created there is a consolidation that happens every + time"). Diagnosis is MEASURED: the SEC-009 audit is + DECLARATION-based, so an undeclared secret is structurally + undetectable -- `creds-audit vr1-office1` read CLEAN on 2026-07-15 + while four region-VM secrets minted 2026-07-13 sat undeclared, and + `admin.pass` surfaced only 2026-07-25 (SEC-020). It is also wired in + exactly ONE place and as PROSE (phase-3 runbook:498), not in + preflight/cloud-assert/repo-lint/gauntlet -- and that line did not + fire at EITHER DC standup (dc0 3 + dc1 1 undeclared at this + session's open). THREE forks await a ruling, one exchange each + (GA-R5): enforcement strength (advisory / preflight-blocking / + plus a PreToolUse guard); `--remote` discovery scope + (declared-directories vs broader sweep, a tenant-isolation + concern); policy home (this D as authority with SEC-009 demoted to + a pointer, vs policy stays in the ledger). NOT implemented -- + PROPOSED means present options, never build. ## 9. Additional defect found while authoring (FIXED in sweep Batch 0.3, 2026-07-19 -- wrap-aware exclusion, GA-F15; history below) diff --git a/docs/changelog-20260725-maas-admin-recovery.md b/docs/changelog-20260725-maas-admin-recovery.md index d03c0e2..34007b3 100644 --- a/docs/changelog-20260725-maas-admin-recovery.md +++ b/docs/changelog-20260725-maas-admin-recovery.md @@ -111,7 +111,9 @@ - (ii) the DURABLE fix for the miss class is a `site-headend-install.sh` amendment to consolidate at mint time (the script currently leaves all four secrets on the VM). Queued, unruled -- a script change needs its harness and a ruling. -- (iii) the human/service conflation is proposable as the next-free D-number, [ARCH]: +- (iii) the human/service conflation is proposable as a D-number, [ARCH] -- still + UNASSIGNED after item 9 took D-137 for the credential pipeline; the two are kept + separate deliberately (see D-137's "Related, deliberately NOT folded in"): `admin` is both the GUI login and the automation identity (its API key drives the `maas admin` CLI profile across **19 call sites in 4 scripts** -- `site-headend-install.sh` 10, `phase-04-network-verify.sh` 5, @@ -142,3 +144,32 @@ - Pre-existing, NOT touched by this session: CURRENT-STATE G14 SEC count (reads 12, actual 16) and section 4 ("RULED-BUT-NOT-BUILT", flagged comprehensively stale 2026-07-25) -- both already operator-deferred to Stage 4 close. + +## Item 9 -- D-137 PROPOSED: credential mint-and-consolidate pipeline [ARCH] + +**What:** new `docs/design-decisions.md` entry D-137, PROPOSED (not ruled, not +implemented). Answers the operator's follow-up ask -- a better minting/saving method +plus "a durable rule to make sure when accounts are created there is a consolidation +that happens every time". Records the measured diagnosis, a three-part proposal (the +invariant; `creds-mint.sh` + `creds-audit --all/--remote` + gate wiring + +`site-headend-install.sh` amendment; the Roosevelt delta), and THREE open forks. +Section 8 of CURRENT-STATE gains item 9; the ledger's machine block goes 4 -> 5 open +decisions. +**Why:** the diagnosis is that the existing SEC-009 control **cannot detect the failure +class it was built for** -- the audit is DECLARATION-based, so an undeclared secret is +structurally invisible. `creds-audit vr1-office1` reported CLEAN on 2026-07-15 while +four secrets minted on the region VM on 2026-07-13 sat undeclared; `admin.pass` surfaced +only 2026-07-25, twelve days later, and only because a task went looking (SEC-020). +Compounding it: no `--all` (`creds-audit.sh:25` takes one mandatory site), and the only +enforcement is PROSE at `runbooks/dc-dc-phase3-maas-enlist-deploy.md:498` -- absent from +preflight/cloud-assert/repo-lint/gauntlet -- which demonstrably did not fire at either DC +standup (dc0 3 + dc1 1 undeclared at this session's open). Admitted as a D under GA-R3 on +the A1 test: Roosevelt mints per-DC IPMI/BMC and Vault material on real hardware, so a +Roosevelt build session should grep this before creating any credential; today the rule +lives only in `docs/security-ledger.md`, a register of exposures, which no gate can cite +as authority. +**Deliberately NOT done:** no tooling built, no enforcement wired, no SEC-009 demotion -- +PROPOSED means present options, never implement (hard rule 1 + GA-R5). The SEC-020 +identity-conflation question is kept SEPARATE to avoid batching two rulings. +**Revert:** delete the D-137 block from `docs/design-decisions.md`, CURRENT-STATE +section 8 item 9, and the ledger machine-block D-137 clause (restore count to 4). diff --git a/docs/design-decisions.md b/docs/design-decisions.md index 7b1b80b..b907c07 100644 --- a/docs/design-decisions.md +++ b/docs/design-decisions.md @@ -4997,3 +4997,101 @@ `docs/audit/stage5-expansion-review-20260724.md`, `docs/audit/committee-20260724-track2-bundle-render.md`. + +## D-137: PROPOSED -- credential mint-and-consolidate pipeline: make consolidation STRUCTURAL, not remembered [ARCH] + +**Status:** PROPOSED 2026-07-25 (this session, repo HEAD `1155729`; operator asked for +"a better best practices method for minting and saving these credentials going forward" +and "a durable rule to make sure when accounts are created there is a consolidation +that happens every time so credentials aren't misplaced or lost" -- the mechanism is +NOT ruled; three forks below are presented, not chosen). Supersedes nothing. Would make +the SEC-009 standing convention a D-governed policy with a Roosevelt-transferable home. + +**Problem -- the existing control cannot detect the failure class it was built for.** +SEC-009 (2026-07-15) established the `~/-creds/` convention AND its enforcement +(`creds-manifests/.manifest` + `scripts/creds-audit.sh`), explicitly BECAUSE a +VM-minted secret had been missed (the NetBox token addendum names that exact class). +Measured evidence that it did not hold: + +- `scripts/site-headend-install.sh:416-455` minted FOUR secrets on the region VM on + 2026-07-13 (`/root/maas-secrets/{db.pass,admin.pass,admin.apikey,lxd-trust.pass}`, + via `newpass`). The office1 manifest was seeded with 11 entries on 2026-07-15 and + `creds-audit vr1-office1` reported CLEAN -- while all four sat undeclared and + invisible. `admin.pass` surfaced only on 2026-07-25, TWELVE days later, and only + because a task went looking for it (SEC-020). +- **Root mechanism: the audit is DECLARATION-based.** The manifest IS the declaration, + so an undeclared secret is structurally undetectable. The `:` provenance + field exists for precisely this class but only helps once a human remembers to write + the row. A green CLEAN is therefore not evidence that nothing was missed. +- `creds-audit.sh:25` takes a single mandatory `` argument -- no `--all`. Auditing + the estate means three invocations and remembering three site names. +- It is wired into exactly ONE place, and as PROSE: + `runbooks/dc-dc-phase3-maas-enlist-deploy.md:498` ("MUST report ... before declaring + this DC done"). It is NOT in `preflight.sh` (THE single pre-deploy gate), NOT in + `cloud-assert.sh`, NOT in `repo-lint`, NOT in the gauntlet. Nothing executable + enforces it. +- Consequence measured at this session's open: dc0 carried THREE undeclared secrets and + dc1 ONE -- i.e. that standup definition-of-done line did not fire at EITHER DC + standup, and both racks were declared done anyway. +- No D governs credential mint/custody generally: D-069 covers Vault unseal-key custody + only; D-126 covers per-env access-key ISOLATION, not lifecycle. The rule currently + lives in `docs/security-ledger.md`, a register of EXPOSURES -- not a decision + authority, so it has no Roosevelt-transferable home and no gate can cite it. + +**Proposal.** + +*1. The rule (the invariant).* Minting and consolidating are ONE operation, never two +steps with a human in between. A credential that exists without a manifest row is a +DEFECT, not a to-do. A secret minted on a site VM is PULLED to the jumphost by the +jumphost-side caller in the same runbook step that mints it -- never "consolidated +later", because later is when it is lost. Values are verified by format or behavior, +never printed, never in argv (the SEC-018 discipline; note `maas changepassword` has no +`--password` and `createadmin --password` violates it, so stdin is the sanctioned path +-- proven working 2026-07-25). + +*2. The tooling that makes it structural.* +- (a) `scripts/creds-mint.sh` -- the ONLY sanctioned way a credential comes into + existence. Modes: `--generate` (openssl, umask 077), `--pull :` (VM-minted, + sets provenance automatically), `--stdin` (externally minted). In ONE run it writes + the file 0600, appends the manifest row, refuses to overwrite an existing entry, and + exits non-zero unless `creds-audit` is CLEAN afterward. Consolidation becomes + impossible to skip because it is not a separate action. +- (b) `creds-audit.sh --all` (iterate `creds-manifests/*.manifest`; no site name to + remember) and `--remote` -- the DISCOVERY inversion. `--remote` walks a declared set + of known secret locations (new `creds-manifests/vm-secret-locations`: ` `), + enumerates what is actually THERE by metadata only, and FAILS on any file with no + matching `:` row. This is the only proposed piece that would have caught + `admin.pass` on 2026-07-15; without it the audit stays blind by construction. +- (c) Gate wiring so it cannot be forgotten: `creds-audit --all` inside + `scripts/preflight.sh`, plus an offline-safe harness in the gauntlet; the phase-3 + standup line stays as belt-and-braces rather than as the only control. +- (d) `site-headend-install.sh` amendment: on completion emit a machine-readable list of + the secrets it minted (paths + modes, NO values) so the caller can `creds-mint --pull` + each one deterministically. This script minted all four missed secrets; closing the + class at its source is the highest-leverage single change. + +*3. Roosevelt delta (the A1 test).* Roosevelt mints per-DC IPMI/BMC credentials, Vault +material, and per-DC MAAS service credentials on real hardware where a lost credential +can mean a lost node. A Roosevelt build session should grep THIS before creating any +credential. That is why the rule belongs in a D and not only in an exposure register. + +**Open forks (operator rules; PROPOSED means present, not implement).** +1. ENFORCEMENT STRENGTH: (a) advisory -- audit reports, human acts; (b) blocking -- + `preflight.sh` hard-fails on an unconsolidated or undeclared secret, so no deploy + proceeds; (c) blocking PLUS a PreToolUse guard that refuses secret-writing command + shapes outside `creds-mint.sh`. Trade: (c) is the only option that constrains an + agent mid-session, but adds a hook that can itself misfire on legitimate shapes. +2. `--remote` DISCOVERY SCOPE: declared-directories-only (predictable, but a secret + minted somewhere undeclared stays invisible) vs a broader filesystem sweep for + secret-shaped filenames (catches more, but is invasive on a live region and could + surface tenant material -- a hard-isolation concern on a commercial multi-tenant + cloud). +3. POLICY HOME: this D becomes the credential-lifecycle authority and SEC-009's + convention block demotes to a pointer, vs the policy staying in the security ledger + with this D covering only the tooling. + +**Related, deliberately NOT folded in.** SEC-020 flagged a separate identity question -- +`admin` doubles as the human GUI login and the automation identity (its API key drives +the `maas admin` profile across 19 call sites in 4 scripts). That is "who holds +accounts"; this D is "how secret material is stored". Same lifecycle family, different +decisions; folding them would batch two rulings and violate GA-R5. diff --git a/docs/session-ledger.md b/docs/session-ledger.md index 1e616cf..ae77e48 100644 --- a/docs/session-ledger.md +++ b/docs/session-ledger.md @@ -33,7 +33,9 @@ _Re-seeded from a 2026-07-25 scan (SEC-020 session; the prior seeding was the 2026-07-23 close and had gone stale on every line -- counts and next-free both). Re-run `bash scripts/ledger-scan.sh` to refresh._ -- **PROPOSED / OPEN decisions (4):** D-068 (Vault substrate hardening, Roosevelt -- sole remainder +- **PROPOSED / OPEN decisions (5):** D-137 (credential mint-and-consolidate pipeline [ARCH] -- + PROPOSED 2026-07-25, operator-requested; 3 forks unruled: enforcement strength, --remote + discovery scope, policy home. NOT implemented), D-068 (Vault substrate hardening, Roosevelt -- sole remainder is Q2 path selection at Roosevelt Vault design time), D-131 (node-facing DNS strategy for rack-only controllers [ARCH] -- PARTIALLY RULED: sub-1 ruled + delivered 2026-07-21, sub-2 ruled 2026-07-21 (metal-admin only), sub-3 resolved 2026-07-21 (no defect), sub-4 open + pinned DNS