I really like OSSEC, the open-source intrusion detection system, and deploy it wherever I'm working. Not only is it great from a security point of view (detecting brute force attacks, crawlers, XSS injection attempts, bad permissions on files, modificatons to files, notification of installed/removed packages, presence of rootkits etc etc), but it's also really good at exposing the general state of things on your infrastructure that might otherwise go unnoticed (even if they're logged). Such examples are network issues e.g LDAP or NRPE traffic issues between your machines, or third parties such as PEAR or APT providers and so on, as well as segfaults, PHP fatal errors that are logged in syslog (surely those are picked up before deployment to production, right? RIGHT?) and much more.
What's more, it's highly customisable through its use of 'decoders' and rulesets, and in fact, there is a contributed decoder/set of rules for Drupal that were written by Justin C Klein Keane. You can find them here.
I find the decoder and its rules to work pretty much out of the box. A couple of them I add to the active-response configuration, so that certain rule IDs that are triggered warrant an automatic block against the source IP address.
There is just one change that I at first thought of making to the decoder, and that is that I tend to define custom 'identities' for each Drupal site in its Drupal Syslog settings, so that I can more easily filter my logs for messages from specific sites. The default is 'drupal', which is not too descriptive, and Justin's decoder is explicitly coded to only match on that program_name.
Having set up different syslog identifiers in Drupal (or 'program_name' as defined in OSSEC), I was wondering why my logs weren't being decoded properly and thus not triggering rules as expected. This was the reason.
Trying to decide how to solve the problem, I realised the program_name attribute is a regex, so I defined mine with 'OR' pipes like this:
.. before it finally occurred to me that this was too awkward to maintain. Instead, I have opted to prefix each of my syslog identities in each Drupal site with:
drupal-<short site name>
This way the original regex still stands because it begins with 'drupal', and now the decoder works and rules triggered properly. Simple!
One other thing I will point out (not covered in Justin's post, possibly because it wasn't possible in OSSEC back when he wrote it) is that you can store your custom decoder in /var/ossec/etc/local_decoder.xml (instead of /var/ossec/etc/decoder.xml, which may get overwritten on upgrades), in the same way that you can store custom rules in /var/ossec/rules/local_rules.xml.