Merge remote-tracking branch 'origin/main' into poam-hardening

# Conflicts:
#	CLAUDE.md
This commit is contained in:
Audiobuzz
2026-07-12 05:54:41 +00:00
18 changed files with 1277 additions and 84 deletions
+48 -7
View File
@@ -11,10 +11,11 @@ control. The per-build **generated** report
post-remediation scan) cross-references this file: any non-`pass` rule **not**
listed here is flagged **REVIEW**.
Posture decisions (2026-06-18, lab phase):
Posture decisions (2026-06-18, lab phase; offload updated 2026-07-12):
- **FIPS: OFF** — revisit alongside UKI signing / Secure Boot.
- **Audit offload: LOCAL-only** — auditd runs and logs to the tmpfs overlay; no
remote collector yet.
- **Audit offload: REMOTE over syslog-TLS** — audisp-syslog + rsyslog `omfwd`
(gtls :6514, fleet-CA x509/name) to `serving/audit-collector` (see row 6;
was LOCAL-only until 2026-06-19, plaintext until 2026-07-12).
- **CI: report-only** — `oscap eval` publishes ARF + HTML; never fails the build.
## Intentional deviations
@@ -109,8 +110,9 @@ SELinux user (`semanage login`) so the `staff_r`→`sysadm_r` sudo transition is
authorized at runtime. `staff_u` (not `sysadm_u`) is used so SSH login isn't gated
by the `ssh_sysadm_login` boolean. **⚠ Two bench gates before trusting:** (a)
admin SSH login + `sudo` + every privileged op must work under `staff_u`
confinement — if it locks out, `enable_stig=false` is the escape hatch and this
reverts to a justified deviation; (b) reproducibility — `semanage` rebuilds the
confinement — if it locks out, waive the offending rule in the tailoring as a
justified deviation (STIG is now enforced-true — there is no `enable_stig=false`
escape hatch, POA&M P-03); (b) reproducibility — `semanage` rebuilds the
SELinux policy store, so confirm the verity hash is stable across two builds (and
normalize in 2d hygiene if it drifts).
@@ -135,7 +137,8 @@ reboot** — it cannot exfiltrate data, alter the read-only root, or bypass auth
a shell. Authenticated reboot paths (`systemctl reboot` over the key-only admin
SSH session) are unaffected either way. The console itself is otherwise locked
down (kiosk autologin to a single locked browser; no getty shell on tty1;
`debug_shell` is lab-only and never shipped). If a future deployment wants the
the `debug_shell` back-door was removed from the template entirely, 2026-07-11).
If a future deployment wants the
hotkey disabled (e.g. a physically exposed terminal), re-select both rule IDs.
## 14. Local SELinux policy module `chrony_dhcp_dispatcher` (added 2026-07-03)
@@ -214,7 +217,9 @@ turns app-allowlisting ON for the whole root at runtime for the first time**, so
**BENCH-VERIFY HARD:** boot + kiosk render + admin SSH + sudo + TPM enrolment all
still work (nothing legit is untrusted — the 4 custom binaries + rpmdb are trusted),
a novel `/tmp` binary is now **blocked** (EPERM), and no new AVCs (extend the `.te`
if any). `enable_stig=false` is the escape hatch if it regresses the boot/secure path.
if any). If it regresses the boot/secure path, waive the offending rule in the
tailoring as a justified deviation — STIG is enforced-true (no `enable_stig=false`
escape hatch, POA&M P-03).
**VERIFIED 2026-07-04 (build `fapolicyd-tmpfs-12043d3`, host `comet-beacon-54`) —
enforcing, no false positives.** `fapolicyd active (running)`, `permissive = 0`,
@@ -289,6 +294,42 @@ boot; (b) no other chrony-log AVC (extend here if one appears); (c)
**reproducibility** — `semodule -i` rebuilds the policy store, re-check verity hash
stability (same concern as #14/#15). Only shipped when `enable_stig=true`.
## 17. STIG NTP-server rules unselected under `secure_ntp` (added 2026-07-11)
**Rules waived:** `chronyd_specify_remote_server`, `chronyd_or_ntpd_set_maxpoll`
(unselected in `diskless-tailoring.xml`; plus a belt-and-suspenders re-strip in
`2c-STIG-postfix`).
**Why:** these rules remediate by writing a **static, unauthenticated**
`server <pool> maxpoll 16` into `/etc/chrony.conf`. The fleet instead configures
chrony's time source **dynamically at runtime** — a **fleet-CA-authenticated NTS**
server derived from the DHCP domain (`secure_ntp=true`, RFC 8915) or DHCP option-42
(`false`) — via the NM dispatcher writing `sourcedir /run/chrony-dhcp`, with
`ntstrustedcerts`/`nocerttimecheck` baked. The STIG *intent* (time is synchronised,
and under NTS **authenticated**) is fully met; the rules only fail because they
look for a literal baked `server` line the fleet deliberately doesn't have.
**The security reason this is not just cosmetic (F-03/P-18):** the ordering is the
trap — `2c-STIG` runs **after** the `secure_ntp` chrony step, so an un-waived
`chronyd_specify_remote_server` **re-injects** a plain `server 0.us.pool.ntp.mil
maxpoll 16` that the earlier step already commented out. That plain server is a
**silent unauthenticated fallback**: with it present, chrony will happily sync
non-NTS time, so a DHCP/DNS/NTP spoofer could shift the clock — defeating the whole
point of NTS. Leaving it in means the host is **not fail-closed**. Observed on
`comet-beacon-54` 2026-07-11: NTS working (`chronyc authdata` cookies > 0) *and* the
STIG `0.us.pool.ntp.mil` line still in `chrony.conf` and syncing in parallel.
**Fix:** unselect the two rules (so remediation injects nothing) **and**, when
`secure_ntp=true`, re-comment any `server`/`pool` in `2c-STIG-postfix` (in case a
future rule adds one) so **only** the NTS `sourcedir` + `ntstrustedcerts` remain.
Under `secure_ntp=false` the re-strip does not run (the DHCP option-42 dispatcher
path needs the handed servers).
**BENCH-VERIFY:** on a clean secure_ntp build, `grep -E '^(server|pool)'
/etc/chrony.conf` returns nothing (only `sourcedir`/`ntstrustedcerts`), and
`chronyc -N authdata` shows the NTS source with cookies > 0 as the **only** selected
source (no `0.us.pool.ntp.mil` fallback). Only applies when `enable_stig=true`.
## Things that are NOT deviations (kept / enforced)
- **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).