Skip to content

(MODULES-11857) Scaffold OWASP CRS v4 support on EL10 via crs_source enum#2637

Open
SugatD wants to merge 6 commits into
mainfrom
MODULES-11857
Open

(MODULES-11857) Scaffold OWASP CRS v4 support on EL10 via crs_source enum#2637
SugatD wants to merge 6 commits into
mainfrom
MODULES-11857

Conversation

@SugatD

@SugatD SugatD commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

Summary

Scaffolds OWASP Core Rule Set (CRS) v4 support on EL10, where there is no mod_security_crs package, while preserving the existing package-based behaviour on EL7/8/9. Implements the design locked in the SPIKE MODULES-11852 (air-gapped customer with internal mirrors → mirror-first, no required internet call).

Introduces a crs_source enum on apache::mod::security:

crs_source Behaviour Default for
package install mod_security_crs + per-rule symlinks (v2/v3 layout) — unchanged EL7/8/9
archive fetch CRS v4 tarball via puppet/archive from a configurable crs_archive_source (e.g. an internal mirror) + checksum, extract, wire v4 includes opt-in
path use a pre-staged CRS v4 directory (crs_path), no download opt-in
none engine only, no CRS EL10

Changes

  • manifests/params.ppcrs_source defaults (none on EL10, package elsewhere); archive source/checksum default to undef (user-pinned, no module-shipped version → avoids the CRS version/CVE treadmill).
  • manifests/mod/security.pp — new params + case $crs_source for acquisition; rule activation branches between legacy per-rule symlinks (package) and the v4 include layout (archive/path); fail-fast validation when required inputs are missing. Extract dir is kept outside the purged modsec_dir.
  • templates/mod/security_crs_v4.conf.epp — emits IncludeOptional <dir>/crs-setup.conf + rules/*.conf, auto-loaded via the existing IncludeOptional ${modsec_dir}/*.conf.
  • metadata.json / .fixtures.yml — add puppetlabs/archive dependency.
  • spec/classes/mod/security_spec.rb — cover none/archive/path modes + fail-fast cases.

Validation

  • puppet parser validate, epp validate, puppet-lint, rubocop, metadata_lint: clean
  • Unit specs: 282 examples, 0 failures (all crs_source values, with/without-checksum archive, fail-fast)
  • Acceptance (CI): passes on all EL platforms incl. RedHat-10 / 10-arm (new spec/acceptance/mod_security_crs_v4_spec.rb exercises path + archive)
  • Both modes also validated end-to-end on a RHEL 10.1 VM (apply, idempotency, configtest, SQLi/XSS/LFI → 403)

Known limitation / follow-up

  • v4 tuning params — the CRS tuning parameters (paranoia_level, *_anomaly_threshold, allowed_methods, DOS knobs, …) currently feed only the legacy security_crs.conf (package mode). In archive/path (v4) modes the CRS-shipped crs-setup.conf is used as-is, so those params are not applied. Operators can edit crs-setup.conf directly (preserved by the creates guard). Tracked as follow-up MODULES-11895 — not a blocker for this PR.

CI note

The only red checks are Debian-13, SLES-12, SLES-15 acceptance — pre-existing platform failures (Debian-13 systemd start; SLES missing apache2ctl), unrelated to this change (same set is red on main nightly; this PR does not touch those code paths).

Relates to MODULES-11852 (design SPIKE), MODULES-11851 (engine restore), MODULES-11739 (parent), MODULES-11895 (follow-up).

🤖 Generated with Claude Code

…enum

Add a crs_source enum (package/archive/path/none) to apache::mod::security
so CRS can be deployed on EL10, which has no mod_security_crs package, while
preserving the package-based behaviour on EL7/8/9.

- params.pp: crs_source defaults to none on EL10, package elsewhere; archive
  source/checksum default to undef (user-pinned, no version treadmill).
- security.pp: case $crs_source selects acquisition (package install /
  puppet-archive fetch+extract / pre-staged path / none) and branches rule
  activation between legacy per-rule symlinks (package) and the v4 include
  layout (archive/path). Extract dir kept outside the purged modsec_dir.
- templates/mod/security_crs_v4.conf.epp: emits the v4 crs-setup.conf +
  rules/*.conf includes, auto-loaded via modsec_dir/*.conf.
- metadata.json/.fixtures.yml: add puppetlabs/archive dependency.
- spec: cover none/archive/path modes and fail-fast validation.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Comment thread metadata.json Outdated
SugatD and others added 5 commits June 30, 2026 11:52
The puppet-archive module is published as puppet/archive (Vox Pupuli), not
puppetlabs/archive, which does not exist on the Forge. The wrong name made
dependency-checker crash in CI and the fixture clone fail. Point both
metadata.json and .fixtures.yml at the correct module/repo.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Latest published puppet/archive is 8.1.0; the dependency-checker requires the
current Forge version to satisfy the declared range. Bump the upper bound to
< 9.0.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Make crs_source => archive work end-to-end:
- Add crs_version param (user-pinned). CRS tarballs unpack to a versioned
  coreruleset-<version>/ dir, so pinning the version makes the extract path
  and includes deterministic. Extract into a base dir (default /usr/share).
- Create the active crs-setup.conf from the shipped crs-setup.conf.example
  via an exec guarded by creates (preserves later user edits).
- Update unit specs for the versioned layout and the new fail-fast on
  missing crs_version.

Resolves the extraction TODO from the initial scaffold.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Covers crs_source => path and archive on EL10 with a self-contained,
internet-free CRS fixture (built on the target) that also stands in for an
internal mirror. Asserts idempotent apply, the v4 include wiring, that
crs-setup.conf is created from the example in archive mode, and that
apachectl configtest passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Archive mode passed checksum_type unconditionally, so with no crs_archive_checksum
puppet/archive verified against an empty expected checksum and failed
("Download file checksum mismatch (expected: ...)"). A trusted internal mirror
may legitimately be used without a checksum. Set checksum_verify only when a
checksum is supplied. Caught by the new EL10 acceptance test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@SugatD SugatD marked this pull request as ready for review July 9, 2026 11:11
@SugatD SugatD requested review from a team, bastelfreak, ekohl and smortex as code owners July 9, 2026 11:11
@SugatD

SugatD commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Acceptance tests now pass on all Enterprise Linux platforms (RedHat-7/8/9/10 + 10-arm, Rocky, CentOS), including the new spec/acceptance/mod_security_crs_v4_spec.rb which exercises both crs_source => path and archive on EL10. Both modes were also validated end-to-end on a RHEL 10.1 VM (apply, idempotency, apachectl configtest, and SQLi/XSS/LFI requests returning 403).

@kenyon — as requested, holding until acceptance passed; it now does, so this is ready for review.

The only red checks are Debian-13, SLES-12, and SLES-15 acceptance. These are pre-existing, unrelated platform failures (Debian-13 systemd start; SLES missing /usr/sbin/apache2ctl) — the same set is red on main's nightly and this PR does not touch those code paths.

Follow-up captured as MODULES-11895 (wiring the ModSecurity tuning params into the CRS v4 crs-setup.conf) — not a blocker here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants