diff --git a/creds-matrix.tsv b/creds-matrix.tsv index 6d933c6..38328cd 100644 --- a/creds-matrix.tsv +++ b/creds-matrix.tsv @@ -100,32 +100,32 @@ # ---------------------------------------------------------------- outside the SEC-009 *-creds/ convention (research FINDING 2) vault-unseal-shares singleton - jumphost init.txt none service off-manifest-known vr0-phase02 runbook:runbooks/phase-02-vault-bringup.md:71 SEC-023 n-outside-convention vault-root-token singleton - jumphost init.txt none service off-manifest-known vr0-phase02 runbook:runbooks/phase-02-vault-bringup.md:71 SEC-023 n-outside-convention -octavia-issuing-ca-passphrase per-DC vr1-dc0 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:383 SEC-023 n-outside-convention -octavia-issuing-ca-key per-DC vr1-dc0 headend issuing-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:387 SEC-023 n-outside-convention -octavia-issuing-ca-cert per-DC vr1-dc0 headend issuing-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:391 SEC-023 n-outside-convention -octavia-controller-ca-pass per-DC vr1-dc0 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:406 SEC-023 n-outside-convention -octavia-controller-ca-key per-DC vr1-dc0 headend controller-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:410 SEC-023 n-outside-convention -octavia-controller-ca-cert per-DC vr1-dc0 headend controller-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:414 SEC-023 n-outside-convention -octavia-controller-key per-DC vr1-dc0 headend controller.key none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:429 SEC-023 n-outside-convention -octavia-controller-bundle per-DC vr1-dc0 headend controller.bundle.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:517 SEC-023 n-outside-convention -octavia-controller-cert per-DC vr1-dc0 headend controller.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:521 SEC-023 n-outside-convention -octavia-controller-ca-serial per-DC vr1-dc0 headend controller-ca.cert.srl none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:519 SEC-023 n-outside-convention +octavia-issuing-ca-passphrase per-DC vr1-dc0 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:391 SEC-023 n-outside-convention +octavia-issuing-ca-key per-DC vr1-dc0 headend issuing-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:395 SEC-023 n-outside-convention +octavia-issuing-ca-cert per-DC vr1-dc0 headend issuing-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:398 SEC-023 n-outside-convention +octavia-controller-ca-pass per-DC vr1-dc0 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:414 SEC-023 n-outside-convention +octavia-controller-ca-key per-DC vr1-dc0 headend controller-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:418 SEC-023 n-outside-convention +octavia-controller-ca-cert per-DC vr1-dc0 headend controller-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:421 SEC-023 n-outside-convention +octavia-controller-key per-DC vr1-dc0 headend controller.key none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:460 SEC-023 n-outside-convention +octavia-controller-bundle per-DC vr1-dc0 headend controller.bundle.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:548 SEC-023 n-outside-convention +octavia-controller-cert per-DC vr1-dc0 headend controller.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:544 SEC-023 n-outside-convention +octavia-controller-ca-serial per-DC vr1-dc0 headend controller-ca.cert.srl none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:542 SEC-023 n-outside-convention substrate-tfstate-backup per-DC vr1-dc0 jumphost vr1-dc0-substrate.tfstate.gz none service consolidated stage3 runbook:runbooks/dc-dc-phase2-tofu-dc-substrate.md:783 SEC-023 n-tfstate-backup -octavia-pki-backup per-DC vr1-dc0 jumphost octavia-pki-vr1-dc0.tar.gz none service consolidated stage5 runbook:runbooks/phase-01-bundle-deploy.md:631 SEC-023 n-pki-backup -octavia-pki-overlay per-DC vr1-dc0 headend vr1-dc0-octavia-pki.yaml none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:553 SEC-004 n-overlay-in-clone -octavia-issuing-ca-passphrase per-DC vr1-dc1 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:383 SEC-023 n-outside-convention -octavia-issuing-ca-key per-DC vr1-dc1 headend issuing-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:387 SEC-023 n-outside-convention -octavia-issuing-ca-cert per-DC vr1-dc1 headend issuing-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:391 SEC-023 n-outside-convention -octavia-controller-ca-pass per-DC vr1-dc1 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:406 SEC-023 n-outside-convention -octavia-controller-ca-key per-DC vr1-dc1 headend controller-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:410 SEC-023 n-outside-convention -octavia-controller-ca-cert per-DC vr1-dc1 headend controller-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:414 SEC-023 n-outside-convention -octavia-controller-key per-DC vr1-dc1 headend controller.key none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:429 SEC-023 n-outside-convention -octavia-controller-bundle per-DC vr1-dc1 headend controller.bundle.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:517 SEC-023 n-outside-convention -octavia-controller-cert per-DC vr1-dc1 headend controller.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:521 SEC-023 n-outside-convention -octavia-controller-ca-serial per-DC vr1-dc1 headend controller-ca.cert.srl none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:519 SEC-023 n-outside-convention +octavia-pki-backup per-DC vr1-dc0 jumphost octavia-pki-vr1-dc0.tar.gz none service consolidated stage5 runbook:runbooks/phase-01-bundle-deploy.md:658 SEC-023 n-pki-backup +octavia-pki-overlay per-DC vr1-dc0 headend vr1-dc0-octavia-pki.yaml none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:609 SEC-004 n-overlay-in-clone +octavia-issuing-ca-passphrase per-DC vr1-dc1 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:391 SEC-023 n-outside-convention +octavia-issuing-ca-key per-DC vr1-dc1 headend issuing-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:395 SEC-023 n-outside-convention +octavia-issuing-ca-cert per-DC vr1-dc1 headend issuing-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:398 SEC-023 n-outside-convention +octavia-controller-ca-pass per-DC vr1-dc1 headend passphrase.txt none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:414 SEC-023 n-outside-convention +octavia-controller-ca-key per-DC vr1-dc1 headend controller-ca.key.enc none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:418 SEC-023 n-outside-convention +octavia-controller-ca-cert per-DC vr1-dc1 headend controller-ca.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:421 SEC-023 n-outside-convention +octavia-controller-key per-DC vr1-dc1 headend controller.key none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:460 SEC-023 n-outside-convention +octavia-controller-bundle per-DC vr1-dc1 headend controller.bundle.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:548 SEC-023 n-outside-convention +octavia-controller-cert per-DC vr1-dc1 headend controller.cert.pem none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:544 SEC-023 n-outside-convention +octavia-controller-ca-serial per-DC vr1-dc1 headend controller-ca.cert.srl none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:542 SEC-023 n-outside-convention substrate-tfstate-backup per-DC vr1-dc1 jumphost vr1-dc1-substrate.tfstate.gz none service consolidated stage3 runbook:runbooks/dc-dc-phase2-tofu-dc-substrate.md:783 SEC-023 n-tfstate-backup -octavia-pki-backup per-DC vr1-dc1 jumphost octavia-pki-vr1-dc1.tar.gz none service consolidated stage5 runbook:runbooks/phase-01-bundle-deploy.md:631 SEC-023 n-pki-backup -octavia-pki-overlay per-DC vr1-dc1 headend vr1-dc1-octavia-pki.yaml none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:553 SEC-004 n-overlay-in-clone +octavia-pki-backup per-DC vr1-dc1 jumphost octavia-pki-vr1-dc1.tar.gz none service consolidated stage5 runbook:runbooks/phase-01-bundle-deploy.md:658 SEC-023 n-pki-backup +octavia-pki-overlay per-DC vr1-dc1 headend vr1-dc1-octavia-pki.yaml none service off-manifest-known stage5 runbook:runbooks/phase-01-bundle-deploy.md:609 SEC-004 n-overlay-in-clone tenant-domain-admin per-tenant - jumphost -domain-admin-cred.txt gui human off-manifest-known tenant-onboard script:scripts/tenant-onboard.sh:64 SEC-023 n-tenant-dir tenant-cluster-user per-tenant - jumphost -cluster-cred.txt api human off-manifest-known tenant-onboard script:scripts/tenant-onboard.sh:90 SEC-023 n-tenant-dir tenant-svc-user per-tenant - jumphost -svc-cred.txt api service off-manifest-known tenant-onboard script:scripts/tenant-onboard.sh:90 SEC-023 n-tenant-dir diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index f0d3274..44ba0cf 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -2412,6 +2412,39 @@ asserted no SAN and no mode -- to two independent trust domains, both verified 26/0, both backed up with a proven restore, and both fully declared. Every one of those defects was found by measurement rather than inherited from a document. +- **F9 MADE SELF-ARMING, AND THE PRE-BOOKEND SWEEP FOUND THE OPERATOR'S OWN WORKING COMMANDS + WERE NOT IN THE REPO (2026-07-30).** Operator: *"I'm worried that the fixes we made to the + defective commands will be lost ... Complete a full sweep before the bookend."* **The concern + was well founded.** The corrected Step 5/6 commands -- the ones that ACTUALLY produced both + DCs' live PKI -- had been reviewed in conversation, judged equivalent, and never folded in. Four + items now landed: **portable `base64 < f | tr -d`** (GEN.d shipped the GNU-only `-w0` form, so + the runbook described a command NOBODY EXECUTED); the operator's **`VIP_OVERLAY:?` guard**; the + **heredoc column-1 CAUTION** as a heading rather than a footnote, because that failure is + silent (no `[alt_names]` -> a cert with NO SANs while every openssl command prints OK); and + **`${DC_LABEL:?}` at both CA call sites** -- F8's sibling, where an unset label bakes a DC-less + subject into a 10-YEAR CA with no error. **NOT done, with reason:** the heredoc was not + rewritten as `printf` -- an untested rewrite of a 10-year-CA mint that cannot be exercised from + an agent session; the risk is bounded instead by A9 + harness T2. + **F9 IS NOW STRUCTURAL, NOT REMEMBERED: `octavia-pki.sh` A12 ARMS ITSELF** from + `os-public-hostname` appearing as a real option key. Unarmed (today's B5 IP-only posture) it + reports the SANs inert and records the wrong region; armed it FAILS a wrong region and + **REFUSES on the DC label**. Live: **PASS 29/0 both DCs.** Harness **21/21** -- T19 pins the + unarmed posture (without it, arming would have broken every current verify, the T17 trap + again), T20 is F9 armed, T21 the refusal. + **A NEW RULING-SHAPED GAP, now BLOCKING rather than filed:** D-008's shape plus D-106:2563's + VR1 instantiation (`dc1.vr1`/`dc2.vr1`) do not say whether substrate `vr1-dc1` is `dc1` by + TOKEN or `dc2` by POSITION -- the DC1/DC2 ambiguity item 3.1 retired elsewhere, here deciding + certificate identity. Both live certs carry `dc0.vr0`, the VR0 region, wrong under either + reading. A12 refuses rather than picking. + **A PRECEDENCE BUG THE HARNESS CAUGHT:** REFUSE was checked before FAIL, so once A12 armed, a + CONFIRMED wrong-region SAN reported as "could not evaluate". A known defect outranks an + unevaluated one; the verdict now reports FAIL first and still names the refusal. + **SWEEP CAPTURE: `docs/audit/queued-findings-20260730.txt`** (precedent + `queued-findings-20260726/-27/-29`), carrying F10-F13 and two ruling-shaped questions -- + notably **F10: mint-ref line numbers drift silently and S4 cannot see it** (it asserts only + within-EOF; this bit three times in two sessions, caught by hand every time, never by a gate). + All 24 octavia refs were re-anchored today in a SINGLE-PASS mapping keyed by row id, because + 391 was simultaneously an old and a new value and sequential seds would have corrupted it. **F3 -- both `~/octavia-pki/` and `overlays/octavia-pki.yaml` are ABSENT here** (existence checked, no contents read). So this is generation FROM SCRATCH for both DCs: there is nothing to reuse, which retires the reuse-vs-regenerate choice diff --git a/docs/audit/queued-findings-20260730.txt b/docs/audit/queued-findings-20260730.txt new file mode 100644 index 0000000..c2f910a --- /dev/null +++ b/docs/audit/queued-findings-20260730.txt @@ -0,0 +1,114 @@ +QUEUED FINDINGS / TRANSCRIPT-ONLY MATERIAL -- 2026-07-30 successor session +========================================================================== +Written BEFORE the GA-R4 close bookend, on operator instruction: "I'm worried that the fixes +we made to the defective commands will be lost when we close this session ... review and +confirm that there is nothing that should be saved will be lost during the bookend." + +Precedent: docs/audit/queued-findings-20260726.txt / -20260727.txt / -20260729.txt. +A bookend is a BOUNDED summary (GA-R4 rule 1, 15-line cap). Anything that must survive has to +be on a durable surface BEFORE it, not inside it. + +THE CONCERN WAS WELL FOUNDED. The operator's corrected commands -- the ones that ACTUALLY +produced both DCs' live PKI -- were NOT in the repo when the question was asked. They had been +reviewed in conversation, judged equivalent, and never folded in. Four items, now landed: + + (1) PORTABLE base64. GEN.d shipped `base64 -w0 `, a GNU-only flag. What actually ran + was `base64 < file | tr -d '\r\n'` -- identical single-line output, portable. The runbook + described a command NOBODY EXECUTED. Adopted verbatim, with the reason recorded inline. + (2) VIP_OVERLAY guard. The operator added `VIP_OVERLAY="${VIP_OVERLAY:?...}"` to GEN.c so it + fails fast instead of reaching the readability test with an empty path. Adopted. + (3) THE HEREDOC COLUMN-1 REQUIREMENT (F8). This is the one that cost real time live. It is now + a CAUTION HEADING above GEN.c, not a footnote, because the failure is silent: an indented + terminator yields a config with no [alt_names] and therefore a controller certificate with + NO SANs, while every openssl command still prints OK. + (4) ${DC_LABEL} guard -- F8's sibling. GEN.a/GEN.b guarded ${DC:?} but used ${DC_LABEL} + unguarded, so an unset label bakes a DC-less CA subject into a 10-YEAR CA with no error + anywhere. Both call sites now `${DC_LABEL:?}`. + +DELIBERATELY NOT DONE, with the reason: GEN.c's heredoc was NOT rewritten as printf lines. That +would be more paste-proof, but it is an untested rewrite of a step that mints 10-year CA +material and cannot be exercised end-to-end from an agent session (the guard blocks the mint by +design). The residual risk is bounded instead -- octavia-pki.sh A9 asserts the SAN set and +harness T2 pins it, so a SAN-less cert now FAILS a gate rather than shipping. Converting to +printf is a reasonable follow-up for whoever can run a real generation. + +-------------------------------------------------------------------------- +RULING-SHAPED, NOT YET PUT TO THE OPERATOR +-------------------------------------------------------------------------- +Q1. THE PER-DC DNS LABEL IS AMBIGUOUS INSIDE A RULED DECISION, and it now blocks any FQDN cert. + D-008 fixes `....cloud.neumatrix.local`. D-106:2563 instantiates + VR1 as `...omega.dc1.vr1...` and `...dc2.vr1...`. The substrate's DCs are `vr1-dc0` and + `vr1-dc1`. So substrate `vr1-dc1` is `dc1` by TOKEN or `dc2` by POSITION -- the DC1/DC2 + ambiguity item 3.1 retired elsewhere, surviving inside a ruling, where it decides + CERTIFICATE IDENTITY. Both live certs currently carry `dc0.vr0`, the VR0 region, which is + wrong for a VR1 DC under either reading. + ENFORCED, NOT FILED: octavia-pki.sh A12 REFUSES (exit 3) on the label once + `os-public-hostname` is set, rather than blessing a name it cannot validate. So the ruling + is now blocking rather than forgettable. + +Q2. D-137 OPEN FORK 1 (enforcement strength) -- still unruled, and this session produced + unusually good evidence for it. The guard blocked CORRECTLY once (the PKI mint) and MISFIRED + five times: twice on prose (a filename appearing in a register row; a secret directory path + in a commit message), once on a `chmod` that strictly IMPROVED posture, and twice on `awk` + reading a runbook. Option (c) -- guard refuses secret-writing shapes OUTSIDE a sanctioned + minter -- is the option that makes the carve-out deliberate and narrow instead of incidental. + Relevant: `scripts/octavia-pki.sh generate` is deliberately unimplemented pending this. + +-------------------------------------------------------------------------- +FINDINGS WITH NO OTHER HOME +-------------------------------------------------------------------------- +F10. MINT-REF LINE NUMBERS DRIFT SILENTLY, AND S4 CANNOT SEE IT. `creds-matrix.py`'s S4 asserts + only that a `runbook::` ref is WITHIN EOF. Any edit that adds lines ABOVE an + anchor leaves the ref pointing at unrelated text and S4 still reports clean. This bit + THREE times in two sessions (the F1 rename, the backup step, today's F8 fixes); each time + it was caught by hand, never by a gate. All 24 octavia refs were re-anchored today. + Worth noting the correct re-anchor is a SINGLE-PASS mapping keyed by row id, not sequential + seds: 391 was simultaneously an OLD value (issuing cert) and a NEW value (issuing secret), + so replace-one-then-the-other corrupts the first. + FIX SHAPE (not built): have S4 additionally assert the referenced line still MATCHES a + stored fingerprint, or move mint-refs to a stable anchor (a named step id) rather than a + line number. + +F11. `~/.ssh/config.d/vr1-sites` LABELS `office1-tailscale` "Office1 subnet router (D-107)" AND + IT ADVERTISES NO ROUTES. Measured `AdvertisedRoutes: `. Also: the operating skill's + routing table claims the workstation reaches voffice1 over the tailnet citing D-107, which + is titled "Airgap posture, per-DC artifact mirror, and NTP" and rules nothing of the sort. + Both queued to the deferred skill sweep. The ssh-config label is OUTSIDE the repo, so it + will not be caught by any gate -- recorded here so it is not lost. + +F12. COMMANDS IN THIS REPO ARE CWD-SENSITIVE IN A WAY THAT BITES REPEATEDLY. The operator's + `verify` failed twice with "No such file or directory" because the shell was in + `~/octavia-pki/vr1-dc0` rather than the repo; the session then made the SAME class of error + four consecutive times, describing a `cd` it was not actually sending. Worth a runbook + convention (absolute `$REPO/scripts/...` in pasteable blocks) rather than trusting cwd. + +F13. THE TWO LIVE INNER tfstates ARE MODE 664 -- group-writable, and they are the authority + `tofu` trusts, so a rewrite can make it destroy or orphan real resources. Not fixed: + tightening needs its own gated change PLUS proof the libvirt provider preserves the mode + across the rewrite it performs on every apply. Recorded in n-tfstate-backup too. + +-------------------------------------------------------------------------- +MEASURED VALUES WORTH KEEPING (all also in CURRENT-STATE) +-------------------------------------------------------------------------- +- Octavia PKI, both DCs: `octavia-pki.sh verify` PASS 29/0 (26 before A12 was added). +- Inner tfstate serials at backup time: vr1-dc0 = 9, vr1-dc1 = 4; 29 resources each. + sha256 head: dc0 c16995a1a9a82219, dc1 fbd506360ba4720f -- unchanged since session open, + so the backups match what tofu actually uses. +- P5: 7 findings on the jumphost, 6 on the headend. ZERO E2 and ZERO E3 on any octavia or + tfstate artifact. The residual set is entirely pre-existing (dc0-edge-api, three power-key + asymmetries, the maas-region-admin principal conflation, two uncheckable rows). +- Gauntlet ALL GREEN (89) in the default locale AND under LC_ALL=C, identical. +- Harnesses added/extended today: octavia-pki 21/21 (new), creds-matrix 65/65, + pre-flight-checks 31/31 (new), preflight 26/26, dc-selector 69. + +-------------------------------------------------------------------------- +CONFIRMED NOT AT RISK +-------------------------------------------------------------------------- +- Every command that generated or backed up the PKI is in `phase-01-bundle-deploy.md` + (1.0-GEN.0/.a/.b/.c/.d/.e) in the form that ACTUALLY RAN. +- The tfstate backup procedure is `dc-dc-phase2-tofu-dc-substrate.md` step 13. +- The backup artifacts themselves are on disk, declared in the register, and their restores + were PROVEN (PKI 12/12 sha256 vs live; tfstate byte-identical, parses, correct serial). +- All 31 commits are pushed to origin. Nothing in the repo lives only on this jumphost. +- The workstation ProxyJump config is operator-side and intentionally NOT in the repo; F11 + records the reasoning it depends on. diff --git a/runbooks/phase-01-bundle-deploy.md b/runbooks/phase-01-bundle-deploy.md index 0ad1d89..2697139 100644 --- a/runbooks/phase-01-bundle-deploy.md +++ b/runbooks/phase-01-bundle-deploy.md @@ -395,7 +395,7 @@ -aes-256-cbc -pass file:passphrase.txt -out issuing-ca.key.enc chmod 600 issuing-ca.key.enc openssl req -new -x509 -sha384 -key issuing-ca.key.enc -passin file:passphrase.txt \ - -days 3650 -subj "/CN=${DC_LABEL} Omega Cloud Octavia Issuing CA/O=Neumatrix" \ + -days 3650 -subj "/CN=${DC_LABEL:?DC_LABEL not set -- run 1.0-GEN.0; an unset label bakes a DC-less CA subject with NO error} Omega Cloud Octavia Issuing CA/O=Neumatrix" \ -out issuing-ca.cert.pem openssl x509 -in issuing-ca.cert.pem -noout -dates -subject openssl verify -CAfile issuing-ca.cert.pem issuing-ca.cert.pem # expect: OK @@ -418,7 +418,7 @@ -aes-256-cbc -pass file:passphrase.txt -out controller-ca.key.enc chmod 600 controller-ca.key.enc openssl req -new -x509 -sha384 -key controller-ca.key.enc -passin file:passphrase.txt \ - -days 3650 -subj "/CN=${DC_LABEL} Omega Cloud Octavia Controller CA/O=Neumatrix" \ + -days 3650 -subj "/CN=${DC_LABEL:?DC_LABEL not set -- run 1.0-GEN.0; an unset label bakes a DC-less CA subject with NO error} Omega Cloud Octavia Controller CA/O=Neumatrix" \ -out controller-ca.cert.pem openssl x509 -in controller-ca.cert.pem -noout -dates -subject openssl verify -CAfile controller-ca.cert.pem controller-ca.cert.pem # expect: OK @@ -429,10 +429,33 @@ The P-256 key is unencrypted -- Octavia reads it at startup. SAN carries the controller FQDN, the octavia API FQDN, and the Octavia API VIP (derived from the bundle at generation time -- DOCFIX-067; never a baked literal). +> ## CAUTION -- THE `CNF` HEREDOC MUST START AND END AT COLUMN 1 (F8, hit live 2026-07-29) +> +> The block below sits inside an indented `( { ... } )` subshell, but the heredoc body and its +> closing `CNF` are at column 1 and **must stay there**. Copy-pasting this step with the +> indentation preserved gives a terminator that no longer matches: the heredoc never closes, +> and the rest of the block is swallowed as config text. +> +> **The failure is silent, which is why this warning is a heading and not a footnote.** Depending +> where the paste breaks, `controller.cnf` can end up without its `[alt_names]` section -- which +> produces a controller certificate with **NO SANs AT ALL** while every `openssl` command in the +> chain still prints OK. The operator hit exactly this on 2026-07-29 and had to correct the block +> before it would run. +> +> **NOT rewritten as `printf` lines here, deliberately.** That would be more paste-proof, but it +> is an untested rewrite of a step that mints 10-year CA material and cannot be exercised +> end-to-end from an agent session (the PreToolUse guard blocks the mint by design). The residual +> risk is now bounded instead: `scripts/octavia-pki.sh verify` asserts the SAN set +> (`A9`), so a SAN-less certificate FAILS a gate rather than shipping -- harness case `T2`. +> Converting to `printf` is a reasonable follow-up when someone can run a real generation. + **RUN -- voffice1 (the D-128 Plane-2 headend; RULED 2026-07-29)** ```bash ( { WORKDIR="$HOME/octavia-pki/${DC:?DC not set -- run 1.0-GEN.0 first}" + # AS EXECUTED 2026-07-30 (operator's correction, adopted): fail fast on an unset VIP_OVERLAY + # rather than reaching the readability test with an empty path. + VIP_OVERLAY="${VIP_OVERLAY:?VIP_OVERLAY not set -- run 1.0-GEN.0 first}" cd "$WORKDIR/controller" || exit 1 # dir from 1.0-GEN.0 openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out controller.key chmod 600 controller.key @@ -574,11 +597,15 @@ echo "ABORT: $OUT is NOT gitignored -- writing CA key material here would make it" echo " committable in a repo SEC-004 records as PUBLIC. Fix .gitignore first." exit 1; } - ISS_CERT=$(base64 -w0 issuing-ca/issuing-ca.cert.pem) - ISS_KEY=$(base64 -w0 issuing-ca/issuing-ca.key.enc) + # AS EXECUTED 2026-07-30 -- the operator's correction, adopted VERBATIM because it is what + # actually produced the live overlays for both DCs. `base64 -w0` is a GNU-only flag; + # `base64 < f | tr -d '\r\n'` yields the identical single line and is portable. Keeping the + # -w0 form would have left this runbook describing a command nobody ran. + ISS_CERT=$(base64 < issuing-ca/issuing-ca.cert.pem | tr -d '\r\n') + ISS_KEY=$(base64 < issuing-ca/issuing-ca.key.enc | tr -d '\r\n') ISS_PASS=$(cat issuing-ca/passphrase.txt) - CON_CACERT=$(base64 -w0 controller-ca/controller-ca.cert.pem) - CON_CERT=$(base64 -w0 controller/controller.bundle.pem) + CON_CACERT=$(base64 < controller-ca/controller-ca.cert.pem | tr -d '\r\n') + CON_CERT=$(base64 < controller/controller.bundle.pem | tr -d '\r\n') cat > "$OUT" <