Hi,
Since moving to Rocky Linux 9.8, ModSecurity no longer writes anything to the audit log when the CRS rules are included inside a <VirtualHost>. The exact same setup works fine on Rocky 8.
Versions
- Rocky 9.8:
mod_security-2.9.6-4.el9,httpd-2.4.62-13.el9_8.6 - Rocky 8:
mod_security-2.9.6-2.el8_10,httpd-2.4.37-65.module+el8.10.0+40312+2c72bb9b.10(works)
Configuration
/etc/httpd/conf.modules.d/10-modsec.conf (loads the module and the main config, global context):
LoadModule security2_module modules/mod_security2.so
<IfModule !mod_unique_id.c>
LoadModule unique_id_module modules/mod_unique_id.so
</IfModule>
Include /etc/modsec/modsec.conf
/etc/modsec/modsec.conf (main config, audit log settings):
SecRuleEngine On
SecAuditEngine RelevantOnly
SecAuditLog /var/log/modsecurity_audit.log
SecDefaultAction "phase:2,log,pass"
SecResponseBodyAccess Off
SecRequestBodyAccess On
SecDebugLog /var/log/modsecurity_debug.log
SecDebugLogLevel 0
/etc/modsec/vhosts/website.conf CRS setup and rules for website:
SecDefaultAction "phase:1,log,auditlog,pass"
SecDefaultAction "phase:2,log,auditlog,pass"
SecResponseBodyAccess On
SecAction \
"id:900000,\
phase:1,\
pass,\
t:none,\
nolog,\
setvar:tx.blocking_paranoia_level=1"
SecAction \
"id:900001,\
phase:1,\
pass,\
t:none,\
nolog,\
tag:'OWASP_CRS',\
ver:'OWASP_CRS/4.30.0',\
setvar:tx.detection_paranoia_level=1"
SecAction \
"id:900990,\
phase:1,\
pass,\
t:none,\
nolog,\
setvar:tx.crs_setup_version=400"
Include /etc/modsec/crs/rules/*.conf
/etc/httpd/conf.d/website.conf VirtualHost of a protected site, where the CRS rules are included:
<VirtualHost *:80>
DocumentRoot /var/www/html/app
ServerName website.local
<Directory "/var/www/html/app">
AllowOverride All
Options +FollowSymLinks +ExecCGI
Options -Indexes
<FilesMatch "\.php$">
SetHandler "proxy:unix:/var/run/php80-php-fpm.socket|fcgi://website.local"
</FilesMatch>
</Directory>
Include /etc/modsec/vhosts/website.conf
ErrorLog "/var/log/httpd/website.local-error_log"
CustomLog "/var/log/httpd/website.local-access_log" combined
</VirtualHost>
The CRS rules are included inside the VirtualHost because only some sites need the WAF.
Behaviour
- CRS rules included outside any VirtualHost: audit log is written normally
- CRS rules included inside a VirtualHost: audit log stays empty, and the debug log shows:
Audit log: Skipping request since there is nowhere to write to.
There are no SELinux denials, and the log file exists and is writable.
What I found
- Red Hat KB 7143907 describes the same issue after upgrading to RHEL 9.8 with mod_security-2.9.6-4 (the resolution is subscriber-only)
- Upstream ModSecurity issue #3446 reports the same message on Amazon Linux 2023, and a comment there points to the Fedora
pipedlogspatch (related to upstream issue #2822), which moves the audit log opening to theopen_logshook
My guess is that a VirtualHost with its own ModSecurity config inherits the log path but not the opened file descriptor.
Questions
- Has anyone else hit this on Rocky 9.8?
- Is there a known fix or a planned package update?
- Is there a cleaner workaround than keeping all rules global and disabling the engine per host with
ctl:ruleEngine=Off?
Thanks!