|
8 | 8 | # Configures the location of audit and debug logs. |
9 | 9 | # |
10 | 10 | # @param crs_package |
11 | | -# Name of package that installs CRS rules. |
12 | | -# |
| 11 | +# Name of package that installs CRS rules. Only used when `crs_source` is `package`. |
| 12 | +# |
| 13 | +# @param crs_source |
| 14 | +# How the OWASP Core Rule Set is obtained: |
| 15 | +# * `package` - install `crs_package` and activate rules via per-rule symlinks (v2/v3 layout). Default on EL7/8/9. |
| 16 | +# * `archive` - download the CRS v4 tarball via `puppet/archive` from `crs_archive_source` (e.g. an internal mirror) and wire the v4 includes. |
| 17 | +# * `path` - use a pre-staged CRS v4 directory given by `crs_path` (no download); only wires the v4 includes. |
| 18 | +# * `none` - engine only, no CRS managed. Default on EL10. |
| 19 | +# |
| 20 | +# @param crs_archive_source |
| 21 | +# Source URL or path for the CRS v4 tarball when `crs_source` is `archive`. No module default |
| 22 | +# (user-pinned, e.g. an internal mirror) to avoid a version/CVE maintenance treadmill. Required for `archive`. |
| 23 | +# |
| 24 | +# @param crs_archive_checksum |
| 25 | +# Checksum of the CRS v4 tarball for verification when `crs_source` is `archive`. |
| 26 | +# |
| 27 | +# @param crs_archive_checksum_type |
| 28 | +# Checksum algorithm for `crs_archive_checksum` (e.g. `sha256`). |
| 29 | +# |
| 30 | +# @param crs_version |
| 31 | +# The pinned CRS version (e.g. `4.27.0`), required for `crs_source => archive`. It fixes the |
| 32 | +# extracted `coreruleset-<version>` directory name so the include paths are deterministic. |
| 33 | +# |
| 34 | +# @param crs_path |
| 35 | +# For `crs_source => path`: absolute path to the pre-staged CRS v4 directory (contains |
| 36 | +# `crs-setup.conf` and `rules/`). For `crs_source => archive`: overrides the extraction base |
| 37 | +# directory (default `/usr/share`); the ruleset then lives at `<crs_path>/coreruleset-<crs_version>`. |
| 38 | +# |
13 | 39 | # @param activated_rules |
14 | 40 | # An array of rules from the modsec_crs_path or absolute to activate via symlinks. |
15 | 41 | # |
|
139 | 165 | # |
140 | 166 | # @note On RHEL/EL 10 the ModSecurity engine is provided by EPEL (enable EPEL |
141 | 167 | # yourself; this module does not manage it). The OWASP CRS package |
142 | | -# (`mod_security_crs`) is not available on EL10, so the class manages the |
143 | | -# engine only there and does not install or activate CRS rules. |
| 168 | +# (`mod_security_crs`) is not available on EL10, so `crs_source` defaults to |
| 169 | +# `none` (engine only). CRS v4 can be opted into there via `crs_source => |
| 170 | +# 'archive'` (downloaded from `crs_archive_source`, e.g. an internal mirror) |
| 171 | +# or `crs_source => 'path'` (a pre-staged directory). EL7/8/9 keep the |
| 172 | +# package-based default unchanged. |
144 | 173 | class apache::mod::security ( |
145 | 174 | Stdlib::Absolutepath $logroot = $apache::params::logroot, |
146 | 175 | Integer $version = $apache::params::modsec_version, |
147 | 176 | Optional[String] $crs_package = $apache::params::modsec_crs_package, |
| 177 | + Enum['package', 'archive', 'path', 'none'] $crs_source = $apache::params::modsec_crs_source, |
| 178 | + Optional[String[1]] $crs_archive_source = $apache::params::modsec_crs_archive_source, |
| 179 | + Optional[String[1]] $crs_archive_checksum = $apache::params::modsec_crs_archive_checksum, |
| 180 | + String[1] $crs_archive_checksum_type = $apache::params::modsec_crs_archive_checksum_type, |
| 181 | + Optional[String[1]] $crs_version = undef, |
| 182 | + Optional[Stdlib::Absolutepath] $crs_path = undef, |
148 | 183 | Array[String] $activated_rules = $apache::params::modsec_default_rules, |
149 | 184 | Boolean $custom_rules = $apache::params::modsec_custom_rules, |
150 | 185 | Optional[Array[String]] $custom_rules_set = $apache::params::modsec_custom_rules_set, |
|
227 | 262 | lib => 'mod_unique_id.so', |
228 | 263 | } |
229 | 264 |
|
230 | | - if $crs_package { |
231 | | - package { $crs_package: |
232 | | - ensure => 'installed', |
233 | | - before => [ |
234 | | - File[$apache::confd_dir], |
235 | | - File[$modsec_dir], |
236 | | - ], |
| 265 | + # Effective on-disk CRS v4 directory used in the include wiring. Kept outside |
| 266 | + # $modsec_dir, which is managed with purge => true and would otherwise remove |
| 267 | + # the extracted rule tree. |
| 268 | + # - path: $crs_path is the ready CRS directory (contains crs-setup.conf + rules/). |
| 269 | + # - archive: CRS tarballs unpack to a versioned dir, so the ruleset lives at |
| 270 | + # <base>/coreruleset-<crs_version> under the extraction base. |
| 271 | + $_crs_extract_base = $crs_path ? { |
| 272 | + undef => '/usr/share', |
| 273 | + default => $crs_path, |
| 274 | + } |
| 275 | + $_crs_dir = $crs_source ? { |
| 276 | + 'archive' => "${_crs_extract_base}/coreruleset-${crs_version}", |
| 277 | + default => $crs_path, |
| 278 | + } |
| 279 | + |
| 280 | + # CRS acquisition. The activation wiring is selected later by the same |
| 281 | + # $crs_source: `package` keeps the legacy per-rule symlinks (v2/v3 layout), |
| 282 | + # while `archive`/`path` use the v4 include layout. |
| 283 | + case $crs_source { |
| 284 | + 'package': { |
| 285 | + if $crs_package { |
| 286 | + package { $crs_package: |
| 287 | + ensure => 'installed', |
| 288 | + before => [ |
| 289 | + File[$apache::confd_dir], |
| 290 | + File[$modsec_dir], |
| 291 | + ], |
| 292 | + } |
| 293 | + } |
237 | 294 | } |
| 295 | + 'archive': { |
| 296 | + if ! $crs_archive_source { |
| 297 | + fail('apache::mod::security: crs_source => "archive" requires crs_archive_source (URL/path to the CRS v4 tarball, e.g. an internal mirror).') |
| 298 | + } |
| 299 | + if ! $crs_version { |
| 300 | + fail('apache::mod::security: crs_source => "archive" requires crs_version (the pinned CRS version, e.g. "4.27.0"); it fixes the extracted coreruleset-<version> directory name.') |
| 301 | + } |
| 302 | + |
| 303 | + file { $_crs_extract_base: |
| 304 | + ensure => directory, |
| 305 | + } |
| 306 | + |
| 307 | + # Both the release "-minimal" asset and the source archive unpack to a |
| 308 | + # versioned top-level dir, coreruleset-<crs_version>/. Checksum |
| 309 | + # verification is only enabled when a checksum is supplied (a trusted |
| 310 | + # internal mirror may legitimately be used without one). |
| 311 | + archive { 'coreruleset.tar.gz': |
| 312 | + ensure => present, |
| 313 | + path => '/var/cache/coreruleset.tar.gz', |
| 314 | + source => $crs_archive_source, |
| 315 | + checksum => $crs_archive_checksum, |
| 316 | + checksum_type => $crs_archive_checksum_type, |
| 317 | + checksum_verify => $crs_archive_checksum =~ NotUndef, |
| 318 | + extract => true, |
| 319 | + extract_path => $_crs_extract_base, |
| 320 | + creates => "${_crs_dir}/crs-setup.conf.example", |
| 321 | + cleanup => true, |
| 322 | + require => File[$_crs_extract_base], |
| 323 | + } |
| 324 | + |
| 325 | + # CRS ships crs-setup.conf.example; create the active crs-setup.conf from |
| 326 | + # it once. The creates guard prevents clobbering later user edits. |
| 327 | + exec { 'apache-crs-setup-conf': |
| 328 | + command => ['/bin/cp', "${_crs_dir}/crs-setup.conf.example", "${_crs_dir}/crs-setup.conf"], |
| 329 | + creates => "${_crs_dir}/crs-setup.conf", |
| 330 | + require => Archive['coreruleset.tar.gz'], |
| 331 | + notify => Class['apache::service'], |
| 332 | + } |
| 333 | + } |
| 334 | + 'path': { |
| 335 | + if ! $crs_path { |
| 336 | + fail('apache::mod::security: crs_source => "path" requires crs_path (absolute path to a pre-staged CRS v4 directory).') |
| 337 | + } |
| 338 | + } |
| 339 | + 'none': {} |
| 340 | + default: {} |
238 | 341 | } |
239 | 342 |
|
240 | 343 | # Template uses: |
|
329 | 432 | } |
330 | 433 | } |
331 | 434 |
|
332 | | - if $manage_security_crs { |
| 435 | + if $manage_security_crs and $crs_source == 'package' { |
| 436 | + # Legacy CRS v2/v3 layout: a tuning conf plus per-rule symlinks under |
| 437 | + # activated_rules/. Unchanged behaviour for EL7/8/9 package installs. |
333 | 438 | # Template uses: |
334 | 439 | # - $_secdefaultaction |
335 | 440 | # - $critical_anomaly_score |
|
381 | 486 | apache::security::rule_link { $activated_rules: } |
382 | 487 | } |
383 | 488 | } |
| 489 | + |
| 490 | + if $manage_security_crs and $crs_source in ['archive', 'path'] { |
| 491 | + # CRS v4 layout: load crs-setup.conf then rules/*.conf from the CRS |
| 492 | + # directory. Dropped into $modsec_dir so the existing |
| 493 | + # `IncludeOptional ${modsec_dir}/*.conf` in security.conf picks it up. |
| 494 | + file { "${modsec_dir}/security_crs_v4.conf": |
| 495 | + ensure => file, |
| 496 | + content => epp('apache/mod/security_crs_v4.conf.epp', { 'crs_dir' => $_crs_dir }), |
| 497 | + require => File[$modsec_dir], |
| 498 | + notify => Class['apache::service'], |
| 499 | + } |
| 500 | + } |
384 | 501 | } |
0 commit comments