# Queued findings + unlogged advice -- end-of-session sweep, 2026-07-26 # # WHY THIS FILE EXISTS. The 2026-07-26 session ran long and produced two classes of # content that lived only in the session transcript: committee findings that were # ACKNOWLEDGED but deliberately NOT acted on, and a secrets-storage recommendation given # verbally on request. A transcript is not a repo surface. This is the durable copy. # # NOTHING HERE IS RULED OR BUILT. These are logged findings and unruled advice (hard rule # 1: findings are logged, never executed mid-step). Status lives in CURRENT-STATE only. ================================================================================ PART A -- ADVICE GIVEN VERBALLY THAT IS **NOT** ALREADY REPO-CARRIED ================================================================================ IMPORTANT FRAMING, checked before writing this: MOST of the secrets-storage recommendation given in session was ALREADY in the repo and is NOT new. - OpenBao / BUSL relicensing / the fork question .... docs/D-068-vault-1.8-vs-1.16-analysis.md - Vault auto-unseal, root-Vault topology ............ same file + D-069 discussion - `scripts/creds-mint.sh` (atomic mint->store->register, with modes, refusal-to-overwrite, and a creds-audit gate) ........................... docs/design-decisions.md D-137, item 2(a) A future session should read those FIRST and treat the items below as the delta, not as a new proposal. Re-proposing what is already ruled is this project's measured failure mode. --- A1. Tang / Clevis (NBDE) as the no-HSM unseal mechanism [NOT in repo: 0 hits] No HSM or KMS is available (operator-confirmed 2026-07-26), which removes the standard Vault auto-unseal path. Network-bound disk encryption (Tang servers + Clevis binding) is the usual on-prem substitute: unseal material is recoverable ONLY while the host can reach N Tang servers on the management network, so a disk that leaves the datacenter is inert. It maps onto the existing per-DC isolation posture (SEC-012/-016 per-DC power keys) and costs no hardware. Suggested shape: DC Vaults transit-unseal from an Office1 unsealer; the unsealer's own material Tang-bound (plus TPM measurement if Roosevelt hardware has TPM 2.0 -- UNKNOWN, and it decides Tang-alone vs Tang+TPM); Shamir shares exist only as physical break-glass, split across sites, never on a jumphost. --- A2. MAAS 3.7 Vault integration is AVAILABLE AND DISABLED [MEASURED 2026-07-26] ssh voffice1 'sudo maas config-vault status' -> status: disabled unconfigured_regions: [voffice1] MAAS 3.3+ can store its secrets in Vault instead of its database -- including power credentials, the category behind SEC-012, SEC-016 and SEC-021. This is a native, supported, in-stack capability that is simply switched off. ** CIRCULAR DEPENDENCY, design around it before enabling at Roosevelt: MAAS provisions the metal, Vault runs on that metal, and MAAS-with-Vault will not start without Vault. On bare metal that is a bootstrap-ordering problem, not a config step. The usual answer is a management-site Vault that is NOT MAAS-provisioned. Enabling it in VR1 FIRST -- where the substrate is virtual and recoverable -- is what a rehearsal is for. --- A3. Vault SSH secrets engine (SSH CA) [NOT in repo: 0 hits] Six of the twelve no-mint credentials in the research capture are ed25519 keypairs, and every per-DC power key, edge key and service key is a static file that lives forever. An SSH CA issuing short-lived certificates collapses that entire category: no file to consolidate, no key to rotate, no matrix row that can go stale. Highest structural leverage of anything discussed, and it depends on the fork decision (A-framing) landing first. --- A4. Sequencing advice, and one recommendation to NOT do something Recommended order: (1) resolve the Vault-vs-OpenBao fork question; (2) build the D-137 `creds-mint.sh` already specified in item 2(a) -- BEFORE Stage 5, because Stage 5 is the largest credential-minting event in the project (per-DC MAAS keys, the Juju cloud credential, bootstrap controller/CA/agent secrets, and behind them Vault init material, the 8 Octavia PKI artifacts and admin-openrc); (3) MAAS->Vault rehearsed in VR1; (4) SSH CA; (5) Juju + Barbican secret backends. RECOMMENDED AGAINST: a sops/age encryption-at-rest stopgap. It was raised and then withdrawn in the same session -- if the Vault path is real it is throwaway work, and tooling churn that presents as progress is this project's own recorded failure mode (GA-F06). ================================================================================ PART B -- COMMITTEE FINDINGS ACKNOWLEDGED BUT **NOT** ACTED ON ================================================================================ From the six-lens audit, 2026-07-26. Each was reproduced or reasoned by its lens and left deliberately. Ranked by consequence. --- B1. `mint-ref` line pins rot SILENTLY [lens 6] `s4_mint_ref` checks only that the target file exists and that the line number is <= EOF. There is NO content assertion. Edit anything above a cited line and the mint-ref now points at unrelated code while S4 still reports `[ok] every script:/runbook: reference resolves`. 30+ rows carry line pins into actively-edited runbooks and scripts. AT ROOSEVELT the runbooks are rewritten for bare metal, so every line-pinned mint-ref becomes wrong-but-passing simultaneously. Suggested fix: store an anchor token (step id, function name, short literal) alongside or instead of the line, and assert it appears at/near the cited line. --- B2. Ruling-5 remediation and ruling-5 EVASION are indistinguishable to the checker [lens 4] S6 groups by `id`. The sanctioned fix for the `maas-region-admin` conflation (migrate the 19 `maas admin` call sites to a service identity) and the evasion (rename one row's id to `maas-region-admin-svc`) BOTH turn the check green. The notes warn humans not to do the latter; nothing mechanical distinguishes them. --- B3. No non-emptiness check in tier 2 [lens 2] `creds-audit.sh:59` asserts `[ -s "$path" ]`; the matrix checker has no equivalent. A zero-byte credential file reads as PRESENT and correctly-moded. --- B4. `sec-ref` is never validated [lens 2] Contrast S4 (mint-ref) and S7 (notes-ref), both of which resolve their references. A wrong SEC pointer is exactly the class caught by hand FOUR times this session (SEC-015 once, then both `juju-maas-user` rows, plus the tfstate row). A validator must parse the ledger's TABLE form (`| SEC-006 |`), not `## SEC-` headings. --- B5. No "source-of-record implies a consolidated copy" invariant [lens 2] `netbox-secret-key` and `netbox-admin` are VM-resident with NO consolidated copy at all -- the exact founding SEC-009 shape ("a VM-minted secret has no forcing function to reach the folder") -- and nothing flags it. --- B6. `cardinality` is largely inert, with a one-token bypass [lenses 2 + 6] Of 81 rows the field affects only S1's enum validation and S5's `per-DC` filter; `singleton`, `per-site`, `per-node` and `per-tenant` have no semantic effect, and `per-node` is used by no row. Relabelling a row `per-DC` -> `singleton` removes it from S5 entirely -- the cheapest way to silence the standing SEC-021 asymmetry findings, and nothing guards it. The plan claims cardinality is "REQUIRED for Roosevelt transfer -- without it the matrix cannot express '9 nodes'"; as built it expresses no such thing. Either make it load-bearing (an `instances` field, or template expansion generating the per-DC/per-node/per-tenant row set) or demote the claim. THIS IS A DESIGN QUESTION AND NEEDS AN OPERATOR RULING. --- B7. S5 is structurally BINARY [lens 6] `dcs = ["vr1-dc0", "vr1-dc1"]`, `DC_TOKEN_RE = dc[01]`, `SITE_KEY_RE` an enum of `vr1-*` literals, and a pairwise set-difference. A third DC needs four source edits and S5 does not generalise to N sites. Suggested fix: derive the site set from the matrix, validate region-qualification by SHAPE not enum, and restructure S5 to group-by-normalised-shape across N sites. --- B8. T22's metadata-only guard is narrower than it reads [lens 1] The wordlist omits `open()` -- the checker's actual read mechanism -- and `dd`, `sed`, `awk`, `base64`. It also greps comments and docstrings, so prose alone can false-RED it (measured twice this session: the word "more" tripped it). T51 partially covers the transfer half. --- B9. `--dc` narrows only S5 [lens 1] Its help text says it narrows the per-DC checks; in fact S1-S4, S6, S7 and tier 2 still process all rows, so the flag WEAKENS a run rather than scoping it. Either make it narrow the run or remove it. --- B10. Low severity, recorded for completeness [lens 1] Dead code at the `observed`-membership guard (unreachable since `observed` is pre-populated); `s3_render_drift`'s unused `notes` parameter; `os.path.join(repo, path)` returns an absolute mint-ref path unchanged, escaping the repo bound; S7's orphan scan only considers keys prefixed `n-`. ================================================================================ PART C -- ALSO DEFERRED BY RULING (recorded so they are not mistaken for oversights) ================================================================================ - SEC-024 RETENTION: whether the two `terraform.tfstate.pre-*` state-surgery snapshots should exist at all. Operator-deferred to stage close 2026-07-26. Both gates (G6, G16) are CLOSED and the outer plan has converged to zero diff repeatedly since, but deletion is irreversible with no other copy of that state. - SEC-024 umask CAUSE: not investigated (outside the ruled scope). A future `tofu apply` may write 0664 again; the P5 gate will catch it. - `--render` source-field derivation from `vm-secret-locations`: not wired; two fields are explicitly skipped as PENDING rather than silently matched. - Manifests are not yet REPLACED by rendered output. Ruling 2 makes them generated; doing the flip changes what `creds-audit` demands at three sites, so it stays operator-gated.