Releases: doccaz/scap2salt
Release list
v1.0.14 — MLM container-volume deploy + nftables masking
PCI-DSS v4 hardening Salt formulas for SUSE, generated by scap2salt and packaged as MLM/Uyuni formulas with form. Two per-OS RPMs are attached — assign one per system-group.
Coverage (pci-dss-4 profile)
| SLE 15 (AppArmor) | SLE 16 (SELinux) | |
|---|---|---|
| Native mapping | 209/238 remediable (87%) | 197/230 (85%) |
| Live OpenSCAP compliance | 92.9% (223/17) | 91.6% (207/19) |
What's new in 1.0.14
service_*_disablednow passes — the OVAL requiresLoadState=masked, not just disabled. Disabled-service rules now alsoservice.masked(e.g.service_nftables_disabled→ pass).- Formula RPM now deploys into the live MLM container volumes on SL Micro. The Uyuni Salt master reads
/srv/salt+/srv/formula_metadata, which on a containerised server are podman volumes under/var/lib/containers/storage. Because SL Micro installs RPMs viatransactional-update(whose%postruns in a chroot where that storage is shadowed), deployment is now done on first boot by a bundleddeploy-<formula>.serviceoneshot (vendor-enabled via a packagedmulti-user.target.wantssymlink), with a/usr/libexec/deploy-<formula>.shhelper for immediate deploy. - Per-OS formula names
PCI_DSS_v4_SLE15/PCI_DSS_v4_SLE16for clean, case-correct labels in the MLM Formulas list. - Looked into and documented the residual fails:
sysctl_fs_suid_dumpable(runtime hardened to 0; static check left untouched to avoid anrpm_verify_hashesviolation) and the pam-file hashing rules (oscap 1.4.1 can't credit them on SUSE; the effective controlset_password_hashing_algorithm_logindefspasses).
Install (containerised MLM on SL Micro)
sudo transactional-update pkg install --allow-unsigned-rpm ./PCI_DSS_v4_SLE16-hardening-formula-1.0.14-0.noarch.rpm
sudo reboot # required to activate the transactional install; the formula auto-deploys on bootThen assign PCI DSS V4 SLE16 (or …SLE15) to a system/group in the Formulas tab, toggle categories, and apply the highstate. See each RPM's bundled README for the writable-root and traditional-server paths.
v1.0.13 — Fix broken formula after sub-group revert
Reverts the v1.0.12 sub-group form.yml change that broke MLM formula assignment.
What broke in v1.0.12: Changing category toggles from flat booleans (pci_dss.sysctl: True) to sub-groups (pci_dss.sysctl.enabled: True) is a schema-breaking change. MLM stores saved form values in its database and can't render the pillar when the schema changes, causing highstate to fail with a Jinja error.
What's fixed: emit_formula() reverts to flat boolean categories. Jinja guards revert from p.get(cat, {}).get('enabled', True) back to p.get(cat, True).
Kept from v1.0.12:
- Group-level
$helptext clarifying AppArmor/SELinux runtime detection - Short clean category labels in
CAT_LABELS - PCI-DSS section references in
CAT_HELP(tooltip/$helpfields) metadata.ymlname field update
Note on form layout: MLM renders boolean fields as checkboxes with tooltip-only $help. The visible inline description per-category (and indentation under the master switch) would require the sub-group schema, which breaks existing assignments — not feasible without a migration path.
v1.0.11
v1.0.11 — Fix auditd/audit-rules.service immutable-flag loop
Root cause
The zz-pci-immutable.rules fragment sets -e 2 (immutable mode) after the first successful highstate. On subsequent systemctl start audit-rules.service calls (e.g. when Salt tries to start auditd), augenrules --load calls auditctl -R which hits «Rule exists» because:
auditctl -Dsilently exits 0 but does nothing (rules are locked)- Existing kernel rules can't be replaced without a reboot
Fix
Install a systemd drop-in at /etc/systemd/system/audit-rules.service.d/pci-immutable.conf that wraps augenrules with an immutability check:
[Service]
ExecStart=
ExecStart=/bin/sh -c 'if auditctl -s 2>/dev/null | grep -q "enabled 2"; then echo "Audit rules immutable (-e 2), skipping reload"; exit 0; fi; /sbin/augenrules --load'When audit rules are immutable (already correctly loaded from the previous boot run), the wrapper exits 0 so audit-rules.service succeeds and auditd can start.
Included from v1.0.10
- Formula UI: each category label shows its PCI-DSS requirement refs inline
metadata.yml:name:field fixes «Pci Dss» → «PCI-DSS v4 Hardening» tab label- Master-switch
$helptooltip explains the enable toggle
v1.0.10
v1.0.10 — auditd boot-failure fix + formula UI improvements
Fixes
- services.sls:
audit_prereq_resetnow also runsauditctl -Dbefore resetting the failedaudit-rules.service, clearing any partially-loaded kernel audit rules that would cause «Rule exists» on the next reload attempt.
Formula UI improvements
- form.yml: each category checkbox label now shows its PCI-DSS requirement section inline (e.g. SSH server hardening — PCI-DSS §2.2.4, §2.2.7, §8.3.1) — always visible, not just as a tooltip.
- form.yml: "Enable PCI-DSS hardening" toggle gets a tooltip explaining it is the master on/off switch; when unchecked, all categories are skipped without removing the formula assignment.
- metadata.yml: added
name: PCI-DSS v4 Hardeningso the MLM Formulas tab shows the correct title instead of the auto-formatted "Pci Dss". - Capitalisation: "Sudo defaults" and "Systemd core dump policy" now start with a capital letter; all category descriptions lead with their PCI-DSS section reference.
v1.0.9
v1.0.9 — AppArmor/SLE 16 compatibility + auditd service fix
Fixes
- mac.sls: AppArmor states are now guarded by a Jinja runtime check for
/sys/kernel/security/apparmor. On SELinux systems (SLE 16) these states are silently skipped instead of failing with package-not-found errors. - services.sls: Added
audit_prereq_resetstate that resetsaudit-rules.serviceif it is stuck in a failed state from boot-time duplicate-rule errors, before Salt attempts to startauditd.
v1.0.8
v1.0.7
Changes in v1.0.7
Bug fixes
augenrules --load"Rule exists" errors: CaC time-related audit rules (audit_rules_time_adjtimex,audit_rules_time_settimeofday,audit_rules_time_stime) all generate the same combined-a always,exit -F arch=... -S adjtimex -S settimeofdayline. Each rule got its own fragment file, soaugenruleswould concatenate three copies of the same rule intoaudit.rules. The kernel rejects duplicates with"Rule exists", causingaugenrulesto exit non-zero, which failsaudit-rules.serviceand cascades toauditd.service. The fix:emit_treenow globally deduplicates rule lines across all audit fragments before rendering. The first fragment in sort order (adjtimex) keeps the combined rule;settimeofdayandstimefragments become empty and are omitted entirely.
v1.0.6
Changes in v1.0.6
Bug fixes
stimesyscall in b64 audit rules:augenrules --load(and thereforeaudit-rules.serviceandauditd.service) was failing on modern kernels becausestime(syscall nr 25) was removed from x86_64 in Linux 5.x. The audit mapper now strips-S stimefrom b64 rules; b32 rules keep it for 32-bit compatibility. If stripping leaves a b64 rule with no syscalls and no other filters, that line is dropped entirely./etc/sshand/tmpare directories:file_permissions_sshd_pub_keyandfile_permissions_unauthorized_world_writablewere generatingfile.managedstates targeting/etc/sshand/tmp, which Salt rejects for directory paths. Both are now added to the known-directory set and emitfile.directorystates.
v1.0.5
Changes in v1.0.5
Bug fixes (found during SLE 16 highstate test run)
- sysctl values unresolved:
m_sysctlnow callsshell_resolve()on the extracted value, so shell variable references like$SYSCTL_SETTING_VALUEexpand to their actual numeric defaults instead of being passed literally to the kernel (fixed 7 failing sysctl states) chronyd_or_ntpdservice not found: normalise the combined service name from the SCAP rule tochronyd, which is the actual NTP daemon on SUSE systems- Directories in
file.managed: cron directories (/etc/cron.d,/etc/cron.daily,/etc/cron.hourly,/etc/cron.monthly,/etc/cron.weekly) now usefile.directoryinstead offile.managed; Salt rejectsfile.managedwhen the target is a directory - Missing files on minimal installs:
lineinfilecategory now emits afile.managedpreamble (withmakedirs: Trueandreplace: False) for/etc/login.defs,/etc/default/useradd, and/etc/ssh/sshd_config.d/01-complianceascode-reinforce-os-defaults.confbefore anyfile.replacestates touch them - Optional app config files:
/etc/postfix/main.cfand/etc/libuser.confstates now carryonlyif: test -f <path>so the state is skipped cleanly when the package is not installed /etc/security/limits.d/missing:limits_disable_coredumpsstate now includesmakedirs: Truerpm_verify_*exits non-zero: appended2>/dev/null || truesoxargs rpm --setperms/--setugidsreturning non-zero does not fail the state
v1.0.4
Changes in v1.0.4
Bug fixes
- SLE 16 compatibility: Remove
create_if_not_foundfrom allfile.replacestates — this keyword is not a valid Salt parameter and is strictly rejected on SLE 16's Salt version. Affected mappers:m_auditd_conf,m_chronyd_user(two remaining occurrences after previous 1.0.3 partial fix). - sshd drop-in file: Add a
file.managedpreamble state (sshd_dropin_create) insshd.slsthat creates/etc/ssh/sshd_config.d/00-pci-hardening.confwithmakedirs: Trueandreplace: False, so subsequentfile.replacestates do not fail on a missing file.