From 4e9ab45d34d35b58c6b2a3e4c15c68697625560b Mon Sep 17 00:00:00 2001 From: Audiobuzz Date: Sun, 12 Jul 2026 06:43:00 +0000 Subject: [PATCH] =?UTF-8?q?2c-STIG:=20sudo=20SELinux=20elevation=20rule=20?= =?UTF-8?q?must=20be=20%wheel=20=E2=80=94=20SSG=20OVAL=20only=20matches=20?= =?UTF-8?q?%group=20sudoers=20rules?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The per-user rule elevated fine at runtime (bench-verified staff_u->sysadm_r on comet-beacon-54) but scanned fail: the OVAL patterns are ^\s*%\w+.*TYPE=/ROLE=, so only a %group rule can pass. Write the drop-in as %wheel (the admin is a wheel member; same file 2c wrote, so no unconfined per-user rule survives). --- diskless.pkr.hcl | 11 ++++++++--- docs/TODO.md | 30 ++++++++++++++++++------------ docs/stig-deviations.md | 28 ++++++++++++++++------------ 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/diskless.pkr.hcl b/diskless.pkr.hcl index 9df6aee..723c386 100644 --- a/diskless.pkr.hcl +++ b/diskless.pkr.hcl @@ -933,8 +933,13 @@ build { # SELinux context. SSG ships no auto-fix. Decision (2026-06-20): # REMEDIATE WITH CONFINEMENT. Two parts: # 1. Rewrite the admin sudoers rule to add the role/type transition - # (KEEP NOPASSWD — the admin is key-only; #8). This is what the - # OVAL check looks for, so it makes the rule pass. + # (KEEP NOPASSWD — the admin is key-only; #8). The rule MUST be a + # **%group rule** (%wheel — the admin is a wheel member): the SSG + # OVAL patterns are `^\s*%\w+.*TYPE=(\w+)` / `...ROLE=(\w+)`, so a + # per-USER rule never matches and the scan fails even though the + # runtime transition works (confirmed on scan poam-hardening-5bc6d27: + # bench host elevated staff_u->sysadm_r fine, rule still `fail`). + # This replaces the per-user rule 2c wrote (same file, overwritten). # 2. Map the admin to the confined **staff_u** SELinux user so the # staff_r->sysadm_r sudo transition is actually authorized at # runtime (unconfined_u cannot reach sysadm_r). staff_u (NOT @@ -949,7 +954,7 @@ build { "if [ -n \"$ADMIN_USER\" ] && id \"$ADMIN_USER\" >/dev/null 2>&1; then", " echo \"==> supplemental: sudo SELinux elevation — confining $ADMIN_USER to staff_u + sudoers role/type\"", " command -v semanage >/dev/null 2>&1 || dnf install -y policycoreutils-python-utils", - " printf '%s ALL=(ALL) TYPE=sysadm_t ROLE=sysadm_r NOPASSWD:ALL\\n' \"$ADMIN_USER\" > \"/etc/sudoers.d/$ADMIN_USER\"", + " printf '%%wheel ALL=(ALL) TYPE=sysadm_t ROLE=sysadm_r NOPASSWD:ALL\\n' > \"/etc/sudoers.d/$ADMIN_USER\"", " chmod 0440 \"/etc/sudoers.d/$ADMIN_USER\"", " visudo -cf \"/etc/sudoers.d/$ADMIN_USER\"", " restorecon \"/etc/sudoers.d/$ADMIN_USER\"", diff --git a/docs/TODO.md b/docs/TODO.md index bc293d2..7cd376b 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -207,15 +207,19 @@ pass / N/A. mouse on real hardware — the build-VM-generated policy + default block target would otherwise lock out console input). - **`selinux_context_elevation_for_sudo` — REMEDIATED WITH CONFINEMENT - (decision 2026-06-20).** 2c-STIG now rewrites the admin sudoers to - `TYPE=sysadm_t ROLE=sysadm_r NOPASSWD:ALL` and maps the admin to **`staff_u`** - (`semanage login`) so the sudo role transition is authorized. ⚠ **TWO BENCH - GATES:** (a) admin SSH login + sudo + privileged ops must work under `staff_u` - confinement (if it locks out, waive the offending rule in the tailoring as a - justified deviation — `enable_stig=false` is no longer available, STIG is - enforced-true); (b) **reproducibility** — `semanage` rebuilds the policy store; - confirm the verity hash is stable across two builds (normalize in 2d if it - drifts). Needs `policycoreutils-python-utils` (installed in 2c-STIG if absent). + (decision 2026-06-20; scan-fix 2026-07-12).** 2c-STIG rewrites the admin + sudoers drop-in to `%wheel ALL=(ALL) TYPE=sysadm_t ROLE=sysadm_r NOPASSWD:ALL` + and maps the admin to **`staff_u`** (`semanage login`) so the sudo role + transition is authorized. **Must be a %group rule:** the first cut used a + per-user rule — runtime elevation worked (bench-verified 2026-07-12, + `comet-beacon-54`) but the SSG OVAL (`^\s*%\w+.*TYPE=`) only matches %group + rules, so the scan stayed `fail` (the 1 REVIEW row on `poam-hardening-5bc6d27`). + ⚠ **BENCH GATES:** (a) admin SSH login + sudo under `staff_u` confinement — + VERIFIED 2026-07-12 (re-confirm after the %wheel change; same account via its + group, behaviour should be identical); (b) **reproducibility** — `semanage` + rebuilds the policy store; confirm the verity hash is stable across two builds + (normalize in 2d if it drifts). Needs `policycoreutils-python-utils` + (installed in 2c-STIG if absent). **Expected next-build report: 0–1 REVIEW** (0 if both postfix→N/A and usbguard→pass land and sudo confinement holds; the triage was validated by @@ -1000,10 +1004,12 @@ smoke test. record **drained losslessly** after the real cert was restored (original timestamp preserved); STIG scan of record: all three `rsyslog_encrypt_offload_*` rules **pass**, 401 pass / 1 fail, 0 new - REVIEW rows (the 1 remaining REVIEW is the pre-existing + REVIEW rows (the 1 remaining REVIEW was the pre-existing `selinux_context_elevation_for_sudo` — runtime behaviour verified working - on the same host, likely an OVAL word-order artifact: the check may want - `ROLE=... TYPE=...` where 2c-STIG writes `TYPE=... ROLE=...` — follow-up). + on the same host; ROOT CAUSE found in the ARF and FIXED 2026-07-12: the SSG + OVAL only matches **%group** sudoers rules (`^\s*%\w+.*TYPE=`), and 2c-STIG + wrote a per-user rule — now writes `%wheel ...`; next scan should be 0 + REVIEW). Bench gotcha worth keeping: the smallstep password file location varies by image version (`$STEPPATH/password` vs `$STEPPATH/secrets/password`) — issue-cert.sh probes both (fixed 2026-07-12 after hitting it live). diff --git a/docs/stig-deviations.md b/docs/stig-deviations.md index 60c2be9..33664dc 100644 --- a/docs/stig-deviations.md +++ b/docs/stig-deviations.md @@ -103,18 +103,22 @@ private keys stored on the host; host keys regenerate per boot). SSG ships no automated fix; the STIG manual remediation (`... TYPE=sysadm_t ROLE=sysadm_r ...`) requires the admin to reach the `sysadm_r` role, which `unconfined_u` cannot. So the provisioner (2c-STIG) now -(1) rewrites the admin sudoers rule to ` ALL=(ALL) TYPE=sysadm_t -ROLE=sysadm_r NOPASSWD:ALL` (keeps NOPASSWD — the admin is key-only, #8 — and is -what the OVAL check matches), and (2) maps the admin to the confined **`staff_u`** -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, 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). +(1) rewrites the admin sudoers drop-in to `%wheel ALL=(ALL) TYPE=sysadm_t +ROLE=sysadm_r NOPASSWD:ALL` (keeps NOPASSWD — the admin is key-only, #8), and +(2) maps the admin to the confined **`staff_u`** 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. **Scan-vs-runtime finding (2026-07-12, scan `poam-hardening-5bc6d27`):** +the first cut wrote a per-USER rule (` ALL=...`), which elevates fine at +runtime (bench host `comet-beacon-54`: `sudo id` → +`staff_u:sysadm_r:sysadm_t`) but the rule still scanned **fail** — the SSG OVAL +patterns (`^\s*%\w+.*TYPE=(\w+)` / `...ROLE=(\w+)`) only match **%group** +rules. Fixed by writing the rule for `%wheel` (the admin is a wheel member); +next scan should pass. **Bench status:** (a) SSH login + sudo under `staff_u` +confinement VERIFIED 2026-07-12 (re-check after the %wheel change — behaviour +should be identical, the rule targets the same account via its group); (b) +reproducibility of the verity hash across two builds (semanage rebuilds the +policy store) — still open. ## 13. Ctrl+Alt+Del console reboot hotkey kept enabled (decision 2026-06-20)