This commit is contained in:
Audiobuzz
2026-06-18 12:03:45 +00:00
parent ada4aa4b18
commit 3b776dd970
47 changed files with 3416 additions and 110 deletions
+87 -9
View File
@@ -5,6 +5,24 @@ Persistent backlog, kept in sync with the working session task tracker. Status:
---
## Current build posture (LAB / test) — as of 2026-06-18
The image currently builds in **open-network test mode**. These toggles must be
flipped back for a secure/production build (consolidated as item #8):
- `disable_dot1x=true` / CI `DISABLE_DOT1X="true"` → `rd.dot1x=0` (NO 802.1X /
MACsec; open NVMe-oF). **TEMPORARY.**
- `nvmet_traddr` / CI `NVMET_TRADDR="192.168.50.10"` → hardcoded IP (should be a
per-env DNS name like `nvme.fleet.lab` once DNS-at-boot is trusted).
- Unsigned UKI (`sb_key`/`sb_cert` not passed) → Secure Boot must be OFF on the
test target. Production needs CI/HSM signing.
- `enable_kiosk=false` by default (CI may set true); `enable_stig=true`;
`boot_splash=true`; NTP via DHCP→serving-host chrony.
What's working/verified vs awaiting bench is per-item below. Cross-cutting
bench-verify checklist lives in `CLAUDE.md` → "Known bench-verify items".
---
## [x] 1. Port the dracut module off `network-legacy` → `network-manager`
**DONE — test path VERIFIED ON THE BENCH 2026-06-17** (host stays up past the
@@ -56,11 +74,28 @@ in **[stig-deviations.md](stig-deviations.md)** (curated register) and reported
per-build by **[../scripts/stig-deviations.sh](../scripts/stig-deviations.sh)**
(non-pass rules tagged intentional vs REVIEW); CI publishes
`stig-report.html` + `stig-arf.xml` + `stig-deviations.md`. Scanner tooling is
removed from the shipped image. **BENCH-VERIFY:** SSG datastream name; boot/login
still work; reproducible verity hash across two builds; triage REVIEW rows.
removed from the shipped image. **BENCH-VERIFY:** boot/login still work;
reproducible verity hash across two builds; triage REVIEW rows.
**FINDING 2026-06-18 (FIXED) — false-clean scan.** The first hardened build
(branch `hardening`, `ada4aa4`) produced a report reading "0 REVIEW / clean",
but the ARF had **0 pass, 0 fail** — only 462 `notapplicable` + 1068
`notselected`. Root cause: the provisioner selected the datastream with
`ls ssg-rhel9-ds.xml ssg-rl9-ds.xml | head -1`, which picks **rhel9**
alphabetically; the RHEL9 datastream's CPE dictionary has **no Rocky entry**, so
on Rocky 9.8 every selected rule went `notapplicable` and **nothing was actually
evaluated or remediated** — the image was unhardened despite a clean-looking
report. Fixes: (a) provisioner now maps `/etc/os-release $ID` → datastream
(Rocky→`ssg-rl9-ds.xml`); (b) provisioner **aborts the build** if the scan
evaluates 0 rules; (c) `stig-deviations.sh` flags an **INVALID SCAN** and exits
non-zero on 0-evaluated. **Re-run the hardened build** and confirm pass/fail
counts are non-zero before trusting any deviations report.
Remaining (future hardening, currently waived — see the register): FIPS,
firewall, remote audit offload, per-host/rotatable admin access.
firewall, per-host/rotatable admin access. **Remote audit offload — receiver
DONE** (`serving/audit-collector/`, rsyslog over TCP/514, per-source-host files;
DNS name `${AUDIT_HOST}`); the **image-side sender** (audisp-syslog + rsyslog
forward to `audit.fleet.lab`) is still to wire — see that dir's README.
### Original spec (retained for reference)
@@ -116,7 +151,12 @@ re-export a **v3** PDF (key change: `rootovl` → `systemd.volatile=overlay` in
step 8 and §5). Retire/reset the errata afterward. Needs the design-doc source
(not in this repo).
## [~] 4. Kiosk mode — autologin + fullscreen Chromium loading a URL
## [x] 4. Kiosk mode — autologin + fullscreen Chromium loading a URL
**WORKING (display-verified 2026-06-17).** Remaining bits are polish (GPU/mesa
trim, ship via CI `enable_kiosk=true`) and the phone-home/NTP lockdown (done) —
all captured in the sub-notes below. Secure-path render check is folded into #8.
**WORKING / display-verified 2026-06-17** (kiosk renders Chromium fullscreen on
the configured URL). Build-flagged OFF by default for now (`enable_kiosk=false`)
@@ -147,11 +187,19 @@ Path to getting here (don't re-discover):
smaller image. **Re-enable with `-var enable_kiosk=true` when returning to
kiosk work** — CI does not pass the var, so CI currently builds lean (no
kiosk) too; add `-var enable_kiosk=true` to the Gitea workflow to ship it.
- `kiosk_url` Packer var (default `http://boot.fleet.lab/kiosk/` — the
self-contained test page served by the boot HTTP server at
`serving/http/kiosk/`, via the `/kiosk/` nginx location; validates a boot
without external connectivity. Empty disables the whole install). Wired in CI
as `KIOSK_URL` env.
- `kiosk_url` Packer var (default `http://boot.fleet.lab/kiosk/` — the kiosk
**SPA** (`serving/kiosk-app/`, Svelte 5 + Tailwind v4, a cyber sci-fi
spaceship monitoring/control terminal) served by the boot HTTP server, which
**reverse-proxies** `/kiosk/` to the `kiosk` container; self-contained so a
boot validates without external connectivity. Empty disables the whole
install). Wired in CI as `KIOSK_URL` env.
- **Kiosk SPA (`serving/kiosk-app/`)** — replaced the old single static
`serving/http/kiosk/index.html` (2026-06-18). Top navbar + 5 pages
(Bridge/Reactor/Nav/Life Support/Comms) with dummy telemetry; hash routing;
builds in a 2-stage Docker image (Vite → nginx), reverse-proxied at `/kiosk/`
by the main serving nginx (loopback `127.0.0.1:${KIOSK_APP_PORT:-8088}`).
`npm run build` verified locally; container build untested (no docker here).
Dummy data lives in `src/lib/data.js` (swap for a fleet API later).
- Provisioner enables EPEL, installs `weston chromium mesa-dri-drivers
mesa-libEGL mesa-libgbm dejavu-sans-fonts`, creates a passwordless
unprivileged `kiosk` user (video/input groups).
@@ -439,3 +487,33 @@ export is read-only + single-namespace = inherently small attack surface.
— it's the fleet's disk). Ties into #6 (rolling updates) availability.
- Revisit a memory-safe target only if/when an off-the-shelf one matures
(e.g. a future Rust-for-Linux `nvmet`).
## [ ] 8. Return to secure / production posture (un-toggle the lab flags)
Consolidates the cleanup of the temporary lab toggles (see "Current build
posture" at the top) and the secure-path bench-verifies deferred while testing
the open-network path. Do these together, then run the full secure boot-chain
smoke test.
- **Re-enable 802.1X/MACsec:** `disable_dot1x=false` (CI `DISABLE_DOT1X="false"`).
Removes `rd.dot1x=0`/`ip=dhcp`; the hook owns the link (macsec0).
- **NVMe discovery by DNS:** `nvmet_traddr=nvme.fleet.lab` (CI), resolved at boot
by the serving dnsmasq — drop the hardcoded `192.168.50.10`.
- **Signing:** wire `sb_key`/`sb_cert` (CI/HSM secrets) for a signed UKI; enable
Secure Boot on targets. Until then the loud unsigned warning must stay.
- **Bench-verify on the secure path** (swtpm + hostapd + FreeRADIUS,
`disable_dot1x=false`) — the items deferred this session:
- NM port secure path: `en*` UNMANAGED + `macsec0` MANAGED/renewing, MKA
survives switch-root, NVMe stays up past lease (item #1 risk).
- NTP via DHCP option 42 reaches chrony over macsec0 (`chronyc sources`).
- Plymouth `fleet` theme: test-path render VERIFIED 2026-06-18; still confirm
the auth→macsec rows reach `done` live on the secure path.
- STIG remediation didn't break the secure path; reproducible verity hash;
triage the generated `stig-deviations.md` REVIEW rows (item #2).
- **Secure-path NVMe connect trigger:** the test path uses
`nvmf-connect.service` (gated `rd.dot1x=0`); confirm the secure path's
connect (dracut nvmf over macsec0) actually fires, or give it an equivalent
trigger. Apply the same `-k 30 -l -1 -c 10` keep-alive/reconnect flags to the
secure `nvme connect` as the test path has.
- **Future hardening waived for now** (from the STIG register): FIPS, firewall,
remote audit offload, per-host/rotatable admin (SSH CA / config-agent).
+1 -1
View File
@@ -26,7 +26,7 @@ Posture decisions (2026-06-18, lab phase):
| 3 | **AIDE / file integrity** (`package_aide_installed`, `aide_build_database`, `aide_periodic_cron_checking`, `aide_scan_notification`, `aide_verify_*`) | The root is read-only and cryptographically verified; an on-disk AIDE db would also be non-deterministic and break the reproducible verity hash. | **dm-verity** verifies the whole root filesystem against a signed root hash on every read — continuous, hardware-backed integrity that supersedes AIDE's periodic scan. |
| 4 | **Firewall** (`service_firewalld_enabled`, `package_firewalld_installed`, `set_firewalld_default_zone`) | Currently `firewall --disabled`; auto-enabling firewalld/nftables risks the NVMe/TCP (`:4420`) and NetworkManager paths during bring-up. | Isolated boot LAN; egress controlled at the serving-stack / network firewall layer. **Future hardening** — re-enable with explicit allow rules once the secure path is verified. |
| 5 | **FIPS** (`enable_fips_mode`, `grub2_enable_fips_mode`, `package_dracut-fips_installed`) | Decision: off for the lab phase (interacts with the still-unsigned UKI / Secure Boot story). | Revisit with signing. No weakened crypto is configured in the meantime. |
| 6 | **Remote audit offload** (`auditd_audispd_configure_remote_server`, `..._encrypt_sent_records`, `..._network_failure_action`, `rsyslog_remote_loghost`) | Decision: local-only for now; no collector deployed. | auditd enabled and recording locally. **Future hardening** — `audisp-remote`/rsyslog to a per-environment collector DNS name (host-generic, no per-host state). |
| 6 | **Remote audit offload** (`auditd_audispd_configure_remote_server`, `..._encrypt_sent_records`, `..._network_failure_action`, `rsyslog_remote_loghost`) | Decision: local-only for now; image not yet forwarding. | auditd enabled and recording locally. **Receiver now deployed** — `serving/audit-collector/` (rsyslog over TCP/514, per-source-host files, DNS name `${AUDIT_HOST}`). **Remaining hardening** — wire the image-side sender (audisp-syslog + rsyslog forward to the host-generic `audit.fleet.lab`, no per-host state); then this row's `rsyslog_remote_loghost` should pass. |
| 7 | **Smart card login** (`require_smart_card_login`, `sssd_enable_smartcard`, `install_smartcard_packages`) | Diskless hosts have no smartcard reader; admin access is SSH key-based. Enforcing smartcard login would lock the host out. | Admin auth is an SSH **key-only** account; root is locked; password auth disabled. |
| 8 | **NOPASSWD sudo** (`sudo_remove_nopasswd`) | The baked admin is a **passwordless, key-only** account, so `sudo` cannot prompt for a password — NOPASSWD is required for it to function at all. | Single fleet-generic admin, key-only, `wheel`; no interactive password exists to protect. Tracked for the eventual per-host/rotatable access model (SSH CA / config-agent). |
| 9 | **GUI / autologin / GDM** (gnome screensaver, GDM banner, automatic-login rules) | No GNOME/GDM is installed; the kiosk is an **intentional** autologin single-app (weston + Chromium) session on kiosk builds. | Kiosk user is unprivileged and passwordless; the session runs a single locked-down browser (no shell, no nav). Applies to kiosk builds only; non-kiosk builds don't install the GUI stack. |