Nagios, mod_security and check_http
Posted by Mike Haller
on Monday, March 15. 2010
at 23:34
in Hosting
Nagios is a tool for monitoring services, and I am using it to monitor virtual hosts. mod_security is an Apache httpd module which looks for suspicious HTTP traffic (e.g. trojans or hacker attacks) and blocks them.As both tools are unaware of each other (which is a good thing) and i had an urgent need to write yet another blog post about minor technical quirks, let us look into todays issue more closely.
Nagios issues commands, such as check_http, to check for the status of services. These commands in turn execute plugins with predefined command line arguments. The default definition for the check_http command looks like this:
define command {
command_name check_http
command_line $USER1$/check_http -H $HOSTADDRESS$
}
Let's assume the following host and service definitions for my personal blog:
define host {
use template
name www.mhaller.de
host_name www.mhaller.de
alias www.mhaller.de
address 78.47.170.226
}
define service {
use generic-service
host_name www.mhaller.de
service_description HTTP
check_command check_http
}
When Nagios runs, it will periodically execute the following command:
/usr/lib/nagios/plugins/check_http -H 78.47.170.226
Up until now, this looks fine, although there's missing something. I would have expected www.mhaller.de to appear somewhere in the command line, but it doesnt. So, let's try it out. Unfortunately, we get the following warning message:
Nagios shows a warning, because mod_security detects a Bad Request
HTTP WARNING: HTTP/1.1 400 Bad Request - 485 bytes in 0.007 second response time
Looking at the HTTP Requests and failure log of mod_security, we will see that the HTTP request sent by check_http is invalid, as it's missing the "Accept:" HTTP header and the "Host:" header is wrong. The "Host:" header should be the virtual host name (www.mhaller.de) instead of the resolved IP address. The webserver is using the "Host:" header to identify which virtual host is requested, as there are multiple sites deployed which resolve to the same IP address. Requesting a resource with an IP address makes it hard for Apache to decide which web site should be returned. Also, mod_security identifies such requests as bad practice since many spammers and automated spam tools often use the wrong "Host:" header, if at all.
--f5096465-A-- [15/Mar/2010:14:11:03 +0100] S54x538AAAEAAGe2JhUAAACN 85.10.205.17 57720 78.47.170.227 80 --f5096465-B-- GET / HTTP/1.1 User-Agent: check_http/v1.4.14 (nagios-plugins 1.4.14) Connection: close Host: 78.47.170.227 --f5096465-F-- HTTP/1.1 400 Bad Request Content-Length: 304 Connection: close Content-Type: text/html; charset=iso-8859-1
The fix is pretty simple. I'll just add the host alias which I already have in the host definition and use it as the "Host:" header using the "-H" parameter. Then, I'll use the IP address of the host using the "-I" parameter. Finally adding an additional HTTP Header using the "-k" Parameter makes the HTTP request valid and mod_security rules should pass:
# 'check_http' command definition
define command {
command_name check_http
command_line $USER1$/check_http -H $HOSTALIAS$ -I $HOSTADDRESS$ -k "Accept: text/html"
}
This tells Nagios and the check_http command to populate a correct and valid HTTP Request for the correct virtual host:
GET / HTTP/1.1 User-Agent: check_http/v1.4.14 (nagios-plugins 1.4.14) Connection: close Host: www.mhaller.de Accept: text/html
Now i'm telling Nagios to reload its configuration by executing /etc/init.d/nagios reload and see what happens: the health check resumes to a friendly green OK
Nagios shows OK as mod_security is pleased
HTTP OK: HTTP/1.1 200 OK - 34224 bytes in 0.293 second response time
