@calltelemetry/ct-lab-mcp 0.8.98 → 0.8.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/stig/SHA256SUMS +18 -0
- package/assets/stig/files/ct-luks-firstboot.service +13 -0
- package/assets/stig/files/ct-luks-firstboot.sh +35 -0
- package/assets/stig/guest/keyhash.sh +4 -0
- package/assets/stig/guest/read-recovery.sh +2 -0
- package/assets/stig/guest/scan-disa.sh +17 -0
- package/assets/stig/guest/scan.sh +22 -0
- package/assets/stig/guest/shred-recovery.sh +2 -0
- package/assets/stig/guest/test-recovery.sh +3 -0
- package/assets/stig/guest/trim.sh +3 -0
- package/assets/stig/guest/verify-root.sh +9 -0
- package/assets/stig/guest/verify-user.sh +9 -0
- package/assets/stig/ks.cfg.pkrtpl +95 -0
- package/assets/stig/scripts/assess.sh +39 -0
- package/assets/stig/scripts/errata.sh +19 -0
- package/assets/stig/scripts/remediate.sh +127 -0
- package/assets/stig/scripts/seal.sh +46 -0
- package/assets/stig/tailoring.xml +16 -0
- package/assets/stig/template.pkr.hcl +252 -0
- package/dist/src/generated-version.d.ts +1 -1
- package/dist/src/generated-version.js +1 -1
- package/dist/src/stig/live.d.ts +116 -0
- package/dist/src/stig/live.d.ts.map +1 -0
- package/dist/src/stig/live.js +339 -0
- package/dist/src/stig/live.js.map +1 -0
- package/dist/src/stig/model.d.ts +160 -0
- package/dist/src/stig/model.d.ts.map +1 -0
- package/dist/src/stig/model.js +384 -0
- package/dist/src/stig/model.js.map +1 -0
- package/dist/src/stig/ports.d.ts +149 -0
- package/dist/src/stig/ports.d.ts.map +1 -0
- package/dist/src/stig/ports.js +7 -0
- package/dist/src/stig/ports.js.map +1 -0
- package/dist/src/stig/receipt.d.ts +35 -0
- package/dist/src/stig/receipt.d.ts.map +1 -0
- package/dist/src/stig/receipt.js +112 -0
- package/dist/src/stig/receipt.js.map +1 -0
- package/dist/src/stig/runner.d.ts +109 -0
- package/dist/src/stig/runner.d.ts.map +1 -0
- package/dist/src/stig/runner.js +471 -0
- package/dist/src/stig/runner.js.map +1 -0
- package/dist/src/tools/appliance-claim-spec-schema.v1.json +1 -1
- package/dist/src/tools/appliance-claim-tools.d.ts +10 -4
- package/dist/src/tools/appliance-claim-tools.d.ts.map +1 -1
- package/dist/src/tools/appliance-claim-tools.js +10 -2
- package/dist/src/tools/appliance-claim-tools.js.map +1 -1
- package/dist/src/tools/claim-creation-projection.d.ts +1 -1
- package/dist/src/tools/claim-creation-projection.js +1 -1
- package/dist/src/tools/claim-custody.d.ts +7 -7
- package/dist/src/tools/claimed-import-qcow.d.ts +2 -2
- package/dist/src/tools/host-maintenance-shutdown.d.ts +4 -4
- package/dist/src/tools/host-migrate-vm.d.ts +4 -4
- package/dist/src/tools/index.d.ts.map +1 -1
- package/dist/src/tools/index.js +3 -0
- package/dist/src/tools/index.js.map +1 -1
- package/dist/src/tools/purge-slots.d.ts +1 -1
- package/dist/src/tools/sandbox-tools.d.ts +8 -8
- package/dist/src/tools/stig-tools.d.ts +47 -0
- package/dist/src/tools/stig-tools.d.ts.map +1 -0
- package/dist/src/tools/stig-tools.js +125 -0
- package/dist/src/tools/stig-tools.js.map +1 -0
- package/dist/src/tools/vm-action.d.ts +2 -2
- package/package.json +2 -1
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
a5f48191effe1b243c4d4fc5565cbbe31b6a6085aedf9a3b924e68d0b9ae399c files/ct-luks-firstboot.service
|
|
2
|
+
5dc732b176181200ed18e6cf2448551d7c5e1a31cbd7bd9f4cbda4d30a4ad2eb files/ct-luks-firstboot.sh
|
|
3
|
+
dc035a0b24f24ff1a0e75fbbb9ff20262c1f83ef41d6c4e35a9bf7895ffd72e5 ks.cfg.pkrtpl
|
|
4
|
+
97cda67f5851fcfd05a9a8dd4b0f885f9b5bad2ff85570935f14555356edbcdf scripts/assess.sh
|
|
5
|
+
7c8b9f536f7d2fa81b26b125a8edccf7bc64c9959e5d5ce6482bab231e21ecd2 scripts/errata.sh
|
|
6
|
+
9780d258e74fb8eb997a27c6866ddc3fdd78f54c5e61eb616618c5a3445056ef scripts/remediate.sh
|
|
7
|
+
5e3760cfd6a752b5c97e6e1f6f557df385f4be3d2a4acc1b125480f785b0dbcb scripts/seal.sh
|
|
8
|
+
43560c40096a28b180685fe1383344a6d454a3a18666f2ead4a1ddd3d72ed7fd tailoring.xml
|
|
9
|
+
9a7e78eefcb3d8ce28dc137e56dc43ae6b6f3ba4bdecf9f3c0abe64658432105 template.pkr.hcl
|
|
10
|
+
eb119e742a4791404ca298c962515ffe3492814dfc72aecac16c420ccb3b0ccc guest/keyhash.sh
|
|
11
|
+
3a964e9dc60fcb7492fabf2117fa04d91e0f5e34d0b3b1fe003aa7253f0daeeb guest/read-recovery.sh
|
|
12
|
+
921ce015bb3f5188ccd861aef30fb1aed2588e729c371c3c8379802ce0c24be1 guest/scan.sh
|
|
13
|
+
9abadcf3c9a1334447a6f349c6c78105d090550d6e8c09adb0320fc1a73e5019 guest/shred-recovery.sh
|
|
14
|
+
0af1b98d2acf8827ac3861a0ec25f507483a3dc902f00ed215ce13b6dc4db0dc guest/test-recovery.sh
|
|
15
|
+
6a63f43c312eed5941f0b86044ebe8b3457ce9412c5d9a1ceda67316d16a4209 guest/trim.sh
|
|
16
|
+
6b3eab512392c9b68499cb3b4a753377bcc499b810e7259d8ede5e10861bf674 guest/verify-root.sh
|
|
17
|
+
770cbf1c4ea374772d6e80734b1fe4d7d7f5826c8c528a5371f4dfea196479d7 guest/verify-user.sh
|
|
18
|
+
b4a37a0425369c99dfe9b63086155b7ffaa0ef73f98b158143ecb0cd84d45d94 guest/scan-disa.sh
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=CallTelemetry clone first boot: re-encrypt LUKS with a new volume key, bind TPM2
|
|
3
|
+
ConditionPathExists=/etc/ct-luks-bootstrap.key
|
|
4
|
+
After=cloud-final.service
|
|
5
|
+
Wants=cloud-final.service
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=oneshot
|
|
9
|
+
ExecStart=/usr/bin/bash /usr/local/sbin/ct-luks-firstboot.sh
|
|
10
|
+
TimeoutStartSec=0
|
|
11
|
+
|
|
12
|
+
[Install]
|
|
13
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# First boot of a clone (D-020). The template ships LUKS2 on the LVM PV unlocked by a
|
|
3
|
+
# template-wide bootstrap key embedded in the initramfs. Here, once per clone:
|
|
4
|
+
# 1. online re-encrypt (new volume key),
|
|
5
|
+
# 2. add a per-clone recovery passphrase (controller escrows it, then removes the file),
|
|
6
|
+
# 3. bind unlock to this clone's own TPM2 (clevis),
|
|
7
|
+
# 4. remove the bootstrap keyslot and key from the initramfs, then reboot.
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
exec >>/var/log/ct-luks-firstboot.log 2>&1
|
|
10
|
+
echo "== $(date -u +%FT%TZ) ct-luks-firstboot start"
|
|
11
|
+
key=/etc/ct-luks-bootstrap.key
|
|
12
|
+
[ -f "$key" ] || { echo "bootstrap key absent; nothing to do"; exit 0; }
|
|
13
|
+
[ -c /dev/tpmrm0 ] || { echo "ERROR: no TPM2 device (/dev/tpmrm0); clone needs its own tpmstate0"; exit 1; }
|
|
14
|
+
dev="$(blkid -t TYPE=crypto_LUKS -o device | head -n1)"
|
|
15
|
+
[ -n "$dev" ] || { echo "ERROR: no LUKS device"; exit 1; }
|
|
16
|
+
|
|
17
|
+
cryptsetup reencrypt --key-file "$key" --pbkdf pbkdf2 --resilience none --batch-mode "$dev"
|
|
18
|
+
echo "reencrypt done $(date -u +%FT%TZ)"
|
|
19
|
+
|
|
20
|
+
umask 077
|
|
21
|
+
openssl rand -base64 60 | tr -dc 'A-Za-z0-9' | head -c 40 > /root/.luks-recovery
|
|
22
|
+
cryptsetup luksAddKey --key-file "$key" --pbkdf pbkdf2 --batch-mode "$dev" /root/.luks-recovery
|
|
23
|
+
|
|
24
|
+
clevis luks bind -f -d "$dev" -k "$key" tpm2 '{"pcr_bank":"sha256","pcr_ids":"7"}'
|
|
25
|
+
|
|
26
|
+
cryptsetup luksRemoveKey --batch-mode "$dev" "$key"
|
|
27
|
+
sed -i "s#${key}#none#" /etc/crypttab
|
|
28
|
+
rm -f /etc/dracut.conf.d/ct-luks-bootstrap.conf
|
|
29
|
+
shred -u "$key"
|
|
30
|
+
dracut -f --regenerate-all
|
|
31
|
+
fstrim -av || true # give the fully re-encrypted thin disk back (discards pass through LUKS)
|
|
32
|
+
touch /var/lib/ct-luks-firstboot.done
|
|
33
|
+
systemctl disable ct-luks-firstboot.service
|
|
34
|
+
echo "== $(date -u +%FT%TZ) done; rebooting to prove unattended TPM unlock"
|
|
35
|
+
systemctl reboot
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# sha256 of the LUKS volume key (never printed): proves two clones have different keys.
|
|
3
|
+
# The recovery passphrase arrives on stdin after the sudo password line.
|
|
4
|
+
o=$(cryptsetup luksDump --dump-master-key --batch-mode --key-file - $(blkid -t TYPE=crypto_LUKS -o device|head -n1)) && grep -q "MK dump" <<<"$o" && printf "%s" "$o" | sha256sum | cut -d" " -f1
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Second scan of a v3 clone: DISA's official V2R8 SCAP benchmark (profile MAC-1_Classified), next to the SSG scan.
|
|
3
|
+
# Writes into /var/tmp/ct-scan (created by scan.sh). Templates built before the dual-scan recipe do not carry the
|
|
4
|
+
# benchmark; then only a marker is written and the caller decides whether that is acceptable.
|
|
5
|
+
set -e
|
|
6
|
+
e=/var/tmp/ct-scan
|
|
7
|
+
ev=/root/stig-evidence
|
|
8
|
+
b=$ev/U_RHEL_8_V2R8_STIG_SCAP_1-3_Benchmark.xml
|
|
9
|
+
mkdir -p $e
|
|
10
|
+
if [ ! -f "$b" ]; then echo absent > $e/clone-disa-absent; chown -R ctadmin $e; exit 0; fi
|
|
11
|
+
drc=0
|
|
12
|
+
oscap xccdf eval --profile xccdf_mil.disa.stig_profile_MAC-1_Classified --results-arf $e/clone-disa-arf.xml --report $e/clone-disa-report.html $b > $e/clone-disa-stdout.txt 2>&1 || drc=$?
|
|
13
|
+
echo oscap_disa_exit=$drc
|
|
14
|
+
for r in pass fail notapplicable notchecked informational error unknown; do echo result_$r=$(grep -c "^Result.*$r\$" $e/clone-disa-stdout.txt || true); done > $e/clone-disa-summary.txt
|
|
15
|
+
grep -B2 -E '^Result.*(fail|error)$' $e/clone-disa-stdout.txt | grep '^Rule' > $e/clone-disa-failed-rules.txt || true
|
|
16
|
+
sha256sum $b | cut -d' ' -f1 > $e/clone-disa-benchmark.sha256
|
|
17
|
+
chown -R ctadmin $e
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# oscap on the clone itself (pinned datastream + tailoring baked into the template). Run as root.
|
|
3
|
+
# Output goes to /var/tmp/ct-scan, never under /home: root-owned scan output there would itself trip the
|
|
4
|
+
# home-file ownership rules. Faithful to the `do_scan` block of the known-good clone.sh.
|
|
5
|
+
set -e
|
|
6
|
+
e=/var/tmp/ct-scan
|
|
7
|
+
mkdir -p $e; ev=/root/stig-evidence; rc=0
|
|
8
|
+
oscap xccdf eval --tailoring-file $ev/tailoring.xml --profile xccdf_com.calltelemetry_profile_stig_ct --results-arf $e/clone-arf.xml --report $e/clone-report.html $ev/ssg-rhel8-ds.xml > $e/clone-stdout.txt 2>&1 || rc=$?
|
|
9
|
+
echo oscap_exit=$rc
|
|
10
|
+
for r in pass fail notapplicable notchecked informational error; do echo result_$r=$(grep -c "^Result.*$r\$" $e/clone-stdout.txt || true); done > $e/clone-summary.txt
|
|
11
|
+
grep -B2 -E '^Result.*(fail|error)$' $e/clone-stdout.txt | grep '^Rule' > $e/clone-failed-rules.txt || true
|
|
12
|
+
grep -B3 -E '^Result.*notchecked$' $e/clone-stdout.txt | grep -E '^(Title|Rule)' > $e/clone-notchecked.txt || true
|
|
13
|
+
{ echo '## encrypt_partitions: lsblk -f'; lsblk -f
|
|
14
|
+
echo; echo '## encrypt_partitions: LUKS header (no key material)'; cryptsetup luksDump $(blkid -t TYPE=crypto_LUKS -o device|head -n1) | grep -vE '^[[:space:]]+(Salt|Digest|Key material|AF stripes|AF hash):' | head -60
|
|
15
|
+
echo; echo '## security_patches_up_to_date: outstanding security advisories'; dnf -q updateinfo list security 2>&1 | grep -c . || true
|
|
16
|
+
echo; echo '## selinux_user_login_roles: semanage login -l'; semanage login -l
|
|
17
|
+
echo; echo '## configured_firewalld_default_deny / configure_firewalld_ports'; firewall-cmd --get-default-zone; firewall-cmd --zone=drop --list-all
|
|
18
|
+
echo; echo '## account_temp_expire_date: accounts with an expiry'; awk -F: '$1!="root"{print $1}' /etc/passwd | while read u; do chage -l $u | grep -H --label=$u 'Account expires'; done | grep -v never || echo 'none (no temporary accounts)'
|
|
19
|
+
echo; echo '## auditd partition size'; df -h /var/log/audit | tail -n1
|
|
20
|
+
echo; echo '## ssh_keys_passphrase_protected: private keys in user homes'; find /home /root -maxdepth 3 -name 'id_*' ! -name '*.pub' 2>/dev/null | grep . || echo 'none'
|
|
21
|
+
echo; echo '## sssd certmap trust anchor'; grep -c certmap /etc/sssd/sssd.conf; } > $e/clone-manual-evidence.txt 2>&1
|
|
22
|
+
chown -R ctadmin $e
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Privileged half of the clone verification. Prints key=value lines; never key material.
|
|
3
|
+
dev=$(blkid -t TYPE=crypto_LUKS -o device|head -n1)
|
|
4
|
+
echo sudo_id=$(id -Z)
|
|
5
|
+
echo luks_type=$(cryptsetup isLuks -v $dev >/dev/null && cryptsetup luksDump $dev | sed -n "s/^Version:[[:space:]]*//p")
|
|
6
|
+
echo luks_passphrase_slots=$(cryptsetup luksDump $dev | grep -cE "^ [0-9]+: luks2")
|
|
7
|
+
echo clevis_tpm2_tokens=$(cryptsetup luksDump $dev | grep -c "clevis")
|
|
8
|
+
echo bootstrap_key_file=$(test -e /etc/ct-luks-bootstrap.key && echo present || echo absent)
|
|
9
|
+
echo tpm_bound=$(clevis luks list -d $dev | grep -c tpm2)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Unprivileged half of the clone verification (known-good clone.sh `verify`).
|
|
3
|
+
echo fips_enabled=$(cat /proc/sys/crypto/fips_enabled)
|
|
4
|
+
echo selinux=$(getenforce)
|
|
5
|
+
echo host=$(hostname)
|
|
6
|
+
echo context=$(id -Z)
|
|
7
|
+
ls /dev/tpmrm0 >/dev/null 2>&1 && echo tpm=present
|
|
8
|
+
grep ^PRETTY_NAME= /etc/os-release
|
|
9
|
+
echo kernel=$(uname -r)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# RHEL 8.10 STIG template install. The installer applies the DISA STIG profile
|
|
2
|
+
# from the DVD's scap-security-guide; Packer then re-remediates and assesses with
|
|
3
|
+
# the pinned SSG release. The PV is LUKS2 with a template-wide bootstrap key; each clone
|
|
4
|
+
# re-encrypts with a new volume key and binds its own TPM2 at first boot (D-020).
|
|
5
|
+
text --non-interactive
|
|
6
|
+
cdrom
|
|
7
|
+
lang en_US.UTF-8
|
|
8
|
+
keyboard --xlayouts=us
|
|
9
|
+
timezone UTC --utc
|
|
10
|
+
rootpw --lock
|
|
11
|
+
selinux --enforcing
|
|
12
|
+
firewall --enabled --service=ssh
|
|
13
|
+
network --bootproto=dhcp --device=link --onboot=yes --activate --hostname=${hostname}
|
|
14
|
+
services --enabled=sshd,qemu-guest-agent,chronyd,auditd --disabled=kdump
|
|
15
|
+
firstboot --disable
|
|
16
|
+
eula --agreed
|
|
17
|
+
skipx
|
|
18
|
+
|
|
19
|
+
zerombr
|
|
20
|
+
clearpart --all --initlabel --disklabel=gpt
|
|
21
|
+
bootloader --location=mbr --iscrypted --password=${grub_pbkdf2}
|
|
22
|
+
part /boot/efi --fstype=efi --size=1024 --fsoptions="umask=0077,shortname=winnt,nosuid,nodev"
|
|
23
|
+
part /boot --fstype=xfs --size=2048 --fsoptions="nosuid,nodev"
|
|
24
|
+
part pv.01 --size=1 --grow --encrypted --luks-version=luks2 --pbkdf=pbkdf2 --passphrase=${luks_bootstrap}
|
|
25
|
+
volgroup vg_root pv.01
|
|
26
|
+
logvol / --vgname=vg_root --name=root --fstype=xfs --size=24576
|
|
27
|
+
logvol /home --vgname=vg_root --name=home --fstype=xfs --size=16384 --fsoptions="nodev,nosuid,noexec"
|
|
28
|
+
logvol /tmp --vgname=vg_root --name=tmp --fstype=xfs --size=8192 --fsoptions="nodev,nosuid,noexec"
|
|
29
|
+
logvol /var --vgname=vg_root --name=var --fstype=xfs --size=24576 --fsoptions="nodev"
|
|
30
|
+
logvol /var/log --vgname=vg_root --name=log --fstype=xfs --size=16384 --fsoptions="nodev,nosuid,noexec"
|
|
31
|
+
logvol /var/log/audit --vgname=vg_root --name=audit --fstype=xfs --size=8192 --fsoptions="nodev,nosuid,noexec"
|
|
32
|
+
logvol /var/tmp --vgname=vg_root --name=vartmp --fstype=xfs --size=8192 --fsoptions="nodev,nosuid,noexec"
|
|
33
|
+
logvol /opt --vgname=vg_root --name=opt --fstype=xfs --size=8192
|
|
34
|
+
logvol swap --vgname=vg_root --name=swap --size=8192
|
|
35
|
+
|
|
36
|
+
# Temporary build-only administrator (D-019). Removed by seal.sh.
|
|
37
|
+
user --name=${ssh_username} --groups=wheel --iscrypted --password=${build_password_hash}
|
|
38
|
+
sshkey --username=${ssh_username} "${ssh_public_key}"
|
|
39
|
+
|
|
40
|
+
%packages --excludedocs
|
|
41
|
+
@^minimal-environment
|
|
42
|
+
openssh-server
|
|
43
|
+
openssh-clients
|
|
44
|
+
qemu-guest-agent
|
|
45
|
+
sudo
|
|
46
|
+
chrony
|
|
47
|
+
dracut-fips
|
|
48
|
+
crypto-policies-scripts
|
|
49
|
+
cloud-init
|
|
50
|
+
cloud-utils-growpart
|
|
51
|
+
openscap-scanner
|
|
52
|
+
scap-security-guide
|
|
53
|
+
aide
|
|
54
|
+
audit
|
|
55
|
+
rsyslog
|
|
56
|
+
fapolicyd
|
|
57
|
+
usbguard
|
|
58
|
+
tmux
|
|
59
|
+
cryptsetup
|
|
60
|
+
clevis
|
|
61
|
+
clevis-luks
|
|
62
|
+
clevis-dracut
|
|
63
|
+
tpm2-tools
|
|
64
|
+
sssd
|
|
65
|
+
sssd-tools
|
|
66
|
+
openssl
|
|
67
|
+
firewalld
|
|
68
|
+
subscription-manager
|
|
69
|
+
policycoreutils-python-utils
|
|
70
|
+
%end
|
|
71
|
+
|
|
72
|
+
%addon com_redhat_kdump --disable
|
|
73
|
+
%end
|
|
74
|
+
|
|
75
|
+
%addon org_fedora_oscap
|
|
76
|
+
content-type = scap-security-guide
|
|
77
|
+
profile = xccdf_org.ssgproject.content_profile_stig
|
|
78
|
+
%end
|
|
79
|
+
|
|
80
|
+
%post --erroronfail
|
|
81
|
+
# Template-wide LUKS bootstrap key, embedded in the initramfs so the template boots
|
|
82
|
+
# unattended. Replaced per clone by ct-luks-firstboot (new volume key + TPM2).
|
|
83
|
+
printf '%s' '${luks_bootstrap}' > /etc/ct-luks-bootstrap.key
|
|
84
|
+
chmod 0400 /etc/ct-luks-bootstrap.key
|
|
85
|
+
sed -i 's#^\(luks-[^ ]* [^ ]* \)none#\1/etc/ct-luks-bootstrap.key#' /etc/crypttab
|
|
86
|
+
cat > /etc/dracut.conf.d/ct-luks-bootstrap.conf <<'DRACUT'
|
|
87
|
+
add_dracutmodules+=" crypt clevis "
|
|
88
|
+
install_items+=" /etc/ct-luks-bootstrap.key "
|
|
89
|
+
DRACUT
|
|
90
|
+
dracut -f --regenerate-all
|
|
91
|
+
# The build user must be usable over key-only SSH with no TTY (Packer): no expired password.
|
|
92
|
+
chage -d "$(date +%F)" -M 99999 -E -1 ${ssh_username}
|
|
93
|
+
%end
|
|
94
|
+
|
|
95
|
+
reboot
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Final STIG assessment of the rebooted image. Reports are copied to the controller.
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
evidence=/root/stig-evidence
|
|
6
|
+
out=/home/${BUILD_USER}/stig-report
|
|
7
|
+
rc=0
|
|
8
|
+
oscap xccdf eval \
|
|
9
|
+
--tailoring-file "$evidence/tailoring.xml" \
|
|
10
|
+
--profile xccdf_com.calltelemetry_profile_stig_ct \
|
|
11
|
+
--results-arf "$evidence/final-arf.xml" \
|
|
12
|
+
--report "$evidence/final-report.html" \
|
|
13
|
+
"$evidence/ssg-rhel8-ds.xml" > "$evidence/final-stdout.txt" 2>&1 || rc=$?
|
|
14
|
+
echo "oscap eval exit=$rc"
|
|
15
|
+
[ "$rc" -eq 0 ] || [ "$rc" -eq 2 ]
|
|
16
|
+
|
|
17
|
+
{
|
|
18
|
+
echo "fips_enabled=$(cat /proc/sys/crypto/fips_enabled)"
|
|
19
|
+
echo "selinux=$(getenforce)"
|
|
20
|
+
echo "kernel=$(uname -r)"
|
|
21
|
+
grep -E '^(NAME|VERSION_ID)=' /etc/os-release
|
|
22
|
+
rpm -q scap-security-guide openscap-scanner
|
|
23
|
+
echo "tailoring_sha256=$(cut -d" " -f1 "$evidence/tailoring.sha256")"
|
|
24
|
+
echo "ds_sha256=$(sha256sum "$evidence/ssg-rhel8-ds.xml" | cut -d" " -f1)"
|
|
25
|
+
echo "dnf_security_outstanding=$(dnf -q updateinfo list security 2>/dev/null | grep -c . || true)"
|
|
26
|
+
lsblk -f > "$evidence/lsblk.txt"; cryptsetup luksDump "$(blkid -t TYPE=crypto_LUKS -o device | head -n1)" > "$evidence/luksdump-template.txt" 2>&1 || true
|
|
27
|
+
for r in pass fail notapplicable notchecked informational error; do
|
|
28
|
+
echo "result_${r}=$(grep -c "^Result.*${r}\$" "$evidence/final-stdout.txt" || true)"
|
|
29
|
+
done
|
|
30
|
+
} > "$evidence/summary.txt"
|
|
31
|
+
cat "$evidence/summary.txt"
|
|
32
|
+
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > "$evidence/rpm-qa-final.txt"
|
|
33
|
+
grep -B2 -E '^Result.*fail$' "$evidence/final-stdout.txt" | grep '^Rule' | sed 's/^Rule[[:space:]]*//' > "$evidence/failed-rules.txt" || true
|
|
34
|
+
|
|
35
|
+
rm -rf "$out"
|
|
36
|
+
install -d -o "${BUILD_USER}" -g "${BUILD_USER}" -m 0700 "$out"
|
|
37
|
+
cp "$evidence"/{lsblk.txt,luksdump-template.txt,tailoring.xml,tailoring.sha256,errata.txt,final-arf.xml,final-report.html,final-stdout.txt,summary.txt,failed-rules.txt,remediate-report.html,remediate-stdout.txt,rpm-qa-final.txt} "$out/"
|
|
38
|
+
cp -r "$evidence/install-time-oscap" "$out/" 2>/dev/null || true
|
|
39
|
+
chown -R "${BUILD_USER}:${BUILD_USER}" "$out"
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Apply current RHEL 8.10 errata through RHSM, then reboot into the updated kernel.
|
|
3
|
+
# Registration is removed again by seal.sh. Credentials arrive as environment variables
|
|
4
|
+
# and are never echoed.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
: "${RHSM_ORG:?}" "${RHSM_KEY:?}"
|
|
8
|
+
subscription-manager register --org "$RHSM_ORG" --activationkey "$RHSM_KEY" --force >/dev/null
|
|
9
|
+
subscription-manager repos --list-enabled | grep -E '^Repo ID' || true
|
|
10
|
+
dnf -y update
|
|
11
|
+
install -d -m 0700 /root/stig-evidence
|
|
12
|
+
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > /root/stig-evidence/rpm-qa-post-errata.txt
|
|
13
|
+
{
|
|
14
|
+
echo "kernel_installed=$(rpm -q kernel --qf '%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort -V | tail -n1)"
|
|
15
|
+
echo "security_advisories_outstanding=$(dnf -q updateinfo list security 2>/dev/null | grep -c . || true)"
|
|
16
|
+
echo "errata_applied=$(date -u +%FT%TZ)"
|
|
17
|
+
} > /root/stig-evidence/errata.txt
|
|
18
|
+
cat /root/stig-evidence/errata.txt
|
|
19
|
+
(sleep 3; systemctl reboot) >/dev/null 2>&1 &
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# CallTelemetry organization settings, then the pinned SSG STIG remediation with the
|
|
3
|
+
# organization tailoring, then reboot. oscap exits 2 when rules still fail after
|
|
4
|
+
# remediation; that is a finding, not a build failure.
|
|
5
|
+
set -euo pipefail
|
|
6
|
+
|
|
7
|
+
ds="$SSG_DATASTREAM"
|
|
8
|
+
echo "${SSG_DATASTREAM_SHA256} ${ds}" | sha256sum -c -
|
|
9
|
+
profile=xccdf_com.calltelemetry_profile_stig_ct
|
|
10
|
+
|
|
11
|
+
evidence=/root/stig-evidence
|
|
12
|
+
install -d -m 0700 "$evidence"
|
|
13
|
+
cp "$ds" "$evidence/ssg-rhel8-ds.xml"
|
|
14
|
+
cp "$TAILORING" "$evidence/tailoring.xml"
|
|
15
|
+
sha256sum "$evidence/tailoring.xml" > "$evidence/tailoring.sha256"
|
|
16
|
+
rpm -qa --qf '%{NAME}-%{VERSION}-%{RELEASE}.%{ARCH}\n' | sort > "$evidence/rpm-qa-pre-remediate.txt"
|
|
17
|
+
cp /root/anaconda-ks.cfg "$evidence/" 2>/dev/null || true
|
|
18
|
+
cp -r /root/openscap_data "$evidence/install-time-oscap" 2>/dev/null || true
|
|
19
|
+
|
|
20
|
+
# --- clone first-boot encryption (D-020) ---
|
|
21
|
+
install -m 0755 "$FILES_DIR/ct-luks-firstboot.sh" /usr/local/sbin/ct-luks-firstboot.sh
|
|
22
|
+
install -m 0644 "$FILES_DIR/ct-luks-firstboot.service" /etc/systemd/system/ct-luks-firstboot.service
|
|
23
|
+
systemctl daemon-reload
|
|
24
|
+
systemctl enable ct-luks-firstboot.service
|
|
25
|
+
restorecon -F /usr/local/sbin/ct-luks-firstboot.sh /etc/systemd/system/ct-luks-firstboot.service
|
|
26
|
+
|
|
27
|
+
# --- GRUB: non-default superuser (grub2_uefi_admin_username), keep the PBKDF2 password ---
|
|
28
|
+
sed -i 's/set superusers="root"/set superusers="grubadmin"/; s/password_pbkdf2 root /password_pbkdf2 grubadmin /' /etc/grub.d/01_users
|
|
29
|
+
grep -q 'superusers="grubadmin"' /etc/grub.d/01_users
|
|
30
|
+
grub2-mkconfig -o /boot/grub2/grub.cfg >/dev/null 2>&1
|
|
31
|
+
grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg >/dev/null 2>&1 || true
|
|
32
|
+
|
|
33
|
+
# --- DNS: two lab nameservers, independent of DHCP (network_configure_name_resolution) ---
|
|
34
|
+
cat > /etc/NetworkManager/conf.d/90-ct-dns.conf <<NM
|
|
35
|
+
[global-dns-domain-*]
|
|
36
|
+
servers=${DNS_SERVERS}
|
|
37
|
+
NM
|
|
38
|
+
systemctl restart NetworkManager
|
|
39
|
+
sleep 5
|
|
40
|
+
|
|
41
|
+
# --- firewalld: default zone drop, ssh allowed (set_firewalld_default_zone) ---
|
|
42
|
+
firewall-cmd --permanent --zone=drop --add-service=ssh >/dev/null
|
|
43
|
+
firewall-cmd --zone=drop --add-service=ssh >/dev/null
|
|
44
|
+
firewall-cmd --set-default-zone=drop >/dev/null
|
|
45
|
+
|
|
46
|
+
# --- chrony: server directives only (chronyd_server_directive) ---
|
|
47
|
+
sed -i '/^pool /d' /etc/chrony.conf
|
|
48
|
+
for s in ${NTP_SERVERS//,/ }; do
|
|
49
|
+
grep -q "^server $s " /etc/chrony.conf || echo "server $s iburst maxpoll 16" >> /etc/chrony.conf
|
|
50
|
+
done
|
|
51
|
+
systemctl restart chronyd
|
|
52
|
+
|
|
53
|
+
# --- SSSD with a certmap rule (sssd_enable_certmap); CAC matchrule is a placeholder ---
|
|
54
|
+
cat > /etc/sssd/sssd.conf <<'SSSD'
|
|
55
|
+
[sssd]
|
|
56
|
+
config_file_version = 2
|
|
57
|
+
services = nss, pam
|
|
58
|
+
domains = ctlocal
|
|
59
|
+
|
|
60
|
+
[domain/ctlocal]
|
|
61
|
+
id_provider = files
|
|
62
|
+
|
|
63
|
+
[pam]
|
|
64
|
+
pam_cert_auth = True
|
|
65
|
+
|
|
66
|
+
[certmap/ctlocal/dod_cac]
|
|
67
|
+
matchrule = <SAN>.*EDIPI@mil
|
|
68
|
+
maprule = (userCertificate;binary={cert!bin})
|
|
69
|
+
domains = ctlocal
|
|
70
|
+
SSSD
|
|
71
|
+
chmod 0600 /etc/sssd/sssd.conf
|
|
72
|
+
systemctl enable sssd
|
|
73
|
+
|
|
74
|
+
# --- sudo: elevate SELinux context (selinux_context_elevation_for_sudo); password still required ---
|
|
75
|
+
cat > /etc/sudoers.d/ct-selinux-elevation <<'SUDOERS'
|
|
76
|
+
%wheel ALL=(ALL) TYPE=sysadm_t ROLE=sysadm_r ALL
|
|
77
|
+
SUDOERS
|
|
78
|
+
chmod 0440 /etc/sudoers.d/ct-selinux-elevation
|
|
79
|
+
visudo -cf /etc/sudoers.d/ct-selinux-elevation
|
|
80
|
+
|
|
81
|
+
# --- cloud-init default user: ctadmin in wheel, password sudo only (no NOPASSWD) ---
|
|
82
|
+
cat > /etc/cloud/cloud.cfg.d/99-ct-stig.cfg <<'CLOUD'
|
|
83
|
+
system_info:
|
|
84
|
+
default_user:
|
|
85
|
+
name: ctadmin
|
|
86
|
+
gecos: CallTelemetry administrator
|
|
87
|
+
groups: [wheel, adm, systemd-journal]
|
|
88
|
+
sudo: false
|
|
89
|
+
lock_passwd: false
|
|
90
|
+
shell: /bin/bash
|
|
91
|
+
ssh_pwauth: false
|
|
92
|
+
CLOUD
|
|
93
|
+
|
|
94
|
+
# --- SELinux user mapping: administrators log in as staff_u and elevate to sysadm_r via sudo ---
|
|
95
|
+
semanage login -m -s staff_u -r s0-s0:c0.c1023 __default__
|
|
96
|
+
|
|
97
|
+
# --- init-file and host-key permissions that must also hold on clones ---
|
|
98
|
+
# New users inherit /etc/skel; root's init files must be <= 0740 (file_permission_user_init_files*).
|
|
99
|
+
# The build user (removed at seal) was created before /etc/skel was fixed.
|
|
100
|
+
chmod 0740 /home/${BUILD_USER}/.bash_logout /home/${BUILD_USER}/.bash_profile /home/${BUILD_USER}/.bashrc
|
|
101
|
+
# cloud-init already created ctadmin on the build VM's own first boot (removed again at seal).
|
|
102
|
+
chmod 0740 /home/ctadmin/.bash_logout /home/ctadmin/.bash_profile /home/ctadmin/.bashrc 2>/dev/null || true
|
|
103
|
+
chmod 0740 /etc/skel/.bash_logout /etc/skel/.bash_profile /etc/skel/.bashrc /root/.bash_logout /root/.bash_profile /root/.bashrc /root/.cshrc /root/.tcshrc 2>/dev/null || true
|
|
104
|
+
# sshd-keygen creates host keys 0640 root:ssh_keys on every clone's first boot; the STIG
|
|
105
|
+
# (file_permissions_sshd_private_key) requires 0600. Re-assert it whenever sshd starts.
|
|
106
|
+
install -d /etc/systemd/system/sshd.service.d
|
|
107
|
+
cat > /etc/systemd/system/sshd.service.d/10-ct-hostkey-perms.conf <<'DROPIN'
|
|
108
|
+
[Service]
|
|
109
|
+
ExecStartPre=/usr/bin/bash -c 'chmod 0600 /etc/ssh/ssh_host_*_key'
|
|
110
|
+
DROPIN
|
|
111
|
+
systemctl daemon-reload
|
|
112
|
+
chmod 0600 /etc/ssh/ssh_host_*_key
|
|
113
|
+
|
|
114
|
+
# --- SSG STIG remediation with the organization tailoring ---
|
|
115
|
+
rc=0
|
|
116
|
+
oscap xccdf eval \
|
|
117
|
+
--tailoring-file "$evidence/tailoring.xml" \
|
|
118
|
+
--profile "$profile" \
|
|
119
|
+
--remediate \
|
|
120
|
+
--results-arf "$evidence/remediate-arf.xml" \
|
|
121
|
+
--report "$evidence/remediate-report.html" \
|
|
122
|
+
"$evidence/ssg-rhel8-ds.xml" > "$evidence/remediate-stdout.txt" 2>&1 || rc=$?
|
|
123
|
+
echo "oscap remediate exit=$rc"
|
|
124
|
+
[ "$rc" -eq 0 ] || [ "$rc" -eq 2 ]
|
|
125
|
+
|
|
126
|
+
fips-mode-setup --check
|
|
127
|
+
(sleep 3; systemctl reboot) >/dev/null 2>&1 &
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# Generalize the image for cloning and remove the temporary build access (D-019).
|
|
3
|
+
set -euo pipefail
|
|
4
|
+
|
|
5
|
+
# Drop the RHSM registration and entitlement certificates (errata step registered this build).
|
|
6
|
+
subscription-manager unregister >/dev/null 2>&1 || true
|
|
7
|
+
subscription-manager clean >/dev/null 2>&1 || true
|
|
8
|
+
rm -rf /etc/pki/entitlement/* /etc/pki/consumer/* /var/lib/rhsm/*
|
|
9
|
+
|
|
10
|
+
# cloud-init created ctadmin on this build VM; clones create their own (from the fixed /etc/skel).
|
|
11
|
+
userdel --remove ctadmin 2>/dev/null || true
|
|
12
|
+
|
|
13
|
+
# Per-instance identity is regenerated on each clone's first boot.
|
|
14
|
+
rm -f /etc/ssh/ssh_host_*
|
|
15
|
+
truncate -s 0 /etc/machine-id
|
|
16
|
+
rm -f /var/lib/dbus/machine-id
|
|
17
|
+
cloud-init clean --logs --seed
|
|
18
|
+
rm -f /etc/NetworkManager/system-connections/*.nmconnection
|
|
19
|
+
rm -rf /root/stig-evidence/*.xml.bak /var/tmp/* /tmp/* 2>/dev/null || true
|
|
20
|
+
journalctl --rotate && journalctl --vacuum-time=1s >/dev/null
|
|
21
|
+
find /var/log -type f -name '*.log' -exec truncate -s 0 {} +
|
|
22
|
+
dnf clean all >/dev/null
|
|
23
|
+
history -c || true
|
|
24
|
+
|
|
25
|
+
# Clones authenticate with the claim's cloud-init key, never the build key.
|
|
26
|
+
rm -rf "/home/${BUILD_USER}/.ssh" "/home/${BUILD_USER}/stig-report" "/home/${BUILD_USER}/ssg-rhel8-ds.xml"
|
|
27
|
+
usermod --lock --expiredate 1 "${BUILD_USER}"
|
|
28
|
+
# Delete the account when Packer shuts the VM down, after this session ends.
|
|
29
|
+
unit=/etc/systemd/system/ct-remove-build-user.service
|
|
30
|
+
cat > "$unit" <<EOF
|
|
31
|
+
[Unit]
|
|
32
|
+
Description=Remove temporary template build user at shutdown
|
|
33
|
+
|
|
34
|
+
[Service]
|
|
35
|
+
Type=oneshot
|
|
36
|
+
RemainAfterExit=yes
|
|
37
|
+
ExecStart=/bin/true
|
|
38
|
+
ExecStop=/usr/sbin/userdel --remove --force ${BUILD_USER}
|
|
39
|
+
ExecStop=/bin/rm -f ${unit} /etc/systemd/system/multi-user.target.wants/ct-remove-build-user.service
|
|
40
|
+
|
|
41
|
+
[Install]
|
|
42
|
+
WantedBy=multi-user.target
|
|
43
|
+
EOF
|
|
44
|
+
systemctl daemon-reload
|
|
45
|
+
systemctl enable --now ct-remove-build-user.service
|
|
46
|
+
sync
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!-- Organization-defined values for the DISA RHEL 8 STIG profile (SSG 0.1.82).
|
|
3
|
+
Only values the STIG leaves to the organization are set; no rule is selected out.
|
|
4
|
+
accounts_authorized_local_users: the STIG requires the organization to define the
|
|
5
|
+
authorized local accounts. The list is the RHEL 8 minimal system accounts present on
|
|
6
|
+
the image, the CallTelemetry administrator (ctadmin, created by cloud-init on clones),
|
|
7
|
+
and ctbuild (temporary Packer build account, deleted when the template is sealed). -->
|
|
8
|
+
<xccdf-1.2:Tailoring xmlns:xccdf-1.2="http://checklists.nist.gov/xccdf/1.2" id="xccdf_com.calltelemetry_tailoring_stig_ct">
|
|
9
|
+
<xccdf-1.2:benchmark href="ssg-rhel8-ds.xml"/>
|
|
10
|
+
<xccdf-1.2:version time="2026-10-16T00:00:00">1</xccdf-1.2:version>
|
|
11
|
+
<xccdf-1.2:Profile id="xccdf_com.calltelemetry_profile_stig_ct" extends="xccdf_org.ssgproject.content_profile_stig">
|
|
12
|
+
<xccdf-1.2:title>DISA RHEL 8 STIG - CallTelemetry organization-defined values</xccdf-1.2:title>
|
|
13
|
+
<xccdf-1.2:description>Extends the SSG STIG profile; sets only organization-defined variables.</xccdf-1.2:description>
|
|
14
|
+
<xccdf-1.2:set-value idref="xccdf_org.ssgproject.content_value_var_accounts_authorized_local_users_regex">^(root|bin|daemon|adm|lp|sync|shutdown|halt|mail|operator|games|ftp|nobody|dbus|systemd-coredump|systemd-resolve|tss|polkitd|clevis|unbound|sssd|fapolicyd|chrony|sshd|postfix|ctadmin|ctbuild)$</xccdf-1.2:set-value>
|
|
15
|
+
</xccdf-1.2:Profile>
|
|
16
|
+
</xccdf-1.2:Tailoring>
|