diff --git a/creds-manifests/vr1-dc1.manifest b/creds-manifests/vr1-dc1.manifest index a0ec24f..71d7663 100644 --- a/creds-manifests/vr1-dc1.manifest +++ b/creds-manifests/vr1-dc1.manifest @@ -15,3 +15,11 @@ vr1-dc1_svc_ed25519 600 local vr1-dc1_svc_ed25519.pub 644 local +# Edge service keypair (D-112(c) console bootstrap; minted 2026-07-22 on vcloud +# at the G12 dc1 edge-bootstrap step -- dc0 precedent, whose manifest rows are +# a queued backfill finding). +vr1-dc1-edge_ed25519 600 local +vr1-dc1-edge_ed25519.pub 644 local +# Edge REST API key/secret, minted on the edge via the vendor model +# (D-113(a2)); consolidated to vcloud 2026-07-22 at the G12 edge-address step. +opnsense-api.txt 600 local diff --git a/docs/CURRENT-STATE.md b/docs/CURRENT-STATE.md index bf8c0b5..02fd26a 100644 --- a/docs/CURRENT-STATE.md +++ b/docs/CURRENT-STATE.md @@ -475,7 +475,7 @@ | G9 | DC0 outer apply (deploy step A) | [V] operator-gated, logged (`run-logged.sh`), after G1-G8; audit exit criteria met (charter Phase 6). SEC pre-apply dependency (S2): SEC-010's transit FORWARD-drop is applied+verified at deploy step B via `site-headend-install.sh --host-nodes --check` on vvr1-dc0 (gate G10) -- the ONLY SEC row gated on this apply (register of record: security-ledger). CANONICAL ENTRY DOC (probe hole H1): `runbooks/dc-dc-phase2-tofu-dc-substrate.md`, with `docs/dc0-deploy-readiness.md` section E as the step table | operator | CLOSED 2026-07-19: G8 same-session planes check passed (6x 0 leases, 0 attachments); saved plan == 6/0/6 applied in the logged dc0-deploy window; convergence re-plan = no differences; vvr1-dc0 running, prior guests untouched | | G10 | Deploy steps B-E in-sequence gates: SEC-010 `--host-nodes --check` on vvr1-dc0; depth-4 nested boot; D-125 foreign-MAC egress test; MAAS reachability + `TF_VAR_maas_api_key` before step D; netem placeholder step E | [V] exercised during the gated deploy | session (each mutation operator-approved) | Step B DONE 2026-07-20 (`--check` EXIT 0 incl. SEC-010, `docs/audit/stepB-check-20260720-final.txt`; interfaces enp1s0/enp2s0). Depth-4 nested boot DONE (10 domains running inside vvr1-dc0). D-125 egress isolation test PASS 2026-07-20 (`docs/audit/d125-egress-gate-20260720-matrix.txt`), and the edge itself now egresses 0% loss after the v4 addressing. Step D COMPLETE incl. commissioning: ALL 9 NODES READY 2026-07-21 (two stacked faults diagnosed + fixed -- `docs/audit/commissioning-diag-20260721.txt`; section 1). Step E (netem) DONE 2026-07-21: sudo fragment installed+verified, module local-mode amendment, targeted apply 1/0/0 exact (operator-ruled at the 1/1/0 STOP), placeholder profile live on virbr5, virbr7/virbr3 untouched (`docs/audit/stepE-netem-20260721.txt` + `outer-{plan,apply}-20260721-netem*.txt`). **G10 CLOSED 2026-07-21** | | G11 | Operator signs THIS document | [R] read top-to-bottom; discrepancies resolved in the document | operator | CLOSED: RE-SIGNED 2026-07-19 at audit exit, section 11 (replaces the 2026-07-18 signature) | -| G12 | `vr1-dc1` build | [R] operator rules dc1 transit/rack addressing; then vars + substrate authored | operator + session | OPEN -- [R] leg CLOSED 2026-07-21: addressing RATIFIED (D-124 amendment 2026-07-21, utterance quoted). [V] leg IN PROGRESS (branch `dc-dc-g12-dc1-substrate`): apex confirm-free DONE 2026-07-21 -- planes/uplink already assigned+consistent, transit 172.31.0.4/30 + rack 10.12.68.2 FREE (`docs/audit/dc1-apex-confirm-20260721.txt`); importer per-site dc1 support shipped (harness 117/117) with live dry-run preflight PASS (`docs/audit/dc1-rack-import-dryrun-20260721.txt`). vars + substrate root + lib-net dc1 arm COMMITTED 2026-07-22 (successor session landed the disconnected item 3 + the harness reconcile as changelog item 4): six harnesses reconciled to the ratified dc1 arm, phase-00 PLANES parity guard added, rbd-mirror/radosgw cross-DC reminder fixed; gauntlet **ALL GREEN (76)** (`docs/audit/gauntlet-20260722-g12-reconcile.txt`), repo-lint 0-fail. Apex `--commit` EXECUTED 2026-07-22 (operator-gated): 172.31.0.4/30 + 10.12.68.2/22 CREATED, post-commit read-back idempotent (`docs/audit/dc1-rack-import-commit-20260722.txt`). dc1 svc key minted (creds-audit CLEAN), tfvars authored (local), **outer step-A apply DONE 2026-07-22**: saved plan 5/0/0 exact, converged ZERO DIFF (section 5), vvr1-dc1 RUNNING, prior guests untouched (as-executed log dc1-deploy; changelog-20260722-g12-dc1-build.md). **Step B COMPLETE 2026-07-22**: cloudinit-vm interface_macs port + voffice1 dc1-transit NIC (0/2/0 exact, MACs pinned both domains, post-bounce battery ALL PASS, converged zero diff -- `docs/audit/outer-plan-20260722-voffice1-dc1nic.txt`), transit LIVE (voffice1 .5/30 <-> rack .6/30, dc1-key ssh proven), rack ENROLLED (region lists vvr1-dc1 `nmpcq4`), SEC-010 applied+verified BOTH ends, OPNsense 26.7 base staged via hash-verified copy of dc0's proven artifact; named gate EXIT 0 `docs/audit/dc1-stepB-check-20260722-final.txt` (changelog-20260722 items 5-8, three queued findings). **Step C COMPLETE 2026-07-22**: inner apply FROM voffice1 -- plan 28/0/0 exact (54 pinned MACs verified in-capture), one fix-forward (serial-log staging dir absent on dc1; queued to standup DoD), resume 10/0/0 exit 0; 28/28 in state, convergence ZERO DIFF (`docs/audit/inner-converge-20260722-dc1-stepC.txt`), **10/10 domains RUNNING inside vvr1-dc1**, edge at the 26.7 FreeBSD login prompt (D-112 datapoint #2); dc1 inner tfstate ON voffice1 (site backup set). **D-125 egress gate PASS 2026-07-22** (two identical runs, dc0 criteria exact, isolation confirmed -- `docs/audit/d125-egress-gate-20260722-dc1.txt`). NEXT (gated): edge bootstrap (D-112(c)/D-113(a2)) + v4 addressing (WAN 172.30.3.2, LAN 10.12.64.1/22), rack standup DoD (dc-rack-net dc1 + forwarder 10.12.68.3, region-side DHCP primary_rack nmpcq4 + D-120 range, maas-node-power) | +| G12 | `vr1-dc1` build | [R] operator rules dc1 transit/rack addressing; then vars + substrate authored | operator + session | OPEN -- [R] leg CLOSED 2026-07-21: addressing RATIFIED (D-124 amendment 2026-07-21, utterance quoted). [V] leg IN PROGRESS (branch `dc-dc-g12-dc1-substrate`): apex confirm-free DONE 2026-07-21 -- planes/uplink already assigned+consistent, transit 172.31.0.4/30 + rack 10.12.68.2 FREE (`docs/audit/dc1-apex-confirm-20260721.txt`); importer per-site dc1 support shipped (harness 117/117) with live dry-run preflight PASS (`docs/audit/dc1-rack-import-dryrun-20260721.txt`). vars + substrate root + lib-net dc1 arm COMMITTED 2026-07-22 (successor session landed the disconnected item 3 + the harness reconcile as changelog item 4): six harnesses reconciled to the ratified dc1 arm, phase-00 PLANES parity guard added, rbd-mirror/radosgw cross-DC reminder fixed; gauntlet **ALL GREEN (76)** (`docs/audit/gauntlet-20260722-g12-reconcile.txt`), repo-lint 0-fail. Apex `--commit` EXECUTED 2026-07-22 (operator-gated): 172.31.0.4/30 + 10.12.68.2/22 CREATED, post-commit read-back idempotent (`docs/audit/dc1-rack-import-commit-20260722.txt`). dc1 svc key minted (creds-audit CLEAN), tfvars authored (local), **outer step-A apply DONE 2026-07-22**: saved plan 5/0/0 exact, converged ZERO DIFF (section 5), vvr1-dc1 RUNNING, prior guests untouched (as-executed log dc1-deploy; changelog-20260722-g12-dc1-build.md). **Step B COMPLETE 2026-07-22**: cloudinit-vm interface_macs port + voffice1 dc1-transit NIC (0/2/0 exact, MACs pinned both domains, post-bounce battery ALL PASS, converged zero diff -- `docs/audit/outer-plan-20260722-voffice1-dc1nic.txt`), transit LIVE (voffice1 .5/30 <-> rack .6/30, dc1-key ssh proven), rack ENROLLED (region lists vvr1-dc1 `nmpcq4`), SEC-010 applied+verified BOTH ends, OPNsense 26.7 base staged via hash-verified copy of dc0's proven artifact; named gate EXIT 0 `docs/audit/dc1-stepB-check-20260722-final.txt` (changelog-20260722 items 5-8, three queued findings). **Step C COMPLETE 2026-07-22**: inner apply FROM voffice1 -- plan 28/0/0 exact (54 pinned MACs verified in-capture), one fix-forward (serial-log staging dir absent on dc1; queued to standup DoD), resume 10/0/0 exit 0; 28/28 in state, convergence ZERO DIFF (`docs/audit/inner-converge-20260722-dc1-stepC.txt`), **10/10 domains RUNNING inside vvr1-dc1**, edge at the 26.7 FreeBSD login prompt (D-112 datapoint #2); dc1 inner tfstate ON voffice1 (site backup set). **D-125 egress gate PASS 2026-07-22** (two identical runs, dc0 criteria exact, isolation confirmed -- `docs/audit/d125-egress-gate-20260722-dc1.txt`). **Edge bootstrap + v4 addressing COMPLETE 2026-07-23** (changelog-20260723-g12-dc1-edge.md): D-112(c) console bootstrap done (SSH + dc1 edge key materialized; payload needed `util.inc`/`shell_safe()` -- dc0 lesson iv the `.b64` artifact lacked), key-only SSH VERIFIED (`15.1-RELEASE-p1`); D-113(a2) API key MINTED via the vendor model + smoke test `GET core/firmware/status` exit 0 `product_abi 26.7` (second 26.7 datapoint); edge ADDRESSED -- WAN `172.30.3.2/24` gw `172.30.3.1` (egress 1.1.1.1 0% loss), LAN `192.168.1.1` -> `10.12.64.1/22` (ruled provider-public gw), API answers at the new LAN; interim reach leg removed, rack provider-public leg `10.12.64.2/22` LIVE on virbr4. Creds consolidated to `~/vr1-dc1-creds/opnsense-api.txt` (creds-audit CLEAN, 5 entries); rack edge-key copy shredded (**SEC-015** transient, remediated). Two queued findings: bootstrap `.b64` missing `util.inc`; `opnsense-bootstrap-apikey.sh` scp had a transient post-restart-sshd failure (readiness-wait/retry candidate). NEXT (gated): rack standup DoD (dc-rack-net dc1 arm + harness, then install dc1 + forwarder 10.12.68.3, region-side DHCP primary_rack nmpcq4 + D-120 range 10.12.68.100-.200, maas-node-power dc1 arm), commission 9/9 to Ready, then G12 close-out (gauntlet/repo-lint/consolidation/memory review/skill sweep/operator-gated merge to main) | | G13 | D-129 residuals | [R] operator-gated live plugin install on office1-opnsense; qga channel retrofit at that edge's next scheduled restart. All 4 sub-decisions RULED 2026-07-21 (D-129 Status line) -- only the two execution items remain | operator | OPEN (execution only; decision content complete) | | G14 | 9 OPEN SEC rows (SEC-001, -003..-008, plus SEC-012 + SEC-013 opened 2026-07-20 for credentials this deploy created; SEC-010 CLOSED 2026-07-20, operator-ruled, applied+verified both transit ends) | [R] per-row: rotations/flips at v1 close (external to VR1 track); SEC-012 also carries a SCOPE question (libvirt-group grant is broader than the power verbs MAAS needs), SEC-013 is tied to whether `opentofu/vr1-dc0-maas` is retired | operator / external | `docs/security-ledger.md` (register of record, GA-R4/F3); count re-verified vs `bash scripts/ledger-scan.sh` 2026-07-20 | | G15 | D-068 / D-071 rulings | [R] operator rules (section 8); neither blocks the VR1 substrate | operator | D-071 ADOPTED 2026-07-21 (all four points); D-068 remains PROPOSED/OPEN (items 2-3 + the item-1 re-scoped migration plan) | diff --git a/docs/changelog-20260723-g12-dc1-edge.md b/docs/changelog-20260723-g12-dc1-edge.md new file mode 100644 index 0000000..569ee60 --- /dev/null +++ b/docs/changelog-20260723-g12-dc1-edge.md @@ -0,0 +1,129 @@ +# 2026-07-23 -- G12 [V] leg: dc1 edge bootstrap + v4 addressing (session changelog) + +Session scope: resume the G12 [V] leg from the 2026-07-22 close handoff +(edge bootstrap onward). Branch `dc-dc-g12-dc1-substrate`. One changelog per +session (GA-R2/D1); every item carries its revert. Live mutations gated +(operator ran in `manual` permission mode -- see Item 0). Edge-phase mutations +mostly run UNWRAPPED (approval prompt = the gate); the console bootstrap went +through the `~/as-executed/2026-07-22-dc1-deploy.log` wrap. + +## Item 0 -- permission-mode friction (recorded; no repo change) + +The session opened in `auto` mode, whose classifier BLOCKS remote +`sudo`/mutation shapes (matched by the project `ssh * sudo *` ask rule) +instead of surfacing them for approval -- so it cannot deliver "operator +approves each mutation." Resolved by switching to `manual` mode (alias for +`default`; no classifier): allow-rules flow read-only rack probes, project ask +rules prompt every gated mutation, deny rules + `guard-destructive.py` stay +active. Session allow-rules for the dc1/dc0 rack ssh shapes were added to +`.claude/settings.local.json` (the operator later broadened to `ssh *`). +Revert: none (session-scoped settings; remove the added allow lines at close +if desired). + +## Item 1 -- dc1 edge service keypair minted + manifest + +`~/vr1-dc1-creds/vr1-dc1-edge_ed25519` (0600/0644) minted on vcloud, +`creds-manifests/vr1-dc1.manifest` extended (edge key + `opnsense-api.txt`), +`creds-audit vr1-dc1` CLEAN (5 entries). Revert: `git checkout` the manifest; +delete the keypair. + +## Item 2 -- D-112(c) console bootstrap COMPLETE (edge SSH + service key) + +Driver `d112c-console-dc1.py` (dc1 adaptation of the dc0-PROVEN v6, retrieved +verbatim from `vvr1-dc0:~/d112c-console.py`): serial console -> factory +root/opnsense -> shell -> ship+run bootstrap PHP (enable ssh, permitrootlogin, +install dc1 edge pubkey, `write_config`) -> materialize PHP +(`local_user_set()`, dc0 lesson v). Transcript `~/d112c-console-dc1.log` on +the rack: `CONFIG-WRITTEN`, `AK-IN-CONFIG=152`, `USER-MATERIALIZED`; +`/root/.ssh/authorized_keys` (115 B) created (was absent). Edge banner +confirms **vtnet0 = LAN 192.168.1.1/24, vtnet1 = WAN** (dc0 mapping). +**FINDING (logged, not fixed mid-step):** the dc0 `d112c-bootstrap.php` on the +rack required only `config.inc`, so my first bootstrap PHP threw +`Call to undefined function shell_safe()` at `config.inc:311` (in +`write_config()->make_config_revision_entry()`) and aborted BEFORE writing -- +this is **dc0 lesson (iv)** (shell_safe lives in `util.inc`, measured on dc0's +identical 26.7 image). Added `require_once("util.inc")`; two diagnostic lines +made csh-safe (edge root shell is tcsh; `2>&1` = "Ambiguous output redirect"). +Re-ran clean. The proven dc0 `.b64` bootstrap artifact is missing this include +-- a real gap if replayed; queue: fold `util.inc` into the canonical console +bootstrap payload. Revert: config-only; re-run factory reset on the edge to +undo (or leave -- it is the intended state). + +## Item 3 -- key-only SSH to the edge VERIFIED (D-112(c) proof) + +Reached the edge via a ProxyCommand chain from vcloud (rack key for the jump, +edge key for the final hop -- per-hop keys; a plain `-J` applies one key to all +hops and the rack rejected it). `root@192.168.1.1` -> `uname -r` = +`15.1-RELEASE-p1`, `ifconfig -l` = vtnet0/vtnet1/lo0/enc0/pfsync0/pflog0. +Second D-112(c) datapoint after dc0. + +## Item 4 -- D-113(a2) API key MINTED + smoke test PASS + +Interim reach leg `192.168.1.2/24` added on the rack provider-public bridge +`virbr4` (measured this session) to reach the factory edge LAN. Edge-config +scripts + edge key staged on the rack (dc0 method; the mint script SSHes +edge-direct, no ProxyJump). Key minted via the vendor `opnsense-mint-apikey.php` +(`apikeys->add()` -- the GUI's own path); key/secret 80 chars, 173 B -> +`~/opnsense-api.txt` (0600, secret never printed). Smoke test from the rack: +`GET core/firmware/status` -> exit 0, `product_abi 26.7`. First proof the +D-113(a2) API path works on 26.7 for dc1. +**FINDING (logged):** `opnsense-bootstrap-apikey.sh`'s first `scp` to the edge +failed once with `scp: Connection closed` -- TRANSIENT: the edge sshd was not +ready in the moment right after the console bootstrap's `configctl openssh +restart` (both default `scp` and `scp -O` succeeded minutes later; the edge is +reachable and scp works). Unblocked via an ssh-pipe mint (vendor PHP shipped +by `ssh 'cat >'`, retrieved by `ssh -n 'cat' > file`) -- during which a +missing `-n` on the edge ssh calls let them EAT the rack `bash -s` heredoc +stdin (mint ran, retrieve/cleanup lines were swallowed); re-run with `-n` +retrieved the already-minted key cleanly. Queue: a post-restart sshd +readiness wait / one scp retry in `opnsense-bootstrap-apikey.sh`. Revert: delete +the API key via the edge API + remove `~/vr1-dc1-creds/opnsense-api.txt`. + +## Item 5 -- edge v4 addressing (WAN then LAN; reach-handoff) + +`opnsense-set-interface-v4.sh` run VERBATIM from the rack (plain scp works +after warm-up; no repo edit). Values confirmed from committed `lib-net.sh` +(provider-public `10.12.64.0/22` gw `10.12.64.1`, D-124 amendment) + the D-124 +uplink `172.30.3.0/24`. +- **WAN first** (script ordering rule): dhcp -> `172.30.3.2/24` gw + `172.30.3.1`, applied + read back on the kernel (vtnet1). Edge egress + VERIFIED: ping 1.1.1.1 = 0% loss. +- **Permanent rack leg** `10.12.64.2/22` added on `virbr4` (so the rack keeps + reach after the edge LAN moves). +- **LAN last**: `192.168.1.1/24` -> `10.12.64.1/22` (vtnet0). The apply drops + the `192.168.1.1` session mid-command (expected; the foreground ssh hung on + the dead interface and was TaskStop-ped -- config was already saved+applied). + Verified independently at the NEW LAN via the rack's `10.12.64.2` leg: + `ifconfig vtnet0` = `inet 10.12.64.1 netmask 0xfffffc00` (/22); API + `GET core/firmware/status` at `10.12.64.1` -> exit 0, abi 26.7. +- Interim `192.168.1.2/24` removed; `virbr4` now carries only `10.12.64.2/22` + (dc0 end-state exactly). +Revert: re-address LAN/WAN back via the same script; the leg adds/dels are +`ip addr add/del` (non-persistent). + +## Item 6 -- creds consolidated + rack edge-key WIPED (SEC-015 closed transient) + +API creds pulled rack -> `~/vr1-dc1-creds/opnsense-api.txt` (0600, 1 key + 1 +secret). Rack edge-key copy `shred -u`'d; staged edge-config scripts + +console driver + rack creds copy removed (`ls` confirms none remain). The +non-secret console transcript `~/d112c-console-dc1.log` retained as an audit +artifact. **SEC-015** opened for the transient edge-key-on-rack exposure +(minted->wiped same phase; disclosed). Revert: n/a (cleanup). + +## Milestone + +dc1 edge fully bootstrapped + addressed -- D-112(c) console bootstrap and +D-113(a2) REST API both PROVEN on 26.7 (second datapoint after dc0). Edge: +WAN `172.30.3.2/24` gw `172.30.3.1` (egress 0% loss), LAN `10.12.64.1/22` +(the ruled provider-public gateway), API answering at the new LAN. + +## Next (gated, not run here) + +Rack standup DoD: `dc-rack-net.sh` needs a MEASURED `dc1)` site-table arm +(provider-public `10.12.64.2/22`, metal-admin `10.12.68.2/22`, forwarder +`10.12.68.3` -> region BIND `10.10.0.20`) + harness update, then +`install dc1`; region-side MAAS (metal-admin `dns_servers=10.12.68.3 +allow_dns=false`, DHCP `primary_rack=nmpcq4`, D-120 range +`10.12.68.100-.200`); `maas-node-power.sh` dc1 arm; commission 9/9 to Ready +(D-121 Option C); then G12 close-out (gauntlet, repo-lint, consolidation, +memory review, skill sweep, operator-gated merge to `main`). diff --git a/docs/security-ledger.md b/docs/security-ledger.md index 8e93cdd..1f396e7 100644 --- a/docs/security-ledger.md +++ b/docs/security-ledger.md @@ -23,6 +23,7 @@ | SEC-013 | 2026-07-20 | **MAAS API key materialized to disk on the region.** An admin-scoped MAAS API key (`consumer:token:secret`) was placed by the operator in a 0600 file on `voffice1` so the `opentofu/vr1-dc0-maas` root could consume it via `TF_VAR_maas_api_key`. It grants FULL MAAS admin API access (machines, power, deploy, users). Two exposure surfaces beyond the file itself: (a) the OpenTofu **state file** of any root that uses the maas provider records it -- unavoidable with this provider, so that state inherits credential handling (0600, never committed); (b) a MAAS CLI profile was also created for the operator user from the same key. It was verified by FORMAT ONLY (71 bytes, 3 colon-separated parts) and never printed, echoed, or passed in argv. | 2026-07-20 step-D part 2; `opentofu/vr1-dc0-maas/main.tf` header; session changelog item 15 | operator | **OPEN -- rotation obligation (surface NARROWED 2026-07-21).** The retire-fully ruling was executed 2026-07-21: `opentofu/vr1-dc0-maas` removed from the repo, the on-disk key file (`~/vr1-dc0-creds/maas-api-key.txt` on voffice1) and the root's `terraform.tfstate` DELETED, absence verified by listing (session changelog 2026-07-21 items 13-15; NOTE the pod-object deletion cascaded to the 9 machine records -- incident capture `docs/audit/incident-20260721-pod-delete-cascade.txt`, recovered same-day). REMAINING surface: the operator's MAAS CLI profile only. Rotate the underlying API key at v1 close, or immediately if `voffice1` is rebuilt/shared. Custody detail off-repo per D-069. | | SEC-014 | 2026-07-21 | **Rack cluster secret exposed to session context.** During the commissioning diagnosis, a read of `/var/snap/maas//agent.yaml` on the DC0 rack (hunting the agent resolver's config surface) returned the rack's MAAS cluster `secret` into the Claude session context, the operator terminal scrollback, and the as-executed log (`~/as-executed/2026-07-21-ops-commissioning-diag.log`, 0600, jumphost-only). The secret authenticates rack<->region enrollment. The read was not anticipated to contain a credential (config file, not a key file); disclosed same-session. | 2026-07-21 session changelog item 6; docs/audit/commissioning-diag-20260721.txt | operator | **OPEN -- rotation obligation.** Rotate the MAAS shared secret (= rack re-enrollment for `7chphy`) at a convenient maintenance point, or immediately if session artifacts leave the jumphost. Process fix queued: add `agent.yaml` to the guard hook's never-read list alongside key/cred globs. | | SEC-011 | 2026-07-16 | **Node least-connectivity gap (not an L2 breach).** Under D-121 Option C role separation, all nodes get a uniform 6-plane NIC set, so a ceph-osd STORAGE node has a leg on provider-public (external/FIP) + data-tenant (tenant geneve) -- planes it never binds per D-052. Planes stay isolated L2 (no crosstalk). | 2026-07-16 plane-segregation review; `opentofu/main.tf` `local.vr1_dc0_node_nics` | operator | **CLOSED 2026-07-16 (operator ruling -- keep uniform 6-NIC).** Review R3-F10: A2's cross-examination refuted the attack-surface concern -- in the isolated-L2 sim the unbound vNICs have no reachability out, and pruning would INCREASE Roosevelt-delta (baremetal trunks all VLANs to every node on bonded NICs, so all planes are present regardless of L3 binding). Uniform 6-NIC is the more Roosevelt-faithful model. Accepted non-issue; no code change. | +| SEC-015 | 2026-07-23 | **dc1 edge SSH private key staged transiently on the DC1 rack.** The `vr1-dc1-edge_ed25519` private key (root-granting on `vr1-dc1-opnsense`) was scp'd to `vvr1-dc1:~/vr1-dc1-edge_ed25519` (0600) so `opnsense-bootstrap-apikey.sh` -- which SSHes the edge directly, no ProxyJump -- could mint the API key there (dc0 method). It existed on the rack only for the mint + v4-addressing phase and was `shred -u`'d immediately after (absence verified by `ls`). The permanent copy stays on vcloud `~/vr1-dc1-creds/` (SEC-007 pattern: edge SSH is the only management path -- a rotation obligation, not a delete-me). | 2026-07-23 session changelog item 6; docs/changelog-20260723-g12-dc1-edge.md | operator | **OPEN -- rotation obligation (transient exposure already remediated).** The on-disk rack copy is gone; the standing surface is the vcloud key + the minted API key/secret (`~/vr1-dc1-creds/opnsense-api.txt`). Rotate both at v1 close, or immediately if vcloud is rebuilt/shared. Roosevelt note: metal edges reached differently may avoid the rack-staging step entirely (a ProxyCommand-from-vcloud mint keeps the key off the rack -- deferred, not adopted this build to stay on the dc0-proven path). | **STANDING CONVENTION (SEC-009, 2026-07-15): per-site credential/env consolidation.** ALL sensitive files AND environment/config files for a site live in a single `~/-creds/` folder on vcloud,