Fixed the secure boot enrollment script
This commit is contained in:
+28
-2
@@ -622,10 +622,29 @@ smoke test.
|
||||
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.
|
||||
- **Signing — SIGNED-UKI + SECURE-BOOT-ON PATH BENCH-VERIFIED on the Proxmox VM
|
||||
(HTTP boot, 2026-06-20).** CI signs the UKI when `SB_KEY`/`SB_CERT` secrets are
|
||||
set (`db` key); `fleet-sb-enroll` enrols db→KEK→PK from the baked public `.auth`
|
||||
files; OVMF then boots the signed UKI under enforcing Secure Boot. Confirmed
|
||||
end-to-end: CI-signed UKI verifies (`sbverify`), enrolment succeeds, VM boots
|
||||
with `mokutil --sb-state` = enabled.
|
||||
**Key generation + enrolment procedure: [secure-boot-keys.md](secure-boot-keys.md)**
|
||||
(the PK/KEK/db trio; `db` = `sb_key`/`sb_cert`, PK/KEK stay offline).
|
||||
- **Bug fixed during bring-up (2026-06-20):** `fleet-sb-enroll` built its 4-byte
|
||||
EFI attribute prefix in a bash variable (`ATTR=$'\x27\x00\x00\x00'`). Bash
|
||||
strings can't hold NULs → only `0x27` survived → efivarfs read a corrupt
|
||||
attribute u32 → every write failed with `EINVAL` ("dd: Invalid argument").
|
||||
Now emitted directly with `printf` at write time. (Red herring on the way:
|
||||
Proxmox EFI disks default to `pre-enrolled-keys=1`, so `mokutil --db` shows
|
||||
the MS cert even in Setup Mode — looked like a non-empty-db rejection but was
|
||||
the NUL bug all along; it failed identically on a clean `pre-enrolled-keys=0`
|
||||
disk.)
|
||||
- **REMAINING for production:** (a) **secure path** — re-verify signed boot with
|
||||
`disable_dot1x=false` (802.1X/MACsec), not just the test path; (b) **820 / PXE
|
||||
path** — sign `snponly.efi` with the same `db` key so the iPXE front-end also
|
||||
passes Secure Boot (the VM's HTTP path has no iPXE stage, so this is still
|
||||
unverified on real PXE hardware); (c) confirm signing is reproducible (verity
|
||||
hash stable across two signed builds).
|
||||
- **PXE-only iPXE fallback — BENCH-VERIFIED on the EliteBook 820 G4 (2026-06-20).**
|
||||
Firmware without UEFI HTTP boot chainloads `serving/tftp/snponly.efi` → renders
|
||||
`autoexec.ipxe` (ifopen + DHCP-retry + `imgargs <real cmdline>`) → UKI over HTTP
|
||||
@@ -638,6 +657,13 @@ smoke test.
|
||||
(iii) iPXE aborts the script on any unguarded command failure (use `||`);
|
||||
(iv) Secure Boot OFF makes systemd-stub take iPXE's load options as the cmdline,
|
||||
so the entrypoint extracts the UKI's real `.cmdline` and feeds it via `imgargs`.
|
||||
**Tidied 2026-06-20** once PortFast was identified: dropped the `autoexec.ipxe` +
|
||||
`ifopen` + DHCP-retry STP workaround; `boot.ipxe` is now just
|
||||
`dhcp`+`imgfetch`+`imgargs`+`boot` reached via normal iPXE autoboot. Re-verified
|
||||
on the 820 G4. **SB-on simplification:** when Secure Boot is enabled the cmdline
|
||||
injection is unnecessary (the stub ignores the loader cmdline) — collapse
|
||||
`boot.ipxe` to a plain `chain` of the UKI and drop the `.cmdline` extraction +
|
||||
`binutils` + the artifact mount from the dnsmasq service.
|
||||
- **Sign iPXE for the PXE-only fallback (Secure Boot, production).** The lab
|
||||
`snponly.efi` is **UNSIGNED** → that path needs **Secure Boot OFF**. For
|
||||
production: `sbsign` the iPXE binary with the fleet **db** key (only `db` needed —
|
||||
|
||||
@@ -130,6 +130,35 @@ on a trusted/isolated network (see TODO #10).
|
||||
Only the **public** certs/`.esl`/`.auth` reach the workstation — never copy
|
||||
`PK.key`/`KEK.key`/`db.key` onto a host.
|
||||
|
||||
### Troubleshooting `fleet-sb-enroll` (bench, 2026-06-20)
|
||||
|
||||
**`dd: ... Invalid argument` (EINVAL) on the `db` write** = the firmware's
|
||||
`SetVariable` rejected the payload (EFI_INVALID_PARAMETER), *not* an auth/Setup
|
||||
Mode failure (that surfaces as EACCES / "Permission denied"). Diagnose top-down:
|
||||
|
||||
- **Is the `.auth` actually a signed authenticated variable?** First 16 bytes are
|
||||
an `EFI_TIME`: `sudo od -An -tx1 -N16 db.auth` → a valid one starts with the
|
||||
year little-endian (2026 = `ea 07`). If it starts with `a1 59 c0 a5 …` it's a
|
||||
bare **ESL** (the `sign-efi-sig-list` step was skipped); `30 82 …` is a raw DER
|
||||
cert. Re-create the `.auth` (step 2) and re-bake.
|
||||
- **The 4-byte attribute prefix must contain its NUL bytes.** A bash *variable*
|
||||
**cannot** hold NULs — `ATTR=$'\x27\x00\x00\x00'` silently truncates to the
|
||||
single byte `0x27`, so efivarfs reads a corrupt attribute u32 and the kernel
|
||||
returns EINVAL **before the firmware is even called**. This was a real bug in an
|
||||
early `fleet-sb-enroll`; the fix emits the prefix with `printf '\x27\x00\x00\x00'`
|
||||
at write time (never via a variable). If you hand-roll an enrolment, do the same.
|
||||
- **Proxmox / OVMF red herring:** VM EFI disks default to `pre-enrolled-keys=1`,
|
||||
so `mokutil --db` shows the **Microsoft** cert (`Windows Production PCA 2011`,
|
||||
owner `77fa9abd-…`) *even in Setup Mode*. This looks like a "db not empty →
|
||||
rejected" problem but isn't — the write fails identically on a clean
|
||||
`pre-enrolled-keys=0` disk if the NUL bug is present. For a clean OVMF test bed:
|
||||
`qm set <vmid> --efidisk0 <storage>:1,efitype=4m,pre-enrolled-keys=0`.
|
||||
|
||||
**Verified:** with the fix, a Proxmox VM enrols db→KEK→PK from the baked `.auth`
|
||||
files and boots the CI-signed UKI under **enforcing Secure Boot** over the HTTP
|
||||
boot path (`mokutil --sb-state` = enabled). The PXE/iPXE front-end additionally
|
||||
needs `snponly.efi` signed with `db` — see the iPXE section below.
|
||||
|
||||
## 4. Wire `db` into the build
|
||||
|
||||
```bash
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
>
|
||||
> **A&A framework:** ASD *Information Security Manual* (ISM) — engagement target
|
||||
> **May 2026 release**.
|
||||
>
|
||||
> **Annex version:** 0.2 (2026-06-20). v0.2 reflects: STIG hardening applied +
|
||||
> bench-verified, USBGuard device control enabled, admin `staff_u` confinement,
|
||||
> audit offload verified, UKI signing wired (not yet enforced — new R-13),
|
||||
> PXE/iPXE boot path added.
|
||||
|
||||
---
|
||||
|
||||
@@ -74,8 +79,9 @@ ISM/PSPF style). Ratings are **pre-treatment** unless stated; the AO accepts the
|
||||
|
||||
| Topic | ISM (rep.) | Requirement intent | System implementation | Status | Residual |
|
||||
|---|---|---|---|---|---|
|
||||
| Hardened OS to ASD/vendor guidance | ISM-1407*, ISM-1408* | Apply a recognised hardening baseline. | **DISA STIG** (SSG `profile_stig`, RHEL 9) via `oscap --remediate` with documented tailoring ([stig-deviations.md](stig-deviations.md)). | Partial | R-03 (CI report-only/disabled now) |
|
||||
| Application control / allow-listing | ISM-0843*, ISM-1490*, ISM-1657* | Only approved executables run. | **fapolicyd** (RPM-trust + one trusted kiosk binary) + immutable dm-verity root. | Implemented | — |
|
||||
| Hardened OS to ASD/vendor guidance | ISM-1407*, ISM-1408* | Apply a recognised hardening baseline. | **DISA STIG** (SSG `profile_stig`, RHEL 9) via `oscap --remediate` + documented tailoring + per-build deviations report ([stig-deviations.md](stig-deviations.md)); **applied + bench-verified 2026-06-20**, all REVIEW rows triaged. | Partial | R-03 (CI must ship `enable_stig=true` + signed/SB-on) |
|
||||
| Application control / allow-listing | ISM-0843*, ISM-1490*, ISM-1657* | Only approved executables run. | **fapolicyd** (RPM-trust + two trusted local binaries: kiosk-session, fleet-sb-enroll) + immutable dm-verity root. | Implemented | — |
|
||||
| Device / removable-media control | ISM-0341*, ISM-1551* | Control USB / peripheral devices. | **USBGuard enforcing** (`ImplicitPolicyTarget=block` + hardware-independent HID/hub allowlist + LinuxAudit). Verified: USB mass storage blocked, console input preserved. | Implemented | — |
|
||||
| Software / OS integrity | ISM-1493* | Detect unauthorised modification. | **dm-verity** continuous block-level verification of the read-only root against a signed hash; **reproducible** build. | Implemented | — |
|
||||
| Disable unneeded functionality | ISM-0380*, ISM-1416* | Minimise installed software/services. | `@^minimal` install; scanner tooling removed post-scan; FROM-scratch artifact image; kiosk = single app. | Implemented | — |
|
||||
| Hardened user applications (browser) | ISM-1486*, ISM-1412* | Lock down high-risk apps. | Chromium enterprise lockdown policy; weston kiosk; no shell/nav/plugins. | Implemented | — |
|
||||
@@ -89,7 +95,7 @@ ISM/PSPF style). Ratings are **pre-treatment** unless stated; the AO accepts the
|
||||
| Topic | ISM (rep.) | Requirement intent | System implementation | Status | Residual |
|
||||
|---|---|---|---|---|---|
|
||||
| Strong machine authentication | ISM-1546*, ISM-0974* | Mutual, certificate-based auth. | **802.1X EAP-TLS**, client key non-exportable in **TPM** (`0x81010001`), cert in TPM NV. | Partial | R-01 (not bench-verified; disabled in test builds), R-08 (placeholder CA) |
|
||||
| Privileged access restricted | ISM-1507*, ISM-0445* | Limit & control admin access. | Single key-only `wheel` admin; root login disabled. | Partial | R-05 |
|
||||
| Privileged access restricted | ISM-1507*, ISM-0445* | Limit & control admin access. | Single key-only `wheel` admin; root login disabled; admin **confined to `staff_u`** with a sudo `sysadm_r`/`sysadm_t` role/type transition (SELinux context elevates on privilege use). | Partial | R-05 |
|
||||
| Secure remote administration | ISM-1506*, ISM-1232* | Hardened admin channel. | SSH **key-only**, password & keyboard-interactive off, hardened ciphers/MACs/KEX (STIG crypto policy; ECDSA/RSA keys — ed25519 excluded by policy). | Implemented | — |
|
||||
| No default/shared credentials | ISM-1304* | No baked credentials. | No per-host secrets in any artifact; identity from TPM at runtime; `machine-id` empty; host keys regenerated at first boot. | Implemented | — |
|
||||
| MFA for privileged users | ISM-1173*, ISM-1504* | MFA on privileged access. | Machine auth is cert+TPM (strong). **Human admin MFA on the management plane not yet enforced.** | Partial | R-05 |
|
||||
@@ -109,7 +115,7 @@ ISM/PSPF style). Ratings are **pre-treatment** unless stated; the AO accepts the
|
||||
|
||||
| Topic | ISM (rep.) | Requirement intent | System implementation | Status | Residual |
|
||||
|---|---|---|---|---|---|
|
||||
| Centralised event logging | ISM-0988*, ISM-1405* | Logs centrally collected. | `audisp-syslog`→rsyslog `omfwd` (disk-assisted queue) → dedicated collector (`serving/audit-collector/`). | Partial | R-07 |
|
||||
| Centralised event logging | ISM-0988*, ISM-1405* | Logs centrally collected. | `audisp-syslog`→rsyslog `omfwd` (disk-assisted queue) → dedicated collector (`serving/audit-collector/`); **bench-verified end-to-end 2026-06-20**. auditd `space_left_action`→syslog (no MTA). | Partial | R-07 |
|
||||
| Required events logged | ISM-0582*, ISM-1537* | Log security-relevant events. | STIG auditd rule set; kernel `audit=1`, `audit_backlog_limit=8192`. | Implemented | — |
|
||||
| Protect logs in transit | ISM-1432*, ISM-0407* | Encrypt/authenticate log transport. | **Plaintext** offload on isolated LAN (rsyslog TLS rules waived — see [STIG #6](stig-deviations.md)). | Waived (lab) | **R-07** |
|
||||
| Log retention & integrity | ISM-0859*, ISM-1815* | Retain & protect logs. | Per-source-host files on collector; retention policy & tamper-protection not yet defined. | Planned | R-07 |
|
||||
@@ -144,7 +150,7 @@ ISM/PSPF style). Ratings are **pre-treatment** unless stated; the AO accepts the
|
||||
| Topic | ISM (rep.) | Requirement intent | System implementation | Status | Residual |
|
||||
|---|---|---|---|---|---|
|
||||
| Media sanitisation / no data remanence | ISM-0347*, ISM-1218* | Prevent data remanence. | **Diskless** — no persistent local media; writable layer is **RAM tmpfs**, gone at power-off. | Implemented | — |
|
||||
| Tamper-evidence / boot integrity | ISM-1542*, ISM-0312* | Detect firmware/boot tampering. | **UEFI Secure Boot** + signed UKI + immutable signed cmdline + dm-verity; TPM measurements available for attestation. | Partial | R-11 (remote attestation not yet implemented) |
|
||||
| Tamper-evidence / boot integrity | ISM-1542*, ISM-0312* | Detect firmware/boot tampering. | Design: **UEFI Secure Boot** + signed UKI (+ signed iPXE on the PXE path) + immutable signed cmdline + dm-verity; TPM measurements available. Signing **wired in CI** + key/enrolment procedure + baked `fleet-sb-enroll` helper, but **lab runs unsigned with SB OFF**. | Partial | **R-13** (signing not enforced), R-11 (no remote attestation) |
|
||||
| Device identification | ISM-1195* | Uniquely identify devices. | Identity derived from TPM cert (hostnqn from cert serial); no spoofable per-host config. | Implemented | — |
|
||||
|
||||
### 2.11 Guidelines for Procurement, Outsourcing & Evaluated Products
|
||||
@@ -165,11 +171,12 @@ asked to accept. Treatments map to [docs/TODO.md](TODO.md) (working POA&M).
|
||||
|---|---|---|---|---|---|---|---|
|
||||
| **R-01** | Secure path (802.1X EAP-TLS + MACsec) **implemented but not bench-verified end-to-end**; disabled in test builds (`disable_dot1x=true`). Until verified, devices may attach to an unauthenticated/unencrypted link. | 2.4, 2.7, 2.8 (ISM-1546*, 0520*, 1187*) | Likely × Major → **High** | Test path on an isolated lab LAN; full auth stack present (dormant); design follows ASD intent. | Full boot-chain bench test (swtpm + hostapd + FreeRADIUS): port `Authorized`, macsec0 addressed, MKA survives switch-root, NVMe root mounts. Re-enable in CI. | **Low** (once verified) | Platform team — *before production ATO* |
|
||||
| **R-02** | `debug_shell=true` bakes a **passwordless root shell** on a tty — an undocumented privileged access path. | 2.5 (ISM-1491*) | Possible × Severe → **High** | Lab-only; physical access required; isolated environment. | Set `debug_shell=false` for all non-lab builds; assert absent in CI. | **Low** | Platform team — *before production* |
|
||||
| **R-03** | STIG hardening currently **report-only / disabled in CI** (`enable_stig=false`); shipped images may be unhardened. | 2.3 (ISM-1407*/1408*) | Possible × Major → **Medium** | Tailoring + register exist; SELinux/fapolicyd still on; re-enable is a single flag. | Flip `ENABLE_STIG="true"`; confirm scan evaluates >0 rules; triage REVIEW rows (buckets A/B/C in TODO #2). | **Low** | Platform team — *before assessment* |
|
||||
| **R-03** | STIG hardening **applied + bench-verified** (2026-06-20, all REVIEW rows triaged); residual is ensuring **CI ships `enable_stig=true`** for production builds (it was toggled off during bring-up). | 2.3 (ISM-1407*/1408*) | Possible × Moderate → **Medium** | Tailoring + register + per-build report; SELinux/fapolicyd/USBGuard on; verified on a real hardened build. | Confirm `ENABLE_STIG="true"` in CI; keep the 0-eval guard; re-run the deviations report on the assessed build. | **Low** | Platform team — *before assessment* |
|
||||
| **R-04** | NVMe/TCP **root traffic plaintext** on the LAN — exposure of OS content / injection if the segment is compromised. | 2.9 (ISM-1139*/1453*) | Unlikely × Major → **Medium** | Isolated boot LAN; MACsec on the access link (once R-01 done) protects the first hop; dm-verity makes injected root blocks fail verification (integrity preserved even if confidentiality isn't). | Production: TLS/IPsec for the storage transport, or rely on MACsec end-to-end across the fabric; document the decision. | **Low–Medium** | Platform/network — *production* |
|
||||
| **R-05** | **NOPASSWD key-only admin**; no per-host or rotatable access model; human admin MFA on the mgmt plane not enforced. | 2.4 (ISM-1507*/1173*) | Possible × Moderate → **Medium** | Single fleet-generic admin, key-only, root disabled, ECDSA/RSA key, fully audited; no interactive password to attack. | Per-host/rotatable access (SSH CA / config-agent) + admin MFA on the management plane. | **Low–Medium** | Platform team — *roadmap* |
|
||||
| **R-05** | **NOPASSWD key-only admin**; no per-host or rotatable access model; human admin MFA on the mgmt plane not enforced. | 2.4 (ISM-1507*/1173*) | Possible × Moderate → **Medium** | Single fleet-generic admin, key-only, root disabled, ECDSA/RSA key, **now SELinux-confined to `staff_u`** with sudo role/type elevation, fully audited; no interactive password to attack. | Per-host/rotatable access (SSH CA / config-agent) + admin MFA on the management plane. | **Low–Medium** | Platform team — *roadmap* |
|
||||
| **R-06** | **FIPS off**; ISM **AACA/AACP conformance not formally asserted**; crypto-module evaluation status unconfirmed. | 2.9 (ISM-0471*/1139*/1277*) | Possible × Major → **Medium** | Modern STIG crypto policy; non-exportable TPM key; no deliberately weak algorithms. Acceptable at OFFICIAL; **mandatory to resolve for PROTECTED+.** | Assert AACA/AACP conformance; decide on FIPS module / evaluated crypto alongside Secure Boot signing. | **Low** (at appropriate classification) | Security + Platform — *before PROTECTED+* |
|
||||
| **R-07** | Audit-log **offload plaintext**, **single-site**, **no SIEM alerting**; logs interceptable/repudiable and not actively reviewed. | 2.6 (ISM-1432*/0109*/0859*) | Possible × Moderate → **Medium** | Isolated LAN; disk-assisted queue (no loss on collector blip); auditd local copy; per-source files. | rsyslog **TLS** (gtls/6514) + bundle CA in image (re-select the 3 waived `rsyslog_encrypt_offload_*` rules); define retention + integrity; forward to SIEM with alerting. | **Low** | Platform/SecOps — *production* |
|
||||
| **R-07** | Audit-log **offload plaintext**, **single-site**, **no SIEM alerting**; logs interceptable/repudiable and not actively reviewed. (Transport **bench-verified working** 2026-06-20.) | 2.6 (ISM-1432*/0109*/0859*) | Possible × Moderate → **Medium** | Isolated LAN; disk-assisted queue (no loss on collector blip); auditd local copy; per-source files; LinuxAudit captures USBGuard events. | rsyslog **TLS** (gtls/6514) + bundle CA in image (re-select the 3 waived `rsyslog_encrypt_offload_*` rules); define retention + integrity; forward to SIEM with alerting. | **Low** | Platform/SecOps — *production* |
|
||||
| **R-13** | **Boot chain unsigned / Secure Boot OFF** in the lab — the UKI and (on the PXE path) iPXE are not signed and SB is not enforced, so a substituted boot artifact would not be rejected by firmware. | 2.10 (ISM-1542*/0312*) | Possible × Major → **Medium** | dm-verity still rejects a tampered *root*; isolated lab LAN; signing is **wired in CI** + key/enrolment procedure + baked `fleet-sb-enroll` ready; only the enforcement is pending. | Enrol fleet `db` (PK/KEK/db per [secure-boot-keys.md](secure-boot-keys.md)); set `SB_KEY`/`SB_CERT` CI secrets; `sbsign` the UKI **and** iPXE; enable Secure Boot on targets. | **Low** | Platform team — *before production* |
|
||||
| **R-08** | **Placeholder RADIUS CA** (`files/etc/dot1x/radius-ca.pem`) — real EAP-TLS trust anchor not provisioned; auth cannot succeed and trust is unestablished. | 2.4 (ISM-1546*) | Certain (lab) × Major → **Medium** | Documented as a placeholder; environment-specific provisioning is the intended path; no real CA committed. | Provision the environment's real RADIUS CA out-of-band (not committed unless classification permits). | **Low** | Environment owner — *before production* |
|
||||
| **R-09** | **Host firewall disabled**; host exposes more network surface than necessary. | 2.7 (ISM-1416*) | Possible × Moderate → **Low–Medium** | Isolated LAN; minimal services; egress controlled at the network/serving layer; no kiosk inbound. | Re-enable firewalld with explicit allow rules (NVMe/TCP `:4420`, DHCP, log offload, SSH) once the secure path is verified. | **Low** | Platform/network — *after R-01* |
|
||||
| **R-10** | **Patch SLA undefined** — no documented cadence for rebuilding/redeploying against new CVEs. | 2.5 (ISM-1144*/1472*) | Likely × Moderate → **Medium** | Atomic rebuild/redeploy model makes patching fast & uniform; reproducible builds. | Define patch cadence & critical-CVE SLA; automate rebuild triggers. | **Low** | Platform team — *roadmap* |
|
||||
@@ -192,10 +199,12 @@ Likelihood ↓
|
||||
```
|
||||
|
||||
*The heatmap shows pre-treatment positions; every item has a treatment to Low /
|
||||
Low–Medium. The AO is asked to authorise on the basis that R-01, R-02, R-03, R-08
|
||||
and R-12 are **closed before production**, and R-04/R-05/R-06/R-07/R-09/R-10/R-11
|
||||
are either accepted with compensating controls (isolated-LAN lab) or carried on
|
||||
the POA&M with target dates.*
|
||||
Low–Medium. The AO is asked to authorise on the basis that **R-01, R-02, R-08,
|
||||
R-12 and R-13** (and confirming R-03's `enable_stig=true`) are **closed before
|
||||
production**, and R-04/R-05/R-06/R-07/R-09/R-10/R-11 are either accepted with
|
||||
compensating controls (isolated-LAN lab) or carried on the POA&M with target
|
||||
dates. Newly strengthened in v0.2: device control (USBGuard, now Implemented),
|
||||
admin SELinux confinement (R-05), and STIG applied+verified (R-03 reduced).*
|
||||
|
||||
---
|
||||
|
||||
@@ -215,6 +224,11 @@ the POA&M with target dates.*
|
||||
anything flagged **REVIEW** is an unjustified finding.
|
||||
6. **Confirm lab-only flags are off** in the assessed build: `debug_shell=false`,
|
||||
`enable_stig=true`, `disable_dot1x=false`, real RADIUS CA in place.
|
||||
7. **Confirm boot-chain signing is enforced** (R-13): `db` enrolled, Secure Boot
|
||||
ON, UKI + iPXE signed (`sbverify`). The PXE/iPXE path's SB-OFF cmdline
|
||||
workaround should be a no-op once SB is on.
|
||||
8. **Witness device control** (USBGuard): a USB mass-storage device is blocked and
|
||||
logged, console HID still works.
|
||||
|
||||
---
|
||||
|
||||
|
||||
+69
-28
@@ -15,10 +15,10 @@
|
||||
|---|---|
|
||||
| System name | Diskless Fleet Boot System ("the fleet") |
|
||||
| Document type | System Security Plan (SSP) |
|
||||
| Version | 0.1 (DRAFT — pre-assessment) |
|
||||
| Date | 2026-06-19 |
|
||||
| Version | 0.2 (DRAFT — pre-assessment) |
|
||||
| Date | 2026-06-20 |
|
||||
| Author / maintainer | System Owner (delegate) |
|
||||
| Status | Lab / pre-production. Secure path (802.1X/MACsec) not yet bench-verified. |
|
||||
| Status | Lab / pre-production. STIG hardening applied + bench-verified (unsigned, Secure Boot OFF); secure path (802.1X/MACsec) not yet bench-verified. |
|
||||
| Companion documents | [Annex A — ISM control cross-reference & residual risk](ssp-annex-a-ism-residual-risk.md); [Architecture design v2](diskless-fleet-design-v2.pdf); [Design errata](design-v2-errata.md); [STIG deviation register](stig-deviations.md); [Backlog / POA&M source](TODO.md) |
|
||||
|
||||
> **Currency caveat (read before relying on control numbers).** This SSP and its
|
||||
@@ -72,8 +72,19 @@ manifest. One commit = one release = one digest = one manifest entry.
|
||||
|
||||
### 2.2 Boot and trust chain (control flow)
|
||||
|
||||
1. **UEFI Secure Boot** measures and verifies the UKI signature (vendor/Secure
|
||||
Boot key) before execution.
|
||||
> **Boot transport (two paths, auto-selected):** HTTP-boot-capable firmware
|
||||
> fetches the UKI directly over UEFI HTTP boot. Firmware **without** HTTP boot
|
||||
> (e.g. HP EliteBook 820 G4) falls back to **PXE → iPXE → HTTP** (dnsmasq serves
|
||||
> iPXE over TFTP, which chainloads the same UKI). Both land on the same signed
|
||||
> UKI. **Lab status:** Secure Boot is currently **OFF** and the UKI/iPXE are
|
||||
> **unsigned** — signing is wired in CI and the key procedure is documented
|
||||
> ([secure-boot-keys.md](secure-boot-keys.md)) but not yet enforced (residual
|
||||
> R-03/signing in Annex A).
|
||||
|
||||
1. **UEFI Secure Boot** (when enabled) measures and verifies the UKI signature
|
||||
against the enrolled `db` key before execution. On the PXE/iPXE path the iPXE
|
||||
binary is likewise verified against `db`; only the fleet's own `db` need be
|
||||
enrolled (no Microsoft CA / shim).
|
||||
2. **UKI (systemd-stub)** carries the kernel, the `--no-hostonly` initramfs, and
|
||||
an **immutable, signed kernel command line** (includes the dm-verity root
|
||||
hash and STIG kernel parameters). No GRUB.
|
||||
@@ -102,7 +113,9 @@ the tmpfs overlay, the TPM-backed identity, and the hardened OS configuration.
|
||||
The boundary's external interfaces are: (a) the **access link** (802.1X-controlled
|
||||
port, MACsec-encrypted); (b) the **NVMe/TCP** root storage session; (c)
|
||||
**outbound audit log** forwarding; (d) the **kiosk application** endpoint the
|
||||
browser renders. Each crossing is a control point addressed in Annex A.
|
||||
browser renders; (e) the **boot transport** (UEFI HTTP boot, or PXE/TFTP→iPXE)
|
||||
that delivers the UKI; and (f) **USB/peripheral** ports, now mediated by USBGuard
|
||||
(§5.2). Each crossing is a control point addressed in Annex A.
|
||||
|
||||
### 2.4 Data and classification
|
||||
|
||||
@@ -151,12 +164,19 @@ This system follows the ISM A&A lifecycle:
|
||||
Milestones (POA&M)** (this repo's [TODO.md](TODO.md) is the working POA&M
|
||||
source).
|
||||
|
||||
**Current status:** Pre-assessment **DRAFT**. The system is functional in a lab
|
||||
configuration. Several controls are **partial or deferred** and are tracked as
|
||||
residual risks with treatment plans (Annex A §3). The security-critical path
|
||||
(802.1X/MACsec) is **implemented but not yet bench-verified end-to-end** and is
|
||||
currently disabled in test builds (`disable_dot1x=true`) — this is the single
|
||||
largest gate on a production authorisation.
|
||||
**Current status:** Pre-assessment **DRAFT (v0.2)**. The system is functional in a
|
||||
lab configuration. **Progress since v0.1 (2026-06-20):** DISA STIG hardening
|
||||
applied and **bench-verified** on a real build (kiosk, key-only SSH, audit
|
||||
offload, DHCP-named host, NVMe/verity root all good with hardening on); USBGuard
|
||||
device control enabled + verified; admin confined to `staff_u`; UKI signing wired
|
||||
in CI + Secure Boot key/enrolment procedure documented; both **HTTP-boot and
|
||||
PXE/iPXE** boot paths working (the latter verified on an EliteBook 820 G4).
|
||||
Several controls remain **partial or deferred**, tracked as residual risks with
|
||||
treatments (Annex A §3). The two largest gates on a production ATO: (a) the
|
||||
secure path (**802.1X/MACsec**) is implemented but **not yet bench-verified** and
|
||||
is disabled in test builds (`disable_dot1x=true`, R-01); (b) the lab runs
|
||||
**unsigned with Secure Boot OFF** (R-13) and with a lab-only **passwordless-root
|
||||
debug shell** that must be removed (R-02).
|
||||
|
||||
## 5. Security control implementation — by ISM cyber security principle
|
||||
|
||||
@@ -180,23 +200,43 @@ summarises the implementation posture.
|
||||
- **Boot & OS integrity:** **Secure Boot** + **signed UKI** with an **immutable
|
||||
cmdline**; **dm-verity** read-only root (continuous cryptographic integrity);
|
||||
**erofs** immutable filesystem; **reproducible** build (verity hash is a pure
|
||||
function of inputs).
|
||||
- **System hardening:** **DISA STIG** baseline via OpenSCAP/SSG with a documented
|
||||
tailoring; **SELinux enforcing**; **fapolicyd** application allow-listing (the
|
||||
exec guard for the writable RAM overlay that dm-verity cannot cover);
|
||||
**key-only SSH**, root login disabled, hardened ciphers/MACs/KEX; **kiosk
|
||||
lockdown** (single locked browser, no shell/navigation).
|
||||
function of inputs). Signing is **wired in CI** (`sbsign`/ukify via
|
||||
`SB_KEY`/`SB_CERT` secrets) with a documented PK/KEK/db key + enrolment
|
||||
procedure ([secure-boot-keys.md](secure-boot-keys.md)) and a baked, efitools-free
|
||||
enrolment helper (`fleet-sb-enroll`); **not yet enforced in the lab** (SB OFF,
|
||||
unsigned — see Annex A).
|
||||
- **System hardening (DISA STIG applied + bench-verified 2026-06-20):** STIG
|
||||
baseline via OpenSCAP/SSG with a documented tailoring + per-build deviations
|
||||
report; all REVIEW rows triaged. **SELinux enforcing**; **fapolicyd**
|
||||
application allow-listing (the exec guard for the writable RAM overlay dm-verity
|
||||
cannot cover); **USBGuard enforcing** (`ImplicitPolicyTarget=block` + a
|
||||
hardware-independent HID/hub allowlist + LinuxAudit — verified blocks USB mass
|
||||
storage while keeping console input; device/removable-media control); **key-only
|
||||
SSH**, root login disabled, hardened ciphers/MACs/KEX (note: STIG crypto policy
|
||||
drops ed25519 → admin key must be ECDSA/RSA); **kiosk lockdown** (single locked
|
||||
browser, no shell/navigation); **postfix removed** (no local MTA — audit-failure
|
||||
notification rides the remote offload, not email).
|
||||
- **Privileged access:** single **key-only `wheel` admin**, root locked. The admin
|
||||
is now **confined to the `staff_u` SELinux user** with a sudoers role/type
|
||||
transition (`sysadm_r`/`sysadm_t`) so privilege elevation re-labels the SELinux
|
||||
context (STIG `selinux_context_elevation_for_sudo`). Still **NOPASSWD** (the
|
||||
account is passwordless/key-only) and fleet-generic — see R-05.
|
||||
- **No persistent attack surface:** diskless; overlay discarded each boot; no
|
||||
per-host secrets in the image.
|
||||
- *Gaps / decisions:* **FIPS OFF** (lab phase); **host firewall disabled**;
|
||||
NVMe/TCP and audit offload **plaintext on the isolated LAN**; NOPASSWD key-only
|
||||
admin; **placeholder RADIUS CA**. See Annex A residual risks.
|
||||
- *Gaps / decisions:* **FIPS OFF** (lab phase); **host firewall disabled** (the
|
||||
workstation; the serving host's ufw is configured); NVMe/TCP and audit offload
|
||||
**plaintext on the isolated LAN**; NOPASSWD admin; **placeholder RADIUS CA**;
|
||||
signing not yet enforced (SB OFF). See Annex A residual risks.
|
||||
|
||||
### 5.3 Detect
|
||||
- **auditd** enabled with STIG audit rules; kernel `audit=1` +
|
||||
`audit_backlog_limit` in the signed cmdline.
|
||||
`audit_backlog_limit` in the signed cmdline. USBGuard device events logged via
|
||||
the LinuxAudit backend. auditd `space_left_action` repointed to **syslog**
|
||||
(no local MTA), so audit-volume alerts ride the remote offload.
|
||||
- **Centralised log offload** via rsyslog (`audisp-syslog` → rsyslog `omfwd`,
|
||||
disk-assisted queue) to a dedicated **audit collector** (`serving/audit-collector/`).
|
||||
**Bench-verified end-to-end 2026-06-20** (records reach the collector,
|
||||
per-source-host files).
|
||||
- *Gaps:* offload currently **plaintext** (TLS planned, R-07); offload is
|
||||
**local site only**; no SIEM correlation/alerting defined yet.
|
||||
|
||||
@@ -215,11 +255,11 @@ AO will expect a maturity view:
|
||||
|
||||
| Mitigation | Posture | Notes |
|
||||
|---|---|---|
|
||||
| Application control | **Strong** | fapolicyd allow-listing + immutable verified root; only RPM-trusted (plus one trusted kiosk binary) executables run. |
|
||||
| Application control | **Strong** | fapolicyd allow-listing + immutable verified root; only RPM-trusted (plus two trusted local binaries: kiosk-session, fleet-sb-enroll) executables run. USBGuard enforces device control on USB ports. |
|
||||
| Patch applications | **Process** | Patching = rebuild + re-sign + redeploy a new digest; cadence/SLA to be defined. |
|
||||
| Configure MS Office macros | **N/A** | No office suite; kiosk is a locked browser. |
|
||||
| User application hardening | **Strong (kiosk)** | Chromium locked down via enterprise policy; no plugins/shell/nav. |
|
||||
| Restrict admin privileges | **Partial** | Single key-only `wheel` admin (NOPASSWD, see R-05); no per-host/rotatable model yet. |
|
||||
| Restrict admin privileges | **Partial** | Single key-only `wheel` admin, root locked, now **SELinux-confined to `staff_u`** with a sudo role/type transition (NOPASSWD, see R-05); no per-host/rotatable model or admin-MFA yet. |
|
||||
| Patch operating systems | **Process** | Same rebuild/redeploy model; immutable image means uniform, atomic OS updates. |
|
||||
| Multi-factor authentication | **Strong (machine)** | Host auth is certificate + TPM-bound key (something-the-machine-has, non-exportable). Human admin MFA to be addressed for the management plane. |
|
||||
| Regular backups | **N/A (by design)** | Diskless, stateless hosts hold nothing to back up; recoverability is re-provisioning from a pinned digest. Backup applies to serving-side state, out of scope here. |
|
||||
@@ -234,13 +274,14 @@ production ATO:
|
||||
|---|---|---|---|
|
||||
| R-01 | Secure path (802.1X/MACsec) not yet bench-verified; currently disabled in test builds. | **High** | Treat — verify before production authorisation. |
|
||||
| R-02 | `debug_shell=true` bakes a **passwordless root shell** on a tty. | **High** | Treat — must be removed before production (lab-only). |
|
||||
| R-03 | STIG hardening temporarily **report-only / disabled in CI** (`enable_stig=false`). | **Medium** | Treat — re-enable before assessment. |
|
||||
| R-03 | STIG hardening **applied + bench-verified** (2026-06-20); residual is that CI ships **unsigned, Secure Boot OFF** and `enable_stig` must be confirmed on for production builds. | **Medium** | Treat — confirm `enable_stig=true` in CI + enforce signing/SB before assessment. |
|
||||
| R-04 | NVMe/TCP root traffic **plaintext** on the lab LAN. | **Medium** | Accept (isolated LAN) / treat for production. |
|
||||
| R-05 | NOPASSWD key-only admin; no per-host or rotatable access model. | **Medium** | Accept with compensating controls / roadmap. |
|
||||
| R-05 | NOPASSWD key-only admin (now `staff_u`-confined); no per-host/rotatable access model or admin-MFA. | **Medium** | Accept with compensating controls / roadmap. |
|
||||
| R-06 | **FIPS off**; ASD-approved-cryptography conformance not yet asserted. | **Medium** | Treat — required for PROTECTED+; revisit with signing. |
|
||||
| R-07 | Audit-log offload **plaintext**, single-site, no SIEM alerting. | **Medium** | Treat — TLS offload + monitoring on roadmap. |
|
||||
| R-07 | Audit-log offload **plaintext** (bench-verified working), single-site, no SIEM alerting. | **Medium** | Treat — TLS offload + monitoring on roadmap. |
|
||||
| R-08 | **Placeholder RADIUS CA** in the repo; real trust anchor not yet provisioned. | **Medium** | Treat — environment-specific, before production. |
|
||||
| R-09 | Host **firewall disabled**. | **Low–Medium** | Accept (isolated LAN) / treat with explicit allow-rules. |
|
||||
| R-09 | Host **firewall disabled** (workstation). | **Low–Medium** | Accept (isolated LAN) / treat with explicit allow-rules. |
|
||||
| R-13 | **Boot chain unsigned / Secure Boot OFF** in the lab (UKI + iPXE); CI signing wired but not enforced. | **Medium** | Treat — enrol `db`, enforce SB + sign UKI & iPXE before production. |
|
||||
|
||||
Each is detailed, ISM-cross-referenced, rated and assigned a treatment in Annex A.
|
||||
|
||||
|
||||
@@ -114,6 +114,30 @@ reverts to a justified deviation; (b) reproducibility — `semanage` rebuilds th
|
||||
SELinux policy store, so confirm the verity hash is stable across two builds (and
|
||||
normalize in 2d hygiene if it drifts).
|
||||
|
||||
## 13. Ctrl+Alt+Del console reboot hotkey kept enabled (decision 2026-06-20)
|
||||
|
||||
The RHEL 9 STIG disables the console reboot hotkey via two rules, both **waived**
|
||||
in the tailoring:
|
||||
- `disable_ctrlaltdel_reboot` — masks `ctrl-alt-del.target` (single Ctrl+Alt+Del).
|
||||
- `disable_ctrlaltdel_burstaction` — sets `CtrlAltDelBurstAction=none` in
|
||||
`/etc/systemd/system.conf` (the rapid 7× burst reboot).
|
||||
|
||||
**Why waived:** the STIG intent is to stop an **unauthenticated console user from
|
||||
causing an unplanned reboot/outage**. On this fleet that risk is structurally
|
||||
absent — the hosts are **diskless and stateless** (immutable erofs+dm-verity root,
|
||||
tmpfs volatile overlay), so a console reboot loses nothing and persists nothing,
|
||||
and a **field technician needs to recover a wedged kiosk from the keyboard when
|
||||
SSH is unavailable**. The two rules are unselected so `--remediate` leaves the
|
||||
systemd default (the hotkey reboots).
|
||||
|
||||
**Compensating control / scope:** the hotkey only triggers a **clean stateless
|
||||
reboot** — it cannot exfiltrate data, alter the read-only root, or bypass auth to
|
||||
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
|
||||
hotkey disabled (e.g. a physically exposed terminal), re-select both rule IDs.
|
||||
|
||||
## Things that are NOT deviations (kept / enforced)
|
||||
|
||||
- **SELinux enforcing** (`selinux --enforcing`; labels preserved into the erofs).
|
||||
|
||||
@@ -28,8 +28,12 @@ EFIVARS=/sys/firmware/efi/efivars
|
||||
GUID_GLOBAL=8be4df61-93ca-11d2-aa0d-00e098032b8c # PK, KEK, SetupMode
|
||||
GUID_DB=d719b2cb-3d3a-4596-a3bc-dad00e67656f # db, dbx
|
||||
# EFI var attributes: NON_VOLATILE|BOOTSERVICE_ACCESS|RUNTIME_ACCESS|
|
||||
# TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x27, little-endian 4 bytes.
|
||||
ATTR=$'\x27\x00\x00\x00'
|
||||
# TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x27, written as a 4-byte little-endian
|
||||
# u32 prefixed to the .auth payload. These 4 bytes contain NULs, so they are
|
||||
# emitted with printf at WRITE TIME, never stored in a variable: a bash string
|
||||
# can't hold a NUL (it truncates at the first one), which would leave only the
|
||||
# 0x27 byte, corrupt the 4-byte attribute field efivarfs reads, and make the
|
||||
# kernel reject the write with EINVAL ("dd: Invalid argument").
|
||||
|
||||
die() { echo "fleet-sb-enroll: $*" >&2; exit 1; }
|
||||
|
||||
@@ -57,7 +61,7 @@ enrol_one() { # $1=var name $2=guid $3=.auth path
|
||||
local f="$EFIVARS/$1-$2" tmp
|
||||
[ -f "$3" ] || die "missing $3"
|
||||
tmp=$(mktemp)
|
||||
printf '%s' "$ATTR" > "$tmp"
|
||||
printf '\x27\x00\x00\x00' > "$tmp" # 4-byte LE attribute prefix (see note above)
|
||||
cat "$3" >> "$tmp"
|
||||
# Existing EFI vars carry the immutable flag; clear it before overwriting.
|
||||
[ -e "$f" ] && chattr -i "$f" 2>/dev/null || true
|
||||
|
||||
@@ -162,5 +162,16 @@
|
||||
<xccdf:select idref="xccdf_org.ssgproject.content_rule_usbguard_allow_hub" selected="true"/>
|
||||
<xccdf:select idref="xccdf_org.ssgproject.content_rule_usbguard_allow_hid_and_hub" selected="true"/>
|
||||
|
||||
<!-- Ctrl+Alt+Del reboot hotkey (decision 2026-06-20): KEEP the console
|
||||
reboot hotkey working on these diskless kiosks. The STIG masks
|
||||
ctrl-alt-del.target + sets CtrlAltDelBurstAction=none to stop an
|
||||
unauthenticated console reboot, but the hosts are STATELESS (immutable
|
||||
erofs+verity root, tmpfs overlay) so a console reboot has no data-loss
|
||||
or persistence risk, and a field tech needs to recover a wedged kiosk
|
||||
without SSH. Unselect both so remediation leaves the systemd default
|
||||
(hotkey reboots). Justified in docs/stig-deviations.md #13. -->
|
||||
<xccdf:select idref="xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_reboot" selected="false"/>
|
||||
<xccdf:select idref="xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_burstaction" selected="false"/>
|
||||
|
||||
</xccdf:Profile>
|
||||
</xccdf:Tailoring>
|
||||
|
||||
Reference in New Issue
Block a user