Integration and Deployment with cfengine

I recently required a larger deployment of OSSEC-HIDS without too much manual intervention. Almost every OSSEC-HIDS tutorial I’ve across says this is possible, yet I was unable to find a tutorial demonstrating it. So, in the spirit of open source, I’m contributing a brief overview.

Prerequisites:

In order to facilitate the key request, I chose to generate a file with the relevant information and copy it back to my cfmaster server. I developed the following tutorial to demonstrate a cfengine copy back scenario: Copy Back with cfengine.

Configuring the cfengine clients:

I added a group to my cfagent.conf for my ossec server named: hg_ossec_server (host group). I then created an ossec-hids.cf containing the following:

  • control

My control sections sets up the variables I’ll be using in the rest of the file.

control:
  any::
    ossec_key_dir = (/usr/local/cfkeys/ossec)
    ossec_req_dir = ( $(util_updir)/ossec )
  • package

I’m using yum to automatically install OSSEC-HIDS from my local RPM Repository.

packages:
  !hg_ossec_server::
      ossec-hids                  action=install
      ossec-hids-client           action=install
  • links

The Links section just links ossec-agent.conf to ossec.conf on the clients.

links:
  !hg_ossec_server::
    /var/ossec/etc/ossec.conf -> /var/ossec/etc/ossec-agent.conf
  • copy

I manage the ossec-agent.conf in cfengine, because my cfengine configurations are all stored in a subversion repository. The first stanza in copy just pushes the most recent copy of the ossec-agent.conf file to my network, setting the dynamic class dc_restart_ossec if the copy occurs.

copy:
  !hg_ossec_server::
      $(distribute)/ossec-agent.conf      dest=/var/ossec/etc/ossec-agent.conf
                                          server=$(policyhost)
                                          mode=640
                                          group=ossec
                                          type=sum
                                          define=dc_restart_ossec

This second stanza in the copy section copies a file from our ossec key directory to the client.keys file on the client. This copy only happens if the two files are different. It also sets dc_restart_ossec if the copy occurs.

$(ossec_key_dir)/$(host).ossec    dest=/var/ossec/etc/client.keys
                                  server=$(policyhost)
                                  mode=640
                                  group=ossec
                                  type=sum
                                  define=dc_restart_ossec
  • processes

My processes block checks to ensure that OSSEC-HIDS is running the correct daemons.

processes:
  !hg_ossec_server::
      "ossec-agentd" elsedefine=dc_restart_ossec
  ``hg_ossec_server``::
      "ossec-remoted" elsedefine=dc_restart_ossec
  • shellcommands

This section is where the certificate request occurs through some devious mechanisms I designed for no other reason than to amuse myself. Hopefully, it amuses others as well. The first thing it does is issue a command that echo’s the client eth0 ipv4 address to a file named ‘’host.ossec’’ in the ossec request directory I defined. The hg_ossec_server class will use this to generate a cert to place in the aforementioned copy block.

shellcommands:
  !hg_ossec_server::
      "/usr/bin/ssh util@$(policyhost) -i $(util_privkey) 'echo $(global.ipv4[eth0]) > $(ossec_req_dir)/$(host).ossec'"

The last statement checks to see if anyone defined dc_restart_ossec, and restart ossec-hids if it was defined.

dc_restart_ossec::
    "/sbin/service ossec-hids restart"

Ok, so who cares?

Well, now, our clients are setup to install, configure, and run OSSEC-HIDS as well as issuing a request for their certificate. However, the certificate directory on the server is empty and so none of them will actually run. This is a problem.

Configuring the OSSEC Server w/cfengine

The cfengine part of this was a pain for me because of the order of the actions I had defined and the extent of work I had done incorrectly in the past. I could have figured out an interesting way to handle this, but I didn’t want to scrap my entire cfengine config and start from scratch. So I created a perl script that allowed me to use the manage_agents script without interaction. It does require the Expect.pm & Regexp::Common from CPAN, but is otherwise stock Perl 5.8.x. I also wrote a shell script wrapper to handle running the perl script and culminating the results. I saved these two scripts in /root/security, so if you put them elsewhere, make sure to update the shell script wrapper.

The scripts for managing keys can be downloaded here

The cfengine bit was really simple, it just had to call my wrapper shell script and set the class. I did this with a control block:

control:
 hg_ossec_server::
   AddClasses = ( ExecResult(/root/security/ossec-scan.sh) )

The combination of the two scripts and this one line in the cfengine configuration handle creating, removing, and exporting the keys, as well as configuring the dc_restart_ossec class if there have been changes.