diff --git a/docs/design-decisions.md b/docs/design-decisions.md index 584a834..65dfb3b 100644 --- a/docs/design-decisions.md +++ b/docs/design-decisions.md @@ -2205,6 +2205,39 @@ importer's 7-second timeout. A console *login shell* has no timing race and can be driven at leisure. These are materially different risks; do not conflate them. +**Option (a) RE-EXAMINED 2026-07-12 at operator request and MEASURED INFEASIBLE on this host.** +Recorded so it is not re-litigated. Baking `/conf/config.xml` into the nano requires writing +FreeBSD UFS2 from Linux, and every route is closed here: + +| Requirement | Measured result | +|---|---| +| Kernel UFS write | `# CONFIG_UFS_FS_WRITE is not set` -- driver is READ-ONLY (`CONFIG_UFS_FS=m`) | +| A FAT partition to write instead | NONE -- MBR (`dos`), a single FreeBSD `a5` partition; UFS only | +| FUSE UFS driver (`fuse-ufs`, `ufs2-tools`) | not present, not packaged | +| libguestfs (`guestfish` / `virt-copy-in`) | not installed | + +Two ways (a) could still be FORCED, both REJECTED: +- **FreeBSD helper VM** (boot a FreeBSD live system with the nano as a second disk; FreeBSD mounts + UFS rw natively; drop the file; power off). It genuinely works and `xorriso` IS present, so a live + ISO could be remastered with an auto-run script -- but it means fetching + remastering a FreeBSD + ISO and maintaining a builder VM forever to deliver one 4.5 KB file. Cost exceeds (c) entirely. +- **Raw byte-patch of the image** (pad the new XML to the default `config.xml`'s exact byte length + and overwrite its data blocks in place, leaving the inode untouched). Probably works -- and + REJECTED anyway: it silently corrupts if the file is not block-contiguous, and it is + NON-TRANSFERABLE (you cannot byte-patch a real appliance's disk on Roosevelt hardware), which is + precisely what this repo's governing constraint forbids. + +**Net: examining (a) properly STRENGTHENED (c).** (a) is not merely less mainstream here -- it is +unavailable without a FreeBSD-shaped detour costing more than (c)'s whole bootstrap. + +**BOOTSTRAP RULED 2026-07-12 (operator: "proceed with the C bootstrap"):** +- **B1 (reach) = (i)** temporary host leg on `virbr2` (`ip addr add 192.168.1.10/24`) -- reversible, + non-persistent, no change to the D-100 network definition. Removed/re-addressed once the edge's + LAN moves to `10.10.0.1`. +- **B2 (authenticate) = (i)** one interactive console login -> enable SSH + install the ed25519 + pubkey ALREADY generated in `~/vr1-office1-creds/`. Thereafter everything is plain SSH/SCP and + fully scriptable. Chosen over GUI/CSRF-scraping to mint an API key (brittle, no gain). + **Once bootstrapped, the steady-state mechanism is:** push `config.xml` (or the equivalent API calls) to the edge, reload, and verify. The config we already render (`opnsense-config.xml.tmpl`, LAN `10.10.0.1/24` + DHCP `.100-.199`, WAN static `172.30.1.2`) is REUSED unchanged -- only the diff --git a/opentofu/modules/opnsense-edge/main.tf b/opentofu/modules/opnsense-edge/main.tf index 86ee676..bf3e8c0 100644 --- a/opentofu/modules/opnsense-edge/main.tf +++ b/opentofu/modules/opnsense-edge/main.tf @@ -204,17 +204,31 @@ ] # OPNsense nano images are SERIAL-console only -- the image ships /boot.config with - # `-S115200 -h`, so its loader expects a serial device. This file-backed serial gives - # the guest that device AND captures boot output to a file, so a first boot can be - # read without an interactive console. + # `-S115200 -h`, so its loader expects a serial device. # - # This is a GENUINE requirement and the single most useful thing DOCFIX-187 added -- - # it is what made the 2026-07-12 fault legible at all. But note the correction - # (DOCFIX-189): adding it did not *change* the fault, it only revealed it. The domain - # triple-faulted both with and without a console. + # `unix` socket + `log`, NOT a plain `file` source. The two roles are different and we + # need BOTH: + # source.unix -> an INTERACTIVE, BIDIRECTIONAL console. Required by D-112(c): the + # bootstrap is a one-time console login to enable SSH. A `file` source is WRITE-ONLY + # capture -- it cannot be typed into, so it cannot bootstrap anything. A unix socket + # is driven non-interactively with `socat - UNIX-CONNECT:`, unlike a `pty`, + # which needs a controlling TTY and is therefore awkward to script. + # log -> keeps the full boot capture we had before. Output emitted BEFORE any + # socket client connects would otherwise be lost; `log` records everything from + # power-on regardless. This capture is what made the 2026-07-12 boot bugs legible at + # all -- do not drop it. + # + # (DOCFIX-189 correction, for the record: adding a console in DOCFIX-187 did not CHANGE + # the original triple-fault, it only revealed it. The domain faulted with and without.) serials = [ { - source = { file = { path = "/var/lib/libvirt/vr1/staging/${var.vm_name}-serial.log" } } + source = { + unix = { + mode = "bind" + path = "/var/lib/libvirt/vr1/staging/${var.vm_name}-console.sock" + } + } + log = { file = "/var/lib/libvirt/vr1/staging/${var.vm_name}-serial.log", append = "on" } target = { port = "0" } } ]