├── README.md
├── attributes
└── ossec.rb
├── libraries
└── core.rb
├── metadata.rb
├── recipes
├── agent.rb
├── default.rb
├── server.rb
└── supervisor_logs.rb
└── templates
└── default
├── .local_rules.xml.erb.swp
├── client.keys.erb
├── internal_options.conf.erb
├── local_decoder.xml.erb
├── local_rules.xml.erb
├── ossec-agent.conf.erb
└── ossec-server.conf.erb
/README.md:
--------------------------------------------------------------------------------
1 | Description
2 | ===========
3 | Fully automated Installation and configuration of ossec-servers and ossec-agents
4 | Manage the key generation and distribution between a server and multiple agents
5 | Clean queues on the server if needed (rid)
6 |
7 | Requirements
8 | ============
9 | Ubuntu 10.04+
10 | (should work with ossec systems if you have the packages)
11 |
12 | Attributes
13 | ==========
14 | # General Attributes
15 |
16 | The attributes below follow the same namespace syntax that OSSEC does. Refer to
17 | the official [OSSEC Documentation](http://www.ossec.net/doc/syntax/ossec_config.html)
18 | for more information.
19 |
20 | Default attributes from the cookbook:
21 |
22 | default[:version] = "2.6"
23 | default[:ossec][:syslog_output][:ip] = "127.0.0.1"
24 | default[:ossec][:syslog_output][:port] = "514"
25 | default[:ossec][:syslog_output][:min_level] = "5"
26 | default[:ossec][:receiver_port] = "1514"
27 | default[:ossec][:log_alert_level] = "1"
28 | default[:ossec][:email_alert_level] = "7"
29 | default[:ossec][:agents] = {}
30 |
31 | Default attributes from the ossec-server role:
32 |
33 | :ossec => {
34 | :email_notification => 'yes',
35 | :email_to => [
36 | 'ossec@example.net',
37 | ],
38 | :email_from => 'ossec-server@example.net',
39 | :smtp_server => 'localhost',
40 | :white_list => [
41 | '127.0.0.1',
42 | '10.1.0.0/16'
43 | ],
44 | :email_alerts => {
45 | 'recipient@example.net' => {
46 | 'level' => '9',
47 | 'group' => 'syscheck',
48 | 'event_location_tag' => 'reputation',
49 | 'event_location_search' => 'roles:*mongodb*',
50 | 'format' => 'sms',
51 | 'rule_id' => '100001',
52 | 'tags' => [
53 | 'do_not_delay',
54 | 'do_not_group'
55 | ]
56 | }
57 | },
58 | :server => {
59 | :service_name => 'ossec-hids-server'
60 | },
61 | :syscheck => {
62 | :frequency => '7200',
63 | :alert_new_files => 'yes',
64 | :auto_ignore => 'no',
65 | :directories => {
66 | '/bin' => {
67 | 'report_changes' => 'no',
68 | 'realtime' => 'yes'
69 | },
70 | '/sbin' => {
71 | 'report_changes' => 'no',
72 | 'realtime' => 'yes'
73 | },
74 | '/usr/bin' => {
75 | 'report_changes' => 'no',
76 | 'realtime' => 'yes'
77 | },
78 | '/usr/sbin' => {
79 | 'report_changes' => 'no',
80 | 'realtime' => 'yes'
81 | },
82 | '/etc' => {
83 | 'report_changes' => 'yes',
84 | 'realtime' => 'yes'
85 | },
86 | '/tmp' => {
87 | 'report_changes' => 'yes',
88 | 'realtime' => 'no'
89 | }
90 | },
91 | :ignore => [
92 | '/etc/openvpn/openvpn-status.log',
93 | '/etc/motd',
94 | '/etc/mcollective/facts.yaml',
95 | '/etc/blkid.tab',
96 | '/etc/mtab',
97 | '/etc/mail/statistics',
98 | '/etc/random-seed',
99 | '/etc/adjtime',
100 | '/etc/prelink.cache',
101 | '/etc/dnscache/stats',
102 | '/etc/dnscache/log',
103 | '/etc/dnscache2/stats',
104 | '/etc/dnscache2/log',
105 | '/etc/tinydns/stats',
106 | '/etc/tinydns/log'
107 | ]
108 | },
109 | :syslog_files => [
110 | '/var/log/syslog',
111 | '/var/log/auth.log',
112 | '/var/log/daemon.log',
113 | '/var/log/kern.log',
114 | '/var/log/mail.log',
115 | '/var/log/user.log',
116 | '/var/log/cron.log'
117 | ],
118 |
119 | ```email_alerts``` is a hash of recipients and servers. Each recipient will
120 | receive all of the alert for the listed location (the list is a regex).
121 | ```event_location_tag``` must contain a valid chef tag. All the nodes listed by
122 | that tag will generate a separate ```email_alerts``` rule.
123 | This is additional to the default list ```email_to``` and is used to send alert to
124 | specific recipients for a limited number of hosts only.
125 |
126 | # Local Rules Definitions
127 | Rules are defined in Ruby Hash format and replicate the XML format of regular
128 | [OSSEC Rules Syntax](http://www.ossec.net/doc/syntax/head_rules.html)
129 | Each rule has a head, a body, tags and info (the last 2 being optional)
130 |
131 | head=
132 | body= Test Rule
133 | body= Big Error
134 | body= server1
135 | tags=
136 | tags=
137 | info= http://IjustGotHacked.com
138 |
139 |
140 | The section below are parsed by the template. The following items are mandatory:
141 | * head/level
142 | * body/description
143 |
144 | ```
145 | :ossec =>
146 | :rules => {
147 | "100001" => {
148 | :head => {
149 | :level => "7",
150 | :maxsize => "65536",
151 | :frequency => "100",
152 | :timeframe => "3600",
153 | :ignore => "5",
154 | :overwrite => "68321"
155 | },
156 | :body => {
157 | :hostname_search => "recipes:mms-agent",
158 | :description => "Super Security Rule for application XYZ",
159 | :match => "super dangerous error happened",
160 | :regex => "^\d+Hello World$",
161 | :decoded_as => "vsftpd",
162 | :category => "windows",
163 | :srcip => "192.168.1.254",
164 | :dstip => "10.1.6.23",
165 | :user => "bob",
166 | :program_name => "nginx",
167 | :time => "09:00-18:00",
168 | :weekday => "monday,tuesday",
169 | :id => "404",
170 | :url => "/changepassword.php",
171 | :if_sid => "100238",
172 | :if_group => "authentication_success",
173 | :if_level => "13",
174 | :if_matched_sid => "12037",
175 | :if_matched_group => "adduser",
176 | :if_matched_level => "7",
177 | :options => "no_email_alert",
178 | :check_diff => "true",
179 | :group => "syscheck"
180 | },
181 | :tags => [
182 | "same_source_ip",
183 | "same_source_port",
184 | "same_dst_port",
185 | "same_location"
186 | ],
187 | :infos => {
188 | :link => "http://trac.example.net/ticket/12345",
189 | :text => "the link above contains additional information"
190 | }
191 | }
192 | }
193 | ```
194 |
195 | ## hostname_search
196 |
197 | To the exception of __hostname_search__, all attributes use the same syntax as the
198 | ossec rule in XML format does.
199 | __hostname_search__ in this cookbook represents a search query that is executed by
200 | the server recipe to populate the `````` with the proper list of hosts,
201 | dynamically pulled from chef. Search criterias can be anything that a chef search
202 | can take. Example: ```recipe:mongodb\:\:replicaset and tags:reputation```
203 |
204 | # Local Decoders Definitions
205 | Decoders are defined in JSON format and replicate the XML format of regular
206 | [OSSEC Decoder Syntax](http://www.ossec.net/doc/syntax/head_decoders.html)
207 |
208 | :ossec => {
209 | :decoders => {
210 | 'apache-errorlog' => {
211 | :program_name => '^httpd|^apache2',
212 | :prematch => {
213 | :parser => '^\S+ [\w+\s*\d+ \S+ \d+] [\S+] |^[warn] |^[notice] |^[error]'
214 | },
215 |
216 | },
217 | 'apache-errorlog-ip-custom' => {
218 | :parent => 'apache-errorlog',
219 | :prematch => {
220 | :offset => 'after_parent',
221 | :parser => '^[client'
222 | },
223 | :regex => {
224 | :offset => 'after_prematch',
225 | :parser => '^ (\d+.\d+.\d+.\d+)]'
226 | },
227 | :order => 'srcip'
228 | },
229 | 'web-accesslog-custom' => {
230 | :parent => 'web-accesslog',
231 | :type => 'web-log',
232 | :prematch => {
233 | :parser => '^\d+.\d+.\d+.\d+ |^::ffff:\d+.\d+.\d+.\d+'
234 | },
235 | :regex => {
236 | :parser => '^\d+.\d+.\d+.\d+ \S+ (\d+.\d+.\d+.\d+) \S+ \S+ \S+ [\S+ \S\d+] "\w+ (\S+) HTTP\S+ (\d+) \S+ "(\S+)"'
237 | },
238 | :order => 'srcip, url, id, extra_data'
239 | }
240 | }
241 | }
242 |
243 | ```prematch``` and ```regex``` are hashes that can have an ```offset``` value and
244 | always have a ```parser``` value. See the ossec documentation for more information.
245 |
246 | # Local Syslog Files
247 | If you want specific log files to be monitored on specific agents, you can use
248 | a `local_syslog_files` block in the agent node attributes. The `apply_to`
249 | parameter of this block is a `Chef::Search()` that will expand to a list of
250 | hosts. If the given agent belong to the list of hosts, it will add the logfile
251 | to its local ossec configuration.
252 |
253 | ```
254 | default_attributes(
255 | :ossec => {
256 | local_syslog_files => {
257 | '/var/log/supervisor/supervisor.log' => {
258 | 'apply_to' => 'supervisor:*',
259 | 'log_format' => 'syslog'
260 | },
261 | }
262 | }
263 | )
264 | ```
265 |
266 | Usage
267 | =====
268 | * `recipe[ossec-server]` should be a stand alone installation
269 | * `recipe[ossec-agent]` should be added (via role[ossec-agent]) to all the nodes of the
270 | environment
271 |
272 | # Example Roles
273 | ## ossec-server
274 | This role can be used to provision an ossec server:
275 |
276 | ```ruby
277 | name 'ossec-server'
278 | description 'OSSEC Server'
279 | run_list(
280 | 'recipe[ossec::server]',
281 | 'role[postfix]'
282 | )
283 | override_attributes(
284 | :ossec => {
285 | :agent => {
286 | :enable => false
287 | }
288 | }
289 | )
290 | default_attributes(
291 | :ossec => {
292 | :email_notification => 'yes',
293 | :email_to => [
294 | 'ossec-alerts@example.net',
295 | ],
296 | :email_from => 'ossec-server',
297 | :smtp_server => 'localhost',
298 | :white_list => [
299 | '127.0.0.1',
300 | '10.0.0.0/0'
301 | ],
302 | :email_alerts => {
303 | 'bob@example.net' => {
304 | 'event_location_tag' => 'project1',
305 | },
306 | 'alice@example.net' => {
307 | 'event_location_tag' => 'project1',
308 | 'group' => 'developers',
309 | },
310 | 'eve@example.net' => {
311 | 'event_location_tag' => 'project2',
312 | 'group' => 'developers',
313 | },
314 | 'mike@example.net' => {
315 | 'event_location_search' => 'tags:project1 OR tags:project2 OR tags:project3',
316 | 'group' => 'developers',
317 | },
318 | 'group2@example.net' => {
319 | 'event_location_search' => 'roles:application-server AND roles:python-django',
320 | 'group' => 'frontend-group',
321 | },
322 | },
323 | :decoders => {
324 | 1 => {
325 | :name => 'apache-errorlog',
326 | :program_name => '^httpd|^apache2',
327 | :prematch => {
328 | :parser => '^\S+ [\w+\s*\d+ \S+ \d+] [\S+] |^[warn] |^[notice] |^[error]'
329 | },
330 |
331 | },
332 | 2 => {
333 | :name => 'apache-errorlog-ip-custom',
334 | :parent => 'apache-errorlog',
335 | :prematch => {
336 | :offset => 'after_parent',
337 | :parser => '^[client'
338 | },
339 | :regex => {
340 | :offset => 'after_prematch',
341 | :parser => '^ (\d+.\d+.\d+.\d+)]'
342 | },
343 | :order => 'srcip'
344 | },
345 | 3 => {
346 | :name => 'web-accesslog-custom',
347 | :parent => 'web-accesslog',
348 | :type => 'web-log',
349 | :prematch => {
350 | :parser => '^\d+.\d+.\d+.\d+ |^::ffff:\d+.\d+.\d+.\d+'
351 | },
352 | :regex => {
353 | :parser => '^\d+.\d+.\d+.\d+ \S+ (\d+.\d+.\d+.\d+) \S+ \S+ \S+ [\S+ \S\d+] "\w+ (\S+) HTTP\S+ (\d+) \S+ "(\S+)"'
354 | },
355 | :order => 'srcip, url, id, extra_data'
356 | }
357 | },
358 | :rules => {
359 | 1002 => {
360 | :head => {
361 | :level => '2',
362 | :overwrite => 'yes'
363 | },
364 | :body => {
365 | :description => 'Unknown problem somewhere in the system.',
366 | :match => 'core_dumped|failure|error|Error|attack|bad |illegal |denied|refused|unauthorized|fatal|fail|Segmentation Fault|Corrupted|Traceback|raise',
367 | :options => 'alert_by_email'
368 | }
369 | },
370 | 1003 => {
371 | :head => {
372 | :level => '6',
373 | :maxsize => '16384',
374 | :overwrite => 'yes'
375 | },
376 | :body => {
377 | :description => 'Non standard syslog message (larger than 16kB).'
378 | }
379 | },
380 | 100003 => {
381 | :head => {
382 | :level => '10'
383 | },
384 | :body => {
385 | :description => 'Successful sudo during non-business hours 6pm to 8am',
386 | :if_sid => '5402,5403',
387 | :time => '10pm - 12am'
388 | }
389 | },
390 | 100004 => {
391 | :head => {
392 | :level => '10'
393 | },
394 | :body => {
395 | :description => 'Successful sudo during weekend.',
396 | :if_sid => '5402,5403',
397 | :weekday => 'weekends'
398 | }
399 | },
400 | 100005 => {
401 | :head => {
402 | :level => '0'
403 | },
404 | :body => {
405 | :description => 'Silencing sudo errors from accounts allowed to sudo anytime',
406 | :if_sid => '100004,100005',
407 | :match => 'nagios'
408 | }
409 | },
410 | 100006 => {
411 | :head => {
412 | :level => '0'
413 | },
414 | :body => {
415 | :description => 'Silencing ossec agent stop/start during business hours 8am to 6pm',
416 | :if_sid => '502,503,504',
417 | :time => '12:00-22:00',
418 | :weekday => 'monday,tuesday,wednesday,thursday,friday'
419 | }
420 | },
421 | 100007 => {
422 | :head => {
423 | :level => '8'
424 | },
425 | :body => {
426 | :description => 'Login outside of business hours 6pm to 8am',
427 | :if_sid => '5501',
428 | :time => '22:00-12:00'
429 | }
430 | },
431 | 100008 => {
432 | :head => {
433 | :level => '8'
434 | },
435 | :body => {
436 | :description => 'Login during weekend.',
437 | :if_sid => '5501',
438 | :weekday => 'weekends'
439 | }
440 | },
441 | 100009 => {
442 | :head => {
443 | :level => '0'
444 | },
445 | :body => {
446 | :description => 'Ignore logins alerts for systems accounts',
447 | :if_sid => '100007,100008',
448 | :match => 'ubuntu|nagios'
449 | }
450 | }
451 | }
452 | }
453 | )
454 | ```
455 |
456 | ## ossec-agent
457 | This role can be used to provision an ossec-agent
458 |
459 | ```ruby
460 | name "ossec-agent"
461 | description "OSSEC Agent"
462 | run_list(
463 | "recipe[ossec::agent]"
464 | )
465 | default_attributes(
466 | :ossec => {
467 | :client => {
468 | :service_name => 'ossec-hids-client'
469 | },
470 | :syscheck => {
471 | :frequency => '7200',
472 | :alert_new_files => 'yes',
473 | :auto_ignore => 'no',
474 | :directories => {
475 | '/bin' => {
476 | 'report_changes' => 'no',
477 | 'realtime' => 'yes'
478 | },
479 | '/boot' => {
480 | 'report_changes' => 'no',
481 | 'realtime' => 'no'
482 | },
483 | '/etc' => {
484 | 'report_changes' => 'yes',
485 | 'realtime' => 'no'
486 | },
487 | '/lib/lsb' => {
488 | 'report_changes' => 'no',
489 | 'realtime' => 'yes'
490 | },
491 | '/lib/modules' => {
492 | 'report_changes' => 'no',
493 | 'realtime' => 'yes'
494 | },
495 | '/lib/plymouth' => {
496 | 'report_changes' => 'no',
497 | 'realtime' => 'yes'
498 | },
499 | '/lib/security' => {
500 | 'report_changes' => 'no',
501 | 'realtime' => 'yes'
502 | },
503 | '/lib/terminfo' => {
504 | 'report_changes' => 'no',
505 | 'realtime' => 'yes'
506 | },
507 | '/lib/ufw' => {
508 | 'report_changes' => 'no',
509 | 'realtime' => 'yes'
510 | },
511 | '/lib/xtables' => {
512 | 'report_changes' => 'no',
513 | 'realtime' => 'no'
514 | },
515 | '/media' => {
516 | 'report_changes' => 'no',
517 | 'realtime' => 'no'
518 | },
519 | '/opt' => {
520 | 'report_changes' => 'no',
521 | 'realtime' => 'no'
522 | },
523 | '/root' => {
524 | 'report_changes' => 'yes',
525 | 'realtime' => 'no'
526 | },
527 | '/srv' => {
528 | 'report_changes' => 'no',
529 | 'realtime' => 'no'
530 | },
531 | '/sbin' => {
532 | 'report_changes' => 'no',
533 | 'realtime' => 'yes'
534 | },
535 | '/usr/' => {
536 | 'report_changes' => 'yes',
537 | 'realtime' => 'yes'
538 | },
539 | '/tmp' => {
540 | 'report_changes' => 'no',
541 | 'realtime' => 'no'
542 | }
543 | },
544 | :ignore => [
545 | '/etc/openvpn/openvpn-status.log',
546 | '/etc/motd',
547 | '/etc/blkid.tab',
548 | '/etc/mtab',
549 | '/etc/mail/statistics',
550 | '/etc/random-seed',
551 | '/etc/adjtime',
552 | '/etc/prelink.cache',
553 | '/root/.bash_history'
554 | ],
555 | :local_ignore => {
556 | '^/opt/graphite/storage/' => {
557 | 'apply_to' => 'roles:graphite-server OR roles:statsd-server',
558 | 'type' => 'sregex'
559 | },
560 | '^/usr/lib/elasticsearch' => {
561 | 'apply_to' => 'roles:elastic-search-cluster',
562 | 'type' => 'sregex'
563 | },
564 | '^/etc/chef/cache/checksums/' => {
565 | 'apply_to' => 'roles:chef-client',
566 | 'type' => 'sregex'
567 | },
568 | '^/srv/rsyslog/' => {
569 | 'apply_to' => 'roles:rsyslog-server',
570 | 'type' => 'sregex'
571 | },
572 | '^/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' => {
573 | 'apply_to' => 'roles:djbdns-server',
574 | 'type' => 'sregex'
575 | }
576 | }
577 | },
578 | :syslog_files => [
579 | '/var/log/syslog',
580 | '/var/log/auth.log',
581 | '/var/log/daemon.log',
582 | '/var/log/kern.log',
583 | '/var/log/mail.log',
584 | '/var/log/user.log',
585 | '/var/log/cron.log',
586 | '/var/log/chef/client.log'
587 | ],
588 | :local_syslog_files => {
589 | '/var/log/supervisor/supervisor.log' => {
590 | 'apply_to' => 'supervisor:*',
591 | 'log_format' => 'syslog'
592 | },
593 | '/var/log/rabbitmq/rabbit1.log' => {
594 | 'apply_to' => 'recipes:rabbitmq',
595 | 'log_format' => 'multi-line:3'
596 | },
597 | '/var/log/nginx/access.log' => {
598 | 'apply_to' => 'nginx:*',
599 | 'log_format' => 'syslog'
600 | },
601 | '/var/log/nginx/error.log' => {
602 | 'apply_to' => 'nginx:*',
603 | 'log_format' => 'syslog'
604 | },
605 | '/var/log/nagios3/nagios.log' => {
606 | 'apply_to' => 'roles:nagios-server',
607 | 'log_format' => 'syslog'
608 | },
609 | '/var/log/nagios3/apache_access.log' => {
610 | 'apply_to' => 'roles:nagios-server',
611 | 'log_format' => 'syslog'
612 | },
613 | '/var/log/nagios3/apache_error.log' => {
614 | 'apply_to' => 'roles:nagios-server',
615 | 'log_format' => 'syslog'
616 | }
617 | }
618 | }
619 | )
620 | ```
621 |
622 | Author
623 | ======
624 | Julien Vehent - julien@linuxwall.info - http://jve.linuxwall.info
625 |
--------------------------------------------------------------------------------
/attributes/ossec.rb:
--------------------------------------------------------------------------------
1 | default[:version] = "2.6"
2 | default[:ossec][:syslog_output][:ip] = "172.16.254.254"
3 | default[:ossec][:syslog_output][:port] = "514"
4 | default[:ossec][:syslog_output][:min_level] = "5"
5 | default[:ossec][:receiver_port] = "1514"
6 | default[:ossec][:log_alert_level] = "1"
7 | default[:ossec][:email_alert_level] = "7"
8 | default[:ossec][:email_maxperhour] = "9999"
9 | default[:ossec][:memory_size] = "100000"
10 | default[:ossec][:remote][:connection] = "secure"
11 | default[:ossec][:agents] = {}
12 | default[:ossec][:rules] = {}
13 | default[:ossec][:email_alerts] = {}
14 | default[:ossec][:agent][:enable] = true
15 | default[:ossec][:server][:service_name] = "ossec-hids-server"
16 | default[:ossec][:client][:service_name] = "ossec-hids-client"
17 |
18 |
19 | # internal options, you probably don't want to touch that
20 | default[:ossec][:internal][:analysisd][:default_timeframe] = "360"
21 | default[:ossec][:internal][:analysisd][:stats_maxdiff] = "25000"
22 | default[:ossec][:internal][:analysisd][:stats_mindiff] = "250"
23 | default[:ossec][:internal][:analysisd][:stats_percent_diff] = "30"
24 | default[:ossec][:internal][:analysisd][:fts_list_size] = "32"
25 | default[:ossec][:internal][:analysisd][:fts_min_size_for_str] = "14"
26 | default[:ossec][:internal][:analysisd][:log_fw] = "1"
27 | default[:ossec][:internal][:logcollector][:loop_timeout] = "2"
28 | default[:ossec][:internal][:logcollector][:open_attempts] = "8"
29 | default[:ossec][:internal][:remoted][:recv_counter_flush] = "128"
30 | default[:ossec][:internal][:remoted][:comp_average_printout] = "19999"
31 | default[:ossec][:internal][:remoted][:verify_msg_id] = "1"
32 | default[:ossec][:internal][:maild][:strict_checking] = "1"
33 | default[:ossec][:internal][:maild][:groupping] = "0"
34 | default[:ossec][:internal][:maild][:full_subject] = "1"
35 | default[:ossec][:internal][:monitord][:compress] = "1"
36 | default[:ossec][:internal][:monitord][:sign] = "1"
37 | default[:ossec][:internal][:monitord][:monitor_agents] = "1"
38 | default[:ossec][:internal][:syscheck][:sleep] = "2"
39 | default[:ossec][:internal][:syscheck][:sleep_after] = "15"
40 | default[:ossec][:internal][:dbd][:reconnect_attempts] = "10"
41 | default[:ossec][:internal][:window][:debug] = "0"
42 | default[:ossec][:internal][:syscheck][:debug] = "0"
43 | default[:ossec][:internal][:remoted][:debug] = "0"
44 | default[:ossec][:internal][:analysisd][:debug] = "0"
45 | default[:ossec][:internal][:logcollector][:debug] = "0"
46 | default[:ossec][:internal][:agent][:debug] = "0"
47 |
--------------------------------------------------------------------------------
/libraries/core.rb:
--------------------------------------------------------------------------------
1 | # Core function for OSSEC
2 | # Used by the server and agent recipes
3 |
4 | module OssecCore
5 |
6 | def ossec_hostname_search()
7 | # resolve the hostname_search of a rule to a list of hosts
8 | node[:ossec][:rules].each do |id,params|
9 | if not params.nil?
10 | params[:body].each do |key, value|
11 | if key.eql?('hostname_search')
12 | hosts_list = search(:node,
13 | "(#{value}) AND roles:ossec-agent "\
14 | " AND chef_environment:#{node.chef_environment}"
15 | ).map {|n| n.hostname}
16 | if hosts_list.empty?
17 | # search didn't return anything
18 | # store a dummy value in the attributes
19 | Chef::Log.info("OSSEC: Hostname search returned empty result. " +
20 | "'#{value}'")
21 | params[:body][:hostname] = "invalid-search-returned-empty-result"
22 | else
23 | # store in the node params but discard the last char
24 | params[:body][:hostname] = hosts_list.join('|')
25 | end
26 | end
27 | end
28 | end
29 | end
30 | end
31 |
32 |
33 | def ossec_event_location_search()
34 | # resolve the location search of an email_alert block to a hostname
35 | node[:ossec][:email_alerts].each do|recipient,params|
36 | if params.has_key?('event_location_search')
37 | dest = search(:node,
38 | "(#{params[:event_location_search]}) " \
39 | "AND chef_environment:#{node.chef_environment}"
40 | ).map {|n| n.hostname}
41 | node.default[:ossec][:email_alerts][recipient][:resolved_search] = dest
42 | end
43 | end
44 | end
45 |
46 |
47 | def ossec_set_local_syslog_file_ignore_flags!()
48 | # go through the list of local logfile and check the ones that
49 | # apply to this node
50 | unless node[:ossec][:local_syslog_files].nil?
51 | node[:ossec][:local_syslog_files].each do |logfile,params|
52 | locations = search(:node,
53 | "(#{params[:apply_to]}) " \
54 | "AND chef_environment:#{node.chef_environment}"
55 | ).map {|n| n.ipaddress}
56 | if locations.include?(node.ipaddress)
57 | node.default[:ossec][:local_syslog_files][logfile][:use_here] = "true"
58 | else
59 | node.default[:ossec][:local_syslog_files][logfile][:use_here] = "false"
60 | end
61 | end
62 | end
63 | end
64 |
65 |
66 | def ossec_set_local_file_ignore_flags!()
67 | # go through the list of locally ignored and check the ones that
68 | # apply to this node
69 | if not node[:ossec][:syscheck][:local_ignore].nil?
70 | node[:ossec][:syscheck][:local_ignore].each do |file,params|
71 | locations = search(:node,
72 | "(#{params[:apply_to]}) " \
73 | "AND chef_environment:#{node.chef_environment}"
74 | ).map {|n| n.ipaddress}
75 | if locations.include?(node.ipaddress)
76 | node.default[:ossec][:syscheck][:local_ignore][file][:use_here] = "true"
77 | else
78 | node.default[:ossec][:syscheck][:local_ignore][file][:use_here] = "false"
79 | end
80 | end
81 | end
82 | end
83 |
84 |
85 | def ossec_agent_create_parameters(agent, server)
86 | # Returns a hash with the identiers for this agent
87 | agent_hash = {}
88 | # IP is defined by lanip, if available (ohai plugin network_addr)
89 | # or by the default ipaddress otherwise
90 | agent_hash[:ip] = agent[:network][:lanip] || agent.ipaddress
91 |
92 | # Ossec limits the agents name length to 32 characters, so to avoid
93 | # names collisions, we concatenate the agent_ip with the first characters
94 | # of the hostname
95 | name = agent_hash[:ip] + "_" + agent[:hostname]
96 | agent_hash[:name] = name[0,31]
97 |
98 | # ossec agent id is an integer used to identify an agent. we force that ID
99 | # to be the IP address without the dots (10.1.2.3 becomes 10123)
100 | agent_hash[:id] = agent_hash[:ip].gsub(".", "")
101 |
102 | agent_hash[:key] = "undef"
103 | if server[:ossec][:agents].key?(agent_hash[:id])
104 | if server[:ossec][:agents][agent_hash[:id]].key?('key')
105 | agent_hash[:key] = server[:ossec][:agents][agent_hash[:id]][:key]
106 | end
107 | end
108 | agent_hash[:rid] = "none"
109 |
110 | return agent_hash
111 | end
112 |
113 |
114 | def ossec_generate_agent_key(agent_hash)
115 | # Returns a 64 characters double md5 hash, used as a symetric key
116 | seed1 = rand(100000000000).to_s
117 | seed2 = rand(100000000000).to_s
118 | str1 = Digest::MD5.hexdigest(seed1 + \
119 | agent_hash[:id] + \
120 | agent_hash[:ip] + \
121 | seed2)
122 | str2 = Digest::MD5.hexdigest(seed2 + \
123 | agent_hash[:name] + \
124 | seed1 + \
125 | agent_hash[:ip] + \
126 | agent_hash[:id])
127 | key = str1 + str2
128 | return key
129 | end
130 |
131 |
132 | def ossec_agent_has_valid_key?(agent_hash, server)
133 | # Does the server have a valid key for this agent ?
134 | if server[:ossec][:agents].key?(agent_hash[:id])
135 | if server[:ossec][:agents][agent_hash[:id]].key?('key')
136 | if server[:ossec][:agents][agent_hash[:id]][:key].length == 64
137 | return true
138 | end
139 | end
140 | end
141 | return false
142 | end
143 |
144 |
145 | def ossec_agent_knows_key?(agent_hash, agent)
146 | # Does the agent have a key that matches the server ?
147 | if agent.key?('ossec')
148 | if agent[:ossec].key?('agents')
149 | if agent[:ossec][:agents].key?(agent_hash[:id])
150 | if agent[:ossec][:agents][agent_hash[:id]].key?('key')
151 | if agent[:ossec][:agents][agent_hash[:id]][:key] == agent_hash[:key]
152 | return true
153 | end
154 | end
155 | end
156 | end
157 | end
158 | return false
159 | end
160 |
161 |
162 | def ossec_verify_agent(agent_hash, server)
163 | # check if this agent (id, name, ip) is defined on the server
164 | if server[:ossec][:agents].key?(agent_hash[:id])
165 | agent_srv_data = server[:ossec][:agents][agent_hash[:id]]
166 | if agent_srv_data[:name].eql?(agent_hash[:name])
167 | if agent_srv_data[:ip].eql?(agent_hash[:ip])
168 | return true
169 | else
170 | Chef::Log.info("OSSEC: agent ip mismatch. " +
171 | "server has '#{agent_srv_data[:ip]}' " +
172 | "agent has '#{agent_hash[:ip]}'")
173 | end
174 | else
175 | Chef::Log.info("OSSEC: agent name mismatch. " +
176 | "server has '#{agent_srv_data[:name]}' " +
177 | "agent has '#{agent_hash[:name]}'")
178 | end
179 | else
180 | Chef::Log.info("OSSEC: agent name '#{agent_hash[:name]}' " +
181 | " ip '#{agent_hash[:ip]}'" +
182 | " configuration not found on server.")
183 | end
184 | return false
185 | end
186 |
187 |
188 | def ossec_agent_is_active?(id)
189 | if File.exists?("/var/ossec/bin/agent_control")
190 | cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
191 | cmd_ret = cmd.run_command
192 | status = cmd.stdout.split(",")
193 | if status[3] && status[3].eql?("Active")
194 | return true
195 | end
196 | end
197 | return false
198 | end
199 |
200 |
201 | def ossec_agent_is_zombie?(id)
202 | if File.exists?("/var/ossec/bin/agent_control")
203 | cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
204 | cmd_ret = cmd.run_command
205 | status = cmd.stdout.split(",")
206 | if not status[6] || status[3] =~ /(Never connected|)/
207 | return true
208 | elsif status[6] !~ /Unknown/
209 | last_keep_alive = Time.parse(status[6])
210 | three_days_ago = (Time.now - (24*60*60*3))
211 | if three_days_ago > last_keep_alive
212 | return true
213 | end
214 | end
215 | end
216 | return false
217 | end
218 |
219 |
220 | def ossec_agent_should_be_removed?(id)
221 | if File.exists?("/var/ossec/bin/agent_control")
222 | cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -s -i #{id}")
223 | cmd_ret = cmd.run_command
224 | status = cmd.stdout.split(",")
225 | if not status[6] or status[6] =~ /Unknown/
226 | return true
227 | else
228 | last_keep_alive = Time.parse(status[6])
229 | seven_days_ago = (Time.now - (24*60*60*7))
230 | if seven_days_ago > last_keep_alive
231 | return true
232 | end
233 | end
234 | end
235 | return false
236 | end
237 |
238 |
239 | def ossec_agent_needs_rid?(id, agent)
240 | # Check if the agent queue needs to be removed, either because the server
241 | # said so, or because the agent asked for it
242 | if agent[:ossec][:agents][id][:rid].eql?("todo") \
243 | or node[:ossec][:agents][id][:rid].eql?("todo")
244 | return true
245 | else
246 | return false
247 | end
248 | end
249 | end
250 |
--------------------------------------------------------------------------------
/metadata.rb:
--------------------------------------------------------------------------------
1 | name "autossec"
2 | maintainer "Julien Vehent"
3 | maintainer_email "julien@linuxwall.info"
4 | license "GPLv2"
5 | description "Installs/Configures ossec"
6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
7 | version "1.0.0"
8 |
9 | depends "postfix"
10 |
--------------------------------------------------------------------------------
/recipes/agent.rb:
--------------------------------------------------------------------------------
1 | # Ossec Agent provisioning recipe
2 | # install the ossec-hids-client package, push the global
3 | # and role specific configuration for the node
4 | # get a key from the ossec-server if there's one
5 |
6 | if not node['lsb']['codename'].eql?('lucid')
7 | return true
8 | end
9 |
10 | class Chef::Recipe
11 | include OssecCore
12 | end
13 |
14 |
15 | # Run this recipe if the node is an agent. Since the ossec::agent recipe is
16 | # added to the base role, ossec-servers will run it as well, making this check
17 | # necessary
18 | if not node[:ossec][:agent][:enable]
19 | # return will exit this recipe
20 | # and continue the chef provisioning
21 | Chef::Log.info("OSSEC: agent is not enabled on this node")
22 | return true
23 | end
24 |
25 | # Search for the ossec server, and do nothing if there's none
26 | ossec_server = search(:node,
27 | "role:ossec-server " \
28 | "AND chef_environment:#{node.chef_environment}"
29 | ).first
30 | if ossec_server.nil?
31 | Chef::Log.info("OSSEC: No ossec server available. Agent will not be provisionned")
32 | return true
33 | end
34 |
35 | # install the agent package
36 | package "ossec-hids-client"
37 |
38 | # define the agent parameters
39 | agent_hash = ossec_agent_create_parameters(node, ossec_server)
40 |
41 | # check for the agent configuration on the server. if the server has none, do
42 | # not continue the provisioning. If the server has a configuration for this
43 | # agent, store the parameters on the node and continue
44 | if ossec_verify_agent(agent_hash, ossec_server)
45 | node.set[:ossec][:agents][agent_hash[:id]] = ossec_server[:ossec][:agents][agent_hash[:id]].to_hash
46 | else
47 | Chef::Log.info("OSSEC: this agent is unknown on the ossec server")
48 | return true
49 | end
50 |
51 | # Make sure that the server prepared a key for us
52 | unless ossec_agent_has_valid_key?(agent_hash, ossec_server)
53 | Chef::Log.info("OSSEC: Server doesn't have a valid key for agent.")
54 | return true
55 | end
56 |
57 | service "ossec-agent" do
58 | provider Chef::Provider::Service::Init
59 | service_name node[:ossec][:client][:service_name]
60 | supports :start => true, :stop => true, :restart => true, :status => true
61 | action [ :start ]
62 | only_if "test -e /var/ossec/etc/ossec.conf && test -e /var/ossec/etc/client.keys"
63 | end
64 |
65 | # Get the IP of the ossec server
66 | ossec_server_ip = ossec_server[:network][:lanip] || ossec_server.ipaddress
67 | # Expand the local syslog files searches from the node attributes
68 | ossec_set_local_syslog_file_ignore_flags!()
69 | ossec_set_local_file_ignore_flags!()
70 | template "/var/ossec/etc/ossec.conf" do
71 | source "ossec-agent.conf.erb"
72 | owner "ossec"
73 | group "ossec"
74 | variables(:ossec_server_ip => ossec_server_ip )
75 | notifies :restart, "service[ossec-agent]"
76 | end
77 |
78 | # If client.keys is modified, ask for a queue rid on the server
79 | template "/var/ossec/etc/client.keys" do
80 | mode 0440
81 | owner "root"
82 | group "ossec"
83 | notifies :create, "ruby_block[set-rid-flag]"
84 | notifies :restart, "service[ossec-agent]"
85 | end
86 |
87 | # "set-rid-flag" is not run by default, but called when the agent's key
88 | # is modified (or created)
89 | ruby_block "set-rid-flag" do
90 | block do
91 | # if the server side rid flag is not set to "done",
92 | # request a queue rid by setting the agent side flag to "todo"
93 | if ossec_server[:ossec][:agents][agent_hash[:id]][:rid].eql?("none")
94 | node.set[:ossec][:agents][agent_hash[:id]][:rid] = "todo"
95 | Chef::Log.info "Setting Queue Rid Flag on"
96 | end
97 | end
98 | action :nothing
99 | end
100 |
101 | # unset rid flag if necessary, check that at every run
102 | if node[:ossec][:agents][agent_hash[:id]][:rid].eql?("todo") \
103 | and ossec_server[:ossec][:agents][agent_hash[:id]][:rid].eql?("done")
104 | ruby_block "unset rid flag" do
105 | block do
106 | node.set[:ossec][:agents][agent_hash[:id]][:rid] = "none"
107 | Chef::Log.info "Setting Queue Rid Flag off"
108 | end
109 | notifies :restart, "service[ossec-agent]"
110 | end
111 | end
112 |
--------------------------------------------------------------------------------
/recipes/default.rb:
--------------------------------------------------------------------------------
1 | #
2 | # Cookbook Name:: ossec
3 | # Recipe:: default
4 | #
5 | include_recipe "ossec::agent"
6 |
7 |
--------------------------------------------------------------------------------
/recipes/server.rb:
--------------------------------------------------------------------------------
1 | # Ossec server provisioning recipe
2 | # install the ossec-hids-server package and push the
3 | # default configuration from the templates
4 |
5 | include_recipe "postfix::default"
6 |
7 | class Chef::Recipe
8 | include OssecCore
9 | end
10 |
11 |
12 | package "ossec-hids-server"
13 |
14 | service "ossec-server" do
15 | provider Chef::Provider::Service::Init
16 | service_name node[:ossec][:server][:service_name]
17 | supports :start => true, :stop => true, :restart => true, :status => true
18 | action [ :start ]
19 | only_if "test -e /var/ossec/etc/ossec.conf"
20 | end
21 |
22 | # Get all the agents at once, more efficient
23 | ossec_agents = search(:node,
24 | "roles:ossec-agent "\
25 | "AND chef_environment:#{node.chef_environment}")
26 |
27 | # resolve searches in server rules
28 | ossec_hostname_search()
29 |
30 | # resolve email_alerts location searches
31 | ossec_event_location_search()
32 |
33 | # initialize the agent hash on the first run
34 | if node[:ossec][:agents].nil?
35 | node.set[:ossec][:agents] = {}
36 | end
37 |
38 | ossec_agents.each do |agent|
39 | # don't process thy self
40 | if agent.ipaddress == node.ipaddress
41 | next
42 | end
43 |
44 | agent_hash = ossec_agent_create_parameters(agent, node)
45 |
46 | # this agent is running fine, go to the next one
47 | if ossec_agent_is_active?(agent_hash[:id])
48 | node.set[:ossec][:agents][agent_hash[:id]][:status] = "active"
49 | next
50 | end
51 |
52 | # check that the agent ID still point to the same IP and hostname
53 | # otherwise, delete the record from the ossec server
54 | if not ossec_verify_agent(agent_hash, node)
55 | Chef::Log.info("OSSEC: deleting server record for agent '#{agent_hash[:id]}'")
56 | node[:ossec][:agents].delete(agent_hash[:id])
57 | end
58 |
59 | # if this agent doesn't have a valid key, generate one
60 | if not ossec_agent_has_valid_key?(agent_hash, node)
61 | Chef::Log.info("OSSEC: agent '#{agent_hash[:id]}' needs a key. Generating one.")
62 | agent_hash[:key] = ossec_generate_agent_key(agent_hash)
63 | agent_hash[:rid] = "todo"
64 | agent_hash[:status] = "key_exists"
65 | end
66 |
67 | # save agent parameters
68 | agent_hash.each do |k,v|
69 | node.set[:ossec][:agents][agent_hash[:id]][k] = v
70 | end
71 |
72 | # Don't continue if the agent has a valid key but doesn't know it yet
73 | if not ossec_agent_knows_key?(agent_hash, agent)
74 | Chef::Log.info("OSSEC: agent '#{agent_hash[:id]}' didn't pick up its key yet.")
75 | next
76 | end
77 |
78 | # Check if it needs a queue cleanup
79 | if ossec_agent_needs_rid?(agent_hash[:id], agent)
80 | ruby_block "ossec queue rid" do
81 | block do
82 | if File.exists?("/var/ossec/queue/rids/#{agent_hash[:id]}")
83 | File.delete("/var/ossec/queue/rids/#{agent_hash[:id]}")
84 | Chef::Log.info("OSSEC: deleted queue for agent '#{agent_hash[:id]}'")
85 | else
86 | Chef::Log.info("OSSEC: No queue for agent '#{agent_hash[:id]}.'")
87 | end
88 | node.set[:ossec][:agents][agent_hash[:id]][:rid] = "done"
89 | end
90 | notifies :restart, "service[ossec-server]"
91 | end
92 | # done with this agent, go to the next one
93 | next
94 | end
95 |
96 | # If after all that, the agent is still not active, mark it as so
97 | if not ossec_agent_is_active?(agent_hash[:id])
98 | if ossec_agent_is_zombie?(agent_hash[:id])
99 | node.set[:ossec][:agents][agent_hash[:id]][:status] = "zombie"
100 | # if the agent is a zombie, perform a rid of its queue on the next run
101 | Chef::Log.info("OSSEC: agent #{agent_hash[:id]} is a zombie. " +
102 | "Request queue deletion")
103 | node.set[:ossec][:agents][agent_hash[:id]][:rid] = "todo"
104 | else
105 | node.set[:ossec][:agents][agent_hash[:id]][:status] = "disconnected"
106 | Chef::Log.info("OSSEC: agent #{agent_hash[:id]} connection failed. " +
107 | "Performing restart")
108 | cmd = Chef::ShellOut.new("/var/ossec/bin/agent_control -R #{agent_hash[:id]}")
109 | cmd_ret = cmd.run_command
110 | end
111 | end
112 | end
113 |
114 | # Remove the attributes of an agent from the ossec server if the agent doesn't
115 | # exist on Chef and the last keep_alive is more than 7 days old
116 | node[:ossec][:agents].each do |agent_id, params|
117 | if params[:status].eql?('key_exists')
118 | next
119 | end
120 |
121 | agent = ossec_agents.select{ |n| (n[:ossec][:agents].has_key?(agent_id) \
122 | && n[:ossec][:agent][:enable])
123 | }.first
124 |
125 | if not agent.nil?
126 | next
127 | end
128 | if ossec_agent_should_be_removed?(agent_id)
129 | Chef::Log.info("OSSEC: Removing old agent '#{agent_id}' - '#{params[:name]}'")
130 | node[:ossec][:agents].delete(agent_id)
131 | else
132 | Chef::Log.info("OSSEC: agent '#{agent_id}' - '#{params[:name]}' is candidate for removal")
133 | node.set[:ossec][:agents][agent_id][:status] = 'candidate_for_removal'
134 | end
135 | end
136 |
137 | template "/var/ossec/etc/client.keys" do
138 | mode 0440
139 | owner "root"
140 | group "ossec"
141 | end
142 |
143 | template "/var/ossec/rules/local_rules.xml" do
144 | owner "root"
145 | group "root"
146 | notifies :restart, "service[ossec-server]"
147 | end
148 |
149 | template "/var/ossec/etc/local_decoder.xml" do
150 | owner "root"
151 | group "root"
152 | notifies :restart, "service[ossec-server]"
153 | end
154 |
155 | template "/var/ossec/etc/ossec.conf" do
156 | source "ossec-server.conf.erb"
157 | owner "ossec"
158 | group "ossec"
159 | variables( :ossec_agents => ossec_agents )
160 | notifies :restart, "service[ossec-server]"
161 | end
162 |
163 | template "/var/ossec/etc/internal_options.conf" do
164 | mode 0444
165 | owner "root"
166 | group "root"
167 | notifies :restart, "service[ossec-server]"
168 | end
169 |
--------------------------------------------------------------------------------
/recipes/supervisor_logs.rb:
--------------------------------------------------------------------------------
1 | # This recipe will list the log file created by supervisor
2 | # and add the necessary attributes to have those monitored
3 | # by the local ossec-agent
4 |
5 | # cleanup, before recreation
6 | node[:ossec][:local_syslog_files].each do |logfile, params|
7 | if logfile =~ /supervisor/
8 | node[:ossec][:local_syslog_files].delete(logfile)
9 | end
10 | end
11 |
12 | # each program run by supervisor has a set of logfiles
13 | node[:supervisor][:programs].each do |program_name, config|
14 | total_procs = config[:numprocs] || 1
15 | # each process of a program has its own log file
16 | 0.upto(total_procs.to_i - 1) do |numproc|
17 | logfile = "#{node[:supervisor][:log_path]}/#{program_name}_#{numproc}_stdout.log"
18 | # add the stdout supervisor log file
19 | node[:ossec][:local_syslog_files][logfile] = {
20 | 'apply_to' => "fqdn:#{node.fqdn}",
21 | 'log_format' => 'syslog',
22 | 'use_here' => 'true'
23 | }
24 | log("Ossec::Supervisor: Adding '#{logfile}' to monitored log files")
25 |
26 | logfile = "#{node[:supervisor][:log_path]}/#{program_name}_#{numproc}_stderr.log"
27 | # add the stderr supervisor log file
28 | node[:ossec][:local_syslog_files][logfile] = {
29 | 'apply_to' => "fqdn:#{node.fqdn}",
30 | 'log_format' => 'syslog',
31 | 'use_here' => 'true'
32 | }
33 | log("Ossec::Supervisor: Adding '#{logfile}' to monitored log files")
34 |
35 | end
36 | end
37 |
--------------------------------------------------------------------------------
/templates/default/.local_rules.xml.erb.swp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jvehent/AutOssec/a9ff216430d6b6fb3af965aebb3e3af29eca46c3/templates/default/.local_rules.xml.erb.swp
--------------------------------------------------------------------------------
/templates/default/client.keys.erb:
--------------------------------------------------------------------------------
1 | <% if not node[:ossec][:agents].nil?
2 | node[:ossec][:agents].sort.each do |ip,fields|
3 | if not fields[:key].nil?
4 | %>
5 | <%= fields[:id] %> <%= fields[:name] %> <%= fields[:ip] %> <%= fields[:key]%>
6 | <% end
7 | end
8 | end
9 | -%>
10 |
--------------------------------------------------------------------------------
/templates/default/internal_options.conf.erb:
--------------------------------------------------------------------------------
1 | # internal_options.conf, Daniel B. Cid (dcid @ ossec.net).
2 | #
3 | # DO NOT TOUCH THIS FILE. The default configuration
4 | # is at ossec.conf. More information at:
5 | # http://www.ossec.net/en/manual.html
6 | #
7 | # This file should be handled with care. It contain
8 | # run time modifications that can affect the use
9 | # of ossec. Only change it if you know what you
10 | # are doing. Again, look first at ossec.conf
11 | # for most of the things you want to change.
12 |
13 |
14 | # Analysisd default rule timeframe.
15 | analysisd.default_timeframe=<%= node[:ossec][:internal][:analysisd][:default_timeframe] %>
16 | # Analysisd stats maximum diff.
17 | analysisd.stats_maxdiff=<%= node[:ossec][:internal][:analysisd][:stats_maxdiff] %>
18 | # Analysisd stats minimum diff.
19 | analysisd.stats_mindiff=<%= node[:ossec][:internal][:analysisd][:stats_mindiff] %>
20 | # Analysisd stats percentage (how much to differ from average)
21 | analysisd.stats_percent_diff=<%= node[:ossec][:internal][:analysisd][:stats_percent_diff] %>
22 | # Analysisd FTS list size.
23 | analysisd.fts_list_size=<%= node[:ossec][:internal][:analysisd][:fts_list_size] %>
24 | # Analysisd FTS minimum string size.
25 | analysisd.fts_min_size_for_str=<%= node[:ossec][:internal][:analysisd][:fts_min_size_for_str] %>
26 | # Analysisd Enable the firewall log (at logs/firewall/firewall.log)
27 | # 1 to enable, 0 to disable.
28 | analysisd.log_fw=<%= node[:ossec][:internal][:analysisd][:log_fw] %>
29 |
30 |
31 | # Logcollector file loop timeout (check every 2 seconds for file changes)
32 | logcollector.loop_timeout=<%= node[:ossec][:internal][:logcollector][:loop_timeout] %>
33 |
34 | # Logcollector number of attempts to open a log file.
35 | logcollector.open_attempts=<%= node[:ossec][:internal][:logcollector][:open_attempts] %>
36 |
37 |
38 | # Remoted counter io flush.
39 | remoted.recv_counter_flush=<%= node[:ossec][:internal][:remoted][:recv_counter_flush] %>
40 |
41 | # Remoted compression averages printout.
42 | remoted.comp_average_printout=<%= node[:ossec][:internal][:remoted][:comp_average_printout] %>
43 |
44 | # Verify msg id (set to 0 to disable it)
45 | remoted.verify_msg_id=<%= node[:ossec][:internal][:remoted][:verify_msg_id] %>
46 |
47 |
48 | # Maild strict checking (0=disabled, 1=enabled)
49 | maild.strict_checking=<%= node[:ossec][:internal][:maild][:strict_checking] %>
50 |
51 | # Maild grouping (0=disabled, 1=enabled)
52 | # Groups alerts within the same e-mail.
53 | maild.groupping=<%= node[:ossec][:internal][:maild][:groupping] %>
54 |
55 | # Maild full subject (0=disabled, 1=enabled)
56 | maild.full_subject=<%= node[:ossec][:internal][:maild][:full_subject] %>
57 |
58 |
59 | # Monitord day_wait. Ammount of seconds to wait before compressing/signing
60 | # the files.
61 | monitord.day_wait=10<%= node[:ossec][:internal][:monitord][:day_wait] %>
62 |
63 | # Monitord compress. (0=do not compress, 1=compress)
64 | monitord.compress=<%= node[:ossec][:internal][:monitord][:compress] %>
65 |
66 | # Monitord sign. (0=do not sign, 1=sign)
67 | monitord.sign=<%= node[:ossec][:internal][:monitord][:sign] %>
68 |
69 | # Monitord monitor_agents. (0=do not monitor, 1=monitor)
70 | monitord.monitor_agents=<%= node[:ossec][:internal][:monitord][:monitor_agents] %>
71 |
72 |
73 | # Syscheck checking/usage speed. To avoid large cpu/memory
74 | # usage, you can specify how much to sleep after generating
75 | # the checksum of X files. The default is to sleep 2 seconds
76 | # after reading 15 files.
77 | syscheck.sleep=<%= node[:ossec][:internal][:syscheck][:sleep] %>
78 | syscheck.sleep_after=<%= node[:ossec][:internal][:syscheck][:sleep_after] %>
79 |
80 |
81 | # Database - maximum number of reconnect attempts
82 | dbd.reconnect_attempts=<%= node[:ossec][:internal][:dbd][:reconnect_attempts] %>
83 |
84 |
85 | # Debug options.
86 | # Debug 0 -> no debug
87 | # Debug 1 -> first level of debug
88 | # Debug 2 -> full debugging
89 |
90 | # Windows debug (used by the windows agent)
91 | windows.debug=<%= node[:ossec][:internal][:window][:debug] %>
92 |
93 | # Syscheck (local, server and unix agent)
94 | syscheck.debug=<%= node[:ossec][:internal][:syscheck][:debug] %>
95 |
96 | # Remoted (server debug)
97 | remoted.debug=<%= node[:ossec][:internal][:remoted][:debug] %>
98 |
99 | # Analysisd (server or local)
100 | analysisd.debug=<%= node[:ossec][:internal][:analysisd][:debug] %>
101 |
102 | # Log collector (server, local or unix agent)
103 | logcollector.debug=<%= node[:ossec][:internal][:logcollector][:debug] %>
104 |
105 | # Unix agentd
106 | agent.debug=<%= node[:ossec][:internal][:agent][:debug] %>
107 |
108 |
109 | # EOF
110 |
--------------------------------------------------------------------------------
/templates/default/local_decoder.xml.erb:
--------------------------------------------------------------------------------
1 | <% node[:ossec][:decoders].sort_by{|k,v| k.to_i}.each do |id,params|
2 | if not params.nil?
3 | -%>
4 |
5 | <%
6 | params.sort.each do |key, value|
7 | unless key.eql?('name')
8 | if params[key].is_a?(Hash)
9 | if key.eql?('prematch') or key.eql?('regex')
10 | if params[key].has_key?('offset')
11 | -%>
12 | <<%=key%> offset="<%=params[key][:offset]%>"><%=params[key][:parser]%><%=key%>>
13 | <%
14 | else
15 | -%>
16 | <<%=key%>><%=params[key][:parser]%><%=key%>>
17 | <% end
18 | end
19 | else
20 | -%>
21 | <<%=key%>><%=value%><%=key%>>
22 | <% end
23 | end
24 | end
25 | -%>
26 |
27 | <%
28 | end
29 | end
30 | -%>
31 |
--------------------------------------------------------------------------------
/templates/default/local_rules.xml.erb:
--------------------------------------------------------------------------------
1 |
2 | <%
3 | node[:ossec][:rules].sort_by{|k,v| k.to_i}.each do |id,params|
4 | headers = ""
5 | if params.has_key?('head')
6 | params[:head].sort.each do |key, value|
7 | headers += " " + key + "=\"" + value + "\""
8 | end
9 | end
10 | -%>
11 | >
12 | <%if params.has_key?('body')
13 | params[:body].sort.each do |key, value|
14 | if not key.eql?('hostname_search')
15 | -%>
16 | <<%=key%>><%=value%><%=key%>>
17 | <%
18 | end
19 | end
20 | end
21 | if params.has_key?('tags')
22 | params[:tags].sort.each do |tag|
23 | -%>
24 | <<%=tag%> />
25 | <% end
26 | end
27 | if params.has_key?('info')
28 | params[:info].sort.each do |key, value|
29 | -%>
30 | <%=value%>
31 | <% end
32 | end
33 | -%>
34 |
35 | <%
36 | end
37 | -%>
38 |
39 |
--------------------------------------------------------------------------------
/templates/default/ossec-agent.conf.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%=@ossec_server_ip%>
5 |
6 |
7 |
8 |
9 | <%=node[:ossec][:syscheck][:frequency]%>
10 |
11 |
12 | <%node[:ossec][:syscheck][:directories].sort_by {|k,v| k}.each do |directory,params| -%>
13 | <%=directory%>
14 | <%end-%>
15 |
16 | <%=node[:ossec][:syscheck][:alert_new_files]%>
17 | <%=node[:ossec][:syscheck][:auto_ignore]%>
18 |
19 |
20 | <%node[:ossec][:syscheck][:ignore].sort_by {|k| k}.each do |path| -%>
21 | <%=path%>
22 | <%end-%>
23 |
24 | <%
25 | if not node[:ossec][:syscheck][:local_ignore].nil?
26 | node[:ossec][:syscheck][:local_ignore].sort_by {|k,v| k}.each do |file,params|
27 | if params[:use_here] == "true"
28 | type = 'simple'
29 | unless params[:type].nil?
30 | if params[:type] == 'sregex'
31 | type = 'sregex'
32 | end
33 | end
34 | if type == 'sregex'
35 | -%>
36 | <%=file%>
37 | <% else -%>
38 | <%=file%>
39 | <% end
40 | end
41 | end
42 | end
43 | -%>
44 |
45 |
46 |
47 | /var/ossec/etc/shared/rootkit_files.txt
48 | /var/ossec/etc/shared/rootkit_trojans.txt
49 |
50 |
51 |
52 | <%node[:ossec][:syslog_files].sort_by {|k| k}.each do |file| -%>
53 |
54 | syslog
55 | <%=file%>
56 |
57 | <%end-%>
58 |
59 | <%
60 | if not node[:ossec][:local_syslog_files].nil?
61 | node[:ossec][:local_syslog_files].sort_by {|k,v| k}.each do |logfile,params|
62 | if params[:use_here] == "true"
63 | -%>
64 |
65 | <%=params[:log_format]%>
66 | <%=logfile%>
67 |
68 | <%
69 | end
70 | end
71 | end
72 | -%>
73 |
74 |
--------------------------------------------------------------------------------
/templates/default/ossec-server.conf.erb:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= node[:ossec][:email_notification] %>
5 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
6 | <%= recipient %>
7 | <% end -%>
8 | <%= node[:ossec][:smtp_server] %>
9 | <%= node[:ossec][:email_from]%>
10 | <%=node[:ossec][:email_maxperhour]%>
11 | <%=node[:ossec][:memory_size]%>
12 | <% node[:ossec][:white_list].sort_by {|k| k}.each do |ip| -%>
13 | <%= ip %>
14 | <% end -%>
15 |
16 |
17 |
18 |
19 | rules_config.xml
20 | pam_rules.xml
21 | sshd_rules.xml
22 | syslog_rules.xml
23 | arpwatch_rules.xml
24 | symantec-av_rules.xml
25 | pix_rules.xml
26 | named_rules.xml
27 | smbd_rules.xml
28 | pure-ftpd_rules.xml
29 | proftpd_rules.xml
30 | ms_ftpd_rules.xml
31 | hordeimp_rules.xml
32 | vpopmail_rules.xml
33 | ids_rules.xml
34 | squid_rules.xml
35 | firewall_rules.xml
36 | netscreenfw_rules.xml
37 | postfix_rules.xml
38 | sendmail_rules.xml
39 | imapd_rules.xml
40 | mailscanner_rules.xml
41 | ms-exchange_rules.xml
42 | racoon_rules.xml
43 | vpn_concentrator_rules.xml
44 | spamd_rules.xml
45 | msauth_rules.xml
46 | attack_rules.xml
47 | ossec_rules.xml
48 | apache_rules.xml
49 | web_rules.xml
50 | local_rules.xml
51 |
52 |
53 |
54 | <%=node[:ossec][:remote][:connection]%>
55 | <%= node.ipaddress %>
56 |
57 |
58 |
59 | <%= node[:ossec][:syslog_output][:ip] %>
60 | <%= node[:ossec][:syslog_output][:port] %>
61 | <%= node[:ossec][:syslog_output][:min_level] %>
62 |
63 |
64 |
65 | <%= node[:ossec][:log_alert_level] %>
66 | <%= node[:ossec][:email_alert_level]%>
67 |
68 |
69 |
70 | authentication_success
71 | srcip
72 | Daily report: Successful logins
73 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
74 | <%= recipient %>
75 | <% end -%>
76 |
77 |
78 |
79 | web
80 | Daily report: Web
81 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
82 | <%= recipient %>
83 | <% end -%>
84 |
85 |
86 |
87 | Daily report: Level 7
88 | 7
89 | level
90 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
91 | <%= recipient %>
92 | <% end -%>
93 |
94 |
95 |
96 | Daily report: Level 12
97 | 12
98 | level
99 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
100 | <%= recipient %>
101 | <% end -%>
102 |
103 |
104 |
105 | syscheck
106 | Daily report: File changes
107 | filename
108 | <% node[:ossec][:email_to].sort_by {|k| k}.each do |recipient| -%>
109 | <%= recipient %>
110 | <% end -%>
111 |
112 |
113 | <%
114 | node[:ossec][:email_alerts].sort_by {|k,v| k}.each do |recipient,params|
115 | locations = []
116 | if params.has_key?('event_location_tag')
117 | locations = @ossec_agents.select{
118 | |n| n[:tags].include?(
119 | params[:event_location_tag]
120 | )
121 | }.map {|n2| n2.network.lanip || '172.172.172.172'}
122 | elsif params.has_key?('resolved_search')
123 | locations = params[:resolved_search]
124 | end
125 | locations.sort_by {|k| k}.each do |location|
126 | -%>
127 |
128 | <%=recipient%>
129 | <%=location%>
130 | <% params.sort_by {|k,v| k}.each do |key, value|
131 | unless key =~ /event_location_tag|event_location_search|resolved_search/
132 | if key.eql?('tags')
133 | value.sort_by {|k| k}.each do |tag|
134 | -%>
135 | <<%=tag%> />
136 | <% end
137 | else
138 | -%>
139 | <<%=key%>><%=value%><%=key%>>
140 | <% end
141 | end
142 | end
143 | -%>
144 |
145 | <%
146 | end
147 | end
148 | -%>
149 |
150 |
151 |
152 | <%=node[:ossec][:syscheck][:frequency]%>
153 |
154 |
155 | <%node[:ossec][:syscheck][:directories].sort_by {|k,v| k}.each do |directory,params| -%>
156 | <%=directory%>
157 | <%end-%>
158 |
159 | <%=node[:ossec][:syscheck][:alert_new_files]%>
160 | <%=node[:ossec][:syscheck][:auto_ignore]%>
161 |
162 |
163 | <%node[:ossec][:syscheck][:ignore].sort_by {|k| k}.each do |path| -%>
164 | <%=path%>
165 | <%end-%>
166 |
167 | <%
168 | if not node[:ossec][:syscheck][:local_ignore].nil?
169 | node[:ossec][:syscheck][:local_ignore].sort_by {|k| k}.each do |file,params|
170 | if params[:use_here] == "true"
171 | type = 'simple'
172 | unless params[:type].nil?
173 | if params[:type] == 'sregex'
174 | type = 'sregex'
175 | end
176 | end
177 | if type == 'sregex'
178 | -%>
179 | <%=file%>
180 | <% else -%>
181 | <%=file%>
182 | <% end
183 | end
184 | end
185 | end
186 | -%>
187 |
188 |
189 |
190 |
191 | /var/ossec/etc/shared/rootkit_files.txt
192 | /var/ossec/etc/shared/rootkit_trojans.txt
193 |
194 |
195 |
196 | <%node[:ossec][:syslog_files].sort_by {|k| k}.each do |file| -%>
197 |
198 | syslog
199 | <%=file%>
200 |
201 | <%end-%>
202 |
203 | <%
204 | if not node[:ossec][:local_syslog_files].nil?
205 | node[:ossec][:local_syslog_files].sort_by {|k,v| k}.each do |logfile,params|
206 | if params[:use_here] == "true"
207 | -%>
208 |
209 | <%=params[:log_format]%>
210 | <%=logfile%>
211 |
212 | <%
213 | end
214 | end
215 | end
216 | -%>
217 |
218 |
--------------------------------------------------------------------------------