Add STIG hrdening
This commit is contained in:
+58
-1
@@ -130,6 +130,12 @@ variable "boot_splash" {
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "enable_stig" {
|
||||
type = bool
|
||||
description = "true (default): apply DISA STIG hardening (OpenSCAP + SSG) with a diskless/UKI/kiosk tailoring (files/stig/diskless-tailoring.xml), bake STIG kernel params into the UKI cmdline, and emit a deviations report. false: skip hardening entirely — escape hatch if a build regresses the boot/secure-path bench. FIPS is OFF and audit offload is LOCAL-only regardless (see docs/stig-deviations.md)."
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "sb_key" {
|
||||
type = string
|
||||
description = "Secure Boot signing key (PEM) for the UKI. Empty = unsigned lab build. Production: CI/HSM-held; never enters the build VM."
|
||||
@@ -416,6 +422,51 @@ build {
|
||||
]
|
||||
}
|
||||
|
||||
# --- 2c-STIG. DISA STIG hardening (OpenSCAP + SSG), diskless/UKI/kiosk tailored
|
||||
# Runs after admin (so it hardens the full system incl. the admin/sshd config)
|
||||
# and BEFORE hygiene 2d (so 2d can strip the scanner tooling + reports). The
|
||||
# tailoring (files/stig/diskless-tailoring.xml) unselects rules that are N/A to
|
||||
# this architecture or dangerous to auto-remediate (FIPS off, firewall off,
|
||||
# AIDE, partitions, smartcard, GRUB) — each justified in docs/stig-deviations.md.
|
||||
# FIPS=off, audit offload=local per decision. Gated by enable_stig.
|
||||
provisioner "file" {
|
||||
source = "files/stig"
|
||||
destination = "/tmp/"
|
||||
}
|
||||
provisioner "shell" {
|
||||
environment_vars = ["ENABLE_STIG=${var.enable_stig}"]
|
||||
inline = [
|
||||
"set -e",
|
||||
"if [ \"$ENABLE_STIG\" != \"true\" ]; then echo 'enable_stig=false -> skipping STIG hardening.'; mkdir -p /root; echo '<html><body>STIG hardening disabled for this build (enable_stig=false).</body></html>' > /root/stig-report.html; : > /root/stig-arf.xml; exit 0; fi",
|
||||
"echo '==> Installing OpenSCAP + SCAP Security Guide'",
|
||||
"dnf install -y openscap-scanner scap-security-guide",
|
||||
# SSG ships rhel9 content (usable on Rocky); some rebuilds name it rl9.
|
||||
"DS=$(ls /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml /usr/share/xml/scap/ssg/content/ssg-rl9-ds.xml 2>/dev/null | head -1)",
|
||||
"[ -n \"$DS\" ] || { echo 'ERROR: SSG rhel9 datastream not found' >&2; exit 1; }",
|
||||
"install -D -m0644 /tmp/stig/diskless-tailoring.xml /etc/stig/diskless-tailoring.xml",
|
||||
"echo \"==> Remediating against tailored STIG profile using $DS (this changes a lot)\"",
|
||||
# --remediate returns nonzero when rules remain failed (expected) — tolerate.
|
||||
"oscap xccdf eval --remediate --profile xccdf_org.ssgproject.content_profile_stig_diskless --tailoring-file /etc/stig/diskless-tailoring.xml --results-arf /root/stig-arf.xml --report /root/stig-report.html \"$DS\" || true",
|
||||
# Clean post-remediation eval = the report/ARF of record (no --remediate).
|
||||
"oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_stig_diskless --tailoring-file /etc/stig/diskless-tailoring.xml --results-arf /root/stig-arf.xml --report /root/stig-report.html \"$DS\" || true",
|
||||
"rm -rf /tmp/stig",
|
||||
"echo '==> STIG remediation complete (report at /root/stig-report.html, ARF at /root/stig-arf.xml)'",
|
||||
]
|
||||
}
|
||||
# Pull the scan out to the host artifact dir for CI (before 2d removes it from
|
||||
# the VM). Packer creates the local destination dir on download. Two single-
|
||||
# source downloads (the file provisioner's download direction takes one source).
|
||||
provisioner "file" {
|
||||
direction = "download"
|
||||
source = "/root/stig-report.html"
|
||||
destination = "${var.artifact_dir}/${var.image_version}/stig-report.html"
|
||||
}
|
||||
provisioner "file" {
|
||||
direction = "download"
|
||||
source = "/root/stig-arf.xml"
|
||||
destination = "${var.artifact_dir}/${var.image_version}/stig-arf.xml"
|
||||
}
|
||||
|
||||
# --- 2d. Final image hygiene: strip caches/logs after the LAST dnf step --
|
||||
# MUST be the last provisioner. The `dnf clean all` in step 2 runs BEFORE the
|
||||
# kiosk (2b) and admin (2c) provisioners, and 2b enables EPEL + installs
|
||||
@@ -427,6 +478,12 @@ build {
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"set -eux",
|
||||
# Drop the STIG scanner tooling from the shipped image (the reports were
|
||||
# already downloaded to the host) — slims the erofs + cuts attack surface.
|
||||
# Keep auditd (it's part of the hardened runtime). Best-effort.
|
||||
"dnf remove -y openscap-scanner scap-security-guide openscap-utils 2>/dev/null || true",
|
||||
# The build-time STIG reports must not ship inside the read-only rootfs.
|
||||
"rm -f /root/stig-report.html /root/stig-arf.xml",
|
||||
"dnf clean all",
|
||||
"rm -rf /var/cache/dnf/* /var/cache/PackageKit /var/cache/ldconfig/*",
|
||||
"rm -rf /var/lib/dnf/repos/* /var/log/dnf.* /var/log/hawkey.log",
|
||||
@@ -451,7 +508,7 @@ build {
|
||||
# home dirs) — we dropped mkfs.erofs --all-root, which used to mask this by
|
||||
# flattening everything to root:root. sudo is a no-op if already root, and
|
||||
# the runner has passwordless sudo (cf. the `sudo apt-get` install step).
|
||||
"sudo bash -c \"NVMET_TRADDR='${var.nvmet_traddr}' BOOT_SPLASH='${var.boot_splash}' bash scripts/extract-artifacts.sh output-qemu/diskless-build.qcow2 ${var.artifact_dir}/${var.image_version} ${var.disable_dot1x}\"",
|
||||
"sudo bash -c \"NVMET_TRADDR='${var.nvmet_traddr}' BOOT_SPLASH='${var.boot_splash}' STIG='${var.enable_stig}' bash scripts/extract-artifacts.sh output-qemu/diskless-build.qcow2 ${var.artifact_dir}/${var.image_version} ${var.disable_dot1x}\"",
|
||||
# Hand the OUTPUT FILES back to the build user (their in-erofs ownership is
|
||||
# already baked correctly) so build-oci.sh can write the UKI and push with
|
||||
# the build user's `buildah login`.
|
||||
|
||||
Reference in New Issue
Block a user