Description =========== Fully automated Installation and configuration of ossec-servers and ossec-agents Manage the key generation and distribution between a server and multiple agents Clean queues on the server if needed (rid) Requirements ============ Any of: * Ubuntu 12.04+ * Debian 7.0+ * CentOS 6.0+ (should work with ossec systems if you have the packages) Attributes ========== # General Attributes The attributes below follow the same namespace syntax that OSSEC does. Refer to the official [OSSEC Documentation](http://www.ossec.net/doc/syntax/ossec_config.html) for more information. Default attributes from the cookbook: default["ossec"]["version"] = "2.8" default["ossec"]["syslog_output"]["ip"] = "127.0.0.1" default["ossec"]["syslog_output"]["port"] = "514" default["ossec"]["syslog_output"]["min_level"] = "5" default["ossec"]["receiver_port"] = "1514" default["ossec"]["log_alert_level"] = "1" default["ossec"]["email_alert_level"] = "7" default["ossec"]["agents"] = {} Default attributes from the ossec-server role: "ossec" => { "email_notification" => 'yes', "email_to" => [ 'ossec@example.net', ], "email_from" => 'ossec-server@example.net', "email_idsname" => 'ossec', "smtp_server" => 'localhost', "white_list" => [ '127.0.0.1', '10.1.0.0/16' ], "email_alerts" => { 'recipient@example.net' => { 'level' => '9', 'group' => 'syscheck', 'event_location_tag' => 'reputation', 'event_location_search' => 'roles:*mongodb*', 'format' => 'sms', 'rule_id' => '100001', 'tags' => [ 'do_not_delay', 'do_not_group' ] } }, "server" => { "service_name" => 'ossec-hids-server' }, "syscheck" => { "frequency" => '7200', "alert_new_files" => 'yes', "auto_ignore" => 'no', "directories" => { '/bin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/sbin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/usr/bin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/usr/sbin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/etc' => { 'report_changes' => 'yes', 'realtime' => 'yes' }, '/tmp' => { 'report_changes' => 'yes', 'realtime' => 'no' } }, "ignore" => { '/etc/openvpn/openvpn-status.log' => {}, '/etc/motd' => {}, '/etc/mcollective/facts.yaml' => {}, '/etc/blkid.tab' => {}, '/etc/mtab' => {}, '/etc/hosts.deny' => {}, '/etc/mail/statistics => {}', '/etc/random-seed' => {}, '/etc/adjtime' => {}, '/etc/prelink.cache' => {}, '/etc/dnscache/stats' => {}, '/etc/dnscache/log' => {}, '/etc/dnscache2/stats' => {}, '/etc/dnscache2/log' => {}, '/etc/tinydns/stats' => {}, '/etc/tinydns/log' => {} } }, "syslog_files" => { '/var/log/syslog' => {}, '/var/log/auth.log' => {}, '/var/log/daemon.log' => {}, '/var/log/kern.log' => {}, '/var/log/mail.log' => {}, '/var/log/user.log' => {}, '/var/log/cron.log' => {} } ```email_alerts``` is a hash of recipients and servers. Each recipient will receive all of the alert for the listed location (the list is a regex). ```event_location_tag``` must contain a valid chef tag. All the nodes listed by that tag will generate a separate ```email_alerts``` rule. This is additional to the default list ```email_to``` and is used to send alert to specific recipients for a limited number of hosts only. # Local Rules Definitions Rules are defined in Ruby Hash format and replicate the XML format of regular [OSSEC Rules Syntax](http://www.ossec.net/doc/syntax/head_rules.html) Each rule has a head, a body, tags and info (the last 2 being optional) head= body= Test Rule body= Big Error body= server1 tags= tags= info= http://IjustGotHacked.com The section below are parsed by the template. The following items are mandatory: * head/level * body/description ``` "ossec" => "rules" => { "100001" => { "head" => { "level" => "7", "maxsize" => "65536", "frequency" => "100", "timeframe" => "3600", "ignore" => "5", "overwrite" => "68321" }, "body" => { "hostname_search" => "recipes:mms-agent", "description" => "Super Security Rule for application XYZ", "match" => "super dangerous error happened", "regex" => "^\d+Hello World$", "decoded_as" => "vsftpd", "category" => "windows", "srcip" => "192.168.1.254", "dstip" => "10.1.6.23", "user" => "bob", "program_name" => "nginx", "time" => "09:00-18:00", "weekday" => "monday,tuesday", "id" => "404", "url" => "/changepassword.php", "if_sid" => "100238", "if_group" => "authentication_success", "if_level" => "13", "if_matched_sid" => "12037", "if_matched_group" => "adduser", "if_matched_level" => "7", "options" => "no_email_alert", "check_diff" => "true", "group" => "syscheck" }, "tags" => [ "same_source_ip", "same_source_port", "same_dst_port", "same_location" ], "infos" => { "link" => "http://trac.example.net/ticket/12345", "text" => "the link above contains additional information" } } } ``` ## hostname_search To the exception of __hostname_search__, all attributes use the same syntax as the ossec rule in XML format does. __hostname_search__ in this cookbook represents a search query that is executed by the server recipe to populate the `````` with the proper list of hosts, dynamically pulled from chef. Search criterias can be anything that a chef search can take. Example: ```recipe:mongodb\:\:replicaset and tags:reputation``` # Local Decoders Definitions Decoders are defined in JSON format and replicate the XML format of regular [OSSEC Decoder Syntax](http://www.ossec.net/doc/syntax/head_decoders.html) "ossec" => { "decoders" => { 'apache-errorlog' => { "program_name" => '^httpd|^apache2', "prematch" => { "parser" => '^\S+ [\w+\s*\d+ \S+ \d+] [\S+] |^[warn] |^[notice] |^[error]' }, }, 'apache-errorlog-ip-custom' => { "parent" => 'apache-errorlog', "prematch" => { "offset" => 'after_parent', "parser" => '^[client' }, "regex" => { "offset" => 'after_prematch', "parser" => '^ (\d+.\d+.\d+.\d+)]' }, "order" => 'srcip' }, 'web-accesslog-custom' => { "parent" => 'web-accesslog', "type" => 'web-log', "prematch" => { "parser" => '^\d+.\d+.\d+.\d+ |^::ffff:\d+.\d+.\d+.\d+' }, "regex" => { "parser" => '^\d+.\d+.\d+.\d+ \S+ (\d+.\d+.\d+.\d+) \S+ \S+ \S+ [\S+ \S\d+] "\w+ (\S+) HTTP\S+ (\d+) \S+ "(\S+)"' }, "order" => 'srcip, url, id, extra_data' } } } ```prematch``` and ```regex``` are hashes that can have an ```offset``` value and always have a ```parser``` value. See the ossec documentation for more information. # Local Syslog Files and Syscheck Ignore Files If you want specific log files to be monitored on specific agents, you can use a `syslog_files` block in the agent node attributes. The `apply_to` parameter of this block is a `Chef::Search()` that will expand to a list of hosts. If the given agent belong to the list of hosts, it will add the logfile to its local ossec configuration. log_format will default to "syslog" if not set. If you want to ignore specific files in syscheck, similarly you can use the same `apply_to` option as shown below: ``` default_attributes( "ossec" => { "syslog_files" => { '/var/log/supervisor/supervisor.log' => { 'apply_to' => 'supervisor:*', 'log_format' => 'syslog' } }, "syscheck" => { "ignore" => { '/etc/openvpn/openvpn-status.log' => { 'apply_to' => 'roles:vpn-server' }, '^/opt/graphite/storage/' => { 'apply_to' => 'roles:graphite-server OR roles:statsd-server', 'type' => 'sregex' } } } } ) ``` # OSSEC Rules Enable/Disable You can also choose what rules OSSEC it configured to load. Each of the rules in /var/ossec/rules can be enabled and disabled at will with a very simple format. Note that these do not have an apply_to option and are just boolean values, this is because only the OSSEC server loads the rules into action. The following is an example that will enable the normally disabled `symantec-av-rules.xml` and disable the `web_rules.xml`: ``` default_attributes( "ossec" => { "load_rules" => { 'symantec-av_rules.xml' => true, 'web_rules.xml' => false } } ) ``` # Commands and Auto-Response Since OSSEC is an HIDS system, you can also enable and disable commands and active-response functionality and define your own as needed. You can enable or disable existing defined commands and active-responses using the `enable` flag, and target where they are set using the `apply_to` flag. You can also define any of the allowed active-response options dynamically, such as adding agent_id, rules_group, etc. Here is an example of enabling the firewall-stop command and its auto-response and changing it from the default local to all hosts and adding a `rules_group` to the active-response definition so it only triggers on authentication failures: ``` default_attributes( "ossec" => { "command" => { "firewall-stop" => { "enabled" => true } }, "auto-response => { "firewall-stop" => { "enabled" => true, "location" => "all", "rules_group" => "authentication_failed,authentication_failures" } } } ) ``` Usage ===== * `recipe[ossec-server]` should be a stand alone installation * `recipe[ossec-agent]` should be added (via role[ossec-agent]) to all the nodes of the environment # Example Roles ## ossec-server This role can be used to provision an ossec server: ```ruby name 'ossec-server' description 'OSSEC Server' run_list( 'recipe[ossec-ng::server]', 'role[postfix]' ) override_attributes( "ossec" => { "agent" => { "enable" => false } } ) default_attributes( "ossec" => { "email_notification" => 'yes', "email_to" => [ 'ossec-alerts@example.net', ], "email_from" => 'ossec-server', "smtp_server" => 'localhost', "white_list" => [ '127.0.0.1', '10.0.0.0/0' ], "email_alerts" => { 'bob@example.net' => { 'event_location_tag' => 'project1', }, 'alice@example.net' => { 'event_location_tag' => 'project1', 'group' => 'developers', }, 'eve@example.net' => { 'event_location_tag' => 'project2', 'group' => 'developers', }, 'mike@example.net' => { 'event_location_search' => 'tags:project1 OR tags:project2 OR tags:project3', 'group' => 'developers', }, 'group2@example.net' => { 'event_location_search' => 'roles:application-server AND roles:python-django', 'group' => 'frontend-group', }, }, "decoders" => { 1 => { "name" => 'apache-errorlog', "program_name" => '^httpd|^apache2', "prematch" => { "parser" => '^\S+ [\w+\s*\d+ \S+ \d+] [\S+] |^[warn] |^[notice] |^[error]' }, }, 2 => { "name" => 'apache-errorlog-ip-custom', "parent" => 'apache-errorlog', "prematch" => { "offset" => 'after_parent', "parser" => '^[client' }, "regex" => { "offset" => 'after_prematch', "parser" => '^ (\d+.\d+.\d+.\d+)]' }, "order" => 'srcip' }, 3 => { "name" => 'web-accesslog-custom', "parent" => 'web-accesslog', "type" => 'web-log', "prematch" => { "parser" => '^\d+.\d+.\d+.\d+ |^::ffff:\d+.\d+.\d+.\d+' }, "regex" => { "parser" => '^\d+.\d+.\d+.\d+ \S+ (\d+.\d+.\d+.\d+) \S+ \S+ \S+ [\S+ \S\d+] "\w+ (\S+) HTTP\S+ (\d+) \S+ "(\S+)"' }, "order" => 'srcip, url, id, extra_data' } }, "rules" => { 1002 => { "head" => { "level" => '2', "overwrite" => 'yes' }, "body" => { "description" => 'Unknown problem somewhere in the system.', "match" => 'core_dumped|failure|error|Error|attack|bad |illegal |denied|refused|unauthorized|fatal|fail|Segmentation Fault|Corrupted|Traceback|raise', "options" => 'alert_by_email' } }, 1003 => { "head" => { "level" => '6', "maxsize" => '16384', "overwrite" => 'yes' }, "body" => { "description" => 'Non standard syslog message (larger than 16kB).' } }, 100003 => { "head" => { "level" => '10' }, "body" => { "description" => 'Successful sudo during non-business hours 6pm to 8am', "if_sid" => '5402,5403', "time" => '10pm - 12am' } }, 100004 => { "head" => { "level" => '10' }, "body" => { "description" => 'Successful sudo during weekend.', "if_sid" => '5402,5403', "weekday" => 'weekends' } }, 100005 => { "head" => { "level" => '0' }, "body" => { "description" => 'Silencing sudo errors from accounts allowed to sudo anytime', "if_sid" => '100004,100005', "match" => 'nagios' } }, 100006 => { "head" => { "level" => '0' }, "body" => { "description" => 'Silencing ossec agent stop/start during business hours 8am to 6pm', "if_sid" => '502,503,504', "time" => '12:00-22:00', "weekday" => 'monday,tuesday,wednesday,thursday,friday' } }, 100007 => { "head" => { "level" => '8' }, "body" => { "description" => 'Login outside of business hours 6pm to 8am', "if_sid" => '5501', "time" => '22:00-12:00' } }, 100008 => { "head" => { "level" => '8' }, "body" => { "description" => 'Login during weekend.', "if_sid" => '5501', "weekday" => 'weekends' } }, 100009 => { "head" => { "level" => '0' }, "body" => { "description" => 'Ignore logins alerts for systems accounts', "if_sid" => '100007,100008', "match" => 'ubuntu|nagios' } } } } ) ``` ## ossec-agent This role can be used to provision an ossec-agent ```ruby name "ossec-agent" description "OSSEC Agent" run_list( "recipe[ossec-ng::agent]" ) default_attributes( "ossec" => { "client" => { "service_name" => 'ossec-hids-client' }, "syscheck" => { "frequency" => '7200', "alert_new_files" => 'yes', "auto_ignore" => 'no', "directories" => { '/bin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/boot' => { 'report_changes' => 'no', 'realtime' => 'no' }, '/etc' => { 'report_changes' => 'yes', 'realtime' => 'no' }, '/lib/lsb' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/modules' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/plymouth' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/security' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/terminfo' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/ufw' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/lib/xtables' => { 'report_changes' => 'no', 'realtime' => 'no' }, '/media' => { 'report_changes' => 'no', 'realtime' => 'no' }, '/opt' => { 'report_changes' => 'no', 'realtime' => 'no' }, '/root' => { 'report_changes' => 'yes', 'realtime' => 'no' }, '/srv' => { 'report_changes' => 'no', 'realtime' => 'no' }, '/sbin' => { 'report_changes' => 'no', 'realtime' => 'yes' }, '/usr/' => { 'report_changes' => 'yes', 'realtime' => 'yes' }, '/tmp' => { 'report_changes' => 'no', 'realtime' => 'no' } }, "ignore" => { '/etc/openvpn/openvpn-status.log' => {} '/etc/motd' => {}, '/etc/blkid.tab' => {}, '/etc/mtab' => {}, '/etc/mail/statistics' => {}, '/etc/random-seed' => {}, '/etc/adjtime' => {}, '/etc/prelink.cache' => {}, '/root/.bash_history' => {} '^/opt/graphite/storage/' => { 'apply_to' => 'roles:graphite-server OR roles:statsd-server', 'type' => 'sregex' }, '^/usr/lib/elasticsearch' => { 'apply_to' => 'roles:elastic-search-cluster', 'type' => 'sregex' }, '^/etc/chef/cache/checksums/' => { 'apply_to' => 'roles:chef-client', 'type' => 'sregex' }, '^/srv/rsyslog/' => { 'apply_to' => 'roles:rsyslog-server', 'type' => 'sregex' }, '^/etc/djbdns/public-dnscache/supervise/|^/etc/djbdns/tinydns-internal/supervise/|^/etc/djbdns/public-dnscache/log|^/etc/djbdns/tinydns-internal/log|^/etc/djbdns/tinydns-internal/root/data' => { 'apply_to' => 'roles:djbdns-server', 'type' => 'sregex' } } }, "syslog_files" => { '/var/log/syslog' => {}, '/var/log/auth.log' => {}, '/var/log/daemon.log' => {}, '/var/log/kern.log' => {}, '/var/log/mail.log' => {}, '/var/log/user.log' => {}, '/var/log/cron.log' => {}, '/var/log/chef/client.log' => {}, '/var/log/supervisor/supervisor.log' => { 'apply_to' => 'supervisor:*', 'log_format' => 'syslog' }, '/var/log/rabbitmq/rabbit1.log' => { 'apply_to' => 'recipes:rabbitmq', 'log_format' => 'multi-line:3' }, '/var/log/nginx/access.log' => { 'apply_to' => 'nginx:*', 'log_format' => 'syslog' }, '/var/log/nginx/error.log' => { 'apply_to' => 'nginx:*', 'log_format' => 'syslog' }, '/var/log/nagios3/nagios.log' => { 'apply_to' => 'roles:nagios-server', 'log_format' => 'syslog' }, '/var/log/nagios3/apache_access.log' => { 'apply_to' => 'roles:nagios-server', 'log_format' => 'syslog' }, '/var/log/nagios3/apache_error.log' => { 'apply_to' => 'roles:nagios-server', 'log_format' => 'syslog' } } } ) ``` Author ====== Eric Renfro - psi-jack@linux-help.org - https://linux-help.org Derived from works from: Julien Vehent - julien@linuxwall.info - http://jve.linuxwall.info