diff --git a/pillar/logstash/master.sls b/pillar/logstash/master.sls new file mode 100644 index 000000000..3be98f6b9 --- /dev/null +++ b/pillar/logstash/master.sls @@ -0,0 +1,4 @@ +logstash: + pipelines: + master: + config: "/usr/share/logstash/pipelines/master/*.conf" diff --git a/pillar/top.sls b/pillar/top.sls index 99fe26556..8e8c22de3 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -2,7 +2,8 @@ base: '*': - patch.needs_restarting - 'G@role:so-mastersearch': + 'G@role:so-mastersearch or G@role:so-heavynode': + - match: compound - logstash.mastersearch 'G@role:so-sensor': @@ -19,6 +20,9 @@ base: - auth - minions.{{ grains.id }} + 'G@role:so-master': + - logstash.master + 'G@role:so-eval': - static - firewall.* @@ -32,6 +36,12 @@ base: - firewall.* - minions.{{ grains.id }} + 'G@role:so-heavynode': + - static + - firewall.* + - brologs + - minions.{{ grains.id }} + 'G@role:so-helix': - static - firewall.* diff --git a/salt/common/init.sls b/salt/common/init.sls index 7ed59efa1..4ae78f57b 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -1,6 +1,6 @@ {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} -{%- set GRAFANA = salt['pillar.get']('master:grafana', '0') %} +{% set GRAFANA = salt['pillar.get']('master:grafana', '0') %} # Add socore Group socoregroup: group.present: @@ -343,7 +343,7 @@ dashboard-{{ SN }}: {% if salt['pillar.get']('nodestab', False) %} {%- for SN, SNDATA in salt['pillar.get']('nodestab', {}).items() %} -dashboard-{{ SN }}: +dashboardsearch-{{ SN }}: file.managed: - name: /opt/so/conf/grafana/grafana_dashboards/search_nodes/{{ SN }}-Node.json - user: 939 diff --git a/salt/common/nginx/nginx.conf.so-heavynode b/salt/common/nginx/nginx.conf.so-heavynode new file mode 100644 index 000000000..39688f3df --- /dev/null +++ b/salt/common/nginx/nginx.conf.so-heavynode @@ -0,0 +1,89 @@ +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + # Load modular configuration files from the /etc/nginx/conf.d directory. + # See http://nginx.org/en/docs/ngx_core_module.html#include + # for more information. + include /etc/nginx/conf.d/*.conf; + + server { + listen 80 default_server; + listen [::]:80 default_server; + server_name _; + root /usr/share/nginx/html; + + # Load configuration files for the default server block. + include /etc/nginx/default.d/*.conf; + + location / { + } + + error_page 404 /404.html; + location = /40x.html { + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + } + } + +# Settings for a TLS enabled server. +# +# server { +# listen 443 ssl http2 default_server; +# listen [::]:443 ssl http2 default_server; +# server_name _; +# root /usr/share/nginx/html; +# +# ssl_certificate "/etc/pki/nginx/server.crt"; +# ssl_certificate_key "/etc/pki/nginx/private/server.key"; +# ssl_session_cache shared:SSL:1m; +# ssl_session_timeout 10m; +# ssl_ciphers HIGH:!aNULL:!MD5; +# ssl_prefer_server_ciphers on; +# +# # Load configuration files for the default server block. +# include /etc/nginx/default.d/*.conf; +# +# location / { +# } +# +# error_page 404 /404.html; +# location = /40x.html { +# } +# +# error_page 500 502 503 504 /50x.html; +# location = /50x.html { +# } +# } + +} diff --git a/salt/common/tools/sbin/so-elastic-clear b/salt/common/tools/sbin/so-elastic-clear index 79c7e99ad..2db400839 100644 --- a/salt/common/tools/sbin/so-elastic-clear +++ b/salt/common/tools/sbin/so-elastic-clear @@ -14,6 +14,7 @@ # # You should have received a copy of the GNU General Public License # along with this program. If not, see . +{%- set MASTERIP = salt['pillar.get']('static:masterip', '') -%} . /usr/sbin/so-common SKIP=0 diff --git a/salt/common/tools/sbin/so-zeek-restart b/salt/common/tools/sbin/so-zeek-restart index 29c50f27a..e9e00aafc 100644 --- a/salt/common/tools/sbin/so-zeek-restart +++ b/salt/common/tools/sbin/so-zeek-restart @@ -17,4 +17,4 @@ . /usr/sbin/so-common -/usr/sbin/so-restart bro $1 +/usr/sbin/so-restart zeek $1 diff --git a/salt/common/tools/sbin/so-zeek-start b/salt/common/tools/sbin/so-zeek-start index ccd475bb6..a3d4c86f7 100644 --- a/salt/common/tools/sbin/so-zeek-start +++ b/salt/common/tools/sbin/so-zeek-start @@ -17,4 +17,4 @@ . /usr/sbin/so-common -/usr/sbin/so-start bro $1 +/usr/sbin/so-start zeek $1 diff --git a/salt/common/tools/sbin/so-zeek-stop b/salt/common/tools/sbin/so-zeek-stop index 1e39a2c49..d09417c7f 100644 --- a/salt/common/tools/sbin/so-zeek-stop +++ b/salt/common/tools/sbin/so-zeek-stop @@ -17,4 +17,4 @@ . /usr/sbin/so-common -/usr/sbin/so-stop bro $1 +/usr/sbin/so-stop zeek $1 diff --git a/salt/bro/cron/packetloss.sh b/salt/deprecated-bro/cron/packetloss.sh similarity index 100% rename from salt/bro/cron/packetloss.sh rename to salt/deprecated-bro/cron/packetloss.sh diff --git a/salt/bro/cron/zeek_clean b/salt/deprecated-bro/cron/zeek_clean similarity index 100% rename from salt/bro/cron/zeek_clean rename to salt/deprecated-bro/cron/zeek_clean diff --git a/salt/bro/files/local.bro b/salt/deprecated-bro/files/local.bro similarity index 98% rename from salt/bro/files/local.bro rename to salt/deprecated-bro/files/local.bro index 42112f7ee..afe4b94ca 100644 --- a/salt/bro/files/local.bro +++ b/salt/deprecated-bro/files/local.bro @@ -102,6 +102,9 @@ # is currently considered a preview and therefore not loaded by default. @load base/protocols/smb +# BPF Configuration +@load securityonion/bpfconf + # Add the interface to the log event #@load securityonion/add-interface-to-logs.bro diff --git a/salt/bro/files/local.bro.community b/salt/deprecated-bro/files/local.bro.community similarity index 100% rename from salt/bro/files/local.bro.community rename to salt/deprecated-bro/files/local.bro.community diff --git a/salt/bro/files/node.cfg b/salt/deprecated-bro/files/node.cfg similarity index 100% rename from salt/bro/files/node.cfg rename to salt/deprecated-bro/files/node.cfg diff --git a/salt/bro/init.sls b/salt/deprecated-bro/init.sls similarity index 82% rename from salt/bro/init.sls rename to salt/deprecated-bro/init.sls index 6a972cbe7..8f36be420 100644 --- a/salt/bro/init.sls +++ b/salt/deprecated-bro/init.sls @@ -1,3 +1,7 @@ +{% set interface = salt['pillar.get']('sensor:interface', 'bond0') %} +{% set BPF_ZEEK = salt['pillar.get']('zeek:bpf') %} +{% set BPF_STATUS = 0 %} + # Bro Salt State # Add Bro group brogroup: @@ -103,6 +107,32 @@ zeekcleanscript: - month: '*' - dayweek: '*' +# BPF compilation and configuration +{% if BPF_ZEEK %} + {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', interface + ' ' + BPF_ZEEK|join(" ") ) %} + {% if BPF_CALC['stderr'] == "" %} + {% set BPF_STATUS = 1 %} + {% else %} +zeekbpfcompilationfailure: + test.configurable_test_state: + - changes: False + - result: False + - comment: "BPF Syntax Error - Discarding Specified BPF" + {% endif %} +{% endif %} + +zeekbpf: + file.managed: + - name: /opt/so/conf/bro/bpf + - user: 940 + - group: 940 + {% if BPF_STATUS %} + - contents_pillar: zeek:bpf + {% else %} + - contents: + - "ip or not ip" + {% endif %} + # Sync local.bro {% if salt['pillar.get']('static:broversion', '') == 'COMMUNITY' %} localbrosync: @@ -163,6 +193,7 @@ so-bro: - /nsm/bro/extracted:/nsm/bro/extracted:rw - /opt/so/conf/bro/local.bro:/opt/bro/share/bro/site/local.bro:ro - /opt/so/conf/bro/node.cfg:/opt/bro/etc/node.cfg:ro + - /opt/so/conf/bro/bpf:/opt/bro/share/bro/site/bpf:ro - /opt/so/conf/bro/policy/securityonion:/opt/bro/share/bro/policy/securityonion:ro - /opt/so/conf/bro/policy/custom:/opt/bro/share/bro/policy/custom:ro - /opt/so/conf/bro/policy/intel:/opt/bro/share/bro/policy/intel:rw @@ -171,6 +202,5 @@ so-bro: - file: /opt/so/conf/bro/local.bro - file: /opt/so/conf/bro/node.cfg - file: /opt/so/conf/bro/policy - - + - file: /opt/so/conf/bro/bpf {% endif %} diff --git a/salt/bro/policy/intel/__load__.bro b/salt/deprecated-bro/policy/intel/__load__.bro similarity index 100% rename from salt/bro/policy/intel/__load__.bro rename to salt/deprecated-bro/policy/intel/__load__.bro diff --git a/salt/bro/policy/securityonion/add-interface-to-logs.bro b/salt/deprecated-bro/policy/securityonion/add-interface-to-logs.bro similarity index 100% rename from salt/bro/policy/securityonion/add-interface-to-logs.bro rename to salt/deprecated-bro/policy/securityonion/add-interface-to-logs.bro diff --git a/salt/bro/policy/securityonion/apt1/__load__.bro b/salt/deprecated-bro/policy/securityonion/apt1/__load__.bro similarity index 100% rename from salt/bro/policy/securityonion/apt1/__load__.bro rename to salt/deprecated-bro/policy/securityonion/apt1/__load__.bro diff --git a/salt/bro/policy/securityonion/apt1/apt1-certs.dat b/salt/deprecated-bro/policy/securityonion/apt1/apt1-certs.dat similarity index 100% rename from salt/bro/policy/securityonion/apt1/apt1-certs.dat rename to salt/deprecated-bro/policy/securityonion/apt1/apt1-certs.dat diff --git a/salt/bro/policy/securityonion/apt1/apt1-fqdn.dat b/salt/deprecated-bro/policy/securityonion/apt1/apt1-fqdn.dat similarity index 100% rename from salt/bro/policy/securityonion/apt1/apt1-fqdn.dat rename to salt/deprecated-bro/policy/securityonion/apt1/apt1-fqdn.dat diff --git a/salt/bro/policy/securityonion/apt1/apt1-md5.dat b/salt/deprecated-bro/policy/securityonion/apt1/apt1-md5.dat similarity index 100% rename from salt/bro/policy/securityonion/apt1/apt1-md5.dat rename to salt/deprecated-bro/policy/securityonion/apt1/apt1-md5.dat diff --git a/salt/deprecated-bro/policy/securityonion/bpfconf.bro b/salt/deprecated-bro/policy/securityonion/bpfconf.bro new file mode 100644 index 000000000..595aef8f2 --- /dev/null +++ b/salt/deprecated-bro/policy/securityonion/bpfconf.bro @@ -0,0 +1,106 @@ +##! This script is to support the bpf.conf file like other network monitoring tools use. +##! Please don't try to learn from this script right now, there are a large number of +##! hacks in it to work around bugs discovered in Bro. + +@load base/frameworks/notice + +module BPFConf; + +export { + ## The file that is watched on disk for BPF filter changes. + ## Two templated variables are available; "sensorname" and "interface". + ## They can be used by surrounding the term by doubled curly braces. + const filename = "/opt/bro/share/bro/site/bpf" &redef; + + redef enum Notice::Type += { + ## Invalid filter notice. + InvalidFilter + }; +} + +global filter_parts: vector of string = vector(); +global current_filter_filename = ""; + +type FilterLine: record { + s: string; +}; + +redef enum PcapFilterID += { + BPFConfPcapFilter, +}; + +event BPFConf::line(description: Input::EventDescription, tpe: Input::Event, s: string) + { + local part = sub(s, /[[:blank:]]*#.*$/, ""); + + # We don't want any blank parts. + if ( part != "" ) + filter_parts[|filter_parts|] = part; + } + +event Input::end_of_data(name: string, source:string) + { + if ( name == "bpfconf" ) + { + local filter = join_string_vec(filter_parts, " "); + capture_filters["bpf.conf"] = filter; + if ( Pcap::precompile_pcap_filter(BPFConfPcapFilter, filter) ) + { + PacketFilter::install(); + } + else + { + NOTICE([$note=InvalidFilter, + $msg=fmt("Compiling packet filter from %s failed", filename), + $sub=filter]); + } + + filter_parts=vector(); + } + } + + +function add_filter_file() + { + local real_filter_filename = BPFConf::filename; + + # Support the interface template value. + #if ( SecurityOnion::sensorname != "" ) + # real_filter_filename = gsub(real_filter_filename, /\{\{sensorname\}\}/, SecurityOnion::sensorname); + + # Support the interface template value. + #if ( SecurityOnion::interface != "" ) + # real_filter_filename = gsub(real_filter_filename, /\{\{interface\}\}/, SecurityOnion::interface); + + #if ( /\{\{/ in real_filter_filename ) + # { + # return; + # } + #else + # Reporter::info(fmt("BPFConf filename set: %s (%s)", real_filter_filename, Cluster::node)); + + if ( real_filter_filename != current_filter_filename ) + { + current_filter_filename = real_filter_filename; + Input::add_event([$source=real_filter_filename, + $name="bpfconf", + $reader=Input::READER_RAW, + $mode=Input::REREAD, + $want_record=F, + $fields=FilterLine, + $ev=BPFConf::line]); + } + } + +#event SecurityOnion::found_sensorname(name: string) +# { +# add_filter_file(); +# } + +event bro_init() &priority=5 + { + if ( BPFConf::filename != "" ) + add_filter_file(); + } + + diff --git a/salt/bro/policy/securityonion/conn-add-sensorname.bro b/salt/deprecated-bro/policy/securityonion/conn-add-sensorname.bro similarity index 100% rename from salt/bro/policy/securityonion/conn-add-sensorname.bro rename to salt/deprecated-bro/policy/securityonion/conn-add-sensorname.bro diff --git a/salt/bro/policy/securityonion/file-extraction/__load__.bro b/salt/deprecated-bro/policy/securityonion/file-extraction/__load__.bro similarity index 100% rename from salt/bro/policy/securityonion/file-extraction/__load__.bro rename to salt/deprecated-bro/policy/securityonion/file-extraction/__load__.bro diff --git a/salt/bro/policy/securityonion/file-extraction/extract.bro b/salt/deprecated-bro/policy/securityonion/file-extraction/extract.bro similarity index 100% rename from salt/bro/policy/securityonion/file-extraction/extract.bro rename to salt/deprecated-bro/policy/securityonion/file-extraction/extract.bro diff --git a/salt/bro/policy/securityonion/json-logs/__load__.bro b/salt/deprecated-bro/policy/securityonion/json-logs/__load__.bro similarity index 100% rename from salt/bro/policy/securityonion/json-logs/__load__.bro rename to salt/deprecated-bro/policy/securityonion/json-logs/__load__.bro diff --git a/salt/elastalert/files/elastalert_config.yaml b/salt/elastalert/files/elastalert_config.yaml index 735ccb190..e71f41bf8 100644 --- a/salt/elastalert/files/elastalert_config.yaml +++ b/salt/elastalert/files/elastalert_config.yaml @@ -82,3 +82,7 @@ writeback_index: elastalert_status # sending the alert until this time period has elapsed alert_time_limit: days: 2 + +index_settings: + shards: 1 + replicas: 0 diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index a2493091a..a97a2ae0f 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -31,7 +31,7 @@ {% set esclustername = salt['pillar.get']('master:esclustername', '') %} {% set esheap = salt['pillar.get']('master:esheap', '') %} -{% elif grains['role'] == 'so-node' %} +{% elif grains['role'] == 'so-node' or grains['role'] == 'so-heavynode' %} {% set esclustername = salt['pillar.get']('node:esclustername', '') %} {% set esheap = salt['pillar.get']('node:esheap', '') %} diff --git a/salt/filebeat/etc/filebeat.yml b/salt/filebeat/etc/filebeat.yml index 4706e4c5a..45936c180 100644 --- a/salt/filebeat/etc/filebeat.yml +++ b/salt/filebeat/etc/filebeat.yml @@ -1,4 +1,10 @@ +{%- if grains.role == 'so-heavynode' %} +{%- set MASTER = grains.host %} +{%- else %} {%- set MASTER = grains['master'] %} +{%- endif %} + + {%- set HOSTNAME = salt['grains.get']('host', '') %} {%- set BROVER = salt['pillar.get']('static:broversion', 'COMMUNITY') %} {%- set WAZUHENABLED = salt['pillar.get']('static:wazuh_enabled', '1') %} @@ -67,12 +73,12 @@ filebeat.modules: # List of prospectors to fetch data. filebeat.prospectors: #------------------------------ Log prospector -------------------------------- -{%- if grains['role'] == 'so-sensor' or grains['role'] == "so-eval" or grains['role'] == "so-helix" %} +{%- if grains['role'] == 'so-sensor' or grains['role'] == "so-eval" or grains['role'] == "so-helix" or grains['role'] == "so-heavynode" %} {%- if BROVER != 'SURICATA' %} {%- for LOGNAME in salt['pillar.get']('brologs:enabled', '') %} - type: log paths: - - /nsm/bro/logs/current/{{ LOGNAME }}.log + - /nsm/zeek/logs/current/{{ LOGNAME }}.log fields: type: bro_{{ LOGNAME }} fields_under_root: true diff --git a/salt/filebeat/init.sls b/salt/filebeat/init.sls index 44cc7c65c..8528ecc38 100644 --- a/salt/filebeat/init.sls +++ b/salt/filebeat/init.sls @@ -1,5 +1,4 @@ # Copyright 2014,2015,2016,2017,2018 Security Onion Solutions, LLC - # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -15,13 +14,12 @@ {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} {%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} -{% set FEATURES = salt['pillar.get']('elastic:features', False) %} -{% if FEATURES %} - {% set FEATURES = "-features" %} -{% else %} - {% set FEATURES = '' %} +{% set FEATURES = salt['pillar.get']('elastic:features', False) %} +{% if FEATURES %} + {% set FEATURES = "-features" %} +{% else %} + {% set FEATURES = '' %} {% endif %} - # Filebeat Setup filebeatetcdir: file.directory: @@ -29,21 +27,18 @@ filebeatetcdir: - user: 939 - group: 939 - makedirs: True - filebeatlogdir: file.directory: - name: /opt/so/log/filebeat - user: 939 - group: 939 - makedirs: True - filebeatpkidir: file.directory: - name: /opt/so/conf/filebeat/etc/pki - user: 939 - group: 939 - makedirs: True - # This needs to be owned by root filebeatconfsync: file.managed: @@ -52,7 +47,6 @@ filebeatconfsync: - user: 0 - group: 0 - template: jinja - so-filebeat: docker_container.running: - image: {{ MASTER }}:5000/soshybridhunter/so-filebeat:{{ VERSION }}{{ FEATURES }} @@ -67,13 +61,8 @@ so-filebeat: - /opt/so/wazuh/logs/alerts/:/wazuh/alerts:ro - /opt/so/wazuh/logs/archives/:/wazuh/archives:ro - /opt/so/log/fleet/:/osquery/logs:ro -{%- if grains['role'] == 'so-master' %} - - /etc/pki/filebeat.crt:/usr/share/filebeat/filebeat.crt:ro - - /etc/pki/filebeat.key:/usr/share/filebeat/filebeat.key:ro -{%- else %} - /opt/so/conf/filebeat/etc/pki/filebeat.crt:/usr/share/filebeat/filebeat.crt:ro - /opt/so/conf/filebeat/etc/pki/filebeat.key:/usr/share/filebeat/filebeat.key:ro -{%- endif %} - /etc/ssl/certs/intca.crt:/usr/share/filebeat/intraca.crt:ro - watch: - file: /opt/so/conf/filebeat/etc/filebeat.yml diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index a016a9767..a26993cc0 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -1,7 +1,7 @@ # Firewall Magic for the grid {%- if grains['role'] in ['so-eval','so-master','so-helix','so-mastersearch'] %} {%- set ip = salt['pillar.get']('static:masterip', '') %} -{%- elif grains['role'] == 'so-node' %} +{%- elif grains['role'] == 'so-node' or grains['role'] == 'so-heavynode' %} {%- set ip = salt['pillar.get']('node:mainip', '') %} {%- elif grains['role'] == 'so-sensor' %} {%- set ip = salt['pillar.get']('sensor:mainip', '') %} @@ -584,7 +584,7 @@ enable_standard_analyst_443_{{ip}}: {% endif %} # Rules if you are a Node -{% if grains['role'] == 'so-node' %} +{% if 'node' in grains['role'] %} #This should be more granular iptables_allow_docker: @@ -655,3 +655,39 @@ iptables_drop_all_the_things: - chain: LOGGING - jump: DROP - save: True + +{% if grains['role'] == 'so-heavynode' %} +# Allow Redis +enable_heavynode_redis_6379_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 6379 + - position: 1 + - save: True + +enable_forwardnode_beats_5044_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 5044 + - position: 1 + - save: True + +enable_forwardnode_beats_5644_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 5644 + - position: 1 + - save: True +{% endif %} diff --git a/salt/logstash/conf/pipelines/master/templates/9999_output_redis.conf b/salt/logstash/conf/pipelines/master/templates/9999_output_redis.conf index fa650b538..f176e0b94 100644 --- a/salt/logstash/conf/pipelines/master/templates/9999_output_redis.conf +++ b/salt/logstash/conf/pipelines/master/templates/9999_output_redis.conf @@ -1,10 +1,15 @@ {%- if salt['grains.get']('role') == 'so-master' %} {% set master = salt['pillar.get']('static:masterip', '') %} {%- set nodetype = 'master' %} +{% elif grains.role == 'so-heavynode' %} +{% set master = salt['pillar.get']('node:mainip', '') %} +{%- set nodetype = salt['pillar.get']('node:node_type', 'search') %} {%- else %} {%- set nodetype = salt['pillar.get']('node:node_type', 'storage') %} {% set master = salt['pillar.get']('static:masterip', '') %} {%- endif %} + + output { redis { host => '{{ master }}' diff --git a/salt/logstash/conf/pipelines/search/templates/0900_input_redis.conf b/salt/logstash/conf/pipelines/search/templates/0900_input_redis.conf index 660d2e741..ede940367 100644 --- a/salt/logstash/conf/pipelines/search/templates/0900_input_redis.conf +++ b/salt/logstash/conf/pipelines/search/templates/0900_input_redis.conf @@ -1,4 +1,8 @@ -{% set master = salt['pillar.get']('static:masterip', '') %} +{%- if grains.role == 'so-heavynode' %} +{%- set master = salt['pillar.get']('node:mainip', '') %} +{%- else %} +{%- set master = salt['pillar.get']('static:masterip', '') %} +{% endif -%} input { redis { host => '{{ master }}' diff --git a/salt/logstash/etc/logstash.yml b/salt/logstash/etc/logstash.yml index e5bb76b5b..88f3c527e 100644 --- a/salt/logstash/etc/logstash.yml +++ b/salt/logstash/etc/logstash.yml @@ -63,7 +63,7 @@ # # path.config: # /etc/logstash/conf.d is mapped to /usr/share/logstash/pipeline in the Docker image -{% if grains.role != 'so-mastersearch' %} +{% if grains.role != 'so-mastersearch' and grains.role != 'so-heavynode' and grains.role != 'so-master' %} path.config: /usr/share/logstash/pipeline.enabled/*.conf {% else %} #path.config: /usr/share/logstash/pipeline.enabled/*.conf diff --git a/salt/logstash/init.sls b/salt/logstash/init.sls index 2d94c5354..f92f047fa 100644 --- a/salt/logstash/init.sls +++ b/salt/logstash/init.sls @@ -27,7 +27,7 @@ {% set lsheap = salt['pillar.get']('sensor:lsheap', '') %} {% set lsaccessip = salt['pillar.get']('sensor:lsaccessip', '') %} -{% elif grains['role'] == 'so-node' %} +{% elif grains['role'] == 'so-node' or grains['role'] == 'so-heavynode' %} {% set lsheap = salt['pillar.get']('node:lsheap', '') %} {% set nodetype = salt['pillar.get']('node:node_type', 'storage') %} @@ -162,7 +162,7 @@ lscustsync: lsconfsync: file.managed: - name: /opt/so/conf/logstash/conf.enabled.txt -{% if grains.role == 'so-mastersearch' %} +{% if grains.role == 'so-mastersearch' or grains.role == 'so-heavynode' %} - source: salt://logstash/conf/conf.enabled.txt.so-master {% else %} - source: salt://logstash/conf/conf.enabled.txt.{{ nodetype }} diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index f3e815174..83c7c92e4 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -41,7 +41,7 @@ m2cryptopkgs: bits: 4096 backup: True -{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' or grains['role'] == 'so-mastersearch' %} +{% if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' or grains['role'] == 'so-mastersearch' %} # Request a cert and drop it where it needs to go to be distributed /etc/pki/filebeat.crt: @@ -49,7 +49,11 @@ m2cryptopkgs: - ca_server: {{ ca_server }} - signing_policy: filebeat - public_key: /etc/pki/filebeat.key - - CN: {{ master }} +{% if grains.role == 'so-heavynode' %} + - CN: {{grains.id}} +{% else %} + - CN: {{master}} +{% endif %} - days_remaining: 0 - days_valid: 820 - backup: True @@ -129,7 +133,7 @@ fbcrtlink: backup: True {% endif %} -{% if grains['role'] == 'so-sensor' or grains['role'] == 'so-node' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' or grains['role'] == 'so-mastersearch' %} +{% if grains['role'] == 'so-sensor' or grains['role'] == 'so-node' or grains['role'] == 'so-eval' or grains['role'] == 'so-helix' or grains['role'] == 'so-mastersearch' or grains['role'] == 'so-heavynode' %} fbcertdir: file.directory: @@ -142,7 +146,11 @@ fbcertdir: - ca_server: {{ ca_server }} - signing_policy: filebeat - public_key: /opt/so/conf/filebeat/etc/pki/filebeat.key - - CN: {{ master }} +{% if grains.role == 'so-heavynode' %} + - CN: {{grains.id}} +{% else %} + - CN: {{master}} +{% endif %} - days_remaining: 0 - days_valid: 820 - backup: True diff --git a/salt/suricata/files/suricata.yaml b/salt/suricata/files/suricata.yaml index 093612335..05412fa6c 100644 --- a/salt/suricata/files/suricata.yaml +++ b/salt/suricata/files/suricata.yaml @@ -489,7 +489,7 @@ logging: - file: enabled: yes level: info - filename: /usr/local/var/log/suricata/suricata.log + filename: /var/log/suricata/suricata.log # type: json - syslog: enabled: no diff --git a/salt/suricata/init.sls b/salt/suricata/init.sls index 65b80c9ae..dcea927ae 100644 --- a/salt/suricata/init.sls +++ b/salt/suricata/init.sls @@ -18,7 +18,7 @@ {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} {% set BPF_NIDS = salt['pillar.get']('nids:bpf') %} - +{% set BPF_STATUS = 0 %} # Suricata @@ -85,7 +85,9 @@ surithresholding: # BPF compilation and configuration {% if BPF_NIDS %} {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', interface + ' ' + BPF_NIDS|join(" ") ) %} - {% if BPF_CALC['stderr'] != "" %} + {% if BPF_CALC['stderr'] == "" %} + {% set BPF_STATUS = 1 %} + {% else %} suribpfcompilationfailure: test.configurable_test_state: - changes: False @@ -99,7 +101,7 @@ suribpf: - name: /opt/so/conf/suricata/bpf - user: 940 - group: 940 - {% if BPF_CALC['stderr'] == "" %} + {% if BPF_STATUS %} - contents_pillar: nids:bpf {% else %} - contents: diff --git a/salt/top.sls b/salt/top.sls index 14556b67e..1608b93d6 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -233,3 +233,31 @@ base: {%- if DOMAINSTATS != 0 %} - domainstats {%- endif %} + + 'G@role:so-heavynode': + - ca + - ssl + - common + - firewall + - redis + - logstash + - elasticsearch + - curator + {%- if WAZUH != 0 %} + - wazuh + {%- endif %} + - filebeat + {%- if OSQUERY != 0 %} + - launcher + {%- endif %} + - pcap + - suricata + {%- if BROVER != 'SURICATA' %} + - zeek + {%- endif %} + - wazuh + - filebeat + {%- if OSQUERY != 0 %} + - launcher + {%- endif %} + - schedule diff --git a/salt/wazuh/files/agent/ossec.conf b/salt/wazuh/files/agent/ossec.conf index 8f54e6a08..c5a61e8ad 100644 --- a/salt/wazuh/files/agent/ossec.conf +++ b/salt/wazuh/files/agent/ossec.conf @@ -1,6 +1,6 @@ {%- if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-mastersearch' %} {%- set ip = salt['pillar.get']('static:masterip', '') %} -{%- elif grains['role'] == 'so-node' %} +{%- elif grains['role'] == 'so-node' or grains['role'] == 'so-heavynode' %} {%- set ip = salt['pillar.get']('node:mainip', '') %} {%- elif grains['role'] == 'so-sensor' %} {%- set ip = salt['pillar.get']('sensor:mainip', '') %} diff --git a/salt/wazuh/files/agent/wazuh-register-agent b/salt/wazuh/files/agent/wazuh-register-agent index dbf4a4968..8a8c2ab7f 100755 --- a/salt/wazuh/files/agent/wazuh-register-agent +++ b/salt/wazuh/files/agent/wazuh-register-agent @@ -1,6 +1,6 @@ {%- if grains['role'] == 'so-master' or grains['role'] == 'so-eval' or grains['role'] == 'so-mastersearch' %} {%- set ip = salt['pillar.get']('static:masterip', '') %} -{%- elif grains['role'] == 'so-node' %} +{%- elif grains['role'] == 'so-node' or grains['role'] == 'so-heavynode' %} {%- set ip = salt['pillar.get']('node:mainip', '') %} {%- elif grains['role'] == 'so-sensor' %} {%- set ip = salt['pillar.get']('sensor:mainip', '') %} diff --git a/salt/wazuh/files/wazuh-manager-whitelist b/salt/wazuh/files/wazuh-manager-whitelist index 0cf675f5c..2a8450edb 100644 --- a/salt/wazuh/files/wazuh-manager-whitelist +++ b/salt/wazuh/files/wazuh-manager-whitelist @@ -27,7 +27,7 @@ if grep -q -R "wazuh: 1" /opt/so/saltstack/pillar/*; then echo "Added whitelist entry for {{ MASTERIP }} in $WAZUH_MGR_CFG." echo echo "Restarting OSSEC Server..." - /usr/sbin/so-wazuh-restart + #/usr/sbin/so-wazuh-restart fi fi diff --git a/salt/zeek/files/local.zeek b/salt/zeek/files/local.zeek index 92104dbf0..b902eee32 100644 --- a/salt/zeek/files/local.zeek +++ b/salt/zeek/files/local.zeek @@ -102,10 +102,10 @@ # @load policy/protocols/conn/mac-logging # JA3 - SSL Detection Goodness -@load policy/ja3 +@load ja3 # HASSH -@load policy/hassh +@load hassh # You can load your own intel into: # /opt/so/saltstack/bro/policy/intel/ on the master @@ -121,3 +121,6 @@ redef LogAscii::json_timestamps = JSON::TS_ISO8601; # CVE-2020-0601 @load cve-2020-0601 + +# BPF Configuration +@load securityonion/bpfconf diff --git a/salt/zeek/init.sls b/salt/zeek/init.sls index e0f1f8c9b..f650dec85 100644 --- a/salt/zeek/init.sls +++ b/salt/zeek/init.sls @@ -1,5 +1,7 @@ {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} +{% set BPF_ZEEK = salt['pillar.get']('zeek:bpf') %} +{% set BPF_STATUS = 0 %} # Zeek Salt State # Add Zeek group zeekgroup: @@ -90,6 +92,32 @@ plcronscript: - month: '*' - dayweek: '*' +# BPF compilation and configuration +{% if BPF_ZEEK %} + {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', interface + ' ' + BPF_ZEEK|join(" ") ) %} + {% if BPF_CALC['stderr'] == "" %} + {% set BPF_STATUS = 1 %} + {% else %} +zeekbpfcompilationfailure: + test.configurable_test_state: + - changes: False + - result: False + - comment: "BPF Syntax Error - Discarding Specified BPF" + {% endif %} +{% endif %} + +zeekbpf: + file.managed: + - name: /opt/so/conf/zeek/bpf + - user: 940 + - group: 940 + {% if BPF_STATUS %} + - contents_pillar: zeek:bpf + {% else %} + - contents: + - "ip or not ip" + {% endif %} + localzeeksync: file.managed: - name: /opt/so/conf/zeek/local.zeek @@ -110,6 +138,7 @@ so-zeek: - /opt/so/conf/zeek/node.cfg:/opt/zeek/etc/node.cfg:ro - /opt/so/conf/zeek/policy/securityonion:/opt/zeek/share/zeek/policy/securityonion:ro - /opt/so/conf/zeek/policy/custom:/opt/zeek/share/zeek/policy/custom:ro + - /opt/so/conf/zeek/policy/cve-2020-0601:/opt/zeek/share/zeek/policy/cve-2020-0601:ro - /opt/so/conf/zeek/policy/intel:/opt/zeek/share/zeek/policy/intel:rw - network_mode: host - watch: diff --git a/salt/zeek/policy/securityonion/bpfconf.zeek b/salt/zeek/policy/securityonion/bpfconf.zeek new file mode 100644 index 000000000..bf6431702 --- /dev/null +++ b/salt/zeek/policy/securityonion/bpfconf.zeek @@ -0,0 +1,106 @@ +##! This script is to support the bpf.conf file like other network monitoring tools use. +##! Please don't try to learn from this script right now, there are a large number of +##! hacks in it to work around bugs discovered in Bro. + +@load base/frameworks/notice + +module BPFConf; + +export { + ## The file that is watched on disk for BPF filter changes. + ## Two templated variables are available; "sensorname" and "interface". + ## They can be used by surrounding the term by doubled curly braces. + const filename = "/opt/zeek/share/zeek/site/bpf" &redef; + + redef enum Notice::Type += { + ## Invalid filter notice. + InvalidFilter + }; +} + +global filter_parts: vector of string = vector(); +global current_filter_filename = ""; + +type FilterLine: record { + s: string; +}; + +redef enum PcapFilterID += { + BPFConfPcapFilter, +}; + +event BPFConf::line(description: Input::EventDescription, tpe: Input::Event, s: string) + { + local part = sub(s, /[[:blank:]]*#.*$/, ""); + + # We don't want any blank parts. + if ( part != "" ) + filter_parts[|filter_parts|] = part; + } + +event Input::end_of_data(name: string, source:string) + { + if ( name == "bpfconf" ) + { + local filter = join_string_vec(filter_parts, " "); + capture_filters["bpf.conf"] = filter; + if ( Pcap::precompile_pcap_filter(BPFConfPcapFilter, filter) ) + { + PacketFilter::install(); + } + else + { + NOTICE([$note=InvalidFilter, + $msg=fmt("Compiling packet filter from %s failed", filename), + $sub=filter]); + } + + filter_parts=vector(); + } + } + + +function add_filter_file() + { + local real_filter_filename = BPFConf::filename; + + # Support the interface template value. + #if ( SecurityOnion::sensorname != "" ) + # real_filter_filename = gsub(real_filter_filename, /\{\{sensorname\}\}/, SecurityOnion::sensorname); + + # Support the interface template value. + #if ( SecurityOnion::interface != "" ) + # real_filter_filename = gsub(real_filter_filename, /\{\{interface\}\}/, SecurityOnion::interface); + + #if ( /\{\{/ in real_filter_filename ) + # { + # return; + # } + #else + # Reporter::info(fmt("BPFConf filename set: %s (%s)", real_filter_filename, Cluster::node)); + + if ( real_filter_filename != current_filter_filename ) + { + current_filter_filename = real_filter_filename; + Input::add_event([$source=real_filter_filename, + $name="bpfconf", + $reader=Input::READER_RAW, + $mode=Input::REREAD, + $want_record=F, + $fields=FilterLine, + $ev=BPFConf::line]); + } + } + +#event SecurityOnion::found_sensorname(name: string) +# { +# add_filter_file(); +# } + +event zeek_init() &priority=5 + { + if ( BPFConf::filename != "" ) + add_filter_file(); + } + + diff --git a/setup/functions.sh b/setup/functions.sh index 5e1ef125b..0872d3f31 100644 --- a/setup/functions.sh +++ b/setup/functions.sh @@ -732,13 +732,13 @@ master_static() { echo " cortexorguserkey: $CORTEXORGUSERKEY" >> /opt/so/saltstack/pillar/static.sls echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls - echo "elastic:" >> /opt/so/saltstack/pillar/static.sls - echo " features: False" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then echo " masterupdate: 1" >> /opt/so/saltstack/pillar/static.sls else echo " masterupdate: 0" >> /opt/so/saltstack/pillar/static.sls fi + echo "elastic:" >> /opt/so/saltstack/pillar/static.sls + echo " features: False" >> /opt/so/saltstack/pillar/static.sls } minio_generate_keys() { @@ -851,7 +851,7 @@ reserve_group_ids() { groupadd -g 932 kibana groupadd -g 933 elastalert groupadd -g 934 curator - groupadd -g 937 bro + groupadd -g 937 zeek groupadd -g 939 socore groupadd -g 940 suricata groupadd -g 941 stenographer @@ -1283,6 +1283,14 @@ set_initial_firewall_policy() { ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM fi + if [ $INSTALLTYPE == 'HEAVYNODE' ]; then + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh forward_nodes $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh search_nodes $MAINIP + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh sensorstab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM bond0 + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM + fi + if [ $INSTALLTYPE == 'PARSINGNODE' ]; then echo "blah" fi @@ -1316,7 +1324,7 @@ set_management_interface() { set_node_type() { # Determine the node type based on whiplash choice - if [ $INSTALLTYPE == 'SEARCHNODE' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'MASTERSEARCH' ]; then + if [ $INSTALLTYPE == 'SEARCHNODE' ] || [ $INSTALLTYPE == 'EVALMODE' ] || [ $INSTALLTYPE == 'MASTERSEARCH' ] || [ $INSTALLTYPE == 'HEAVYNODE' ] ; then NODETYPE='search' fi if [ $INSTALLTYPE == 'PARSINGNODE' ]; then diff --git a/setup/so-setup.sh b/setup/so-setup.sh index a2501dfb9..dd1970191 100644 --- a/setup/so-setup.sh +++ b/setup/so-setup.sh @@ -541,7 +541,7 @@ if (whiptail_you_sure) ; then es_heapsize ls_heapsize NODE_ES_HEAP_SIZE="600m" - NODE_LS_HEAP_SIZE="500m" + NODE_LS_HEAP_SIZE="1000m" LSPIPELINEWORKERS=1 LSPIPELINEBATCH=125 LSINPUTTHREADS=1 @@ -803,6 +803,132 @@ if (whiptail_you_sure) ; then fi + ######################## + ## Heavy Node ## + ######################## + + if [ $INSTALLTYPE == 'HEAVYNODE' ]; then + + filter_unused_nics + whiptail_bond_nics + whiptail_management_server + whiptail_master_updates + set_updates + whiptail_homenet_sensor + whiptail_sensor_config + # Calculate lbprocs so we can call it in the prompts + calculate_useable_cores + if [ $NSMSETUP == 'ADVANCED' ]; then + whiptail_bro_pins + whiptail_suricata_pins + whiptail_bond_nics_mtu + else + whiptail_basic_bro + whiptail_basic_suri + fi + + get_log_size_limit + CURCLOSEDAYS=30 + es_heapsize + ls_heapsize + whiptail_node_advanced + if [ $NODESETUP == 'NODEADVANCED' ]; then + whiptail_node_es_heap + whiptail_node_ls_heap + whiptail_node_ls_pipeline_worker + whiptail_node_ls_pipline_batchsize + whiptail_node_ls_input_threads + whiptail_node_ls_input_batch_count + whiptail_cur_close_days + whiptail_log_size_limit + else + NODE_ES_HEAP_SIZE=$ES_HEAP_SIZE + NODE_LS_HEAP_SIZE=1000m + LSPIPELINEWORKERS=$CPUCORES + LSPIPELINEBATCH=125 + LSINPUTTHREADS=1 + LSINPUTBATCHCOUNT=125 + fi + whiptail_make_changes + set_hostname + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + if [ $INSTALLMETHOD == iso ]; then + add_admin_user + disable_onion_user + fi + copy_ssh_key >> $SETUPLOG 2>&1 + { + sleep 0.5 + echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" + set_initial_firewall_policy >> $SETUPLOG 2>&1 + + echo -e "XXX\n3\nCreating Bond Interface... \nXXX" + create_sensor_bond >> $SETUPLOG 2>&1 + echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" + sensor_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + + + + echo -e "XXX\n5\nInstalling Salt Packages... \nXXX" + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n20\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n30\nInitializing Minion... \nXXX" + configure_minion heavynode >> $SETUPLOG 2>&1 + set_node_type >> $SETUPLOG 2>&1 + node_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" + salt_firstcheckin >> $SETUPLOG 2>&1 + # Accept the Salt Key + accept_salt_key_remote >> $SETUPLOG 2>&1 + echo -e "XXX\n40\nApplying SSL Certificates... \nXXX" + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nConfiguring Firewall... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + salt-call state.apply firewall >> $SETUPLOG 2>&1 + echo -e "XXX\n70\nInstalling Elastic Components... \nXXX" + salt-call state.apply logstash >> $SETUPLOG 2>&1 + salt-call state.apply elasticsearch >> $SETUPLOG 2>&1 + salt-call state.apply curator >> $SETUPLOG 2>&1 + salt-call state.apply filebeat >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nInstalling PCAP... \nXXX" + salt-call state.apply pcap >> $SETUPLOG 2>&1 + echo -e "XXX\n60\nInstalling IDS components... \nXXX" + salt-call state.apply suricata >> $SETUPLOG 2>&1 + + checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XX\n97\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + shutdown -r now + else + whiptail_setup_failed + shutdown -r now + fi + + fi + + + + + + + + + else echo "User not sure. Cancelling setup.">> $SETUPLOG 2>&1 whiptail_cancel diff --git a/setup/whiptail.sh b/setup/whiptail.sh index 171f180d2..3316d6e2c 100644 --- a/setup/whiptail.sh +++ b/setup/whiptail.sh @@ -254,6 +254,7 @@ whiptail_install_type() { "MASTERONLY" "Start a new grid" OFF \ "EVALMODE" "Evaluate all the things" OFF \ "MASTERSEARCH" "Master + Search Node" OFF \ + "HEAVYNODE" "Sensor + Search Node" OFF \ "HELIXSENSOR" "Connect this sensor to FireEye Helix" OFF \ "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ "HOTNODE" "TODO Add Hot Node (Search Node without Parsing)" OFF \