diff --git a/pillar/top.sls b/pillar/top.sls index ac46bfc12..7a36dcc53 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -101,6 +101,8 @@ base: - soc.adv_soc - soctopus.soc_soctopus - soctopus.adv_soctopus + - kibana.soc_kibana + - kibana.adv_kibana - strelka.soc_strelka - strelka.adv_strelka - curator.soc_curator @@ -155,6 +157,8 @@ base: - soc.adv_soc - soctopus.soc_soctopus - soctopus.adv_soctopus + - kibana.soc_kibana + - kibana.adv_kibana - strelka.soc_strelka - strelka.adv_strelka - curator.soc_curator @@ -248,6 +252,8 @@ base: - soc.adv_soc - soctopus.soc_soctopus - soctopus.adv_soctopus + - kibana.soc_kibana + - kibana.adv_kibana - curator.soc_curator - curator.adv_curator - backup.soc_backup diff --git a/salt/allowed_states.map.jinja b/salt/allowed_states.map.jinja index 0d88fe034..e7a9a0491 100644 --- a/salt/allowed_states.map.jinja +++ b/salt/allowed_states.map.jinja @@ -3,16 +3,6 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - -{% set ZEEKVER = salt['pillar.get']('global:mdengine', '') %} -{% set PLAYBOOK = salt['pillar.get']('manager:playbook', '0') %} -{% set ELASTALERT = salt['pillar.get']('elastalert:enabled', True) %} -{% set ELASTICSEARCH = salt['pillar.get']('elasticsearch:enabled', True) %} -{% set KIBANA = salt['pillar.get']('kibana:enabled', True) %} -{% set LOGSTASH = salt['pillar.get']('logstash:enabled', True) %} -{% set CURATOR = salt['pillar.get']('curator:enabled', True) %} -{% set REDIS = salt['pillar.get']('redis:enabled', True) %} -{% set STRELKA = salt['pillar.get']('strelka:enabled', '0') %} {% set ISAIRGAP = salt['pillar.get']('global:airgap', False) %} {% import_yaml 'salt/minion.defaults.yaml' as saltversion %} {% set saltversion = saltversion.salt.minion.version %} @@ -217,27 +207,27 @@ ], }, grain='role') %} - {% if (PLAYBOOK != 0) and grains.role in ['so-eval', 'so-manager', 'so-managersearch', 'so-standalone'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-managersearch', 'so-standalone'] %} {% do allowed_states.append('mysql') %} {% endif %} - {%- if ZEEKVER != 'SURICATA' and grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} + {%- if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} {% do allowed_states.append('zeek') %} {%- endif %} - {% if STRELKA and grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} + {% if grains.role in ['so-sensor', 'so-eval', 'so-standalone', 'so-heavynode'] %} {% do allowed_states.append('strelka') %} {% endif %} - {% if ELASTICSEARCH and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-import'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-import'] %} {% do allowed_states.append('elasticsearch') %} {% endif %} - {% if ELASTICSEARCH and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} {% do allowed_states.append('elasticsearch.auth') %} {% endif %} - {% if KIBANA and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch', 'so-import'] %} {% do allowed_states.append('kibana') %} {% do allowed_states.append('kibana.secrets') %} {% endif %} @@ -246,23 +236,19 @@ {% do allowed_states.append('curator') %} {% endif %} - {% if ELASTALERT and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %} {% do allowed_states.append('elastalert') %} {% endif %} - {% if (PLAYBOOK !=0) and grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %} + {% if grains.role in ['so-eval', 'so-manager', 'so-standalone', 'so-managersearch'] %} {% do allowed_states.append('playbook') %} {% endif %} - {% if (PLAYBOOK !=0) and grains.role in ['so-eval'] %} - {% do allowed_states.append('redis') %} - {% endif %} - - {% if LOGSTASH and grains.role in ['so-helixsensor', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-receiver'] %} + {% if grains.role in ['so-helixsensor', 'so-manager', 'so-standalone', 'so-searchnode', 'so-managersearch', 'so-heavynode', 'so-receiver'] %} {% do allowed_states.append('logstash') %} {% endif %} - {% if REDIS and grains.role in ['so-manager', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-receiver'] %} + {% if grains.role in ['so-manager', 'so-standalone', 'so-managersearch', 'so-heavynode', 'so-receiver', 'so-eval'] %} {% do allowed_states.append('redis') %} {% endif %} diff --git a/salt/curator/config.sls b/salt/curator/config.sls new file mode 100644 index 000000000..89ff53b2a --- /dev/null +++ b/salt/curator/config.sls @@ -0,0 +1,81 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from "curator/map.jinja" import CURATORMERGED %} + +# Create the group +curatorgroup: + group.present: + - name: curator + - gid: 934 + +# Add user +curator: + user.present: + - uid: 934 + - gid: 934 + - home: /opt/so/conf/curator + - createhome: False + +# Create the log directory +curlogdir: + file.directory: + - name: /opt/so/log/curator + - user: 934 + - group: 939 + +curactiondir: + file.directory: + - name: /opt/so/conf/curator/action + - user: 934 + - group: 939 + - makedirs: True + +actionconfs: + file.recurse: + - name: /opt/so/conf/curator/action + - source: salt://curator/files/action + - user: 934 + - group: 939 + - template: jinja + - defaults: + CURATORMERGED: {{ CURATORMERGED.elasticsearch.index_settings }} + +curconf: + file.managed: + - name: /opt/so/conf/curator/curator.yml + - source: salt://curator/files/curator.yml + - user: 934 + - group: 939 + - mode: 660 + - template: jinja + - show_changes: False + +curator_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://curator/tools/sbin + - user: 934 + - group: 939 + - file_mode: 755 + +curator_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://curator/tools/sbin_jinja + - user: 934 + - group: 939 + - file_mode: 755 + - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/curator/defaults.yaml b/salt/curator/defaults.yaml index e1333c3a6..eb518264f 100644 --- a/salt/curator/defaults.yaml +++ b/salt/curator/defaults.yaml @@ -1,98 +1,100 @@ -elasticsearch: - index_settings: - logs-import-so: - close: 73000 - delete: 73001 - logs-strelka-so: - close: 30 - delete: 365 - logs-suricata-so: - close: 30 - delete: 365 - logs-syslog-so: - close: 30 - delete: 365 - logs-zeek-so: - close: 30 - delete: 365 - logs-elastic_agent-metricbeat-default: - close: 30 - delete: 365 - logs-elastic_agent-osquerybeat-default: - close: 30 - delete: 365 - logs-elastic_agent-fleet_server-default: - close: 30 - delete: 365 - logs-elastic_agent-filebeat-default: - close: 30 - delete: 365 - logs-elastic_agent-default: - close: 30 - delete: 365 - logs-system-auth-default: - close: 30 - delete: 365 - logs-system-application-default: - close: 30 - delete: 365 - logs-system-security-default: - close: 30 - delete: 365 - logs-system-system-default: - close: 30 - delete: 365 - logs-system-syslog-default: - close: 30 - delete: 365 - logs-windows-powershell-default: - close: 30 - delete: 365 - logs-windows-sysmon_operational-default: - close: 30 - delete: 365 - so-beats: - close: 30 - delete: 365 - so-elasticsearch: - close: 30 - delete: 365 - so-firewall: - close: 30 - delete: 365 - so-ids: - close: 30 - delete: 365 - so-import: - close: 73000 - delete: 73001 - so-kratos: - close: 30 - delete: 365 - so-kibana: - close: 30 - delete: 365 - so-logstash: - close: 30 - delete: 365 - so-netflow: - close: 30 - delete: 365 - so-osquery: - close: 30 - delete: 365 - so-ossec: - close: 30 - delete: 365 - so-redis: - close: 30 - delete: 365 - so-strelka: - close: 30 - delete: 365 - so-syslog: - close: 30 - delete: 365 - so-zeek: - close: 30 - delete: 365 +curator: + enabled: False + elasticsearch: + index_settings: + logs-import-so: + close: 73000 + delete: 73001 + logs-strelka-so: + close: 30 + delete: 365 + logs-suricata-so: + close: 30 + delete: 365 + logs-syslog-so: + close: 30 + delete: 365 + logs-zeek-so: + close: 30 + delete: 365 + logs-elastic_agent-metricbeat-default: + close: 30 + delete: 365 + logs-elastic_agent-osquerybeat-default: + close: 30 + delete: 365 + logs-elastic_agent-fleet_server-default: + close: 30 + delete: 365 + logs-elastic_agent-filebeat-default: + close: 30 + delete: 365 + logs-elastic_agent-default: + close: 30 + delete: 365 + logs-system-auth-default: + close: 30 + delete: 365 + logs-system-application-default: + close: 30 + delete: 365 + logs-system-security-default: + close: 30 + delete: 365 + logs-system-system-default: + close: 30 + delete: 365 + logs-system-syslog-default: + close: 30 + delete: 365 + logs-windows-powershell-default: + close: 30 + delete: 365 + logs-windows-sysmon_operational-default: + close: 30 + delete: 365 + so-beats: + close: 30 + delete: 365 + so-elasticsearch: + close: 30 + delete: 365 + so-firewall: + close: 30 + delete: 365 + so-ids: + close: 30 + delete: 365 + so-import: + close: 73000 + delete: 73001 + so-kratos: + close: 30 + delete: 365 + so-kibana: + close: 30 + delete: 365 + so-logstash: + close: 30 + delete: 365 + so-netflow: + close: 30 + delete: 365 + so-osquery: + close: 30 + delete: 365 + so-ossec: + close: 30 + delete: 365 + so-redis: + close: 30 + delete: 365 + so-strelka: + close: 30 + delete: 365 + so-syslog: + close: 30 + delete: 365 + so-zeek: + close: 30 + delete: 365 diff --git a/salt/curator/disabled.sls b/salt/curator/disabled.sls new file mode 100644 index 000000000..acf9e3701 --- /dev/null +++ b/salt/curator/disabled.sls @@ -0,0 +1,35 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - curator.sostatus + +so-curator: + docker_container.absent: + - force: True + +so-curator_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-curator$ + +so-curator-cluster-close: + cron.absent: + - identifier: so-curator-cluster-close + +so-curator-cluster-delete: + cron.absent: + - identifier: so-curator-cluster-delete + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/curator/enabled.sls b/salt/curator/enabled.sls new file mode 100644 index 000000000..b60058692 --- /dev/null +++ b/salt/curator/enabled.sls @@ -0,0 +1,71 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - curator.config + - curator.sostatus + +so-curator: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-curator:{{ GLOBALS.so_version }} + - start: True + - hostname: curator + - name: so-curator + - user: curator + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-curator'].ip }} + - interactive: True + - tty: True + - binds: + - /opt/so/conf/curator/curator.yml:/etc/curator/config/curator.yml:ro + - /opt/so/conf/curator/action/:/etc/curator/action:ro + - /opt/so/log/curator:/var/log/curator:rw + - require: + - file: actionconfs + - file: curconf + - file: curlogdir + - watch: + - file: curconf + +delete_so-curator_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-curator$ + +so-curator-cluster-close: + cron.present: + - name: /usr/sbin/so-curator-cluster-close > /opt/so/log/curator/cron-close.log 2>&1 + - identifier: so-curator-cluster-close + - user: root + - minute: '2' + - hour: '*/1' + - daymonth: '*' + - month: '*' + - dayweek: '*' + +so-curator-cluster-delete: + cron.present: + - name: /usr/sbin/so-curator-cluster-delete > /opt/so/log/curator/cron-cluster-delete.log 2>&1 + - identifier: so-curator-cluster-delete + - user: root + - minute: '*/5' + - hour: '*' + - daymonth: '*' + - month: '*' + - dayweek: '*' + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/curator/files/curator.yml b/salt/curator/files/curator.yml index 549310d73..4ea1dddf7 100644 --- a/salt/curator/files/curator.yml +++ b/salt/curator/files/curator.yml @@ -4,9 +4,9 @@ # Elastic License 2.0. {% from 'vars/globals.map.jinja' import GLOBALS %} -{% if grains['role'] in ['so-searchnode', 'so-heavynode'] %} +{% if GLOBALS.role in ['so-searchnode', 'so-heavynode'] %} {%- set elasticsearch = GLOBALS.node_ip -%} -{% elif grains['role'] in ['so-eval', 'so-managersearch', 'so-standalone', 'so-manager'] %} +{% elif GLOBALS.role in ['so-eval', 'so-managersearch', 'so-standalone', 'so-manager'] %} {%- set elasticsearch = GLOBALS.manager_ip -%} {%- endif %} {%- set ES_USER = salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:user', '') %} @@ -30,10 +30,8 @@ elasticsearch: id: api_key: master_only: False -{%- if salt['pillar.get']('elasticsearch:auth:enabled') is sameas true %} username: "{{ ES_USER }}" password: "{{ ES_PASS }}" -{%- endif %} logging: loglevel: INFO diff --git a/salt/curator/init.sls b/salt/curator/init.sls index eaa5639ff..201195b60 100644 --- a/salt/curator/init.sls +++ b/salt/curator/init.sls @@ -3,146 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from "curator/map.jinja" import CURATOROPTIONS %} -{% from "curator/map.jinja" import CURATORMERGED %} -{% set REMOVECURATORCRON = False %} - -# Curator -# Create the group -curatorgroup: - group.present: - - name: curator - - gid: 934 - -# Add user -curator: - user.present: - - uid: 934 - - gid: 934 - - home: /opt/so/conf/curator - - createhome: False - -# Create the log directory -curlogdir: - file.directory: - - name: /opt/so/log/curator - - user: 934 - - group: 939 - -curactiondir: - file.directory: - - name: /opt/so/conf/curator/action - - user: 934 - - group: 939 - - makedirs: True - -actionconfs: - file.recurse: - - name: /opt/so/conf/curator/action - - source: salt://curator/files/action - - user: 934 - - group: 939 - - template: jinja - - defaults: - CURATORMERGED: {{ CURATORMERGED }} - -curconf: - file.managed: - - name: /opt/so/conf/curator/curator.yml - - source: salt://curator/files/curator.yml - - user: 934 - - group: 939 - - mode: 660 - - template: jinja - - show_changes: False - -curator_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://curator/tools/sbin - - user: 934 - - group: 939 - - file_mode: 755 - -curator_sbin_jinja: - file.recurse: - - name: /usr/sbin - - source: salt://curator/tools/sbin_jinja - - user: 934 - - group: 939 - - file_mode: 755 - - template: jinja - -so-curator: - docker_container.{{ CURATOROPTIONS.status }}: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-curator:{{ GLOBALS.so_version }} - - start: {{ CURATOROPTIONS.start }} - - hostname: curator - - name: so-curator - - user: curator - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-curator'].ip }} - - interactive: True - - tty: True - - binds: - - /opt/so/conf/curator/curator.yml:/etc/curator/config/curator.yml:ro - - /opt/so/conf/curator/action/:/etc/curator/action:ro - - /opt/so/log/curator:/var/log/curator:rw - - require: - - file: actionconfs - - file: curconf - - file: curlogdir - - watch: - - file: curconf - -append_so-curator_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-curator - - unless: grep -q so-curator /opt/so/conf/so-status/so-status.conf - {% if not CURATOROPTIONS.start %} -so-curator_so-status.disabled: - file.comment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-curator$ - {% else %} -delete_so-curator_so-status.disabled: - file.uncomment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-curator$ - {% endif %} - -so-curator-cluster-close: - cron.present: - - name: /usr/sbin/so-curator-cluster-close > /opt/so/log/curator/cron-close.log 2>&1 - - identifier: so-curator-cluster-close - - user: root - - minute: '2' - - hour: '*/1' - - daymonth: '*' - - month: '*' - - dayweek: '*' - -so-curator-cluster-delete: - cron.present: - - name: /usr/sbin/so-curator-cluster-delete > /opt/so/log/curator/cron-cluster-delete.log 2>&1 - - identifier: so-curator-cluster-delete - - user: root - - minute: '*/5' - - hour: '*' - - daymonth: '*' - - month: '*' - - dayweek: '*' +{% from 'curator/map.jinja' import CURATORMERGED %} +include: +{% if CURATORMERGED.enabled %} + - curator.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - curator.disabled {% endif %} diff --git a/salt/curator/map.jinja b/salt/curator/map.jinja index 65d9f580d..517209635 100644 --- a/salt/curator/map.jinja +++ b/salt/curator/map.jinja @@ -1,18 +1,7 @@ -{% set CURATOROPTIONS = {} %} -{% set ENABLED = salt['pillar.get']('curator:enabled', True) %} -{% do CURATOROPTIONS.update({'manage_sostatus': True}) %} - -# don't start the docker container if curator is disabled via pillar -{% if not ENABLED %} - {% do CURATOROPTIONS.update({'start': False}) %} - {% do CURATOROPTIONS.update({'status': 'absent'}) %} - {% if (TRUECLUSTER and grains.id.split('_')|last == 'searchnode') or (not TRUECLUSTER and grains.id.split('_')|last == 'manager') %} - {% do CURATOROPTIONS.update({'manage_sostatus': False}) %} - {% endif %} -{% else %} - {% do CURATOROPTIONS.update({'start': True}) %} - {% do CURATOROPTIONS.update({'status': 'running'}) %} -{% endif %} +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} {% import_yaml 'curator/defaults.yaml' as CURATORDEFAULTS %} -{% set CURATORMERGED = salt['pillar.get']('elasticsearch:index_settings', CURATORDEFAULTS.elasticsearch.index_settings, merge=true) %} +{% set CURATORMERGED = salt['pillar.get']('curator', CURATORDEFAULTS.curator, merge=true) %} diff --git a/salt/curator/soc_curator.yaml b/salt/curator/soc_curator.yaml new file mode 100644 index 000000000..5e5b1fcc6 --- /dev/null +++ b/salt/curator/soc_curator.yaml @@ -0,0 +1,108 @@ +curator: + enabled: + description: You can enable or disable Curator. + helpLink: curator.html + elasticsearch: + index_settings: + logs-import-so: + close: &close + description: Age, in days, when Curator closes the index. + helpLink: curator.html + forcedType: int + delete: &delete + description: Age, in days, when Curator deletes the index. + helpLink: curator.html + forcedType: int + logs-strelka-so: + close: *close + delete: *delete + logs-suricata-so: + close: *close + delete: *delete + logs-syslog-so: + close: *close + delete: *delete + logs-zeek-so: + close: *close + delete: *delete + logs-elastic_agent-metricbeat-default: + close: *close + delete: *delete + logs-elastic_agent-osquerybeat-default: + close: *close + delete: *delete + logs-elastic_agent-fleet_server-default: + close: *close + delete: *delete + logs-elastic_agent-filebeat-default: + close: *close + delete: *delete + logs-elastic_agent-default: + close: *close + delete: *delete + logs-system-auth-default: + close: *close + delete: *delete + logs-system-application-default: + close: *close + delete: *delete + logs-system-security-default: + close: *close + delete: *delete + logs-system-system-default: + close: *close + delete: *delete + logs-system-syslog-default: + close: *close + delete: *delete + logs-windows-powershell-default: + close: *close + delete: *delete + logs-windows-sysmon_operational-default: + close: *close + delete: *delete + so-beats: + close: *close + delete: *delete + so-elasticsearch: + close: *close + delete: *delete + so-firewall: + close: *close + delete: *delete + so-ids: + close: *close + delete: *delete + so-import: + close: *close + delete: *delete + so-kratos: + close: *close + delete: *delete + so-kibana: + close: *close + delete: *delete + so-logstash: + close: *close + delete: *delete + so-netflow: + close: *close + delete: *delete + so-osquery: + close: *close + delete: *delete + so-ossec: + close: *close + delete: *delete + so-redis: + close: *close + delete: *delete + so-strelka: + close: *close + delete: *delete + so-syslog: + close: *close + delete: *delete + so-zeek: + close: *close + delete: *delete diff --git a/salt/curator/sostatus.sls b/salt/curator/sostatus.sls new file mode 100644 index 000000000..de6459a6d --- /dev/null +++ b/salt/curator/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-curator_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-curator + - unless: grep -q so-curator /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastalert/config.sls b/salt/elastalert/config.sls new file mode 100644 index 000000000..252aa83c0 --- /dev/null +++ b/salt/elastalert/config.sls @@ -0,0 +1,103 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +{% from 'elastalert/map.jinja' import ELASTALERTMERGED %} + +# Create the group +elastagroup: + group.present: + - name: elastalert + - gid: 933 + +# Add user +elastalert: + user.present: + - uid: 933 + - gid: 933 + - home: /opt/so/conf/elastalert + - createhome: False + +elastalogdir: + file.directory: + - name: /opt/so/log/elastalert + - user: 933 + - group: 933 + - makedirs: True + +elastalert_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://elastalert/tools/sbin + - user: 933 + - group: 939 + - file_mode: 755 + +#elastalert_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://elastalert/tools/sbin_jinja +# - user: 933 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +elastarules: + file.directory: + - name: /opt/so/rules/elastalert + - user: 933 + - group: 933 + - makedirs: True + +elastaconfdir: + file.directory: + - name: /opt/so/conf/elastalert + - user: 933 + - group: 933 + - makedirs: True + +elastasomodulesdir: + file.directory: + - name: /opt/so/conf/elastalert/modules/so + - user: 933 + - group: 933 + - makedirs: True + +elastacustmodulesdir: + file.directory: + - name: /opt/so/conf/elastalert/modules/custom + - user: 933 + - group: 933 + - makedirs: True + +elastasomodulesync: + file.recurse: + - name: /opt/so/conf/elastalert/modules/so + - source: salt://elastalert/files/modules/so + - user: 933 + - group: 933 + - makedirs: True + +elastaconf: + file.managed: + - name: /opt/so/conf/elastalert/elastalert_config.yaml + - source: salt://elastalert/files/elastalert_config.yaml.jinja + - context: + elastalert_config: {{ ELASTALERTMERGED.config }} + - user: 933 + - group: 933 + - mode: 660 + - template: jinja + - show_changes: False + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastalert/defaults.yaml b/salt/elastalert/defaults.yaml index 6a051354e..1083fa8fd 100644 --- a/salt/elastalert/defaults.yaml +++ b/salt/elastalert/defaults.yaml @@ -1,4 +1,5 @@ elastalert: + enabled: False config: rules_folder: /opt/elastalert/rules/ scan_subdirectories: true diff --git a/salt/elastalert/disabled.sls b/salt/elastalert/disabled.sls new file mode 100644 index 000000000..5830bbd8f --- /dev/null +++ b/salt/elastalert/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - elastalert.sostatus + +so-elastalert: + docker_container.absent: + - force: True + +so-elastalert_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastalert$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastalert/elastalert_config.map.jinja b/salt/elastalert/elastalert_config.map.jinja deleted file mode 100644 index 26ddc08c9..000000000 --- a/salt/elastalert/elastalert_config.map.jinja +++ /dev/null @@ -1,11 +0,0 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% import_yaml 'elastalert/defaults.yaml' as ELASTALERT %} -{% set elastalert_pillar = salt['pillar.get']('elastalert:config', {}) %} - - -{% do ELASTALERT.elastalert.config.update({'es_host': GLOBALS.manager}) %} -{% do ELASTALERT.elastalert.config.update({'es_username': pillar.elasticsearch.auth.users.so_elastic_user.user}) %} -{% do ELASTALERT.elastalert.config.update({'es_password': pillar.elasticsearch.auth.users.so_elastic_user.pass}) %} - -{% do salt['defaults.merge'](ELASTALERT.elastalert.config, elastalert_pillar, in_place=True) %} - diff --git a/salt/elastalert/enabled.sls b/salt/elastalert/enabled.sls new file mode 100644 index 000000000..3e043b46c --- /dev/null +++ b/salt/elastalert/enabled.sls @@ -0,0 +1,58 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - elastalert.config + - elastalert.sostatus + +wait_for_elasticsearch: + cmd.run: + - name: so-elasticsearch-wait + +so-elastalert: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastalert:{{ GLOBALS.so_version }} + - hostname: elastalert + - name: so-elastalert + - user: so-elastalert + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-elastalert'].ip }} + - detach: True + - binds: + - /opt/so/rules/elastalert:/opt/elastalert/rules/:ro + - /opt/so/log/elastalert:/var/log/elastalert:rw + - /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro + - /opt/so/conf/elastalert/elastalert_config.yaml:/opt/elastalert/config.yaml:ro + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - require: + - cmd: wait_for_elasticsearch + - file: elastarules + - file: elastalogdir + - file: elastacustmodulesdir + - file: elastaconf + - watch: + - file: elastaconf + - onlyif: + - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #} + +delete_so-elastalert_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastalert$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastalert/init.sls b/salt/elastalert/init.sls index 148fe7e1b..d0e86d07f 100644 --- a/salt/elastalert/init.sls +++ b/salt/elastalert/init.sls @@ -1,141 +1,13 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use -# this file except in compliance with the Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'elastalert/elastalert_config.map.jinja' import ELASTALERT as elastalert_config with context %} - -# Create the group -elastagroup: - group.present: - - name: elastalert - - gid: 933 - -# Add user -elastalert: - user.present: - - uid: 933 - - gid: 933 - - home: /opt/so/conf/elastalert - - createhome: False - -elastalogdir: - file.directory: - - name: /opt/so/log/elastalert - - user: 933 - - group: 933 - - makedirs: True - -elastalert_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://elastalert/tools/sbin - - user: 933 - - group: 939 - - file_mode: 755 - -#elastalert_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://elastalert/tools/sbin_jinja -# - user: 933 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -elastarules: - file.directory: - - name: /opt/so/rules/elastalert - - user: 933 - - group: 933 - - makedirs: True - -elastaconfdir: - file.directory: - - name: /opt/so/conf/elastalert - - user: 933 - - group: 933 - - makedirs: True - -elastasomodulesdir: - file.directory: - - name: /opt/so/conf/elastalert/modules/so - - user: 933 - - group: 933 - - makedirs: True - -elastacustmodulesdir: - file.directory: - - name: /opt/so/conf/elastalert/modules/custom - - user: 933 - - group: 933 - - makedirs: True - -elastasomodulesync: - file.recurse: - - name: /opt/so/conf/elastalert/modules/so - - source: salt://elastalert/files/modules/so - - user: 933 - - group: 933 - - makedirs: True - -elastaconf: - file.managed: - - name: /opt/so/conf/elastalert/elastalert_config.yaml - - source: salt://elastalert/files/elastalert_config.yaml.jinja - - context: - elastalert_config: {{ elastalert_config.elastalert.config }} - - user: 933 - - group: 933 - - mode: 660 - - template: jinja - - show_changes: False - -wait_for_elasticsearch: - cmd.run: - - name: so-elasticsearch-wait - -so-elastalert: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastalert:{{ GLOBALS.so_version }} - - hostname: elastalert - - name: so-elastalert - - user: so-elastalert - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastalert'].ip }} - - detach: True - - binds: - - /opt/so/rules/elastalert:/opt/elastalert/rules/:ro - - /opt/so/log/elastalert:/var/log/elastalert:rw - - /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro - - /opt/so/conf/elastalert/elastalert_config.yaml:/opt/elastalert/config.yaml:ro - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - require: - - cmd: wait_for_elasticsearch - - file: elastarules - - file: elastalogdir - - file: elastacustmodulesdir - - file: elastaconf - - watch: - - file: elastaconf - - onlyif: - - "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #} - - -append_so-elastalert_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-elastalert +{% from 'elastalert/map.jinja' import ELASTALERTMERGED %} +include: +{% if ELASTALERTMERGED.enabled %} + - elastalert.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - elastalert.disabled {% endif %} diff --git a/salt/elastalert/map.jinja b/salt/elastalert/map.jinja new file mode 100644 index 000000000..cc395d8ee --- /dev/null +++ b/salt/elastalert/map.jinja @@ -0,0 +1,15 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% import_yaml 'elastalert/defaults.yaml' as ELASTALERTDEFAULTS %} +{% set elastalert_pillar = salt['pillar.get']('elastalert:config', {}) %} + + +{% do ELASTALERTDEFAULTS.elastalert.config.update({'es_host': GLOBALS.manager}) %} +{% do ELASTALERTDEFAULTS.elastalert.config.update({'es_username': pillar.elasticsearch.auth.users.so_elastic_user.user}) %} +{% do ELASTALERTDEFAULTS.elastalert.config.update({'es_password': pillar.elasticsearch.auth.users.so_elastic_user.pass}) %} + +{% set ELASTALERTMERGED = salt['pillar.get']('elastalert', ELASTALERTDEFAULTS.elastalert, merge=True) %} diff --git a/salt/elastalert/soc_elastalert.yaml b/salt/elastalert/soc_elastalert.yaml index fe01f2458..cde09b83e 100644 --- a/salt/elastalert/soc_elastalert.yaml +++ b/salt/elastalert/soc_elastalert.yaml @@ -1,4 +1,7 @@ elastalert: + enabled: + description: You can enable or disable Elastalert. + helpLink: elastalert.html config: disable_rules_on_error: description: Disable rules on failure. diff --git a/salt/elastalert/sostatus.sls b/salt/elastalert/sostatus.sls new file mode 100644 index 000000000..609a4482f --- /dev/null +++ b/salt/elastalert/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-elastalert_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-elastalert + - unless: grep -q so-elastalert /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastic-fleet-package-registry/config.sls b/salt/elastic-fleet-package-registry/config.sls new file mode 100644 index 000000000..aa2872069 --- /dev/null +++ b/salt/elastic-fleet-package-registry/config.sls @@ -0,0 +1,29 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +# Add Group +elasticsagentprgroup: + group.present: + - name: elastic-agent-pr + - gid: 948 + +# Add user +elastic-agent-pr: + user.present: + - uid: 948 + - gid: 948 + - home: /opt/so/conf/elastic-fleet-pr + - createhome: False + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastic-fleet-package-registry/defaults.yaml b/salt/elastic-fleet-package-registry/defaults.yaml new file mode 100644 index 000000000..4f14e168b --- /dev/null +++ b/salt/elastic-fleet-package-registry/defaults.yaml @@ -0,0 +1,2 @@ +elastic_fleet_package_registry: + enabled: False diff --git a/salt/elastic-fleet-package-registry/disabled.sls b/salt/elastic-fleet-package-registry/disabled.sls new file mode 100644 index 000000000..8487fc3d6 --- /dev/null +++ b/salt/elastic-fleet-package-registry/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - elastic-fleet-package-registry.sostatus + +so-elastic-fleet-package-registry: + docker_container.absent: + - force: True + +so-elastic-fleet-package-registry_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastic-fleet-package-registry$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastic-fleet-package-registry/enabled.sls b/salt/elastic-fleet-package-registry/enabled.sls new file mode 100644 index 000000000..5f663e78f --- /dev/null +++ b/salt/elastic-fleet-package-registry/enabled.sls @@ -0,0 +1,43 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - elastic-fleet-package-registry.config + - elastic-fleet-package-registry.sostatus + +so-elastic-fleet-package-registry: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-fleet-package-registry:{{ GLOBALS.so_version }} + - name: so-elastic-fleet-package-registry + - hostname: Fleet-package-reg-{{ GLOBALS.hostname }} + - detach: True + - user: 948 + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-elastic-fleet-package-registry'].ip }} + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-elastic-fleet-package-registry'].port_bindings %} + - {{ BINDING }} + {% endfor %} + +delete_so-elastic-fleet-package-registry_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastic-fleet-package-registry$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elastic-fleet-package-registry/init.sls b/salt/elastic-fleet-package-registry/init.sls index b4cea6542..7a42c57be 100644 --- a/salt/elastic-fleet-package-registry/init.sls +++ b/salt/elastic-fleet-package-registry/init.sls @@ -1,52 +1,13 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use -# this file except in compliance with the Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. -# Add Group -elasticsagentprgroup: - group.present: - - name: elastic-agent-pr - - gid: 948 - - -# Add user -elastic-agent-pr: - user.present: - - uid: 948 - - gid: 948 - - home: /opt/so/conf/elastic-fleet-pr - - createhome: False - -so-elastic-fleet-package-registry: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-fleet-package-registry:{{ GLOBALS.so_version }} - - name: so-elastic-fleet-package-registry - - hostname: Fleet-package-reg-{{ GLOBALS.hostname }} - - detach: True - - user: 948 - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastic-fleet-package-registry'].ip }} - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-elastic-fleet-package-registry'].port_bindings %} - - {{ BINDING }} - {% endfor %} - -append_so-elastic-fleet-package-registry_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-elastic-fleet-package-registry +{% from 'elastic-fleet-package-registry/map.jinja' import ELASTICFLEETPACKAGEREGISTRYMERGED %} +include: +{% if ELASTICFLEETPACKAGEREGISTRYMERGED.enabled %} + - elastic-fleet-package-registry.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - elastic-fleet-package-registry.disabled {% endif %} diff --git a/salt/elastic-fleet-package-registry/map.jinja b/salt/elastic-fleet-package-registry/map.jinja new file mode 100644 index 000000000..54cdedd75 --- /dev/null +++ b/salt/elastic-fleet-package-registry/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'elastic-fleet-package-registry/defaults.yaml' as ELASTICFLEETPACKAGEREGISTRYDEFAULTS %} +{% set ELASTICFLEETPACKAGEREGISTRYMERGED = salt['pillar.get']('elastic_fleet_package_registry', ELASTICFLEETPACKAGEREGISTRYDEFAULTS.elastic_fleet_package_registry, merge=True) %} diff --git a/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml b/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml new file mode 100644 index 000000000..70886c447 --- /dev/null +++ b/salt/elastic-fleet-package-registry/soc_elastic-fleet-package-registry.yaml @@ -0,0 +1,4 @@ +elastic_fleet_package_registry: + enabled: + description: You can enable or disable Elastic Fleet Package Registry. + advanced: True diff --git a/salt/elastic-fleet-package-registry/sostatus.sls b/salt/elastic-fleet-package-registry/sostatus.sls new file mode 100644 index 000000000..191aa7e3d --- /dev/null +++ b/salt/elastic-fleet-package-registry/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-elastic-fleet-package-registry_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-elastic-fleet-package-registry + - unless: grep -q so-elastic-fleet-package-registry /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/config.sls b/salt/elasticfleet/config.sls new file mode 100644 index 000000000..29aa7eb30 --- /dev/null +++ b/salt/elasticfleet/config.sls @@ -0,0 +1,60 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +# Add EA Group +elasticsagentgroup: + group.present: + - name: elastic-agent + - gid: 947 + +# Add EA user +elastic-agent: + user.present: + - uid: 947 + - gid: 947 + - home: /opt/so/conf/elastic-fleet + - createhome: False + +elasticfleet_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://elasticfleet/tools/sbin + - user: 947 + - group: 939 + - file_mode: 755 + +elasticfleet_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://elasticfleet/tools/sbin_jinja + - user: 947 + - group: 939 + - file_mode: 755 + - template: jinja + +eaconfdir: + file.directory: + - name: /opt/so/conf/elastic-fleet + - user: 947 + - group: 939 + - makedirs: True + +eastatedir: + file.directory: + - name: /opt/so/conf/elastic-fleet/state + - user: 947 + - group: 939 + - makedirs: True + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/defaults.yaml b/salt/elasticfleet/defaults.yaml new file mode 100644 index 000000000..d29e08f9a --- /dev/null +++ b/salt/elasticfleet/defaults.yaml @@ -0,0 +1,8 @@ +elasticfleet: + enabled: False + config: + server: + endpoints_enrollment: '' + es_token: '' + grid_enrollment: '' + url: '' diff --git a/salt/elasticfleet/disabled.sls b/salt/elasticfleet/disabled.sls new file mode 100644 index 000000000..1b3f69bc4 --- /dev/null +++ b/salt/elasticfleet/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - elasticfleet.sostatus + +so-elastic-fleet: + docker_container.absent: + - force: True + +so-elastic-fleet_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastic-fleet$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/enabled.sls b/salt/elasticfleet/enabled.sls new file mode 100644 index 000000000..a3982e760 --- /dev/null +++ b/salt/elasticfleet/enabled.sls @@ -0,0 +1,62 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{# This value is generated during node install and stored in minion pillar #} +{% set SERVICETOKEN = salt['pillar.get']('elasticfleet:config:server:es_token','') %} + +include: + - elasticfleet.config + - elasticfleet.sostatus + +{% if SERVICETOKEN != '' %} +so-elastic-fleet: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent:{{ GLOBALS.so_version }} + - name: so-elastic-fleet + - hostname: FleetServer-{{ GLOBALS.hostname }} + - detach: True + - user: 947 + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-elastic-fleet'].ip }} + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-elastic-fleet'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - binds: + - /etc/pki:/etc/pki:ro + #- /opt/so/conf/elastic-fleet/state:/usr/share/elastic-agent/state:rw + - environment: + - FLEET_SERVER_ENABLE=true + - FLEET_URL=https://{{ GLOBALS.node_ip }}:8220 + - FLEET_SERVER_ELASTICSEARCH_HOST=https://{{ GLOBALS.manager }}:9200 + - FLEET_SERVER_SERVICE_TOKEN={{ SERVICETOKEN }} + - FLEET_SERVER_POLICY_ID=FleetServer_{{ GLOBALS.hostname }} + - FLEET_SERVER_ELASTICSEARCH_CA=/etc/pki/tls/certs/intca.crt + - FLEET_SERVER_CERT=/etc/pki/elasticfleet.crt + - FLEET_SERVER_CERT_KEY=/etc/pki/elasticfleet.key + - FLEET_CA=/etc/pki/tls/certs/intca.crt +{% endif %} + +delete_so-elastic-fleet_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elastic-fleet$ + + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/init.sls b/salt/elasticfleet/init.sls index 9476c3b94..c46ca157c 100644 --- a/salt/elasticfleet/init.sls +++ b/salt/elasticfleet/init.sls @@ -1,104 +1,13 @@ # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one -# or more contributor license agreements. Licensed under the Elastic License 2.0; you may not use -# this file except in compliance with the Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. -# These values are generated during node install and stored in minion pillar -{% set SERVICETOKEN = salt['pillar.get']('elasticfleet:server:es_token','') %} -#{% set FLEETSERVERPOLICY = salt['pillar.get']('elasticfleet:server:server_policy','so-manager') %} -#{% set FLEETURL = salt['pillar.get']('elasticfleet:server:url') %} - -# Add EA Group -elasticsagentgroup: - group.present: - - name: elastic-agent - - gid: 947 - -# Add EA user -elastic-agent: - user.present: - - uid: 947 - - gid: 947 - - home: /opt/so/conf/elastic-fleet - - createhome: False - -elasticfleet_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://elasticfleet/tools/sbin - - user: 947 - - group: 939 - - file_mode: 755 - -elasticfleet_sbin_jinja: - file.recurse: - - name: /usr/sbin - - source: salt://elasticfleet/tools/sbin_jinja - - user: 947 - - group: 939 - - file_mode: 755 - - template: jinja - -eaconfdir: - file.directory: - - name: /opt/so/conf/elastic-fleet - - user: 947 - - group: 939 - - makedirs: True - -eastatedir: - file.directory: - - name: /opt/so/conf/elastic-fleet/state - - user: 947 - - group: 939 - - makedirs: True - - - {% if SERVICETOKEN != '' %} -so-elastic-fleet: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elastic-agent:{{ GLOBALS.so_version }} - - name: so-elastic-fleet - - hostname: FleetServer-{{ GLOBALS.hostname }} - - detach: True - - user: 947 - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elastic-fleet'].ip }} - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-elastic-fleet'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - binds: - - /etc/pki:/etc/pki:ro - #- /opt/so/conf/elastic-fleet/state:/usr/share/elastic-agent/state:rw - - environment: - - FLEET_SERVER_ENABLE=true - - FLEET_URL=https://{{ GLOBALS.node_ip }}:8220 - - FLEET_SERVER_ELASTICSEARCH_HOST=https://{{ GLOBALS.manager }}:9200 - - FLEET_SERVER_SERVICE_TOKEN={{ SERVICETOKEN }} - - FLEET_SERVER_POLICY_ID=FleetServer_{{ GLOBALS.hostname }} - - FLEET_SERVER_ELASTICSEARCH_CA=/etc/pki/tls/certs/intca.crt - - FLEET_SERVER_CERT=/etc/pki/elasticfleet.crt - - FLEET_SERVER_CERT_KEY=/etc/pki/elasticfleet.key - - FLEET_CA=/etc/pki/tls/certs/intca.crt - {% endif %} - -append_so-elastic-fleet_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-elastic-fleet +{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %} +include: +{% if ELASTICFLEETMERGED.enabled %} + - elasticfleet.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - elasticfleet.disabled {% endif %} diff --git a/salt/elasticfleet/map.jinja b/salt/elasticfleet/map.jinja new file mode 100644 index 000000000..09c3497d0 --- /dev/null +++ b/salt/elasticfleet/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'elasticfleet/defaults.yaml' as ELASTICFLEETDEFAULTS %} +{% set ELASTICFLEETMERGED = salt['pillar.get']('elasticfleet', ELASTICFLEETDEFAULTS.elasticfleet, merge=True) %} diff --git a/salt/elasticfleet/soc_elasticfleet.yaml b/salt/elasticfleet/soc_elasticfleet.yaml index 4d523c548..e8bf03ad1 100644 --- a/salt/elasticfleet/soc_elasticfleet.yaml +++ b/salt/elasticfleet/soc_elasticfleet.yaml @@ -1,25 +1,30 @@ elasticfleet: - server: - endpoints_enrollment: - description: Endpoint enrollment key. - global: True - helpLink: elastic-fleet.html - sensitive: True - advanced: True - es_token: - description: Elastic auth token. - global: True - helpLink: elastic-fleet.html - sensitive: True - advanced: True - grid_enrollment: - description: Grid enrollment key. - global: True - helpLink: elastic-fleet.html - sensitive: True - advanced: True - url: - description: Agent connection URL. - global: True - helpLink: elastic-fleet.html - advanced: True \ No newline at end of file + enabled: + description: You can enable or disable Elastic Fleet. + advanced: True + helpLink: elastic-fleet.html + config: + server: + endpoints_enrollment: + description: Endpoint enrollment key. + global: True + helpLink: elastic-fleet.html + sensitive: True + advanced: True + es_token: + description: Elastic auth token. + global: True + helpLink: elastic-fleet.html + sensitive: True + advanced: True + grid_enrollment: + description: Grid enrollment key. + global: True + helpLink: elastic-fleet.html + sensitive: True + advanced: True + url: + description: Agent connection URL. + global: True + helpLink: elastic-fleet.html + advanced: True diff --git a/salt/elasticfleet/sostatus.sls b/salt/elasticfleet/sostatus.sls new file mode 100644 index 000000000..392733a4c --- /dev/null +++ b/salt/elasticfleet/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-elastic-fleet_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-elastic-fleet + - unless: grep -q ^so-elastic-fleet$ /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup index 377961938..7c5db70f7 100755 --- a/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup +++ b/salt/elasticfleet/tools/sbin_jinja/so-elastic-fleet-setup @@ -81,10 +81,12 @@ GRIDNODESENROLLMENTOKEN=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "loc pillar_file=/opt/so/saltstack/local/pillar/minions/{{ GLOBALS.minion_id }}.sls printf '%s\n'\ "elasticfleet:"\ - " server:"\ - " es_token: '$ESTOKEN'"\ - " endpoints_enrollment: '$ENDPOINTSENROLLMENTOKEN'"\ - " grid_enrollment: '$GRIDNODESENROLLMENTOKEN'"\ + " enabled: True"\ + " config:"\ + " server:"\ + " es_token: '$ESTOKEN'"\ + " endpoints_enrollment: '$ENDPOINTSENROLLMENTOKEN'"\ + " grid_enrollment: '$GRIDNODESENROLLMENTOKEN'"\ "" >> "$pillar_file" #Store Grid Nodes Enrollment token in Global pillar diff --git a/salt/elasticsearch/ca.sls b/salt/elasticsearch/ca.sls new file mode 100644 index 000000000..7d7f1bdfb --- /dev/null +++ b/salt/elasticsearch/ca.sls @@ -0,0 +1,50 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +# Move our new CA over so Elastic and Logstash can use SSL with the internal CA +catrustdir: + file.directory: + - name: /opt/so/conf/ca + - user: 939 + - group: 939 + - makedirs: True + +{% if GLOBALS.is_manager %} +# We have to add the Manager CA to the CA list +cascriptsync: + cmd.script: + - source: salt://elasticsearch/tools/sbin_jinja/so-catrust + - template: jinja + - defaults: + GLOBALS: {{ GLOBALS }} +{% endif %} + +{% if grains.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-searchnode'] %} +cacertz: + file.managed: + - name: /opt/so/conf/ca/cacerts + - source: salt://elasticsearch/cacerts + - user: 939 + - group: 939 + +capemz: + file.managed: + - name: /opt/so/conf/ca/tls-ca-bundle.pem + - source: salt://elasticsearch/tls-ca-bundle.pem + - user: 939 + - group: 939 +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/config.map.jinja b/salt/elasticsearch/config.map.jinja index 278bbde62..d367de287 100644 --- a/salt/elasticsearch/config.map.jinja +++ b/salt/elasticsearch/config.map.jinja @@ -1,44 +1,43 @@ {% from 'vars/globals.map.jinja' import GLOBALS %} -{% import_yaml 'elasticsearch/defaults.yaml' as ESCONFIG with context %} +{% import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS with context %} {% from 'logstash/map.jinja' import LOGSTASH_NODES with context %} {% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} {% if grains.id.split('_') | last in ['manager','managersearch','standalone'] %} {% if LOGSTASH_NODES | length > 1 %} - {% do ESCONFIG.elasticsearch.config.update({'discovery': {'seed_hosts': []}}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': []}}) %} {% for NODE in LOGSTASH_NODES %} - {% do ESCONFIG.elasticsearch.config.discovery.seed_hosts.append(NODE.keys()|first) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.discovery.seed_hosts.append(NODE.keys()|first) %} {% endfor %} {% if grains.id.split('_') | last == 'manager' %} - {% do ESCONFIG.elasticsearch.config.node.update({'roles': ['master','data','remote_cluster_client']}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.update({'roles': ['master','data','remote_cluster_client']}) %} {% else %} - {% do ESCONFIG.elasticsearch.config.node.update({'roles': ['master', 'data_hot', 'remote_cluster_client']}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.update({'roles': ['master', 'data_hot', 'remote_cluster_client']}) %} {% endif %} {% endif %} {% elif grains.id.split('_') | last == 'searchnode' %} - {% do ESCONFIG.elasticsearch.config.node.update({'roles': ['data_hot', 'ingest']}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.update({'roles': ['data_hot', 'ingest']}) %} {% if HIGHLANDER %} - {% do ESCONFIG.elasticsearch.config.node.roles.extend(['ml', 'master', 'transform']) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.roles.extend(['ml', 'master', 'transform']) %} {% endif %} - {% do ESCONFIG.elasticsearch.config.update({'discovery': {'seed_hosts': [GLOBALS.manager]}}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': [GLOBALS.manager]}}) %} {% endif %} {% if HIGHLANDER %} - {% do ESCONFIG.elasticsearch.config.xpack.ml.update({'enabled': true}) %} + {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.xpack.ml.update({'enabled': true}) %} {% endif %} -{% do ESCONFIG.elasticsearch.config.node.update({'name': GLOBALS.hostname}) %} -{% do ESCONFIG.elasticsearch.config.cluster.update({'name': GLOBALS.hostname}) %} -{% do ESCONFIG.elasticsearch.config.transport.update({'publish_host': GLOBALS.hostname}) %} +{% do ELASTICSEARCHDEFAULTS.elasticsearch.config.node.update({'name': GLOBALS.hostname}) %} +{% do ELASTICSEARCHDEFAULTS.elasticsearch.config.cluster.update({'name': GLOBALS.hostname}) %} +{% do ELASTICSEARCHDEFAULTS.elasticsearch.config.transport.update({'publish_host': GLOBALS.hostname}) %} -{# merge with the elasticsearch pillar #} -{% set ESCONFIG = salt['pillar.get']('elasticsearch:config', default=ESCONFIG.elasticsearch.config, merge=True) %} +{% set ELASTICSEARCHMERGED = salt['pillar.get']('elasticsearch', default=ELASTICSEARCHDEFAULTS.elasticsearch, merge=True) %} {% if salt['pillar.get']('elasticsearch:config:path:repo', False) %} {% for repo in pillar.elasticsearch.config.path.repo %} {# remove elasticsearch.config.path.repo value if the directory doesn't exist on the node #} {% if not salt['file.directory_exists'](repo) %} - {% do ESCONFIG.path.repo.remove(repo) %} + {% do ELASTICSEARCHMERGED.config.path.repo.remove(repo) %} {% endif %} {% endfor %} {% endif %} diff --git a/salt/elasticsearch/config.sls b/salt/elasticsearch/config.sls new file mode 100644 index 000000000..23e11a710 --- /dev/null +++ b/salt/elasticsearch/config.sls @@ -0,0 +1,219 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - ssl + - elasticsearch.ca + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} + +vm.max_map_count: + sysctl.present: + - value: 262144 + +# Add ES Group +elasticsearchgroup: + group.present: + - name: elasticsearch + - gid: 930 + +esconfdir: + file.directory: + - name: /opt/so/conf/elasticsearch + - user: 930 + - group: 939 + - makedirs: True + +# Add ES user +elasticsearch: + user.present: + - uid: 930 + - gid: 930 + - home: /opt/so/conf/elasticsearch + - createhome: False + +elasticsearch_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://elasticsearch/tools/sbin + - user: 930 + - group: 939 + - file_mode: 755 + - exclude_pat: + - so-elasticsearch-pipelines # exclude this because we need to watch it for changes, we sync it in another state + +elasticsearch_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://elasticsearch/tools/sbin_jinja + - user: 939 + - group: 939 + - file_mode: 755 + - template: jinja + - exclude_pat: + - so-elasticsearch-ilm-policy-load # exclude this because we need to watch it for changes, we sync it in another state + - defaults: + GLOBALS: {{ GLOBALS }} + +so-elasticsearch-ilm-policy-load-script: + file.managed: + - name: /usr/sbin/so-elasticsearch-ilm-policy-load + - source: salt://elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load + - user: 930 + - group: 939 + - mode: 754 + - template: jinja + +so-elasticsearch-pipelines-script: + file.managed: + - name: /usr/sbin/so-elasticsearch-pipelines + - source: salt://elasticsearch/tools/sbin/so-elasticsearch-pipelines + - user: 930 + - group: 939 + - mode: 754 + +esingestdir: + file.directory: + - name: /opt/so/conf/elasticsearch/ingest + - user: 930 + - group: 939 + - makedirs: True + +estemplatedir: + file.directory: + - name: /opt/so/conf/elasticsearch/templates/index + - user: 930 + - group: 939 + - makedirs: True + +esrolesdir: + file.directory: + - name: /opt/so/conf/elasticsearch/roles + - user: 930 + - group: 939 + - makedirs: True + +eslibdir: + file.absent: + - name: /opt/so/conf/elasticsearch/lib + +esingestdynamicconf: + file.recurse: + - name: /opt/so/conf/elasticsearch/ingest + - source: salt://elasticsearch/files/ingest-dynamic + - user: 930 + - group: 939 + - template: jinja + +esingestconf: + file.recurse: + - name: /opt/so/conf/elasticsearch/ingest + - source: salt://elasticsearch/files/ingest + - user: 930 + - group: 939 + +eslog4jfile: + file.managed: + - name: /opt/so/conf/elasticsearch/log4j2.properties + - source: salt://elasticsearch/files/log4j2.properties + - user: 930 + - group: 939 + - template: jinja + +esyml: + file.managed: + - name: /opt/so/conf/elasticsearch/elasticsearch.yml + - source: salt://elasticsearch/files/elasticsearch.yaml.jinja + - user: 930 + - group: 939 + - defaults: + ESCONFIG: {{ ELASTICSEARCHMERGED.config }} + - template: jinja + +esroles: + file.recurse: + - source: salt://elasticsearch/roles/ + - name: /opt/so/conf/elasticsearch/roles/ + - clean: True + - template: jinja + - user: 930 + - group: 939 + +nsmesdir: + file.directory: + - name: /nsm/elasticsearch + - user: 930 + - group: 939 + - makedirs: True + +eslogdir: + file.directory: + - name: /opt/so/log/elasticsearch + - user: 930 + - group: 939 + - makedirs: True + +es_repo_dir: + file.directory: + - name: /nsm/elasticsearch/repo/ + - user: 930 + - group: 930 + - require: + - file: nsmesdir + +so-pipelines-reload: + file.absent: + - name: /opt/so/state/espipelines.txt + - onchanges: + - file: esingestconf + - file: esingestdynamicconf + - file: esyml + - file: so-elasticsearch-pipelines-script + +auth_users: + file.managed: + - name: /opt/so/conf/elasticsearch/users.tmp + - source: salt://elasticsearch/files/users + - user: 930 + - group: 930 + - mode: 600 + - show_changes: False + +auth_users_roles: + file.managed: + - name: /opt/so/conf/elasticsearch/users_roles.tmp + - source: salt://elasticsearch/files/users_roles + - user: 930 + - group: 930 + - mode: 600 + - show_changes: False + +auth_users_inode: + require: + - file: auth_users + cmd.run: + - name: cat /opt/so/conf/elasticsearch/users.tmp > /opt/so/conf/elasticsearch/users && chown 930:939 /opt/so/conf/elasticsearch/users && chmod 660 /opt/so/conf/elasticsearch/users + - onchanges: + - file: /opt/so/conf/elasticsearch/users.tmp + +auth_users_roles_inode: + require: + - file: auth_users_roles + cmd.run: + - name: cat /opt/so/conf/elasticsearch/users_roles.tmp > /opt/so/conf/elasticsearch/users_roles && chown 930:939 /opt/so/conf/elasticsearch/users_roles && chmod 660 /opt/so/conf/elasticsearch/users_roles + - onchanges: + - file: /opt/so/conf/elasticsearch/users_roles.tmp + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 37f55ddc7..10cc347d1 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -1,4 +1,5 @@ elasticsearch: + enabled: False retention: retention_pct: 50 config: diff --git a/salt/elasticsearch/disabled.sls b/salt/elasticsearch/disabled.sls new file mode 100644 index 000000000..210ad59a4 --- /dev/null +++ b/salt/elasticsearch/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - elasticsearch.sostatus + +so-elasticsearch: + docker_container.absent: + - force: True + +so-elasticsearch_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elasticsearch$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/enabled.sls b/salt/elasticsearch/enabled.sls new file mode 100644 index 000000000..fa51a4124 --- /dev/null +++ b/salt/elasticsearch/enabled.sls @@ -0,0 +1,183 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'logstash/map.jinja' import LOGSTASH_NODES %} +{% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} +{% set TEMPLATES = salt['pillar.get']('elasticsearch:templates', {}) %} +{% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS %} + +include: + - elasticsearch.config + - elasticsearch.sostatus + +so-elasticsearch: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:{{ GLOBALS.so_version }} + - hostname: elasticsearch + - name: so-elasticsearch + - user: elasticsearch + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-elasticsearch'].ip }} + - extra_hosts: {{ LOGSTASH_NODES }} + - environment: + {% if LOGSTASH_NODES | length == 1 %} + - discovery.type=single-node + {% endif %} + - ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true + ulimits: + - memlock=-1:-1 + - nofile=65536:65536 + - nproc=4096 + - port_bindings: + {% for BINDING in DOCKER.containers['so-elasticsearch'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - binds: + - /opt/so/conf/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro + - /opt/so/conf/elasticsearch/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties:ro + - /nsm/elasticsearch:/usr/share/elasticsearch/data:rw + - /opt/so/log/elasticsearch:/var/log/elasticsearch:rw + - /opt/so/conf/ca/cacerts:/usr/share/elasticsearch/jdk/lib/security/cacerts:ro + {% if GLOBALS.is_manager %} + - /etc/pki/ca.crt:/usr/share/elasticsearch/config/ca.crt:ro + {% else %} + - /etc/ssl/certs/intca.crt:/usr/share/elasticsearch/config/ca.crt:ro + {% endif %} + - /etc/pki/elasticsearch.crt:/usr/share/elasticsearch/config/elasticsearch.crt:ro + - /etc/pki/elasticsearch.key:/usr/share/elasticsearch/config/elasticsearch.key:ro + - /etc/pki/elasticsearch.p12:/usr/share/elasticsearch/config/elasticsearch.p12:ro + - /opt/so/conf/elasticsearch/users_roles:/usr/share/elasticsearch/config/users_roles:ro + - /opt/so/conf/elasticsearch/users:/usr/share/elasticsearch/config/users:ro + {% if ELASTICSEARCHMERGED.config.path.get('repo', False) %} + {% for repo in ELASTICSEARCHMERGED.config.path.repo %} + - {{ repo }}:{{ repo }}:rw + {% endfor %} + {% endif %} + - watch: + - file: cacertz + - file: esyml + - require: + - file: esyml + - file: eslog4jfile + - file: nsmesdir + - file: eslogdir + - file: cacertz + - x509: /etc/pki/elasticsearch.crt + - x509: /etc/pki/elasticsearch.key + - file: elasticp12perms + {% if GLOBALS.is_manager %} + - x509: pki_public_ca_crt + {% else %} + - x509: trusttheca + {% endif %} + - cmd: auth_users_roles_inode + - cmd: auth_users_inode + +delete_so-elasticsearch_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-elasticsearch$ + +{% if GLOBALS.role != "so-searchnode" %} +escomponenttemplates: + file.recurse: + - name: /opt/so/conf/elasticsearch/templates/component + - source: salt://elasticsearch/templates/component + - user: 930 + - group: 939 + - onchanges_in: + - cmd: so-elasticsearch-templates + +# Auto-generate templates from defaults file +{% for index, settings in ES_INDEX_SETTINGS.items() %} + {% if settings.index_template is defined %} +es_index_template_{{index}}: + file.managed: + - name: /opt/so/conf/elasticsearch/templates/index/{{ index }}-template.json + - source: salt://elasticsearch/base-template.json.jinja + - defaults: + TEMPLATE_CONFIG: {{ settings.index_template }} + - template: jinja + - onchanges_in: + - cmd: so-elasticsearch-templates +{% endif %} +{% endfor %} + +{% if TEMPLATES %} +# Sync custom templates to /opt/so/conf/elasticsearch/templates +{% for TEMPLATE in TEMPLATES %} +es_template_{{TEMPLATE.split('.')[0] | replace("/","_") }}: + file.managed: + - source: salt://elasticsearch/templates/index/{{TEMPLATE}} +{% if 'jinja' in TEMPLATE.split('.')[-1] %} + - name: /opt/so/conf/elasticsearch/templates/index/{{TEMPLATE.split('/')[1] | replace(".jinja", "")}} + - template: jinja +{% else %} + - name: /opt/so/conf/elasticsearch/templates/index/{{TEMPLATE.split('/')[1]}} +{% endif %} + - user: 930 + - group: 939 + - onchanges_in: + - cmd: so-elasticsearch-templates +{% endfor %} +{% endif %} + +so-es-cluster-settings: + cmd.run: + - name: /usr/sbin/so-elasticsearch-cluster-settings + - cwd: /opt/so + - template: jinja + - require: + - docker_container: so-elasticsearch + - file: elasticsearch_sbin_jinja + +so-elasticsearch-ilm-policy-load: + cmd.run: + - name: /usr/sbin/so-elasticsearch-ilm-policy-load + - cwd: /opt/so + - require: + - docker_container: so-elasticsearch + - file: so-elasticsearch-ilm-policy-load-script + - onchanges: + - file: so-elasticsearch-ilm-policy-load-script + +so-elasticsearch-templates: + cmd.run: + - name: /usr/sbin/so-elasticsearch-templates-load + - cwd: /opt/so + - template: jinja + - require: + - docker_container: so-elasticsearch + - file: elasticsearch_sbin_jinja + +so-elasticsearch-pipelines: + cmd.run: + - name: /usr/sbin/so-elasticsearch-pipelines {{ GLOBALS.hostname }} + - require: + - docker_container: so-elasticsearch + - file: so-elasticsearch-pipelines-script + +so-elasticsearch-roles-load: + cmd.run: + - name: /usr/sbin/so-elasticsearch-roles-load + - cwd: /opt/so + - template: jinja + - require: + - docker_container: so-elasticsearch + - file: elasticsearch_sbin_jinja +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/init.sls b/salt/elasticsearch/init.sls index 5e2ffae9d..301c836c2 100644 --- a/salt/elasticsearch/init.sls +++ b/salt/elasticsearch/init.sls @@ -3,425 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +{% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} include: - - ssl - -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% set TEMPLATES = salt['pillar.get']('elasticsearch:templates', {}) %} -{% set ROLES = salt['pillar.get']('elasticsearch:roles', {}) %} -{% from 'elasticsearch/config.map.jinja' import ESCONFIG with context %} -{% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS without context %} -{% from 'logstash/map.jinja' import LOGSTASH_NODES %} - -vm.max_map_count: - sysctl.present: - - value: 262144 - -# Add ES Group -elasticsearchgroup: - group.present: - - name: elasticsearch - - gid: 930 - -esconfdir: - file.directory: - - name: /opt/so/conf/elasticsearch - - user: 930 - - group: 939 - - makedirs: True - -# Add ES user -elasticsearch: - user.present: - - uid: 930 - - gid: 930 - - home: /opt/so/conf/elasticsearch - - createhome: False - -{% if GLOBALS.is_manager %} -# We have to add the Manager CA to the CA list -cascriptsync: - file.managed: - - name: /usr/sbin/so-catrust - - source: salt://elasticsearch/tools/sbin_jinja/so-catrust - - user: 939 - - group: 939 - - mode: 750 - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - -# Run the CA magic -cascriptfun: - cmd.run: - - name: /usr/sbin/so-catrust - - require: - - file: cascriptsync -{% endif %} - -elasticsearch_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://elasticsearch/tools/sbin - - user: 930 - - group: 939 - - file_mode: 755 - - exclude_pat: - - so-catrust - - so-elasticsearch-pipelines # exclude this because we need to watch it for changes, we sync it in another state - -elasticsearch_sbin_jinja: - file.recurse: - - name: /usr/sbin - - source: salt://elasticsearch/tools/sbin_jinja - - user: 939 - - group: 939 - - file_mode: 755 - - template: jinja - - exclude_pat: - - so-elasticsearch-ilm-policy-load # exclude this because we need to watch it for changes, we sync it in another state - - defaults: - GLOBALS: {{ GLOBALS }} - -so-elasticsearch-ilm-policy-load-script: - file.managed: - - name: /usr/sbin/so-elasticsearch-ilm-policy-load - - source: salt://elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load - - user: 930 - - group: 939 - - mode: 754 - - template: jinja - -so-elasticsearch-pipelines-script: - file.managed: - - name: /usr/sbin/so-elasticsearch-pipelines - - source: salt://elasticsearch/tools/sbin/so-elasticsearch-pipelines - - user: 930 - - group: 939 - - mode: 754 - -# Move our new CA over so Elastic and Logstash can use SSL with the internal CA -catrustdir: - file.directory: - - name: /opt/so/conf/ca - - user: 939 - - group: 939 - - makedirs: True - -cacertz: - file.managed: - - name: /opt/so/conf/ca/cacerts - - source: salt://common/cacerts - - user: 939 - - group: 939 - -capemz: - file.managed: - - name: /opt/so/conf/ca/tls-ca-bundle.pem - - source: salt://common/tls-ca-bundle.pem - - user: 939 - - group: 939 - -esingestdir: - file.directory: - - name: /opt/so/conf/elasticsearch/ingest - - user: 930 - - group: 939 - - makedirs: True - -estemplatedir: - file.directory: - - name: /opt/so/conf/elasticsearch/templates/index - - user: 930 - - group: 939 - - makedirs: True - -esrolesdir: - file.directory: - - name: /opt/so/conf/elasticsearch/roles - - user: 930 - - group: 939 - - makedirs: True - -eslibdir: - file.absent: - - name: /opt/so/conf/elasticsearch/lib - -esingestdynamicconf: - file.recurse: - - name: /opt/so/conf/elasticsearch/ingest - - source: salt://elasticsearch/files/ingest-dynamic - - user: 930 - - group: 939 - - template: jinja - -esingestconf: - file.recurse: - - name: /opt/so/conf/elasticsearch/ingest - - source: salt://elasticsearch/files/ingest - - user: 930 - - group: 939 - -eslog4jfile: - file.managed: - - name: /opt/so/conf/elasticsearch/log4j2.properties - - source: salt://elasticsearch/files/log4j2.properties - - user: 930 - - group: 939 - - template: jinja - -esyml: - file.managed: - - name: /opt/so/conf/elasticsearch/elasticsearch.yml - - source: salt://elasticsearch/files/elasticsearch.yaml.jinja - - user: 930 - - group: 939 - - defaults: - ESCONFIG: {{ ESCONFIG }} - - template: jinja - -{% if GLOBALS.role != "so-searchnode" %} -escomponenttemplates: - file.recurse: - - name: /opt/so/conf/elasticsearch/templates/component - - source: salt://elasticsearch/templates/component - - user: 930 - - group: 939 - - onchanges_in: - - cmd: so-elasticsearch-templates - -# Auto-generate templates from defaults file -{% for index, settings in ES_INDEX_SETTINGS.items() %} - {% if settings.index_template is defined %} -es_index_template_{{index}}: - file.managed: - - name: /opt/so/conf/elasticsearch/templates/index/{{ index }}-template.json - - source: salt://elasticsearch/base-template.json.jinja - - defaults: - TEMPLATE_CONFIG: {{ settings.index_template }} - - template: jinja - - onchanges_in: - - cmd: so-elasticsearch-templates - {% endif %} -{% endfor %} - -{% if TEMPLATES %} -# Sync custom templates to /opt/so/conf/elasticsearch/templates -{% for TEMPLATE in TEMPLATES %} -es_template_{{TEMPLATE.split('.')[0] | replace("/","_") }}: - file.managed: - - source: salt://elasticsearch/templates/index/{{TEMPLATE}} - {% if 'jinja' in TEMPLATE.split('.')[-1] %} - - name: /opt/so/conf/elasticsearch/templates/index/{{TEMPLATE.split('/')[1] | replace(".jinja", "")}} - - template: jinja - {% else %} - - name: /opt/so/conf/elasticsearch/templates/index/{{TEMPLATE.split('/')[1]}} - {% endif %} - - user: 930 - - group: 939 - - onchanges_in: - - cmd: so-elasticsearch-templates -{% endfor %} -{% endif %} -{% endif %} - -esroles: - file.recurse: - - source: salt://elasticsearch/roles/ - - name: /opt/so/conf/elasticsearch/roles/ - - clean: True - - template: jinja - - user: 930 - - group: 939 - -nsmesdir: - file.directory: - - name: /nsm/elasticsearch - - user: 930 - - group: 939 - - makedirs: True - -eslogdir: - file.directory: - - name: /opt/so/log/elasticsearch - - user: 930 - - group: 939 - - makedirs: True - -es_repo_dir: - file.directory: - - name: /nsm/elasticsearch/repo/ - - user: 930 - - group: 930 - - require: - - file: nsmesdir - -so-pipelines-reload: - file.absent: - - name: /opt/so/state/espipelines.txt - - onchanges: - - file: esingestconf - - file: esingestdynamicconf - - file: esyml - - file: so-elasticsearch-pipelines-script - -auth_users: - file.managed: - - name: /opt/so/conf/elasticsearch/users.tmp - - source: salt://elasticsearch/files/users - - user: 930 - - group: 930 - - mode: 600 - - show_changes: False - -auth_users_roles: - file.managed: - - name: /opt/so/conf/elasticsearch/users_roles.tmp - - source: salt://elasticsearch/files/users_roles - - user: 930 - - group: 930 - - mode: 600 - - show_changes: False - -auth_users_inode: - require: - - file: auth_users - cmd.run: - - name: cat /opt/so/conf/elasticsearch/users.tmp > /opt/so/conf/elasticsearch/users && chown 930:939 /opt/so/conf/elasticsearch/users && chmod 660 /opt/so/conf/elasticsearch/users - - onchanges: - - file: /opt/so/conf/elasticsearch/users.tmp - -auth_users_roles_inode: - require: - - file: auth_users_roles - cmd.run: - - name: cat /opt/so/conf/elasticsearch/users_roles.tmp > /opt/so/conf/elasticsearch/users_roles && chown 930:939 /opt/so/conf/elasticsearch/users_roles && chmod 660 /opt/so/conf/elasticsearch/users_roles - - onchanges: - - file: /opt/so/conf/elasticsearch/users_roles.tmp - -so-elasticsearch: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:{{ GLOBALS.so_version }} - - hostname: elasticsearch - - name: so-elasticsearch - - user: elasticsearch - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-elasticsearch'].ip }} - - extra_hosts: {{ LOGSTASH_NODES }} - - environment: - {% if LOGSTASH_NODES | length == 1 %} - - discovery.type=single-node - {% endif %} - - ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true - ulimits: - - memlock=-1:-1 - - nofile=65536:65536 - - nproc=4096 - - port_bindings: - {% for BINDING in DOCKER.containers['so-elasticsearch'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - binds: - - /opt/so/conf/elasticsearch/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml:ro - - /opt/so/conf/elasticsearch/log4j2.properties:/usr/share/elasticsearch/config/log4j2.properties:ro - - /nsm/elasticsearch:/usr/share/elasticsearch/data:rw - - /opt/so/log/elasticsearch:/var/log/elasticsearch:rw - - /opt/so/conf/ca/cacerts:/usr/share/elasticsearch/jdk/lib/security/cacerts:ro - {% if GLOBALS.is_manager %} - - /etc/pki/ca.crt:/usr/share/elasticsearch/config/ca.crt:ro - {% else %} - - /etc/ssl/certs/intca.crt:/usr/share/elasticsearch/config/ca.crt:ro - {% endif %} - - /etc/pki/elasticsearch.crt:/usr/share/elasticsearch/config/elasticsearch.crt:ro - - /etc/pki/elasticsearch.key:/usr/share/elasticsearch/config/elasticsearch.key:ro - - /etc/pki/elasticsearch.p12:/usr/share/elasticsearch/config/elasticsearch.p12:ro - - /opt/so/conf/elasticsearch/users_roles:/usr/share/elasticsearch/config/users_roles:ro - - /opt/so/conf/elasticsearch/users:/usr/share/elasticsearch/config/users:ro - {% if ESCONFIG.path.get('repo', False) %} - {% for repo in ESCONFIG.path.repo %} - - {{ repo }}:{{ repo }}:rw - {% endfor %} - {% endif %} - - watch: - - file: cacertz - - file: esyml - - require: - - file: esyml - - file: eslog4jfile - - file: nsmesdir - - file: eslogdir - - file: cacertz - - x509: /etc/pki/elasticsearch.crt - - x509: /etc/pki/elasticsearch.key - - file: elasticp12perms - {% if GLOBALS.is_manager %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - - cmd: auth_users_roles_inode - - cmd: auth_users_inode - -append_so-elasticsearch_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-elasticsearch - -{% if GLOBALS.role != "so-searchnode" %} - -so-es-cluster-settings: - cmd.run: - - name: /usr/sbin/so-elasticsearch-cluster-settings - - cwd: /opt/so - - template: jinja - - require: - - docker_container: so-elasticsearch - - file: elasticsearch_sbin_jinja - -so-elasticsearch-ilm-policy-load: - cmd.run: - - name: /usr/sbin/so-elasticsearch-ilm-policy-load - - cwd: /opt/so - - require: - - docker_container: so-elasticsearch - - file: so-elasticsearch-ilm-policy-load-script - - onchanges: - - file: so-elasticsearch-ilm-policy-load-script - -so-elasticsearch-templates: - cmd.run: - - name: /usr/sbin/so-elasticsearch-templates-load - - cwd: /opt/so - - template: jinja - - require: - - docker_container: so-elasticsearch - - file: elasticsearch_sbin_jinja - -so-elasticsearch-pipelines: - cmd.run: - - name: /usr/sbin/so-elasticsearch-pipelines {{ GLOBALS.hostname }} - - require: - - docker_container: so-elasticsearch - - file: so-elasticsearch-pipelines-script - -so-elasticsearch-roles-load: - cmd.run: - - name: /usr/sbin/so-elasticsearch-roles-load - - cwd: /opt/so - - template: jinja - - require: - - docker_container: so-elasticsearch - - file: elasticsearch_sbin_jinja -{% endif %} +{% if ELASTICSEARCHMERGED.enabled %} + - elasticsearch.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif %} {# if 'elasticsearch' in top_states #} + - elasticsearch.disabled +{% endif %} diff --git a/salt/elasticsearch/soc_elasticsearch.yaml b/salt/elasticsearch/soc_elasticsearch.yaml index ded8e5be6..da22268f6 100644 --- a/salt/elasticsearch/soc_elasticsearch.yaml +++ b/salt/elasticsearch/soc_elasticsearch.yaml @@ -1,4 +1,7 @@ elasticsearch: + enabled: + description: You can enable or disable Elasticsearch. + helpLink: elasticsearch.html esheap: description: Specify the memory heap size in (m)egabytes for Elasticsearch. helpLink: elasticsearch.html diff --git a/salt/elasticsearch/sostatus.sls b/salt/elasticsearch/sostatus.sls new file mode 100644 index 000000000..2967a39db --- /dev/null +++ b/salt/elasticsearch/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-elasticsearch_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-elasticsearch + - unless: grep -q so-elasticsearch /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/elasticsearch/template.map.jinja b/salt/elasticsearch/template.map.jinja index 9c90cc28f..49d86d187 100644 --- a/salt/elasticsearch/template.map.jinja +++ b/salt/elasticsearch/template.map.jinja @@ -1,5 +1,5 @@ -{% import_yaml 'elasticsearch/defaults.yaml' as ESCONFIG with context %} -{%- set ES_INDEX_SETTINGS = salt['pillar.get']('elasticsearch:index_settings', default=ESCONFIG.elasticsearch.index_settings, merge=True) %} +{% import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS with context %} +{%- set ES_INDEX_SETTINGS = salt['pillar.get']('elasticsearch:index_settings', default=ELASTICSEARCHDEFAULTS.elasticsearch.index_settings, merge=True) %} {% for index, settings in ES_INDEX_SETTINGS.items() %} {% if settings.index_template is defined %} {% if not settings.get('index_sorting', False) | to_bool and settings.index_template.template.settings.index.sort is defined %} diff --git a/salt/elasticsearch/tools/sbin_jinja/so-catrust b/salt/elasticsearch/tools/sbin_jinja/so-catrust index aec97deeb..fe4ff58bc 100644 --- a/salt/elasticsearch/tools/sbin_jinja/so-catrust +++ b/salt/elasticsearch/tools/sbin_jinja/so-catrust @@ -11,14 +11,14 @@ set -e # Check to see if we have extracted the ca cert. -if [ ! -f /opt/so/saltstack/local/salt/common/cacerts ]; then +if [ ! -f /opt/so/saltstack/local/salt/elasticsearch/cacerts ]; then docker run -v /etc/pki/ca.crt:/etc/ssl/ca.crt --name so-elasticsearchca --user root --entrypoint jdk/bin/keytool {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-elasticsearch:{{ GLOBALS.so_version }} -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -alias SOSCA -import -file /etc/ssl/ca.crt -storepass changeit -noprompt - docker cp so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/common/cacerts - docker cp so-elasticsearchca:/etc/ssl/certs/ca-certificates.crt /opt/so/saltstack/local/salt/common/tls-ca-bundle.pem + docker cp so-elasticsearchca:/usr/share/elasticsearch/jdk/lib/security/cacerts /opt/so/saltstack/local/salt/elasticsearch/cacerts + docker cp so-elasticsearchca:/etc/ssl/certs/ca-certificates.crt /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem docker rm so-elasticsearchca - echo "" >> /opt/so/saltstack/local/salt/common/tls-ca-bundle.pem - echo "sosca" >> /opt/so/saltstack/local/salt/common/tls-ca-bundle.pem - cat /etc/pki/ca.crt >> /opt/so/saltstack/local/salt/common/tls-ca-bundle.pem + echo "" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem + echo "sosca" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem + cat /etc/pki/ca.crt >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem else exit 0 fi diff --git a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load index afeddfa01..afb8bdc67 100755 --- a/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load +++ b/salt/elasticsearch/tools/sbin_jinja/so-elasticsearch-ilm-policy-load @@ -6,15 +6,15 @@ . /usr/sbin/so-common -{% import_yaml 'elasticsearch/defaults.yaml' as ESCONFIG with context %} -{%- set ES_INDEX_SETTINGS = salt['pillar.get']('elasticsearch:index_settings', default=ESCONFIG.elasticsearch.index_settings, merge=True) %} +{%- import_yaml 'elasticsearch/defaults.yaml' as ELASTICSEARCHDEFAULTS %} +{%- set ES_INDEX_SETTINGS = salt['pillar.get']('elasticsearch:index_settings', default=ELASTICSEARCHDEFAULTS.elasticsearch.index_settings, merge=True) %} {%- for index, settings in ES_INDEX_SETTINGS.items() %} - {%- if settings.policy is defined %} +{%- if settings.policy is defined %} echo echo "Setting up {{ index }}-logs policy..." curl -K /opt/so/conf/elasticsearch/curl.config -b "sid=$SESSIONCOOKIE" -s -k -L -X PUT "https://localhost:9200/_ilm/policy/{{ index }}-logs" -H 'Content-Type: application/json' -d'{ "policy": {{ settings.policy | tojson(true) }} }' echo - {%- endif %} +{%- endif %} {%- endfor %} echo diff --git a/salt/idh/config.sls b/salt/idh/config.sls new file mode 100644 index 000000000..dcde9c8e5 --- /dev/null +++ b/salt/idh/config.sls @@ -0,0 +1,85 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'idh/opencanary_config.map.jinja' import RESTRICTIDHSERVICES %} +{% from 'idh/opencanary_config.map.jinja' import OPENCANARYCONFIG %} + +include: + - idh.openssh.config + - firewall + +# If True, block IDH Services from accepting connections on Managment IP +{% if RESTRICTIDHSERVICES %} + {% from 'idh/opencanary_config.map.jinja' import IDH_SERVICES %} + + {% for service in IDH_SERVICES %} + {% if service in ["smnp","ntp", "tftp"] %} + {% set proto = 'udp' %} + {% else %} + {% set proto = 'tcp' %} + {% endif %} +block_mgt_ip_idh_services_{{ proto }}_{{ OPENCANARYCONFIG[service~'_x_port'] }} : + iptables.insert: + - table: filter + - chain: INPUT + - jump: DROP + - position: 1 + - proto: {{ proto }} + - dport: {{ OPENCANARYCONFIG[service~'_x_port'] }} + - destination: {{ GLOBALS.node_ip }} + {% endfor %} +{% endif %} + +# Create a config directory +idhconfdir: + file.directory: + - name: /opt/so/conf/idh + - user: 939 + - group: 939 + - makedirs: True + +# Create a log directory +idhlogdir: + file.directory: + - name: /nsm/idh + - user: 939 + - group: 939 + - makedirs: True + +opencanary_config: + file.managed: + - name: /opt/so/conf/idh/opencanary.conf + - source: salt://idh/idh.conf.jinja + - template: jinja + - defaults: + OPENCANARYCONFIG: {{ OPENCANARYCONFIG }} + +idh_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://idh/tools/sbin + - user: 934 + - group: 939 + - file_mode: 755 + +#idh_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://idh/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idh/defaults.yaml b/salt/idh/defaults.yaml index b0c4d6904..a97931801 100644 --- a/salt/idh/defaults.yaml +++ b/salt/idh/defaults.yaml @@ -1,5 +1,6 @@ idh: - restrict_management_ip: false + enabled: False + restrict_management_ip: False openssh: enable: true config: diff --git a/salt/idh/disabled.sls b/salt/idh/disabled.sls new file mode 100644 index 000000000..253dcc3a1 --- /dev/null +++ b/salt/idh/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - idh.sostatus + +so-idh: + docker_container.absent: + - force: True + +so-idh_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-idh$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idh/enabled.sls b/salt/idh/enabled.sls new file mode 100644 index 000000000..82bee138b --- /dev/null +++ b/salt/idh/enabled.sls @@ -0,0 +1,39 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - idh.config + - idh.sostatus + +so-idh: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-idh:{{ GLOBALS.so_version }} + - name: so-idh + - detach: True + - network_mode: host + - binds: + - /nsm/idh:/var/tmp:rw + - /opt/so/conf/idh/opencanary.conf:/etc/opencanaryd/opencanary.conf:ro + - watch: + - file: opencanary_config + - require: + - file: opencanary_config + +delete_so-idh_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-idh$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idh/init.sls b/salt/idh/init.sls index 895cd61ac..8f2cea37b 100644 --- a/salt/idh/init.sls +++ b/salt/idh/init.sls @@ -3,103 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% import_yaml 'docker/defaults.yaml' as DOCKERDEFAULTS %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'idh/opencanary_config.map.jinja' import RESTRICTIDHSERVICES %} -{% from 'idh/opencanary_config.map.jinja' import OPENCANARYCONFIG %} +{% from 'idh/opencanary_config.map.jinja' import IDHMERGED %} include: - - idh.openssh.config - - firewall - -# If True, block IDH Services from accepting connections on Managment IP -{% if RESTRICTIDHSERVICES %} - {% from 'idh/opencanary_config.map.jinja' import IDH_SERVICES %} - - {% for service in IDH_SERVICES %} - {% if service in ["smnp","ntp", "tftp"] %} - {% set proto = 'udp' %} - {% else %} - {% set proto = 'tcp' %} - {% endif %} -block_mgt_ip_idh_services_{{ proto }}_{{ OPENCANARYCONFIG[service~'_x_port'] }} : - iptables.insert: - - table: filter - - chain: INPUT - - jump: DROP - - position: 1 - - proto: {{ proto }} - - dport: {{ OPENCANARYCONFIG[service~'_x_port'] }} - - destination: {{ GLOBALS.node_ip }} - {% endfor %} -{% endif %} - -# Create a config directory -temp: - file.directory: - - name: /opt/so/conf/idh - - user: 939 - - group: 939 - - makedirs: True - -# Create a log directory -configdir: - file.directory: - - name: /nsm/idh - - user: 939 - - group: 939 - - makedirs: True - -opencanary_config: - file.managed: - - name: /opt/so/conf/idh/opencanary.conf - - source: salt://idh/idh.conf.jinja - - template: jinja - - defaults: - OPENCANARYCONFIG: {{ OPENCANARYCONFIG }} - -idh_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://idh/tools/sbin - - user: 934 - - group: 939 - - file_mode: 755 - -#idh_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://idh/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -so-idh: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-idh:{{ GLOBALS.so_version }} - - name: so-idh - - detach: True - - network_mode: host - - binds: - - /nsm/idh:/var/tmp:rw - - /opt/so/conf/idh/opencanary.conf:/etc/opencanaryd/opencanary.conf:ro - - watch: - - file: opencanary_config - - require: - - file: opencanary_config - -append_so-idh_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-idh - +{% if IDHMERGED.enabled %} + - idh.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - idh.disabled {% endif %} diff --git a/salt/idh/opencanary_config.map.jinja b/salt/idh/opencanary_config.map.jinja index a8b85adbf..420cc7f79 100644 --- a/salt/idh/opencanary_config.map.jinja +++ b/salt/idh/opencanary_config.map.jinja @@ -20,6 +20,7 @@ {% set IDH_PORTGROUPS = {} %} {% import_yaml "idh/defaults.yaml" as IDHCONFIG with context %} +{% set IDHMERGED = salt['pillar.get']('idh', IDHCONFIG.idh, merge=True) %} {% set RESTRICTIDHSERVICES = salt['pillar.get']('idh:restrict_management_ip', default=IDHCONFIG.idh.restrict_management_ip) %} {% set OPENCANARYCONFIG = salt['pillar.get']('idh:opencanary:config', default=IDHCONFIG.idh.opencanary.config, merge=True) %} {# update skinlist to skin.list to avoid issues with SOC UI config #} diff --git a/salt/idh/soc_idh.yaml b/salt/idh/soc_idh.yaml index 60d0203f5..f792812e4 100644 --- a/salt/idh/soc_idh.yaml +++ b/salt/idh/soc_idh.yaml @@ -1,4 +1,7 @@ idh: + enabled: + description: You can enable or disable IDH. + helpLink: idh.html opencanary: config: logger: diff --git a/salt/idh/sostatus.sls b/salt/idh/sostatus.sls new file mode 100644 index 000000000..e5b9da705 --- /dev/null +++ b/salt/idh/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-idh_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-idh + - unless: grep -q so-idh /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idstools/config.sls b/salt/idstools/config.sls new file mode 100644 index 000000000..94692ee9f --- /dev/null +++ b/salt/idstools/config.sls @@ -0,0 +1,42 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - idstools.sync_files + +idstoolslogdir: + file.directory: + - name: /opt/so/log/idstools + - user: 939 + - group: 939 + - makedirs: True + +idstools_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://idstools/tools/sbin + - user: 934 + - group: 939 + - file_mode: 755 + +#idstools_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://idstools/tools/sbin_jinja +# - user: 934 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idstools/defaults.yaml b/salt/idstools/defaults.yaml index e937ebc2d..1be100cec 100644 --- a/salt/idstools/defaults.yaml +++ b/salt/idstools/defaults.yaml @@ -1,4 +1,5 @@ idstools: + enabled: False config: urls: [] ruleset: ETOPEN @@ -6,4 +7,4 @@ idstools: sids: enabled: [] disabled: [] - modify: [] \ No newline at end of file + modify: [] diff --git a/salt/idstools/disabled.sls b/salt/idstools/disabled.sls new file mode 100644 index 000000000..ab0e10d7a --- /dev/null +++ b/salt/idstools/disabled.sls @@ -0,0 +1,31 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - idstools.sostatus + +so-idstools: + docker_container.absent: + - force: True + +so-idstools_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-idstools$ + +so-rule-update: + cron.absent: + - identifier: so-rule-update + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idstools/enabled.sls b/salt/idstools/enabled.sls new file mode 100644 index 000000000..b56d6c2e5 --- /dev/null +++ b/salt/idstools/enabled.sls @@ -0,0 +1,55 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% set proxy = salt['pillar.get']('manager:proxy') %} + +include: + - idstools.config + - idstools.sostatus + +so-idstools: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-idstools:{{ GLOBALS.so_version }} + - hostname: so-idstools + - user: socore + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-idstools'].ip }} + {% if proxy %} + - environment: + - http_proxy={{ proxy }} + - https_proxy={{ proxy }} + - no_proxy={{ salt['pillar.get']('manager:no_proxy') }} + {% endif %} + - binds: + - /opt/so/conf/idstools/etc:/opt/so/idstools/etc:ro + - /opt/so/rules/nids:/opt/so/rules/nids:rw + - watch: + - file: idstoolsetcsync + +delete_so-idstools_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-idstools$ + +so-rule-update: + cron.present: + - name: /usr/sbin/so-rule-update > /opt/so/log/idstools/download.log 2>&1 + - identifier: so-rule-update + - user: root + - minute: '1' + - hour: '7' + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/idstools/etc/rulecat.conf b/salt/idstools/etc/rulecat.conf index 4ba668026..537c3f9e8 100644 --- a/salt/idstools/etc/rulecat.conf +++ b/salt/idstools/etc/rulecat.conf @@ -1,6 +1,5 @@ {%- from 'vars/globals.map.jinja' import GLOBALS %} -{%- import_yaml 'idstools/defaults.yaml' as IDSTOOLSDEFAULTS %} -{%- set IDSTOOLSMERGED = salt['pillar.get']('idstools', IDSTOOLSDEFAULTS.idstools, merge=True) %} +{%- from 'idstools/map.jinja' import IDSTOOLSMERGED %} {%- if GLOBALS.airgap is sameas true -%} --merged=/opt/so/rules/nids/all.rules --local=/opt/so/rules/nids/local.rules @@ -35,4 +34,4 @@ {%- for URL in IDSTOOLSMERGED.config.urls %} --url={{ URL }} {%- endfor %} -{%- endif %} \ No newline at end of file +{%- endif %} diff --git a/salt/idstools/init.sls b/salt/idstools/init.sls index 7ad22e58b..ac1d51717 100644 --- a/salt/idstools/init.sls +++ b/salt/idstools/init.sls @@ -2,78 +2,12 @@ # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% set proxy = salt['pillar.get']('manager:proxy') %} + +{% from 'idstools/map.jinja' import IDSTOOLSMERGED %} include: - - idstools.sync_files - -# IDSTools Setup - -idstoolslogdir: - file.directory: - - name: /opt/so/log/idstools - - user: 939 - - group: 939 - - makedirs: True - -idstools_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://idstools/tools/sbin - - user: 934 - - group: 939 - - file_mode: 755 - -#idstools_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://idstools/tools/sbin_jinja -# - user: 934 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -so-rule-update: - cron.present: - - name: /usr/sbin/so-rule-update > /opt/so/log/idstools/download.log 2>&1 - - identifier: so-rule-update - - user: root - - minute: '1' - - hour: '7' - -so-idstools: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-idstools:{{ GLOBALS.so_version }} - - hostname: so-idstools - - user: socore - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-idstools'].ip }} - {% if proxy %} - - environment: - - http_proxy={{ proxy }} - - https_proxy={{ proxy }} - - no_proxy={{ salt['pillar.get']('manager:no_proxy') }} - {% endif %} - - binds: - - /opt/so/conf/idstools/etc:/opt/so/idstools/etc:ro - - /opt/so/rules/nids:/opt/so/rules/nids:rw - - watch: - - file: idstoolsetcsync - -append_so-idstools_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-idstools - +{% if IDSTOOLSMERGED.enabled %} + - idstools.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - -{% endif%} + - idstools.disabled +{% endif %} diff --git a/salt/idstools/map.jinja b/salt/idstools/map.jinja new file mode 100644 index 000000000..97d12279b --- /dev/null +++ b/salt/idstools/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'idstools/defaults.yaml' as IDSTOOLSDEFAULTS with context %} +{% set IDSTOOLSMERGED = salt['pillar.get']('idstools', IDSTOOLSDEFAULTS.idstools, merge=True) %} diff --git a/salt/idstools/soc_idstools.yaml b/salt/idstools/soc_idstools.yaml index b9c70d835..634f68803 100644 --- a/salt/idstools/soc_idstools.yaml +++ b/salt/idstools/soc_idstools.yaml @@ -1,4 +1,6 @@ idstools: + enabled: + description: You can enable or disable IDSTools. config: oinkcode: description: Enter your registration code or oinkcode for paid NIDS rulesets. diff --git a/salt/idstools/sostatus.sls b/salt/idstools/sostatus.sls new file mode 100644 index 000000000..408b10742 --- /dev/null +++ b/salt/idstools/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-idstools_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-idstools + - unless: grep -q so-idstools /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/influxdb/config.sls b/salt/influxdb/config.sls new file mode 100644 index 000000000..54e20b713 --- /dev/null +++ b/salt/influxdb/config.sls @@ -0,0 +1,96 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'influxdb/map.jinja' import INFLUXMERGED %} + +include: + - salt.minion + - ssl + +# Influx DB +influxconfdir: + file.directory: + - name: /opt/so/conf/influxdb + - makedirs: True + +influxlogdir: + file.directory: + - name: /opt/so/log/influxdb + - dir_mode: 755 + - user: 939 + - group: 939 + - makedirs: True + +influxdbdir: + file.directory: + - name: /nsm/influxdb + - makedirs: True + +influxdb_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://influxdb/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#influxdb_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://influxdb/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +influxdbconf: + file.managed: + - name: /opt/so/conf/influxdb/config.yaml + - source: salt://influxdb/config.yaml.jinja + - user: 939 + - group: 939 + - template: jinja + - defaults: + INFLUXMERGED: {{ INFLUXMERGED }} + +influxdbbucketsconf: + file.managed: + - name: /opt/so/conf/influxdb/buckets.json + - source: salt://influxdb/buckets.json.jinja + - user: 939 + - group: 939 + - template: jinja + - defaults: + INFLUXMERGED: {{ INFLUXMERGED }} + +influxdb-templates: + file.recurse: + - name: /opt/so/conf/influxdb/templates + - source: salt://influxdb/templates + - user: 939 + - group: 939 + - template: jinja + - clean: True + - defaults: + INFLUXMERGED: {{ INFLUXMERGED }} + +influxdb_curl_config: + file.managed: + - name: /opt/so/conf/influxdb/curl.config + - source: salt://influxdb/curl.config.jinja + - mode: 600 + - template: jinja + - show_changes: False + - makedirs: True + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/influxdb/defaults.yaml b/salt/influxdb/defaults.yaml index 373f6a603..29088fea9 100644 --- a/salt/influxdb/defaults.yaml +++ b/salt/influxdb/defaults.yaml @@ -1,4 +1,5 @@ influxdb: + enabled: False config: assets-path: /ui bolt-path: /var/lib/influxdb2/influxd.bolt @@ -74,4 +75,4 @@ influxdb: shard_duration: 604800 downsample: so_long_term: - resolution: 5m \ No newline at end of file + resolution: 5m diff --git a/salt/influxdb/disabled.sls b/salt/influxdb/disabled.sls new file mode 100644 index 000000000..edf27d7b1 --- /dev/null +++ b/salt/influxdb/disabled.sls @@ -0,0 +1,32 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - influxdb.sostatus + +so-influxdb: + docker_container.absent: + - force: True + +so-influxdb_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-influxdb$ + +get_influxdb_size: + cron.absent: + - identifier: get_influxdb_size + - user: root + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/influxdb/enabled.sls b/salt/influxdb/enabled.sls new file mode 100644 index 000000000..209406932 --- /dev/null +++ b/salt/influxdb/enabled.sls @@ -0,0 +1,87 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% set PASSWORD = salt['pillar.get']('secrets:influx_pass') %} +{% set TOKEN = salt['pillar.get']('influxdb:token') %} + +include: + - influxdb.config + - influxdb.sostatus + +so-influxdb: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-influxdb:{{ GLOBALS.so_version }} + - hostname: influxdb + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-influxdb'].ip }} + - environment: + - INFLUXD_CONFIG_PATH=/conf + - INFLUXDB_HTTP_LOG_ENABLED=false + - DOCKER_INFLUXDB_INIT_MODE=setup + - DOCKER_INFLUXDB_INIT_USERNAME=so + - DOCKER_INFLUXDB_INIT_PASSWORD={{ PASSWORD }} + - DOCKER_INFLUXDB_INIT_ORG=Security Onion + - DOCKER_INFLUXDB_INIT_BUCKET=telegraf/so_short_term + - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN={{ TOKEN }} + - binds: + - /opt/so/log/influxdb/:/log:rw + - /opt/so/conf/influxdb/config.yaml:/conf/config.yaml:ro + - /nsm/influxdb:/var/lib/influxdb2:rw + - /etc/pki/influxdb.crt:/conf/influxdb.crt:ro + - /etc/pki/influxdb.key:/conf/influxdb.key:ro + - port_bindings: + {% for BINDING in DOCKER.containers['so-influxdb'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - watch: + - file: influxdbconf + - require: + - file: influxdbconf + - x509: influxdb_key + - x509: influxdb_crt + +delete_so-influxdb_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-influxdb$ + +influxdb-setup: + cmd.run: + - name: /usr/sbin/so-influxdb-manage setup &>> /opt/so/log/influxdb/setup.log + - require: + - file: influxdbbucketsconf + - file: influxdb_curl_config + - docker_container: so-influxdb + +metrics_link_file: + cmd.run: + - name: so-influxdb-manage dashboardpath "Security Onion Performance" > /opt/so/saltstack/local/salt/influxdb/metrics_link.txt + - require: + - docker_container: so-influxdb + +# Install cron job to determine size of influxdb for telegraf +get_influxdb_size: + cron.present: + - name: 'du -s -k /nsm/influxdb | cut -f1 > /opt/so/log/telegraf/influxdb_size.log 2>&1' + - identifier: get_influxdb_size + - user: root + - minute: '*/1' + - hour: '*' + - daymonth: '*' + - month: '*' + - dayweek: '*' + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/influxdb/init.sls b/salt/influxdb/init.sls index 7e10a6798..33b4c3e37 100644 --- a/salt/influxdb/init.sls +++ b/salt/influxdb/init.sls @@ -1,163 +1,13 @@ -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + {% from 'influxdb/map.jinja' import INFLUXMERGED %} -{% if grains['role'] in ['so-manager', 'so-managersearch', 'so-standalone', 'so-eval', 'so-import'] %} -{% set PASSWORD = salt['pillar.get']('secrets:influx_pass') %} -{% set TOKEN = salt['pillar.get']('influxdb:token') %} - include: - - salt.minion - - ssl - -# Influx DB -influxconfdir: - file.directory: - - name: /opt/so/conf/influxdb - - makedirs: True - -influxlogdir: - file.directory: - - name: /opt/so/log/influxdb - - dir_mode: 755 - - user: 939 - - group: 939 - - makedirs: True - -influxdbdir: - file.directory: - - name: /nsm/influxdb - - makedirs: True - -influxdb_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://influxdb/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#influxdb_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://influxdb/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -influxdbconf: - file.managed: - - name: /opt/so/conf/influxdb/config.yaml - - source: salt://influxdb/config.yaml.jinja - - user: 939 - - group: 939 - - template: jinja - - defaults: - INFLUXMERGED: {{ INFLUXMERGED }} - -influxdbbucketsconf: - file.managed: - - name: /opt/so/conf/influxdb/buckets.json - - source: salt://influxdb/buckets.json.jinja - - user: 939 - - group: 939 - - template: jinja - - defaults: - INFLUXMERGED: {{ INFLUXMERGED }} - -influxdb-templates: - file.recurse: - - name: /opt/so/conf/influxdb/templates - - source: salt://influxdb/templates - - user: 939 - - group: 939 - - template: jinja - - clean: True - - defaults: - INFLUXMERGED: {{ INFLUXMERGED }} - -influxdb_curl_config: - file.managed: - - name: /opt/so/conf/influxdb/curl.config - - source: salt://influxdb/curl.config.jinja - - mode: 600 - - template: jinja - - show_changes: False - - makedirs: True - -so-influxdb: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-influxdb:{{ GLOBALS.so_version }} - - hostname: influxdb - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-influxdb'].ip }} - - environment: - - INFLUXD_CONFIG_PATH=/conf - - INFLUXDB_HTTP_LOG_ENABLED=false - - DOCKER_INFLUXDB_INIT_MODE=setup - - DOCKER_INFLUXDB_INIT_USERNAME=so - - DOCKER_INFLUXDB_INIT_PASSWORD={{ PASSWORD }} - - DOCKER_INFLUXDB_INIT_ORG=Security Onion - - DOCKER_INFLUXDB_INIT_BUCKET=telegraf/so_short_term - - DOCKER_INFLUXDB_INIT_ADMIN_TOKEN={{ TOKEN }} - - binds: - - /opt/so/log/influxdb/:/log:rw - - /opt/so/conf/influxdb/config.yaml:/conf/config.yaml:ro - - /nsm/influxdb:/var/lib/influxdb2:rw - - /etc/pki/influxdb.crt:/conf/influxdb.crt:ro - - /etc/pki/influxdb.key:/conf/influxdb.key:ro - - port_bindings: - {% for BINDING in DOCKER.containers['so-influxdb'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - watch: - - file: influxdbconf - - require: - - file: influxdbconf - - x509: influxdb_key - - x509: influxdb_crt - -append_so-influxdb_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-influxdb - -influxdb-setup: - cmd.run: - - name: /usr/sbin/so-influxdb-manage setup &>> /opt/so/log/influxdb/setup.log - - require: - - file: influxdbbucketsconf - - file: influxdb_curl_config - - docker_container: so-influxdb - -metrics_link_file: - cmd.run: - - name: so-influxdb-manage dashboardpath "Security Onion Performance" > /opt/so/saltstack/local/salt/influxdb/metrics_link.txt - - require: - - docker_container: so-influxdb - -# Install cron job to determine size of influxdb for telegraf -get_influxdb_size: - cron.present: - - name: 'du -s -k /nsm/influxdb | cut -f1 > /opt/so/log/telegraf/influxdb_size.log 2>&1' - - identifier: get_influxdb_size - - user: root - - minute: '*/1' - - hour: '*' - - daymonth: '*' - - month: '*' - - dayweek: '*' - -{% endif %} - +{% if INFLUXMERGED.enabled %} + - influxdb.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - influxdb.disabled {% endif %} diff --git a/salt/influxdb/map.jinja b/salt/influxdb/map.jinja index ecbdd1306..beb810f05 100644 --- a/salt/influxdb/map.jinja +++ b/salt/influxdb/map.jinja @@ -1,2 +1,7 @@ -{%- import_yaml 'influxdb/defaults.yaml' as INFLUXDEFAULTS %} -{%- set INFLUXMERGED = salt['pillar.get']('influxdb', default=INFLUXDEFAULTS.influxdb, merge=true) %} +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'influxdb/defaults.yaml' as INFLUXDEFAULTS %} +{% set INFLUXMERGED = salt['pillar.get']('influxdb', default=INFLUXDEFAULTS.influxdb, merge=true) %} diff --git a/salt/influxdb/soc_influxdb.yaml b/salt/influxdb/soc_influxdb.yaml index 7f6ceb316..42566a0a8 100644 --- a/salt/influxdb/soc_influxdb.yaml +++ b/salt/influxdb/soc_influxdb.yaml @@ -1,4 +1,7 @@ influxdb: + enabled: + description: You can enable or disable InfluxDB. + helpLink: influxdb.html config: assets-path: description: Path to the InfluxDB user interface assets located inside the so-influxdb container. @@ -352,4 +355,4 @@ influxdb: resolution: description: Amount of time to turn into a single data point. global: True - helpLink: influxdb.html \ No newline at end of file + helpLink: influxdb.html diff --git a/salt/influxdb/sostatus.sls b/salt/influxdb/sostatus.sls new file mode 100644 index 000000000..dd55053c5 --- /dev/null +++ b/salt/influxdb/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-influxdb_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-influxdb + - unless: grep -q so-influxdb /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kibana/config.map.jinja b/salt/kibana/config.map.jinja deleted file mode 100644 index 9ad1012f7..000000000 --- a/salt/kibana/config.map.jinja +++ /dev/null @@ -1,18 +0,0 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% import_yaml 'kibana/defaults.yaml' as KIBANACONFIG with context %} -{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} - -{% do KIBANACONFIG.kibana.config.server.update({'publicBaseUrl': 'https://' ~ GLOBALS.url_base ~ '/kibana'}) %} -{% do KIBANACONFIG.kibana.config.elasticsearch.update({'hosts': ['https://' ~ GLOBALS.manager ~ ':9200']}) %} - -{% do KIBANACONFIG.kibana.config.elasticsearch.update({'username': salt['pillar.get']('elasticsearch:auth:users:so_kibana_user:user'), 'password': salt['pillar.get']('elasticsearch:auth:users:so_kibana_user:pass')}) %} - -{% do KIBANACONFIG.kibana.config.xpack.fleet.update({'registryUrl': 'http://' ~ GLOBALS.manager_ip ~ ':8080'}) %} - -{% if salt['pillar.get']('kibana:secrets') %} - {% do KIBANACONFIG.kibana.config.xpack.update({'encryptedSavedObjects': {'encryptionKey': pillar['kibana']['secrets']['encryptedSavedObjects']['encryptionKey']}}) %} - {% do KIBANACONFIG.kibana.config.xpack.security.update({'encryptionKey': pillar['kibana']['secrets']['security']['encryptionKey']}) %} - {% do KIBANACONFIG.kibana.config.xpack.update({'reporting': {'encryptionKey': pillar['kibana']['secrets']['reporting']['encryptionKey']}}) %} -{% endif %} - -{% set KIBANACONFIG = salt['pillar.get']('kibana:config', default=KIBANACONFIG.kibana.config, merge=True) %} diff --git a/salt/kibana/config.sls b/salt/kibana/config.sls new file mode 100644 index 000000000..433fc9601 --- /dev/null +++ b/salt/kibana/config.sls @@ -0,0 +1,93 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% import_yaml 'kibana/defaults.yaml' as default_settings %} +{% from 'kibana/map.jinja' import KIBANAMERGED %} + +# Add ES Group +kibanasearchgroup: + group.present: + - name: kibana + - gid: 932 + +# Add ES user +kibana: + user.present: + - uid: 932 + - gid: 932 + - home: /opt/so/conf/kibana + - createhome: False + +# Drop the correct nginx config based on role + +kibanaconfdir: + file.directory: + - name: /opt/so/conf/kibana/etc + - user: 932 + - group: 939 + - makedirs: True + +kibana_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://kibana/tools/sbin + - user: 932 + - group: 939 + - file_mode: 755 + +kibana_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://kibana/tools/sbin_jinja + - user: 932 + - group: 939 + - file_mode: 755 + - template: jinja + - defaults: + GLOBALS: {{ GLOBALS }} + +kibanaconfig: + file.managed: + - name: /opt/so/conf/kibana/etc/kibana.yml + - source: salt://kibana/etc/kibana.yml.jinja + - user: 932 + - group: 939 + - mode: 660 + - template: jinja + - defaults: + KIBANACONFIG: {{ KIBANAMERGED.config }} + - show_changes: False + +kibanalogdir: + file.directory: + - name: /opt/so/log/kibana + - user: 932 + - group: 939 + - makedirs: True + +kibanacustdashdir: + file.directory: + - name: /opt/so/conf/kibana/customdashboards + - user: 932 + - group: 939 + - makedirs: True + +synckibanacustom: + file.recurse: + - name: /opt/so/conf/kibana/customdashboards + - source: salt://kibana/custom + - user: 932 + - group: 939 + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kibana/defaults.yaml b/salt/kibana/defaults.yaml index c0e279ca9..282521d12 100644 --- a/salt/kibana/defaults.yaml +++ b/salt/kibana/defaults.yaml @@ -1,5 +1,5 @@ kibana: - enabled: True + enabled: False config: server: name: kibana @@ -32,4 +32,4 @@ kibana: kibanaServer: hostname: localhost fleet: - registryUrl: "" \ No newline at end of file + registryUrl: "" diff --git a/salt/kibana/disabled.sls b/salt/kibana/disabled.sls new file mode 100644 index 000000000..eed2a623e --- /dev/null +++ b/salt/kibana/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - kibana.sostatus + +so-kibana: + docker_container.absent: + - force: True + +so-kibana_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-kibana$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kibana/enabled.sls b/salt/kibana/enabled.sls new file mode 100644 index 000000000..8f7091a0f --- /dev/null +++ b/salt/kibana/enabled.sls @@ -0,0 +1,53 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - kibana.config + - kibana.sostatus + +# Start the kibana docker +so-kibana: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-kibana:{{ GLOBALS.so_version }} + - hostname: kibana + - user: kibana + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-kibana'].ip }} + - environment: + - ELASTICSEARCH_HOST={{ GLOBALS.manager }} + - ELASTICSEARCH_PORT=9200 + - MANAGER={{ GLOBALS.manager }} + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - binds: + - /opt/so/conf/kibana/etc:/usr/share/kibana/config:rw + - /opt/so/log/kibana:/var/log/kibana:rw + - /opt/so/conf/kibana/customdashboards:/usr/share/kibana/custdashboards:ro + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - port_bindings: + {% for BINDING in DOCKER.containers['so-kibana'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - watch: + - file: kibanaconfig + +delete_so-kibana_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-kibana$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kibana/init.sls b/salt/kibana/init.sls index a9d3c6da9..675106d8f 100644 --- a/salt/kibana/init.sls +++ b/salt/kibana/init.sls @@ -3,125 +3,14 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% import_yaml 'kibana/defaults.yaml' as default_settings %} -{% set KIBANA_SETTINGS = salt['grains.filter_by'](default_settings, default='kibana', merge=salt['pillar.get']('kibana', {})) %} -{% from 'kibana/config.map.jinja' import KIBANACONFIG with context %} - -# Add ES Group -kibanasearchgroup: - group.present: - - name: kibana - - gid: 932 - -# Add ES user -kibana: - user.present: - - uid: 932 - - gid: 932 - - home: /opt/so/conf/kibana - - createhome: False - -# Drop the correct nginx config based on role - -kibanaconfdir: - file.directory: - - name: /opt/so/conf/kibana/etc - - user: 932 - - group: 939 - - makedirs: True - -kibana_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://kibana/tools/sbin - - user: 932 - - group: 939 - - file_mode: 755 - -kibana_sbin_jinja: - file.recurse: - - name: /usr/sbin - - source: salt://kibana/tools/sbin_jinja - - user: 932 - - group: 939 - - file_mode: 755 - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - -kibanaconfig: - file.managed: - - name: /opt/so/conf/kibana/etc/kibana.yml - - source: salt://kibana/etc/kibana.yml.jinja - - user: 932 - - group: 939 - - mode: 660 - - template: jinja - - defaults: - KIBANACONFIG: {{ KIBANACONFIG }} - - show_changes: False - -kibanalogdir: - file.directory: - - name: /opt/so/log/kibana - - user: 932 - - group: 939 - - makedirs: True - -kibanacustdashdir: - file.directory: - - name: /opt/so/conf/kibana/customdashboards - - user: 932 - - group: 939 - - makedirs: True - -synckibanacustom: - file.recurse: - - name: /opt/so/conf/kibana/customdashboards - - source: salt://kibana/custom - - user: 932 - - group: 939 - -# Start the kibana docker -so-kibana: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-kibana:{{ GLOBALS.so_version }} - - hostname: kibana - - user: kibana - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-kibana'].ip }} - - environment: - - ELASTICSEARCH_HOST={{ GLOBALS.manager }} - - ELASTICSEARCH_PORT=9200 - - MANAGER={{ GLOBALS.manager }} - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - binds: - - /opt/so/conf/kibana/etc:/usr/share/kibana/config:rw - - /opt/so/log/kibana:/var/log/kibana:rw - - /opt/so/conf/kibana/customdashboards:/usr/share/kibana/custdashboards:ro - - /sys/fs/cgroup:/sys/fs/cgroup:ro - - port_bindings: - {% for BINDING in DOCKER.containers['so-kibana'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - watch: - - file: kibanaconfig - -append_so-kibana_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-kibana +{% from 'kibana/map.jinja' import KIBANAMERGED %} +include: +{% if KIBANAMERGED.enabled %} + - kibana.enabled + - kibana.so_config_load + - kibana.so_securitySolution_load + - kibana.so_dashboard_load {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - kibana.disabled {% endif %} diff --git a/salt/kibana/map.jinja b/salt/kibana/map.jinja new file mode 100644 index 000000000..bd333f1c4 --- /dev/null +++ b/salt/kibana/map.jinja @@ -0,0 +1,23 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% import_yaml 'kibana/defaults.yaml' as KIBANADEFAULTS with context %} +{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} + +{% do KIBANADEFAULTS.kibana.config.server.update({'publicBaseUrl': 'https://' ~ GLOBALS.url_base ~ '/kibana'}) %} +{% do KIBANADEFAULTS.kibana.config.elasticsearch.update({'hosts': ['https://' ~ GLOBALS.manager ~ ':9200']}) %} + +{% do KIBANADEFAULTS.kibana.config.elasticsearch.update({'username': salt['pillar.get']('elasticsearch:auth:users:so_kibana_user:user'), 'password': salt['pillar.get']('elasticsearch:auth:users:so_kibana_user:pass')}) %} + +{% do KIBANADEFAULTS.kibana.config.xpack.fleet.update({'registryUrl': 'http://' ~ GLOBALS.manager_ip ~ ':8080'}) %} + +{% if salt['pillar.get']('kibana:secrets') %} + {% do KIBANADEFAULTS.kibana.config.xpack.update({'encryptedSavedObjects': {'encryptionKey': pillar['kibana']['secrets']['encryptedSavedObjects']['encryptionKey']}}) %} + {% do KIBANADEFAULTS.kibana.config.xpack.security.update({'encryptionKey': pillar['kibana']['secrets']['security']['encryptionKey']}) %} + {% do KIBANADEFAULTS.kibana.config.xpack.update({'reporting': {'encryptionKey': pillar['kibana']['secrets']['reporting']['encryptionKey']}}) %} +{% endif %} + +{% set KIBANAMERGED = salt['pillar.get']('kibana', default=KIBANADEFAULTS.kibana, merge=True) %} diff --git a/salt/kibana/so_config_load.sls b/salt/kibana/so_config_load.sls index ea9655688..a443e960b 100644 --- a/salt/kibana/so_config_load.sls +++ b/salt/kibana/so_config_load.sls @@ -4,7 +4,7 @@ # Elastic License 2.0. include: - - kibana + - kibana.enabled config_saved_objects: file.managed: @@ -25,5 +25,5 @@ so-kibana-config-load: - name: /usr/sbin/so-kibana-config-load -i /opt/so/conf/kibana/config_saved_objects.ndjson.template - cwd: /opt/so - require: - - sls: kibana + - sls: kibana.enabled - file: config_saved_objects diff --git a/salt/kibana/so_dashboard_load.sls b/salt/kibana/so_dashboard_load.sls index 26cc13f83..3222eabc6 100644 --- a/salt/kibana/so_dashboard_load.sls +++ b/salt/kibana/so_dashboard_load.sls @@ -5,7 +5,7 @@ {% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} include: - - kibana + - kibana.enabled dashboard_saved_objects_template: file.managed: @@ -27,7 +27,7 @@ so-kibana-dashboard-load: - name: /usr/sbin/so-kibana-config-load -i /opt/so/conf/kibana/saved_objects.ndjson.template - cwd: /opt/so - require: - - sls: kibana + - sls: kibana.enabled - file: dashboard_saved_objects_template {%- if HIGHLANDER %} dashboard_saved_objects_template_hl: @@ -50,6 +50,6 @@ so-kibana-dashboard-load_hl: - name: /usr/sbin/so-kibana-config-load -i /opt/so/conf/kibana/hl.ndjson.template - cwd: /opt/so - require: - - sls: kibana + - sls: kibana.enabled - file: dashboard_saved_objects_template_hl {%- endif %} diff --git a/salt/kibana/so_savedobjects_defaults.sls b/salt/kibana/so_savedobjects_defaults.sls index 135053c68..c9fe61ac6 100644 --- a/salt/kibana/so_savedobjects_defaults.sls +++ b/salt/kibana/so_savedobjects_defaults.sls @@ -4,7 +4,7 @@ # Elastic License 2.0. include: - - kibana + - kibana.enabled - kibana.so_config_load - kibana.so_securitySolution_load - kibana.so_dashboard_load diff --git a/salt/kibana/so_securitySolution_load.sls b/salt/kibana/so_securitySolution_load.sls index 0f72adcda..5599b7b88 100644 --- a/salt/kibana/so_securitySolution_load.sls +++ b/salt/kibana/so_securitySolution_load.sls @@ -4,7 +4,7 @@ # Elastic License 2.0. include: - - kibana + - kibana.enabled securitySolution_saved_objects: file.managed: @@ -25,5 +25,5 @@ so-kibana-securitySolution_saved_objects-load: - name: /usr/sbin/so-kibana-config-load -u /opt/so/conf/kibana/securitySolution_saved_objects.ndjson.template - cwd: /opt/so - require: - - sls: kibana + - sls: kibana.enabled - file: securitySolution_saved_objects diff --git a/salt/kibana/soc_kibana.yaml b/salt/kibana/soc_kibana.yaml index 331e7716f..c95512b58 100644 --- a/salt/kibana/soc_kibana.yaml +++ b/salt/kibana/soc_kibana.yaml @@ -1,4 +1,7 @@ kibana: + enabled: + description: You can enable or disable Kibana. + helpLink: kibana.html config: elasticsearch: requestTimeout: diff --git a/salt/kibana/sostatus.sls b/salt/kibana/sostatus.sls new file mode 100644 index 000000000..9bab0efe8 --- /dev/null +++ b/salt/kibana/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-kibana_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-kibana + - unless: grep -q so-kibana /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kratos/config.sls b/salt/kratos/config.sls new file mode 100644 index 000000000..55949ea3c --- /dev/null +++ b/salt/kratos/config.sls @@ -0,0 +1,71 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from "kratos/map.jinja" import KRATOSMERGED %} + +# Add Kratos Group +kratosgroup: + group.present: + - name: kratos + - gid: 928 + +# Add Kratos user +kratos: + user.present: + - uid: 928 + - gid: 928 + - home: /opt/so/conf/kratos + +kratosdir: + file.directory: + - name: /nsm/kratos + - user: 928 + - group: 928 + - mode: 700 + - makedirs: True + +kratosdbdir: + file.directory: + - name: /nsm/kratos/db + - user: 928 + - group: 928 + - mode: 700 + - makedirs: True + +kratoslogdir: + file.directory: + - name: /opt/so/log/kratos + - user: 928 + - group: 928 + - makedirs: True + +kratosschema: + file.managed: + - name: /opt/so/conf/kratos/schema.json + - source: salt://kratos/files/schema.json + - user: 928 + - group: 928 + - mode: 600 + +kratosconfig: + file.managed: + - name: /opt/so/conf/kratos/kratos.yaml + - source: salt://kratos/files/kratos.yaml.jinja + - user: 928 + - group: 928 + - mode: 600 + - template: jinja + - defaults: + KRATOSMERGED: {{ KRATOSMERGED }} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kratos/defaults.yaml b/salt/kratos/defaults.yaml index 8f7a72b00..e0317ed37 100644 --- a/salt/kratos/defaults.yaml +++ b/salt/kratos/defaults.yaml @@ -1,4 +1,5 @@ kratos: + enabled: False config: session: lifespan: 24h diff --git a/salt/kratos/disabled.sls b/salt/kratos/disabled.sls new file mode 100644 index 000000000..0ab998273 --- /dev/null +++ b/salt/kratos/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - kratos.sostatus + +so-kratos: + docker_container.absent: + - force: True + +so-kratos_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-kratos$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kratos/enabled.sls b/salt/kratos/enabled.sls new file mode 100644 index 000000000..9358c9349 --- /dev/null +++ b/salt/kratos/enabled.sls @@ -0,0 +1,69 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - kratos.config + - kratos.sostatus + +so-kratos: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-kratos:{{ GLOBALS.so_version }} + - hostname: kratos + - name: so-kratos + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-kratos'].ip }} + - binds: + - /opt/so/conf/kratos/schema.json:/kratos-conf/schema.json:ro + - /opt/so/conf/kratos/kratos.yaml:/kratos-conf/kratos.yaml:ro + - /opt/so/log/kratos/:/kratos-log:rw + - /nsm/kratos/db:/kratos-data:rw + - port_bindings: + {% for BINDING in DOCKER.containers['so-kratos'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - restart_policy: unless-stopped + - watch: + - file: kratosschema + - file: kratosconfig + - require: + - file: kratosschema + - file: kratosconfig + - file: kratoslogdir + - file: kratosdir + +delete_so-kratos_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-kratos$ + +wait_for_kratos: + http.wait_for_successful_query: + - name: 'http://{{ GLOBALS.manager }}:4434/' + - ssl: True + - verify_ssl: False + - status: + - 200 + - 301 + - 302 + - 404 + - status_type: list + - wait_for: 300 + - request_interval: 10 + - require: + - docker_container: so-kratos + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/kratos/files/kratos.yaml.jinja b/salt/kratos/files/kratos.yaml.jinja index fc67a1db8..e31ec0313 100644 --- a/salt/kratos/files/kratos.yaml.jinja +++ b/salt/kratos/files/kratos.yaml.jinja @@ -1,14 +1 @@ -{%- import_yaml 'kratos/defaults.yaml' as KRATOSDEFAULTS %} - -{%- do KRATOSDEFAULTS.kratos.config.selfservice.flows.settings.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.settings.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.selfservice.flows.verification.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.verification.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.selfservice.flows.login.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.login.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.selfservice.flows.error.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.error.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.selfservice.flows.registration.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.registration.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.selfservice.update({'default_browser_return_url': KRATOSDEFAULTS.kratos.config.selfservice.default_browser_return_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.serve.public.update({'base_url': KRATOSDEFAULTS.kratos.config.serve.public.base_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.serve.admin.update({'base_url': KRATOSDEFAULTS.kratos.config.serve.admin.base_url | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- do KRATOSDEFAULTS.kratos.config.courier.smtp.update({'connection_uri': KRATOSDEFAULTS.kratos.config.courier.smtp.connection_uri | replace("URL_BASE", GLOBALS.url_base)}) %} -{%- set KRATOSMERGED = salt['pillar.get']('kratos:config', default=KRATOSDEFAULTS.kratos.config, merge=true) %} - -{{- KRATOSMERGED | yaml(false) }} +{{ KRATOSMERGED.config | yaml(false) }} diff --git a/salt/kratos/init.sls b/salt/kratos/init.sls index c52ae15f8..9cacfae3c 100644 --- a/salt/kratos/init.sls +++ b/salt/kratos/init.sls @@ -3,118 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} - -# Add Kratos Group -kratosgroup: - group.present: - - name: kratos - - gid: 928 - -# Add Kratos user -kratos: - user.present: - - uid: 928 - - gid: 928 - - home: /opt/so/conf/kratos - -kratosdir: - file.directory: - - name: /nsm/kratos - - user: 928 - - group: 928 - - mode: 700 - - makedirs: True - -kratosdbdir: - file.directory: - - name: /nsm/kratos/db - - user: 928 - - group: 928 - - mode: 700 - - makedirs: True - -kratoslogdir: - file.directory: - - name: /opt/so/log/kratos - - user: 928 - - group: 928 - - makedirs: True - -kratosschema: - file.managed: - - name: /opt/so/conf/kratos/schema.json - - source: salt://kratos/files/schema.json - - user: 928 - - group: 928 - - mode: 600 - -kratosconfig: - file.managed: - - name: /opt/so/conf/kratos/kratos.yaml - - source: salt://kratos/files/kratos.yaml.jinja - - user: 928 - - group: 928 - - mode: 600 - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - -so-kratos: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-kratos:{{ GLOBALS.so_version }} - - hostname: kratos - - name: so-kratos - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-kratos'].ip }} - - binds: - - /opt/so/conf/kratos/schema.json:/kratos-conf/schema.json:ro - - /opt/so/conf/kratos/kratos.yaml:/kratos-conf/kratos.yaml:ro - - /opt/so/log/kratos/:/kratos-log:rw - - /nsm/kratos/db:/kratos-data:rw - - port_bindings: - {% for BINDING in DOCKER.containers['so-kratos'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - restart_policy: unless-stopped - - watch: - - file: kratosschema - - file: kratosconfig - - require: - - file: kratosschema - - file: kratosconfig - - file: kratoslogdir - - file: kratosdir - -append_so-kratos_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-kratos - -wait_for_kratos: - http.wait_for_successful_query: - - name: 'http://{{ GLOBALS.manager }}:4434/' - - ssl: True - - verify_ssl: False - - status: - - 200 - - 301 - - 302 - - 404 - - status_type: list - - wait_for: 300 - - request_interval: 10 - - require: - - docker_container: so-kratos +{% from 'kratos/map.jinja' import KRATOSMERGED %} +include: +{% if KRATOSMERGED.enabled %} + - kratos.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - kratos.disabled {% endif %} diff --git a/salt/kratos/map.jinja b/salt/kratos/map.jinja new file mode 100644 index 000000000..1cdc4337b --- /dev/null +++ b/salt/kratos/map.jinja @@ -0,0 +1,19 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% import_yaml 'kratos/defaults.yaml' as KRATOSDEFAULTS %} + +{% do KRATOSDEFAULTS.kratos.config.selfservice.flows.settings.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.settings.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.selfservice.flows.verification.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.verification.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.selfservice.flows.login.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.login.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.selfservice.flows.error.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.error.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.selfservice.flows.registration.update({'ui_url': KRATOSDEFAULTS.kratos.config.selfservice.flows.registration.ui_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.selfservice.update({'default_browser_return_url': KRATOSDEFAULTS.kratos.config.selfservice.default_browser_return_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.serve.public.update({'base_url': KRATOSDEFAULTS.kratos.config.serve.public.base_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.serve.admin.update({'base_url': KRATOSDEFAULTS.kratos.config.serve.admin.base_url | replace("URL_BASE", GLOBALS.url_base)}) %} +{% do KRATOSDEFAULTS.kratos.config.courier.smtp.update({'connection_uri': KRATOSDEFAULTS.kratos.config.courier.smtp.connection_uri | replace("URL_BASE", GLOBALS.url_base)}) %} + +{% set KRATOSMERGED = salt['pillar.get']('kratos', default=KRATOSDEFAULTS.kratos, merge=true) %} diff --git a/salt/kratos/soc_kratos.yaml b/salt/kratos/soc_kratos.yaml index d2555bf11..1eb9bef40 100644 --- a/salt/kratos/soc_kratos.yaml +++ b/salt/kratos/soc_kratos.yaml @@ -1,4 +1,8 @@ kratos: + enabled: + description: You can enable or disable Kratos. + advanced: True + helpLink: kratos.html config: session: lifespan: diff --git a/salt/kratos/sostatus.sls b/salt/kratos/sostatus.sls new file mode 100644 index 000000000..cf736d8f7 --- /dev/null +++ b/salt/kratos/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-kratos_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-kratos + - unless: grep -q so-kratos /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/logstash/config.sls b/salt/logstash/config.sls new file mode 100644 index 000000000..6ff33ff1a --- /dev/null +++ b/salt/logstash/config.sls @@ -0,0 +1,153 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'logstash/map.jinja' import LOGSTASH_MERGED %} +{% set ASSIGNED_PIPELINES = LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} + +include: + - ssl + {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} + - elasticsearch + {% endif %} + +# Create the logstash group +logstashgroup: + group.present: + - name: logstash + - gid: 931 + +# Add the logstash user for the jog4j settings +logstash: + user.present: + - uid: 931 + - gid: 931 + - home: /opt/so/conf/logstash + +lslibdir: + file.absent: + - name: /opt/so/conf/logstash/lib + +logstash_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://logstash/tools/sbin + - user: 931 + - group: 939 + - file_mode: 755 + +#logstash_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://logstash/tools/sbin_jinja +# - user: 931 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +lsetcdir: + file.directory: + - name: /opt/so/conf/logstash/etc + - user: 931 + - group: 939 + - makedirs: True + +lspipelinedir: + file.directory: + - name: /opt/so/conf/logstash/pipelines + - user: 931 + - group: 939 + +{% for assigned_pipeline in ASSIGNED_PIPELINES %} + {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} +ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }}: + file.managed: + - source: salt://logstash/pipelines/config/{{CONFIGFILE}} + {% if 'jinja' in CONFIGFILE.split('.')[-1] %} + - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}}/{{CONFIGFILE.split('/')[1] | replace(".jinja", "")}} + - template: jinja + - defaults: + GLOBALS: {{ GLOBALS }} + ES_USER: "{{ salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:user', '') }}" + ES_PASS: "{{ salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') }}" + THREADS: {{ LOGSTASH_MERGED.config.pipeline_x_workers }} + BATCH: {{ LOGSTASH_MERGED.config.pipeline_x_batch_x_size }} + {% else %} + - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}}/{{CONFIGFILE.split('/')[1]}} + {% endif %} + - user: 931 + - group: 939 + - mode: 660 + - makedirs: True + - show_changes: False + {% endfor %} + +ls_pipeline_{{assigned_pipeline}}: + file.directory: + - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}} + - user: 931 + - group: 939 + - require: + {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} + - file: ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }} + {% endfor %} + - clean: True +{% endfor %} + +# Copy down all the configs +lspipelinesyml: + file.managed: + - name: /opt/so/conf/logstash/etc/pipelines.yml + - source: salt://logstash/etc/pipelines.yml.jinja + - template: jinja + - defaults: + ASSIGNED_PIPELINES: {{ ASSIGNED_PIPELINES }} + +lsetcsync: + file.recurse: + - name: /opt/so/conf/logstash/etc + - source: salt://logstash/etc + - user: 931 + - group: 939 + - template: jinja + - clean: True + - exclude_pat: pipelines* + - defaults: + LOGSTASH_MERGED: {{ LOGSTASH_MERGED }} + +# Create the import directory +importdir: + file.directory: + - name: /nsm/import + - user: 931 + - group: 939 + - makedirs: True + +# Create the logstash data directory +nsmlsdir: + file.directory: + - name: /nsm/logstash/tmp + - user: 931 + - group: 939 + - makedirs: True + +# Create the log directory +lslogdir: + file.directory: + - name: /opt/so/log/logstash + - user: 931 + - group: 939 + - makedirs: True + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/logstash/defaults.yaml b/salt/logstash/defaults.yaml index 28a7f8896..790ab0f3b 100644 --- a/salt/logstash/defaults.yaml +++ b/salt/logstash/defaults.yaml @@ -1,4 +1,5 @@ logstash: + enabled: False assigned_pipelines: roles: standalone: diff --git a/salt/logstash/disabled.sls b/salt/logstash/disabled.sls new file mode 100644 index 000000000..76901b60a --- /dev/null +++ b/salt/logstash/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - logstash.sostatus + +so-logstash: + docker_container.absent: + - force: True + +so-logstash_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-logstash$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/logstash/enabled.sls b/salt/logstash/enabled.sls new file mode 100644 index 000000000..65905cd6c --- /dev/null +++ b/salt/logstash/enabled.sls @@ -0,0 +1,101 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'logstash/map.jinja' import LOGSTASH_MERGED %} +{% from 'logstash/map.jinja' import REDIS_NODES %} +{% set lsheap = LOGSTASH_MERGED.settings.lsheap %} + +include: + - elasticsearch.ca + - logstash.config + - logstash.sostatus + +so-logstash: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-logstash:{{ GLOBALS.so_version }} + - hostname: so-logstash + - name: so-logstash + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-logstash'].ip }} + - user: logstash + - extra_hosts: {{ REDIS_NODES }} + - environment: + - LS_JAVA_OPTS=-Xms{{ lsheap }} -Xmx{{ lsheap }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-logstash'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - binds: + - /opt/so/conf/elasticsearch/templates/:/templates/:ro + - /opt/so/conf/logstash/etc/:/usr/share/logstash/config/:ro + - /opt/so/conf/logstash/pipelines:/usr/share/logstash/pipelines:ro + - /opt/so/rules:/etc/nsm/rules:ro + - /nsm/import:/nsm/import:ro + - /nsm/logstash:/usr/share/logstash/data:rw + - /opt/so/log/logstash:/var/log/logstash:rw + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - /opt/so/conf/logstash/etc/certs:/usr/share/logstash/certs:ro + {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} + - /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro + - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro + {% endif %} + {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-eval','so-fleet'] %} + - /opt/so/conf/elastic-fleet/certs/elasticfleet-logstash.crt:/usr/share/logstash/elasticfleet-logstash.crt:ro + - /opt/so/conf/elastic-fleet/certs/elasticfleet-logstash.p8:/usr/share/logstash/elasticfleet-logstash.key:ro + {% endif %} + {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} + - /etc/pki/ca.crt:/usr/share/filebeat/ca.crt:ro + {% else %} + - /etc/ssl/certs/intca.crt:/usr/share/filebeat/ca.crt:ro + {% endif %} + {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode'] %} + - /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro + - /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro + {% endif %} + {% if GLOBALS.role == 'so-eval' %} + - /nsm/zeek:/nsm/zeek:ro + - /nsm/suricata:/suricata:ro + - /opt/so/log/fleet/:/osquery/logs:ro + - /opt/so/log/strelka:/strelka:ro + {% endif %} + - watch: + - file: lsetcsync + {% for assigned_pipeline in LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} + - file: ls_pipeline_{{assigned_pipeline}} + {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} + - file: ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }} + {% endfor %} + {% endfor %} + - require: + {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} + - x509: etc_filebeat_crt + {% endif %} + {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} + - x509: pki_public_ca_crt + {% else %} + - x509: trusttheca + {% endif %} + {% if grains.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} + - file: cacertz + - file: capemz + {% endif %} + +delete_so-logstash_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-logstash$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/logstash/init.sls b/salt/logstash/init.sls index 7072ed46d..62b2a2ebb 100644 --- a/salt/logstash/init.sls +++ b/salt/logstash/init.sls @@ -3,237 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'logstash/map.jinja' import REDIS_NODES %} {% from 'logstash/map.jinja' import LOGSTASH_MERGED %} -# Logstash Section - Decide which pillar to use -{% set lsheap = LOGSTASH_MERGED.settings.lsheap %} -{% if GLOBALS.role in ['so-eval','so-managersearch', 'so-manager', 'so-standalone'] %} - {% set nodetype = GLOBALS.role %} -{% endif %} - -{% set ASSIGNED_PIPELINES = LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} -{% set DOCKER_OPTIONS = LOGSTASH_MERGED.docker_options %} - include: - - ssl - {% if GLOBALS.role not in ['so-receiver','so-fleet'] %} - - elasticsearch - {% endif %} - -# Create the logstash group -logstashgroup: - group.present: - - name: logstash - - gid: 931 - -# Add the logstash user for the jog4j settings -logstash: - user.present: - - uid: 931 - - gid: 931 - - home: /opt/so/conf/logstash - -lslibdir: - file.absent: - - name: /opt/so/conf/logstash/lib - -logstash_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://logstash/tools/sbin - - user: 931 - - group: 939 - - file_mode: 755 - -#logstash_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://logstash/tools/sbin_jinja -# - user: 931 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -lsetcdir: - file.directory: - - name: /opt/so/conf/logstash/etc - - user: 931 - - group: 939 - - makedirs: True - -lspipelinedir: - file.directory: - - name: /opt/so/conf/logstash/pipelines - - user: 931 - - group: 939 - -{% for assigned_pipeline in ASSIGNED_PIPELINES %} - {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} -ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }}: - file.managed: - - source: salt://logstash/pipelines/config/{{CONFIGFILE}} - {% if 'jinja' in CONFIGFILE.split('.')[-1] %} - - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}}/{{CONFIGFILE.split('/')[1] | replace(".jinja", "")}} - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - ES_USER: "{{ salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:user', '') }}" - ES_PASS: "{{ salt['pillar.get']('elasticsearch:auth:users:so_elastic_user:pass', '') }}" - THREADS: {{ LOGSTASH_MERGED.config.pipeline_x_workers }} - BATCH: {{ LOGSTASH_MERGED.config.pipeline_x_batch_x_size }} - {% else %} - - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}}/{{CONFIGFILE.split('/')[1]}} - {% endif %} - - user: 931 - - group: 939 - - mode: 660 - - makedirs: True - - show_changes: False - {% endfor %} - -ls_pipeline_{{assigned_pipeline}}: - file.directory: - - name: /opt/so/conf/logstash/pipelines/{{assigned_pipeline}} - - user: 931 - - group: 939 - - require: - {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} - - file: ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }} - {% endfor %} - - clean: True -{% endfor %} - -# Copy down all the configs -lspipelinesyml: - file.managed: - - name: /opt/so/conf/logstash/etc/pipelines.yml - - source: salt://logstash/etc/pipelines.yml.jinja - - template: jinja - - defaults: - ASSIGNED_PIPELINES: {{ ASSIGNED_PIPELINES }} - -lsetcsync: - file.recurse: - - name: /opt/so/conf/logstash/etc - - source: salt://logstash/etc - - user: 931 - - group: 939 - - template: jinja - - clean: True - - exclude_pat: pipelines* - - defaults: - LOGSTASH_MERGED: {{ LOGSTASH_MERGED }} - -# Create the import directory -importdir: - file.directory: - - name: /nsm/import - - user: 931 - - group: 939 - - makedirs: True - -# Create the logstash data directory -nsmlsdir: - file.directory: - - name: /nsm/logstash/tmp - - user: 931 - - group: 939 - - makedirs: True - -# Create the log directory -lslogdir: - file.directory: - - name: /opt/so/log/logstash - - user: 931 - - group: 939 - - makedirs: True - -so-logstash: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-logstash:{{ GLOBALS.so_version }} - - hostname: so-logstash - - name: so-logstash - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-logstash'].ip }} - - user: logstash - - extra_hosts: {{ REDIS_NODES }} - - environment: - - LS_JAVA_OPTS=-Xms{{ lsheap }} -Xmx{{ lsheap }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-logstash'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - binds: - - /opt/so/conf/elasticsearch/templates/:/templates/:ro - - /opt/so/conf/logstash/etc/:/usr/share/logstash/config/:ro - - /opt/so/conf/logstash/pipelines:/usr/share/logstash/pipelines:ro - - /opt/so/rules:/etc/nsm/rules:ro - - /nsm/import:/nsm/import:ro - - /nsm/logstash:/usr/share/logstash/data:rw - - /opt/so/log/logstash:/var/log/logstash:rw - - /sys/fs/cgroup:/sys/fs/cgroup:ro - - /opt/so/conf/logstash/etc/certs:/usr/share/logstash/certs:ro - {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} - - /etc/pki/filebeat.crt:/usr/share/logstash/filebeat.crt:ro - - /etc/pki/filebeat.p8:/usr/share/logstash/filebeat.key:ro - {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-managersearch', 'so-standalone', 'so-import', 'so-eval','so-fleet'] %} - - /opt/so/conf/elastic-fleet/certs/elasticfleet-logstash.crt:/usr/share/logstash/elasticfleet-logstash.crt:ro - - /opt/so/conf/elastic-fleet/certs/elasticfleet-logstash.p8:/usr/share/logstash/elasticfleet-logstash.key:ro - {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} - - /etc/pki/ca.crt:/usr/share/filebeat/ca.crt:ro - {% else %} - - /etc/ssl/certs/intca.crt:/usr/share/filebeat/ca.crt:ro - {% endif %} - {% if GLOBALS.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-searchnode'] %} - - /opt/so/conf/ca/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro - - /opt/so/conf/ca/tls-ca-bundle.pem:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem:ro - {% endif %} - {%- if GLOBALS.role == 'so-eval' %} - - /nsm/zeek:/nsm/zeek:ro - - /nsm/suricata:/suricata:ro - - /opt/so/log/fleet/:/osquery/logs:ro - - /opt/so/log/strelka:/strelka:ro - {%- endif %} - - watch: - - file: lsetcsync - {% for assigned_pipeline in LOGSTASH_MERGED.assigned_pipelines.roles[GLOBALS.role.split('-')[1]] %} - - file: ls_pipeline_{{assigned_pipeline}} - {% for CONFIGFILE in LOGSTASH_MERGED.defined_pipelines[assigned_pipeline] %} - - file: ls_pipeline_{{assigned_pipeline}}_{{CONFIGFILE.split('.')[0] | replace("/","_") }} - {% endfor %} - {% endfor %} - - require: - {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import', 'so-heavynode', 'so-receiver'] %} - - x509: etc_filebeat_crt - {% endif %} - {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - {% if grains.role in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} - - file: cacertz - - file: capemz - {% endif %} - -append_so-logstash_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-logstash - +{% if LOGSTASH_MERGED.enabled %} + - logstash.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - logstash.disabled {% endif %} diff --git a/salt/logstash/map.jinja b/salt/logstash/map.jinja index c4ad5d96a..69e102e78 100644 --- a/salt/logstash/map.jinja +++ b/salt/logstash/map.jinja @@ -1,3 +1,8 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'logstash/defaults.yaml' as LOGSTASH_DEFAULTS %} {% set LOGSTASH_MERGED = salt['pillar.get']('logstash', LOGSTASH_DEFAULTS.logstash, merge=True) %} diff --git a/salt/logstash/soc_logstash.yaml b/salt/logstash/soc_logstash.yaml index f32ac7459..bcb99bad5 100644 --- a/salt/logstash/soc_logstash.yaml +++ b/salt/logstash/soc_logstash.yaml @@ -1,4 +1,7 @@ logstash: + enabled: + description: You can enable or disable Logstash. + helpLink: logstash.html assigned_pipelines: roles: standalone: &assigned_pipelines diff --git a/salt/logstash/sostatus.sls b/salt/logstash/sostatus.sls new file mode 100644 index 000000000..e42e5ebe0 --- /dev/null +++ b/salt/logstash/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-logstash_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-logstash + - unless: grep -q so-logstash /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/manager/init.sls b/salt/manager/init.sls index 47867edaf..2eef1259b 100644 --- a/salt/manager/init.sls +++ b/salt/manager/init.sls @@ -5,10 +5,11 @@ {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'strelka/map.jinja' import STRELKAMERGED %} -{% import_yaml 'manager/defaults.yaml' as MANAGERDEFAULTS %} -{% set MANAGERMERGED = salt['pillar.get']('manager', MANAGERDEFAULTS.manager, merge=true) %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} +{% import_yaml 'manager/defaults.yaml' as MANAGERDEFAULTS %} +{% set MANAGERMERGED = salt['pillar.get']('manager', MANAGERDEFAULTS.manager, merge=true) %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} include: - salt.minion @@ -81,6 +82,17 @@ socore_own_saltstack: - user - group +{% if STRELKAMERGED.rules.enabled %} +strelkarepos: + file.managed: + - name: /opt/so/conf/strelka/repos.txt + - source: salt://strelka/rules/repos.txt.jinja + - template: jinja + - defaults: + STRELKAREPOS: {{ STRELKAMERGED.rules.repos }} + - makedirs: True +{% endif %} + yara_update_script: file.managed: - name: /usr/sbin/so-yara-update diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 4145b16b1..3342f3c15 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -125,9 +125,10 @@ function create_minion_files() { } # Add Elastic settings to the minion file -function add_elastic_to_minion() { +function add_elasticsearch_to_minion() { printf '%s\n'\ "elasticsearch:"\ + " enabled: True"\ " esheap: '$ES_HEAP_SIZE'"\ " " >> $PILLARFILE } @@ -142,16 +143,18 @@ function add_fleet_to_minion() { # Write out settings to minion file printf '%s\n'\ "elasticfleet:"\ - " server:"\ - " es_token: '$ESTOKEN'"\ + " enabled: True"\ + " config:"\ + " server:"\ + " es_token: '$ESTOKEN'"\ " " >> $PILLARFILE } - # Add IDH Services info to the minion file function add_idh_to_minion() { printf '%s\n'\ "idh:"\ + " enabled: True"\ " restrict_management_ip: $IDH_MGTRESTRICT"\ " services:" >> "$PILLARFILE" IFS=',' read -ra IDH_SERVICES_ARRAY <<< "$IDH_SERVICES" @@ -164,6 +167,7 @@ function add_logstash_to_minion() { # Create the logstash advanced pillar printf '%s\n'\ "logstash:"\ + " enabled: True"\ " config:"\ " pipeline_x_workers: $CPUCORES"\ " settings:"\ @@ -180,7 +184,9 @@ function add_analyst_to_minion() { " gui:"\ " enabled: true"\ "sensoroni:"\ - " node_description: '${NODE_DESCRIPTION//\'/''}'" >> $PILLARFILE + " enabled: True"\ + " config:"\ + " node_description: '${NODE_DESCRIPTION//\'/''}'" >> $PILLARFILE } # Add basic host info to the minion file @@ -193,12 +199,25 @@ function add_host_to_minion() { # Add sensoroni specific information - Can we pull node_adrees from the host pillar? function add_sensoroni_to_minion() { - printf '%s\n'\ "sensoroni:"\ - " node_description: '${NODE_DESCRIPTION//\'/''}'"\ - " " >> $PILLARFILE -} + " enabled: True"\ + " config:"\ + " node_description: '${NODE_DESCRIPTION//\'/''}'"\ + " " >> $PILLARFILE +} + +# Add sensoroni specific information - Can we pull node_adrees from the host pillar? +function add_sensoroni_with_analyze_to_minion() { + printf '%s\n'\ + "sensoroni:"\ + " enabled: True"\ + " config:"\ + " analyze:"\ + " enabled: True"\ + " node_description: '${NODE_DESCRIPTION//\'/''}'"\ + " " >> $PILLARFILE +} # Sensor settings for the minion pillar function add_sensor_to_minion() { @@ -206,15 +225,140 @@ function add_sensor_to_minion() { echo " interface: '$INTERFACE'" >> $PILLARFILE echo " mtu: 9000" >> $PILLARFILE echo "zeek:" >> $PILLARFILE - echo " config:" >> $PILLARFILE - echo " node:" >> $PILLARFILE - echo " lb_procs: '$CORECOUNT'" >> $PILLARFILE + echo " enabled: True" >> $PILLARFILE + echo " config:" >> $PILLARFILE + echo " node:" >> $PILLARFILE + echo " lb_procs: '$CORECOUNT'" >> $PILLARFILE echo "suricata:" >> $PILLARFILE - echo " config:" >> $PILLARFILE - echo " af-packet:" >> $PILLARFILE - echo " threads: '$CORECOUNT'" >> $PILLARFILE + echo " config:" >> $PILLARFILE + echo " af-packet:" >> $PILLARFILE + echo " threads: '$CORECOUNT'" >> $PILLARFILE echo "pcap:" >> $PILLARFILE - echo " enabled: True" >> $PILLARFILE + echo " enabled: True" >> $PILLARFILE + echo " " >> $PILLARFILE +} + +function add_playbook_to_minion() { + printf '%s\n'\ + "playbook:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_elastalert_to_minion() { + printf '%s\n'\ + "elastalert:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_kibana_to_minion() { + printf '%s\n'\ + "kibana:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_redis_to_minion() { + printf '%s\n'\ + "redis:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_strelka_strelka_to_minion() { + printf '%s\n'\ + "strelka:"\ + " backend:"\ + " enabled: True"\ + " filestream:"\ + " enabled: True"\ + " frontend:"\ + " enabled: True"\ + " manager:"\ + " enabled: True"\ + " coordinator:"\ + " enabled: True"\ + " gatekeeper:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_curator_to_minion() { + printf '%s\n'\ + "curator:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_telegraf_to_minion() { + printf '%s\n'\ + "telegraf:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_influxdb_to_minion() { + printf '%s\n'\ + "influxdb:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_nginx_to_minion() { + printf '%s\n'\ + "nginx:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_soctopus_to_minion() { + printf '%s\n'\ + "soctopus:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_soc_to_minion() { + printf '%s\n'\ + "soc:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_registry_to_minion() { + printf '%s\n'\ + "registry:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_mysql_to_minion() { + printf '%s\n'\ + "mysql:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_kratos_to_minion() { + printf '%s\n'\ + "kratos:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_idstools_to_minion() { + printf '%s\n'\ + "idstools:"\ + " enabled: True"\ + " " >> $PILLARFILE +} + +function add_elastic_fleet_package_registry_to_minion() { + printf '%s\n'\ + "elastic_fleet_package_registry:"\ + " enabled: True"\ + " " >> $PILLARFILE } function create_fleet_policy() { @@ -261,9 +405,98 @@ function apply_ES_state() { salt-call state.apply elasticsearch concurrent=True } function createEVAL() { - add_elastic_to_minion + add_elasticsearch_to_minion + add_sensor_to_minion + add_strelka_strelka_to_minion + add_elastalert_to_minion + add_kibana_to_minion + add_curator_to_minion + add_telegraf_to_minion + add_influxdb_to_minion + add_nginx_to_minion + add_soctopus_to_minion + add_soc_to_minion + add_registry_to_minion + add_mysql_to_minion + add_kratos_to_minion + add_idstools_to_minion + add_elastic_fleet_package_registry_to_minion +} + +function createSTANDALONE() { + add_elasticsearch_to_minion add_logstash_to_minion add_sensor_to_minion + add_strelka_strelka_to_minion + add_playbook_to_minion + add_elastalert_to_minion + add_kibana_to_minion + add_redis_to_minion + add_curator_to_minion + add_telegraf_to_minion + add_influxdb_to_minion + add_nginx_to_minion + add_soctopus_to_minion + add_soc_to_minion + add_registry_to_minion + add_mysql_to_minion + add_kratos_to_minion + add_idstools_to_minion + add_elastic_fleet_package_registry_to_minion +} + +function createMANAGER() { + add_elasticsearch_to_minion + add_logstash_to_minion + add_playbook_to_minion + add_elastalert_to_minion + add_kibana_to_minion + add_redis_to_minion + add_curator_to_minion + add_telegraf_to_minion + add_influxdb_to_minion + add_nginx_to_minion + add_soctopus_to_minion + add_soc_to_minion + add_registry_to_minion + add_mysql_to_minion + add_kratos_to_minion + add_idstools_to_minion + add_elastic_fleet_package_registry_to_minion +} + +function createMANAGERSEARCH() { + add_elasticsearch_to_minion + add_logstash_to_minion + add_playbook_to_minion + add_elastalert_to_minion + add_kibana_to_minion + add_redis_to_minion + add_curator_to_minion + add_telegraf_to_minion + add_influxdb_to_minion + add_nginx_to_minion + add_soctopus_to_minion + add_soc_to_minion + add_registry_to_minion + add_mysql_to_minion + add_kratos_to_minion + add_idstools_to_minion + add_elastic_fleet_package_registry_to_minion +} + +function createIMPORT() { + add_elasticsearch_to_minion + add_sensor_to_minion + add_kibana_to_minion + add_telegraf_to_minion + add_influxdb_to_minion + add_nginx_to_minion + add_soc_to_minion + add_registry_to_minion + add_kratos_to_minion + add_idstools_to_minion + add_elastic_fleet_package_registry_to_minion } function createFLEET() { @@ -272,51 +505,46 @@ function createFLEET() { create_fleet_policy update_fleet_host_urls update_logstash_outputs + add_telegraf_to_minion + add_nginx_to_minion } function createIDH() { add_idh_to_minion -} - -function createIMPORT() { - add_elastic_to_minion - add_logstash_to_minion - add_sensor_to_minion + add_telegraf_to_minion } function createHEAVYNODE() { - add_elastic_to_minion + add_elasticsearch_to_minion add_logstash_to_minion add_sensor_to_minion -} - -function createMANAGER() { - add_elastic_to_minion - add_logstash_to_minion -} - -function createMANAGERSEARCH() { - add_elastic_to_minion - add_logstash_to_minion + add_strelka_strelka_to_minion + add_redis_to_minion + add_curator_to_minion + add_telegraf_to_minion } function createSENSOR() { add_sensor_to_minion + add_strelka_strelka_to_minion + add_telegraf_to_minion } function createSEARCHNODE() { - add_elastic_to_minion + add_elasticsearch_to_minion add_logstash_to_minion + add_telegraf_to_minion updateMine apply_ES_state } -function createSTANDALONE() { - add_elastic_to_minion +function createRECEIVER() { add_logstash_to_minion - add_sensor_to_minion + add_redis_to_minion + add_telegraf_to_minion } + function testConnection() { retry 15 3 "salt '$MINION_ID' test.ping" True local ret=$? @@ -354,7 +582,12 @@ if [[ "$OPERATION" = 'add' || "$OPERATION" = 'setup' ]]; then fi create_minion_files add_host_to_minion - add_sensoroni_to_minion + managers=("EVAL" "STANDALONE" "IMPORT" "MANAGER" "MANAGERSEARCH") + if echo "${managers[@]}" | grep -qw "$NODETYPE"; then + add_sensoroni_with_analyze_to_minion + else + add_sensoroni_to_minion + fi create$NODETYPE echo "Minion file created for $MINION_ID" fi diff --git a/salt/mysql/config.sls b/salt/mysql/config.sls new file mode 100644 index 000000000..d8788c7c9 --- /dev/null +++ b/salt/mysql/config.sls @@ -0,0 +1,93 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% set MYSQLPASS = salt['pillar.get']('secrets:mysql') %} + +# MySQL Setup +mysqlpkgs: + pkg.installed: + - skip_suggestions: False + - pkgs: + {% if grains['os'] != 'Rocky' %} + {% if grains['oscodename'] == 'bionic' %} + - python3-mysqldb + {% elif grains['oscodename'] == 'focal' %} + - python3-mysqldb + {% endif %} + {% else %} + - python3-mysqlclient + {% endif %} + +mysqletcdir: + file.directory: + - name: /opt/so/conf/mysql/etc + - user: 939 + - group: 939 + - makedirs: True + +mysqlpiddir: + file.directory: + - name: /opt/so/conf/mysql/pid + - user: 939 + - group: 939 + - makedirs: True + +mysqlcnf: + file.managed: + - name: /opt/so/conf/mysql/etc/my.cnf + - source: salt://mysql/etc/my.cnf + - user: 939 + - group: 939 + +mysqlpass: + file.managed: + - name: /opt/so/conf/mysql/etc/mypass + - source: salt://mysql/etc/mypass + - user: 939 + - group: 939 + - template: jinja + - defaults: + MYSQLPASS: {{ MYSQLPASS }} + +mysqllogdir: + file.directory: + - name: /opt/so/log/mysql + - user: 939 + - group: 939 + - makedirs: True + +mysqldatadir: + file.directory: + - name: /nsm/mysql + - user: 939 + - group: 939 + - makedirs: True + +mysql_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://mysql/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#mysql_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://mysql/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/mysql/defaults.yaml b/salt/mysql/defaults.yaml new file mode 100644 index 000000000..87d8cef25 --- /dev/null +++ b/salt/mysql/defaults.yaml @@ -0,0 +1,2 @@ +mysql: + enabled: False diff --git a/salt/mysql/disabled.sls b/salt/mysql/disabled.sls new file mode 100644 index 000000000..805a755e4 --- /dev/null +++ b/salt/mysql/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - mysql.sostatus + +so-mysql: + docker_container.absent: + - force: True + +so-mysql_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-mysql$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/mysql/enabled.sls b/salt/mysql/enabled.sls new file mode 100644 index 000000000..12112121f --- /dev/null +++ b/salt/mysql/enabled.sls @@ -0,0 +1,66 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% set MYSQLPASS = salt['pillar.get']('secrets:mysql') %} + +include: + - mysql.config + - mysql.sostatus + +{% if MYSQLPASS == None %} + +mysql_password_none: + test.configurable_test_state: + - changes: False + - result: False + - comment: "MySQL Password Error - Not Starting MySQL" + +{% else %} + +so-mysql: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-mysql:{{ GLOBALS.so_version }} + - hostname: so-mysql + - user: socore + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-mysql'].ip }} + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-mysql'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - environment: + - MYSQL_ROOT_HOST={{ GLOBALS.so_docker_bip }} + - MYSQL_ROOT_PASSWORD=/etc/mypass + - binds: + - /opt/so/conf/mysql/etc/my.cnf:/etc/my.cnf:ro + - /opt/so/conf/mysql/etc/mypass:/etc/mypass + - /nsm/mysql:/var/lib/mysql:rw + - /opt/so/log/mysql:/var/log/mysql:rw + - watch: + - /opt/so/conf/mysql/etc + - require: + - file: mysqlcnf + - file: mysqlpass +{% endif %} + +delete_so-mysql_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-mysql$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/mysql/init.sls b/salt/mysql/init.sls index 1c0ca70c0..48e4f558c 100644 --- a/salt/mysql/init.sls +++ b/salt/mysql/init.sls @@ -1,134 +1,14 @@ + # Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one # or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{%- set MYSQLPASS = salt['pillar.get']('secrets:mysql') %} - -# MySQL Setup -mysqlpkgs: - pkg.installed: - - skip_suggestions: False - - pkgs: - {% if grains['os'] != 'Rocky' %} - {% if grains['oscodename'] == 'bionic' %} - - python3-mysqldb - {% elif grains['oscodename'] == 'focal' %} - - python3-mysqldb - {% endif %} - {% else %} - - python3-mysqlclient - {% endif %} - -mysqletcdir: - file.directory: - - name: /opt/so/conf/mysql/etc - - user: 939 - - group: 939 - - makedirs: True - -mysqlpiddir: - file.directory: - - name: /opt/so/conf/mysql/pid - - user: 939 - - group: 939 - - makedirs: True - -mysqlcnf: - file.managed: - - name: /opt/so/conf/mysql/etc/my.cnf - - source: salt://mysql/etc/my.cnf - - user: 939 - - group: 939 - -mysqlpass: - file.managed: - - name: /opt/so/conf/mysql/etc/mypass - - source: salt://mysql/etc/mypass - - user: 939 - - group: 939 - - template: jinja - - defaults: - MYSQLPASS: {{ MYSQLPASS }} - -mysqllogdir: - file.directory: - - name: /opt/so/log/mysql - - user: 939 - - group: 939 - - makedirs: True - -mysqldatadir: - file.directory: - - name: /nsm/mysql - - user: 939 - - group: 939 - - makedirs: True - -mysql_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://mysql/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#mysql_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://mysql/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -{% if MYSQLPASS == None %} - -mysql_password_none: - test.configurable_test_state: - - changes: False - - result: False - - comment: "MySQL Password Error - Not Starting MySQL" +{% from 'mysql/map.jinja' import MYSQLMERGED %} +include: +{% if MYSQLMERGED.enabled %} + - mysql.enabled {% else %} - -so-mysql: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-mysql:{{ GLOBALS.so_version }} - - hostname: so-mysql - - user: socore - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-mysql'].ip }} - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-mysql'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - environment: - - MYSQL_ROOT_HOST={{ GLOBALS.so_docker_bip }} - - MYSQL_ROOT_PASSWORD=/etc/mypass - - binds: - - /opt/so/conf/mysql/etc/my.cnf:/etc/my.cnf:ro - - /opt/so/conf/mysql/etc/mypass:/etc/mypass - - /nsm/mysql:/var/lib/mysql:rw - - /opt/so/log/mysql:/var/log/mysql:rw - - watch: - - /opt/so/conf/mysql/etc - - require: - - file: mysqlcnf - - file: mysqlpass -{% endif %} - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - mysql.disabled {% endif %} diff --git a/salt/mysql/map.jinja b/salt/mysql/map.jinja new file mode 100644 index 000000000..dd9a6474e --- /dev/null +++ b/salt/mysql/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'mysql/defaults.yaml' as MYSQLDEFAULTS with context %} +{% set MYSQLMERGED = salt['pillar.get']('mysql', MYSQLDEFAULTS.mysql, merge=True) %} diff --git a/salt/mysql/soc_mysql.yaml b/salt/mysql/soc_mysql.yaml new file mode 100644 index 000000000..4be816d90 --- /dev/null +++ b/salt/mysql/soc_mysql.yaml @@ -0,0 +1,4 @@ +mysql: + enabled: + description: You can enable or disable MySQL. + advanced: True diff --git a/salt/mysql/sostatus.sls b/salt/mysql/sostatus.sls new file mode 100644 index 000000000..2f5dbba06 --- /dev/null +++ b/salt/mysql/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-mysql_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-mysql + - unless: grep -q so-mysql /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/nginx/config.map.jinja b/salt/nginx/config.map.jinja deleted file mode 100644 index 10121c7a8..000000000 --- a/salt/nginx/config.map.jinja +++ /dev/null @@ -1,3 +0,0 @@ -{% import_yaml 'nginx/defaults.yaml' as NGDEFAULTS %} - -{% set NGMERGED = salt['pillar.get']('nginx', NGDEFAULTS.nginx, merge=True) %} diff --git a/salt/nginx/config.sls b/salt/nginx/config.sls new file mode 100644 index 000000000..50ccfae16 --- /dev/null +++ b/salt/nginx/config.sls @@ -0,0 +1,103 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - ssl + +# Drop the correct nginx config based on role +nginxconfdir: + file.directory: + - name: /opt/so/conf/nginx + - user: 939 + - group: 939 + - makedirs: True + +nginxconf: + file.managed: + - name: /opt/so/conf/nginx/nginx.conf + - user: 939 + - group: 939 + - template: jinja + - source: salt://nginx/etc/nginx.conf + - show_changes: False + +nginxlogdir: + file.directory: + - name: /opt/so/log/nginx/ + - user: 939 + - group: 939 + - makedirs: True + +nginxtmp: + file.directory: + - name: /opt/so/tmp/nginx/tmp + - user: 939 + - group: 939 + - makedirs: True + +navigatorconfig: + file.managed: + - name: /opt/so/conf/navigator/navigator_config.json + - source: salt://nginx/files/navigator_config.json + - user: 939 + - group: 939 + - makedirs: True + - template: jinja + +navigatordefaultlayer: + file.managed: + - name: /opt/so/conf/navigator/nav_layer_playbook.json + - source: salt://nginx/files/nav_layer_playbook.json + - user: 939 + - group: 939 + - makedirs: True + - replace: False + - template: jinja + +navigatorpreattack: + file.managed: + - name: /opt/so/conf/navigator/pre-attack.json + - source: salt://nginx/files/pre-attack.json + - user: 939 + - group: 939 + - makedirs: True + - replace: False + +navigatorenterpriseattack: + file.managed: + - name: /opt/so/conf/navigator/enterprise-attack.json + - source: salt://nginx/files/enterprise-attack.json + - user: 939 + - group: 939 + - makedirs: True + - replace: False + +nginx_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://nginx/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#nginx_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://nginx/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/nginx/defaults.yaml b/salt/nginx/defaults.yaml index 0e222c29e..c82d6b5df 100644 --- a/salt/nginx/defaults.yaml +++ b/salt/nginx/defaults.yaml @@ -1,5 +1,6 @@ nginx: - config: - replace_cert: False - throttle_login_burst: 6 - throttle_login_rate: 10 \ No newline at end of file + enabled: False + config: + replace_cert: False + throttle_login_burst: 6 + throttle_login_rate: 10 diff --git a/salt/nginx/disabled.sls b/salt/nginx/disabled.sls new file mode 100644 index 000000000..1e94a7a3b --- /dev/null +++ b/salt/nginx/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - nginx.sostatus + +so-nginx: + docker_container.absent: + - force: True + +so-nginx_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-nginx$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/nginx/enabled.sls b/salt/nginx/enabled.sls new file mode 100644 index 000000000..592388cf6 --- /dev/null +++ b/salt/nginx/enabled.sls @@ -0,0 +1,69 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - nginx.config + - nginx.sostatus + +so-nginx: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-nginx:{{ GLOBALS.so_version }} + - hostname: so-nginx + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-nginx'].ip }} + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - binds: + - /opt/so/conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro + - /opt/so/log/nginx/:/var/log/nginx:rw + - /opt/so/tmp/nginx/:/var/lib/nginx:rw + - /opt/so/tmp/nginx/:/run:rw + - /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/:/opt/socore/html/packages + - /nsm/elastic-fleet/artifacts/:/opt/socore/html/artifacts + {% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} + - /etc/pki/managerssl.crt:/etc/pki/nginx/server.crt:ro + - /etc/pki/managerssl.key:/etc/pki/nginx/server.key:ro + # ATT&CK Navigator binds + - /opt/so/conf/navigator/navigator_config.json:/opt/socore/html/navigator/assets/config.json:ro + - /opt/so/conf/navigator/nav_layer_playbook.json:/opt/socore/html/navigator/assets/playbook.json:ro + - /opt/so/conf/navigator/enterprise-attack.json:/opt/socore/html/navigator/assets/enterprise-attack.json:ro + - /opt/so/conf/navigator/pre-attack.json:/opt/socore/html/navigator/assets/pre-attack.json:ro + - /nsm/repo:/opt/socore/html/repo:ro + {% endif %} + - cap_add: NET_BIND_SERVICE + - port_bindings: + {% for BINDING in DOCKER.containers['so-nginx'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - watch: + - file: nginxconf + - file: nginxconfdir + - require: + - file: nginxconf + {% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} + - x509: managerssl_key + - x509: managerssl_crt + - file: navigatorconfig + - file: navigatordefaultlayer + {% endif %} + +delete_so-nginx_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-nginx$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index f2525b6a9..7a8a24a1f 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -1,6 +1,6 @@ {%- from 'vars/globals.map.jinja' import GLOBALS %} {%- from 'docker/docker.map.jinja' import DOCKER %} -{%- from 'nginx/config.map.jinja' import NGMERGED %} +{%- from 'nginx/map.jinja' import NGINXMERGED %} {%- set role = grains.id.split('_') | last %} {%- set influxpass = salt['pillar.get']('secrets:influx_pass') %} {%- set influxauth = ('so:' + influxpass) | base64_encode %} @@ -34,7 +34,7 @@ http { include /etc/nginx/mime.types; default_type application/octet-stream; - limit_req_zone $binary_remote_addr zone=auth_throttle:10m rate={{ NGMERGED.config.throttle_login_rate }}r/m; + limit_req_zone $binary_remote_addr zone=auth_throttle:10m rate={{ NGINXMERGED.config.throttle_login_rate }}r/m; include /etc/nginx/conf.d/*.conf; @@ -148,7 +148,7 @@ http { location ~ ^/auth/.*?(login) { rewrite /auth/(.*) /$1 break; - limit_req zone=auth_throttle burst={{ NGMERGED.config.throttle_login_burst }} nodelay; + limit_req zone=auth_throttle burst={{ NGINXMERGED.config.throttle_login_burst }} nodelay; limit_req_status 429; proxy_pass http://{{ GLOBALS.manager }}:4433; proxy_read_timeout 90; @@ -306,7 +306,7 @@ http { } location @error429 { - return 302 /login/?thr={{ (120 / NGMERGED.config.throttle_login_rate) | round | int }}; + return 302 /login/?thr={{ (120 / NGINXMERGED.config.throttle_login_rate) | round | int }}; } error_page 500 502 503 504 /50x.html; diff --git a/salt/nginx/init.sls b/salt/nginx/init.sls index 3551c2920..9869aa5d7 100644 --- a/salt/nginx/init.sls +++ b/salt/nginx/init.sls @@ -1,150 +1,13 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'nginx/config.map.jinja' import NGMERGED %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'nginx/map.jinja' import NGINXMERGED %} include: - - ssl - -# Drop the correct nginx config based on role -nginxconfdir: - file.directory: - - name: /opt/so/conf/nginx - - user: 939 - - group: 939 - - makedirs: True - -nginxconf: - file.managed: - - name: /opt/so/conf/nginx/nginx.conf - - user: 939 - - group: 939 - - template: jinja - - source: salt://nginx/etc/nginx.conf - - show_changes: False - -nginxlogdir: - file.directory: - - name: /opt/so/log/nginx/ - - user: 939 - - group: 939 - - makedirs: True - -nginxtmp: - file.directory: - - name: /opt/so/tmp/nginx/tmp - - user: 939 - - group: 939 - - makedirs: True - -navigatorconfig: - file.managed: - - name: /opt/so/conf/navigator/navigator_config.json - - source: salt://nginx/files/navigator_config.json - - user: 939 - - group: 939 - - makedirs: True - - template: jinja - -navigatordefaultlayer: - file.managed: - - name: /opt/so/conf/navigator/nav_layer_playbook.json - - source: salt://nginx/files/nav_layer_playbook.json - - user: 939 - - group: 939 - - makedirs: True - - replace: False - - template: jinja - -navigatorpreattack: - file.managed: - - name: /opt/so/conf/navigator/pre-attack.json - - source: salt://nginx/files/pre-attack.json - - user: 939 - - group: 939 - - makedirs: True - - replace: False - -navigatorenterpriseattack: - file.managed: - - name: /opt/so/conf/navigator/enterprise-attack.json - - source: salt://nginx/files/enterprise-attack.json - - user: 939 - - group: 939 - - makedirs: True - - replace: False - -nginx_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://nginx/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#nginx_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://nginx/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -so-nginx: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-nginx:{{ GLOBALS.so_version }} - - hostname: so-nginx - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-nginx'].ip }} - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - binds: - - /opt/so/conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro - - /opt/so/log/nginx/:/var/log/nginx:rw - - /opt/so/tmp/nginx/:/var/lib/nginx:rw - - /opt/so/tmp/nginx/:/run:rw - - /opt/so/saltstack/local/salt/elasticfleet/files/so_agent-installers/:/opt/socore/html/packages - - /nsm/elastic-fleet/artifacts/:/opt/socore/html/artifacts - {% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} - - /etc/pki/managerssl.crt:/etc/pki/nginx/server.crt:ro - - /etc/pki/managerssl.key:/etc/pki/nginx/server.key:ro - # ATT&CK Navigator binds - - /opt/so/conf/navigator/navigator_config.json:/opt/socore/html/navigator/assets/config.json:ro - - /opt/so/conf/navigator/nav_layer_playbook.json:/opt/socore/html/navigator/assets/playbook.json:ro - - /opt/so/conf/navigator/enterprise-attack.json:/opt/socore/html/navigator/assets/enterprise-attack.json:ro - - /opt/so/conf/navigator/pre-attack.json:/opt/socore/html/navigator/assets/pre-attack.json:ro - - /nsm/repo:/opt/socore/html/repo:ro - - {% endif %} - - cap_add: NET_BIND_SERVICE - - port_bindings: - {% for BINDING in DOCKER.containers['so-nginx'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - watch: - - file: nginxconf - - file: nginxconfdir - - require: - - file: nginxconf - {% if grains.role in ['so-manager', 'so-managersearch', 'so-eval', 'so-standalone', 'so-import'] %} - - x509: managerssl_key - - x509: managerssl_crt - - file: navigatorconfig - - file: navigatordefaultlayer - {% endif %} - -append_so-nginx_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-nginx - +{% if NGINXMERGED.enabled %} + - nginx.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - nginx.disabled {% endif %} diff --git a/salt/nginx/map.jinja b/salt/nginx/map.jinja new file mode 100644 index 000000000..cf2812c5e --- /dev/null +++ b/salt/nginx/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'nginx/defaults.yaml' as NGINXDEFAULTS %} +{% set NGINXMERGED = salt['pillar.get']('nginx', NGINXDEFAULTS.nginx, merge=True) %} diff --git a/salt/nginx/soc_nginx.yaml b/salt/nginx/soc_nginx.yaml index b18e83f42..8b362a538 100644 --- a/salt/nginx/soc_nginx.yaml +++ b/salt/nginx/soc_nginx.yaml @@ -1,4 +1,8 @@ nginx: + enabled: + description: You can enable or disable Nginx. + advanced: True + helpLink: nginx.html config: replace_cert: description: Enable this if you would like to replace the Security Onion Certificate with your own. diff --git a/salt/nginx/sostatus.sls b/salt/nginx/sostatus.sls new file mode 100644 index 000000000..bea5757fa --- /dev/null +++ b/salt/nginx/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-nginx_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-nginx + - unless: grep -q so-nginx /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/pcap/config.map.jinja b/salt/pcap/config.map.jinja index f335c9380..7ed500f25 100644 --- a/salt/pcap/config.map.jinja +++ b/salt/pcap/config.map.jinja @@ -1,3 +1,7 @@ -{% import_yaml 'pcap/defaults.yaml' as pcap_defaults with context %} -{% set pcap_pillar = pillar.pcap %} -{% set PCAPMERGED = salt['defaults.merge'](pcap_defaults, pcap_pillar, in_place=False) %} +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'pcap/defaults.yaml' as PCAPDEFAULTS %} +{% set PCAPMERGED = salt['pillar.get']('pcap', PCAPDEFAULTS.pcap, merge=True) %} diff --git a/salt/pcap/config.sls b/salt/pcap/config.sls new file mode 100644 index 000000000..26236e2ff --- /dev/null +++ b/salt/pcap/config.sls @@ -0,0 +1,116 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from "pcap/config.map.jinja" import PCAPMERGED %} +{% from 'bpf/pcap.map.jinja' import PCAPBPF %} + +{% set BPF_COMPILED = "" %} + +# PCAP Section + +stenographergroup: + group.present: + - name: stenographer + - gid: 941 + +stenographer: + user.present: + - uid: 941 + - gid: 941 + - home: /opt/so/conf/steno + +stenoconfdir: + file.directory: + - name: /opt/so/conf/steno + - user: 941 + - group: 939 + - makedirs: True + +pcap_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://pcap/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +{% if PCAPBPF %} + {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %} + {% if BPF_CALC['stderr'] == "" %} + {% set BPF_COMPILED = ",\\\"--filter=" + BPF_CALC['stdout'] + "\\\"" %} + {% else %} + +bpfcompilationfailure: + test.configurable_test_state: + - changes: False + - result: False + - comment: "BPF Compilation Failed - Discarding Specified BPF" + {% endif %} +{% endif %} + +stenoconf: + file.managed: + - name: /opt/so/conf/steno/config + - source: salt://pcap/files/config.jinja + - user: stenographer + - group: stenographer + - mode: 644 + - template: jinja + - defaults: + PCAPMERGED: {{ PCAPMERGED }} + BPF_COMPILED: "{{ BPF_COMPILED }}" + +stenoca: + file.directory: + - name: /opt/so/conf/steno/certs + - user: 941 + - group: 939 + +pcapdir: + file.directory: + - name: /nsm/pcap + - user: 941 + - group: 941 + - makedirs: True + +pcaptmpdir: + file.directory: + - name: /nsm/pcaptmp + - user: 941 + - group: 941 + - makedirs: True + +pcapoutdir: + file.directory: + - name: /nsm/pcapout + - user: 939 + - group: 939 + - makedirs: True + +pcapindexdir: + file.directory: + - name: /nsm/pcapindex + - user: 941 + - group: 941 + - makedirs: True + +stenolog: + file.directory: + - name: /opt/so/log/stenographer + - user: 941 + - group: 941 + - makedirs: True + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/pcap/defaults.yaml b/salt/pcap/defaults.yaml index 701cde04d..62c60e118 100644 --- a/salt/pcap/defaults.yaml +++ b/salt/pcap/defaults.yaml @@ -1,11 +1,11 @@ pcap: - enabled: True - config: - maxdirectoryfiles: 30000 - diskfreepercentage: 10 - blocks: 2048 - preallocate_file_mb: 4096 - aiops: 128 - pin_to_cpu: False - cpus_to_pin_to: [] - disks: [] \ No newline at end of file + enabled: False + config: + maxdirectoryfiles: 30000 + diskfreepercentage: 10 + blocks: 2048 + preallocate_file_mb: 4096 + aiops: 128 + pin_to_cpu: False + cpus_to_pin_to: [] + disks: [] diff --git a/salt/pcap/disabled.sls b/salt/pcap/disabled.sls new file mode 100644 index 000000000..5643fc870 --- /dev/null +++ b/salt/pcap/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - pcap.sostatus + +so-steno: + docker_container.absent: + - force: True + +so-steno_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-steno$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/pcap/enabled.sls b/salt/pcap/enabled.sls new file mode 100644 index 000000000..b4027065f --- /dev/null +++ b/salt/pcap/enabled.sls @@ -0,0 +1,43 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - pcap.config + - pcap.sostatus + +so-steno: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-steno:{{ GLOBALS.so_version }} + - start: True + - network_mode: host + - privileged: True + - binds: + - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw + - /opt/so/conf/steno/config:/etc/stenographer/config:rw + - /nsm/pcap:/nsm/pcap:rw + - /nsm/pcapindex:/nsm/pcapindex:rw + - /nsm/pcaptmp:/tmp:rw + - /opt/so/log/stenographer:/var/log/stenographer:rw + - watch: + - file: stenoconf + - require: + - file: stenoconf + +delete_so-steno_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-steno$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/pcap/files/config.jinja b/salt/pcap/files/config.jinja index 420d12639..f0a4fc51d 100644 --- a/salt/pcap/files/config.jinja +++ b/salt/pcap/files/config.jinja @@ -1,11 +1,11 @@ { "Threads": [ - { "PacketsDirectory": "/nsm/pcap", "IndexDirectory": "/nsm/pcapindex", "MaxDirectoryFiles": {{ PCAPMERGED.pcap.config.maxdirectoryfiles }}, "DiskFreePercentage": {{ PCAPMERGED.pcap.config.diskfreepercentage }} } + { "PacketsDirectory": "/nsm/pcap", "IndexDirectory": "/nsm/pcapindex", "MaxDirectoryFiles": {{ PCAPMERGED.config.maxdirectoryfiles }}, "DiskFreePercentage": {{ PCAPMERGED.config.diskfreepercentage }} } ] , "StenotypePath": "/usr/bin/stenotype" , "Interface": "{{ pillar.sensor.interface }}" , "Port": 1234 , "Host": "127.0.0.1" - , "Flags": ["-v", "--blocks={{ PCAPMERGED.pcap.config.blocks }}", "--preallocate_file_mb={{ PCAPMERGED.pcap.config.preallocate_file_mb }}", "--aiops={{ PCAPMERGED.pcap.config.aiops }}", "--uid=stenographer", "--gid=stenographer"{{ BPF_COMPILED }}] + , "Flags": ["-v", "--blocks={{ PCAPMERGED.config.blocks }}", "--preallocate_file_mb={{ PCAPMERGED.config.preallocate_file_mb }}", "--aiops={{ PCAPMERGED.config.aiops }}", "--uid=stenographer", "--gid=stenographer"{{ BPF_COMPILED }}] , "CertPath": "/etc/stenographer/certs" } diff --git a/salt/pcap/init.sls b/salt/pcap/init.sls index d71a9b1dd..9de272ad7 100644 --- a/salt/pcap/init.sls +++ b/salt/pcap/init.sls @@ -3,164 +3,15 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} - {% from 'vars/globals.map.jinja' import GLOBALS %} -{% from "pcap/map.jinja" import STENOOPTIONS with context %} -{% from "pcap/config.map.jinja" import PCAPMERGED with context %} -{% from 'bpf/pcap.map.jinja' import PCAPBPF %} - -{% set BPF_COMPILED = "" %} - -# PCAP Section - -stenographergroup: - group.present: - - name: stenographer - - gid: 941 - -stenographer: - user.present: - - uid: 941 - - gid: 941 - - home: /opt/so/conf/steno - -stenoconfdir: - file.directory: - - name: /opt/so/conf/steno - - user: 941 - - group: 939 - - makedirs: True - -pcap_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://pcap/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#pcap_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://pcap/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -{% if PCAPBPF %} - {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %} - {% if BPF_CALC['stderr'] == "" %} - {% set BPF_COMPILED = ",\\\"--filter=" + BPF_CALC['stdout'] + "\\\"" %} - {% else %} - -bpfcompilationfailure: - test.configurable_test_state: - - changes: False - - result: False - - comment: "BPF Compilation Failed - Discarding Specified BPF" - {% endif %} -{% endif %} - -stenoconf: - file.managed: - - name: /opt/so/conf/steno/config - - source: salt://pcap/files/config.jinja - - user: stenographer - - group: stenographer - - mode: 644 - - template: jinja - - defaults: - PCAPMERGED: {{ PCAPMERGED }} - BPF_COMPILED: "{{ BPF_COMPILED }}" - -stenoca: - file.directory: - - name: /opt/so/conf/steno/certs - - user: 941 - - group: 939 - -pcapdir: - file.directory: - - name: /nsm/pcap - - user: 941 - - group: 941 - - makedirs: True - -pcaptmpdir: - file.directory: - - name: /nsm/pcaptmp - - user: 941 - - group: 941 - - makedirs: True - -pcapoutdir: - file.directory: - - name: /nsm/pcapout - - user: 939 - - group: 939 - - makedirs: True - -pcapindexdir: - file.directory: - - name: /nsm/pcapindex - - user: 941 - - group: 941 - - makedirs: True - -stenolog: - file.directory: - - name: /opt/so/log/stenographer - - user: 941 - - group: 941 - - makedirs: True - -so-steno: - docker_container.{{ STENOOPTIONS.status }}: - {% if STENOOPTIONS.status == 'running' %} - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-steno:{{ GLOBALS.so_version }} - - start: {{ STENOOPTIONS.start }} - - network_mode: host - - privileged: True - - binds: - - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw - - /opt/so/conf/steno/config:/etc/stenographer/config:rw - - /nsm/pcap:/nsm/pcap:rw - - /nsm/pcapindex:/nsm/pcapindex:rw - - /nsm/pcaptmp:/tmp:rw - - /opt/so/log/stenographer:/var/log/stenographer:rw - - watch: - - file: stenoconf - - require: - - file: stenoconf - {% else %} {# if stenographer isn't enabled, then stop and remove the container #} - - force: True - {% endif %} - -append_so-steno_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-steno - - unless: grep -q so-steno /opt/so/conf/so-status/so-status.conf - - {% if not STENOOPTIONS.start %} -so-steno_so-status.disabled: - file.comment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-steno$ - {% else %} -delete_so-steno_so-status.disabled: - file.uncomment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-steno$ - {% endif %} +{% from 'pcap/config.map.jinja' import PCAPMERGED %} +include: +{% if PCAPMERGED.enabled and GLOBALS.role != 'so-import'%} + - pcap.enabled +{% elif GLOBALS.role == 'so-import' %} + - pcap.config + - pcap.disabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - pcap.disabled {% endif %} diff --git a/salt/pcap/map.jinja b/salt/pcap/map.jinja deleted file mode 100644 index ee939a0b4..000000000 --- a/salt/pcap/map.jinja +++ /dev/null @@ -1,11 +0,0 @@ -{% set STENOOPTIONS = {} %} -{% set ENABLED = salt['pillar.get']('steno:enabled', 'True') %} - -# don't start the docker container if it is an import node or disabled via pillar -{% if grains.id.split('_')|last == 'import' or ENABLED is sameas false %} - {% do STENOOPTIONS.update({'start': False}) %} - {% do STENOOPTIONS.update({'status': 'absent'}) %} -{% else %} - {% do STENOOPTIONS.update({'start': True}) %} - {% do STENOOPTIONS.update({'status': 'running'}) %} -{% endif %} diff --git a/salt/pcap/sostatus.sls b/salt/pcap/sostatus.sls new file mode 100644 index 000000000..4eebbfb0e --- /dev/null +++ b/salt/pcap/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-steno_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-steno + - unless: grep -q so-steno /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/playbook/config.sls b/salt/playbook/config.sls new file mode 100644 index 000000000..9c8444a56 --- /dev/null +++ b/salt/playbook/config.sls @@ -0,0 +1,112 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% set MYSQLPASS = salt['pillar.get']('secrets:mysql') %} +{% set PLAYBOOKPASS = salt['pillar.get']('secrets:playbook_db') %} + + +include: + - mysql + +create_playbookdbuser: + mysql_user.present: + - name: playbookdbuser + - password: {{ PLAYBOOKPASS }} + - host: "{{ DOCKER.sorange.split('/')[0] }}/255.255.255.0" + - connection_host: {{ GLOBALS.manager }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + +query_playbookdbuser_grants: + mysql_query.run: + - database: playbook + - query: "GRANT ALL ON playbook.* TO 'playbookdbuser'@'{{ DOCKER.sorange.split('/')[0] }}/255.255.255.0';" + - connection_host: {{ GLOBALS.manager }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + +query_updatwebhooks: + mysql_query.run: + - database: playbook + - query: "update webhooks set url = 'http://{{ GLOBALS.manager_ip}}:7000/playbook/webhook' where project_id = 1" + - connection_host: {{ GLOBALS.manager }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + +query_updatename: + mysql_query.run: + - database: playbook + - query: "update custom_fields set name = 'Custom Filter' where id = 21;" + - connection_host: {{ GLOBALS.manager }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + +query_updatepluginurls: + mysql_query.run: + - database: playbook + - query: |- + update settings set value = + "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess + project: '1' + convert_url: http://{{ GLOBALS.manager }}:7000/playbook/sigmac + create_url: http://{{ GLOBALS.manager }}:7000/playbook/play" + where id = 43 + - connection_host: {{ GLOBALS.manager }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + +playbook_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://playbook/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#playbook_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://playbook/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +playbooklogdir: + file.directory: + - name: /opt/so/log/playbook + - dir_mode: 775 + - user: 939 + - group: 939 + - makedirs: True + +{% if 'idh' in salt['cmd.shell']("ls /opt/so/saltstack/local/pillar/minions/|awk -F'_' {'print $2'}|awk -F'.' {'print $1'}").split() %} +idh-plays: + file.recurse: + - name: /opt/so/conf/soctopus/sigma-import + - source: salt://idh/plays + - makedirs: True + cmd.run: + - name: so-playbook-import True + - onchanges: + - file: /opt/so/conf/soctopus/sigma-import +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/playbook/defaults.yaml b/salt/playbook/defaults.yaml new file mode 100644 index 000000000..e75ec6a3c --- /dev/null +++ b/salt/playbook/defaults.yaml @@ -0,0 +1,2 @@ +playbook: + enabled: False diff --git a/salt/playbook/disabled.sls b/salt/playbook/disabled.sls new file mode 100644 index 000000000..c8c876cfb --- /dev/null +++ b/salt/playbook/disabled.sls @@ -0,0 +1,37 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - playbook.sostatus + +so-playbook: + docker_container.absent: + - force: True + +so-playbook_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-playbook$ + +so-playbook-sync_cron: + cron.absent: + - identifier: so-playbook-sync_cron + - user: root + +so-playbook-ruleupdate_cron: + cron.absent: + - identifier: so-playbook-ruleupdate_cron + - user: root + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/playbook/enabled.sls b/salt/playbook/enabled.sls new file mode 100644 index 000000000..22da3c0ff --- /dev/null +++ b/salt/playbook/enabled.sls @@ -0,0 +1,77 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% set PLAYBOOKPASS = salt['pillar.get']('secrets:playbook_db') %} + +include: + - playbook.config + - playbook.sostatus + +{% if PLAYBOOKPASS == None %} + +playbook_password_none: + test.configurable_test_state: + - changes: False + - result: False + - comment: "Playbook MySQL Password Error - Not Starting Playbook" + +{% else %} + +so-playbook: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-playbook:{{ GLOBALS.so_version }} + - hostname: playbook + - name: so-playbook + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-playbook'].ip }} + - binds: + - /opt/so/log/playbook:/playbook/log:rw + - extra_hosts: + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - environment: + - REDMINE_DB_MYSQL={{ GLOBALS.manager }} + - REDMINE_DB_DATABASE=playbook + - REDMINE_DB_USERNAME=playbookdbuser + - REDMINE_DB_PASSWORD={{ PLAYBOOKPASS }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-playbook'].port_bindings %} + - {{ BINDING }} + {% endfor %} + +delete_so-playbook_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-playbook$ + +so-playbook-sync_cron: + cron.present: + - name: /usr/sbin/so-playbook-sync > /opt/so/log/playbook/sync.log 2>&1 + - identifier: so-playbook-sync_cron + - user: root + - minute: '*/5' + +so-playbook-ruleupdate_cron: + cron.present: + - name: /usr/sbin/so-playbook-ruleupdate > /opt/so/log/playbook/update.log 2>&1 + - identifier: so-playbook-ruleupdate_cron + - user: root + - minute: '1' + - hour: '6' + +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/playbook/init.sls b/salt/playbook/init.sls index 930c3b9ec..f8395f7b2 100644 --- a/salt/playbook/init.sls +++ b/salt/playbook/init.sls @@ -3,164 +3,12 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} {% from 'vars/globals.map.jinja' import GLOBALS %} -{%- set MYSQLPASS = salt['pillar.get']('secrets:mysql') -%} -{%- set PLAYBOOKPASS = salt['pillar.get']('secrets:playbook_db') -%} - +{% from 'playbook/map.jinja' import PLAYBOOKMERGED %} include: - - mysql - -create_playbookdbuser: - mysql_user.present: - - name: playbookdbuser - - password: {{ PLAYBOOKPASS }} - - host: "{{ DOCKER.sorange.split('/')[0] }}/255.255.255.0" - - connection_host: {{ GLOBALS.manager }} - - connection_port: 3306 - - connection_user: root - - connection_pass: {{ MYSQLPASS }} - -query_playbookdbuser_grants: - mysql_query.run: - - database: playbook - - query: "GRANT ALL ON playbook.* TO 'playbookdbuser'@'{{ DOCKER.sorange.split('/')[0] }}/255.255.255.0';" - - connection_host: {{ GLOBALS.manager }} - - connection_port: 3306 - - connection_user: root - - connection_pass: {{ MYSQLPASS }} - -query_updatwebhooks: - mysql_query.run: - - database: playbook - - query: "update webhooks set url = 'http://{{ GLOBALS.manager_ip}}:7000/playbook/webhook' where project_id = 1" - - connection_host: {{ GLOBALS.manager }} - - connection_port: 3306 - - connection_user: root - - connection_pass: {{ MYSQLPASS }} - -query_updatename: - mysql_query.run: - - database: playbook - - query: "update custom_fields set name = 'Custom Filter' where id = 21;" - - connection_host: {{ GLOBALS.manager }} - - connection_port: 3306 - - connection_user: root - - connection_pass: {{ MYSQLPASS }} - -query_updatepluginurls: - mysql_query.run: - - database: playbook - - query: |- - update settings set value = - "--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess - project: '1' - convert_url: http://{{ GLOBALS.manager }}:7000/playbook/sigmac - create_url: http://{{ GLOBALS.manager }}:7000/playbook/play" - where id = 43 - - connection_host: {{ GLOBALS.manager }} - - connection_port: 3306 - - connection_user: root - - connection_pass: {{ MYSQLPASS }} - -playbook_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://playbook/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#playbook_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://playbook/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -playbooklogdir: - file.directory: - - name: /opt/so/log/playbook - - dir_mode: 775 - - user: 939 - - group: 939 - - makedirs: True - -{% if PLAYBOOKPASS == None %} - -playbook_password_none: - test.configurable_test_state: - - changes: False - - result: False - - comment: "Playbook MySQL Password Error - Not Starting Playbook" - +{% if PLAYBOOKMERGED.enabled %} + - playbook.enabled {% else %} - -so-playbook: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-playbook:{{ GLOBALS.so_version }} - - hostname: playbook - - name: so-playbook - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-playbook'].ip }} - - binds: - - /opt/so/log/playbook:/playbook/log:rw - - extra_hosts: - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - environment: - - REDMINE_DB_MYSQL={{ GLOBALS.manager }} - - REDMINE_DB_DATABASE=playbook - - REDMINE_DB_USERNAME=playbookdbuser - - REDMINE_DB_PASSWORD={{ PLAYBOOKPASS }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-playbook'].port_bindings %} - - {{ BINDING }} - {% endfor %} - -append_so-playbook_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-playbook - -{% endif %} - -so-playbook-sync_cron: - cron.present: - - name: /usr/sbin/so-playbook-sync > /opt/so/log/playbook/sync.log 2>&1 - - identifier: so-playbook-sync_cron - - user: root - - minute: '*/5' - -so-playbook-ruleupdate_cron: - cron.present: - - name: /usr/sbin/so-playbook-ruleupdate > /opt/so/log/playbook/update.log 2>&1 - - identifier: so-playbook-ruleupdate_cron - - user: root - - minute: '1' - - hour: '6' - -{% if 'idh' in salt['cmd.shell']("ls /opt/so/saltstack/local/pillar/minions/|awk -F'_' {'print $2'}|awk -F'.' {'print $1'}").split() %} -idh-plays: - file.recurse: - - name: /opt/so/conf/soctopus/sigma-import - - source: salt://idh/plays - - makedirs: True - cmd.run: - - name: so-playbook-import True - - onchanges: - - file: /opt/so/conf/soctopus/sigma-import -{% endif %} - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - playbook.disabled {% endif %} diff --git a/salt/playbook/map.jinja b/salt/playbook/map.jinja new file mode 100644 index 000000000..0ee058c68 --- /dev/null +++ b/salt/playbook/map.jinja @@ -0,0 +1,2 @@ +{% import_yaml 'playbook/defaults.yaml' as PLAYBOOKDEFAULTS %} +{% set PLAYBOOKMERGED = salt['pillar.get']('playbook', PLAYBOOKDEFAULTS.playbook, merge=True) %} diff --git a/salt/playbook/soc_playbook.yaml b/salt/playbook/soc_playbook.yaml new file mode 100644 index 000000000..e07ae8653 --- /dev/null +++ b/salt/playbook/soc_playbook.yaml @@ -0,0 +1,4 @@ +playbook: + enabled: + description: You can enable or disable Playbook. + helpLink: playbook.html diff --git a/salt/playbook/sostatus.sls b/salt/playbook/sostatus.sls new file mode 100644 index 000000000..f635746d3 --- /dev/null +++ b/salt/playbook/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-playbook_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-playbook + - unless: grep -q so-playbook /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/redis/config.sls b/salt/redis/config.sls new file mode 100644 index 000000000..d698040f8 --- /dev/null +++ b/salt/redis/config.sls @@ -0,0 +1,68 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'redis/map.jinja' import REDISMERGED %} + +include: + - ssl + +# Redis Setup +redisconfdir: + file.directory: + - name: /opt/so/conf/redis/etc + - user: 939 + - group: 939 + - makedirs: True + +redisworkdir: + file.directory: + - name: /opt/so/conf/redis/working + - user: 939 + - group: 939 + - makedirs: True + +redislogdir: + file.directory: + - name: /opt/so/log/redis + - user: 939 + - group: 939 + - makedirs: True + +redisconf: + file.managed: + - name: /opt/so/conf/redis/etc/redis.conf + - source: salt://redis/etc/redis.conf.jinja + - user: 939 + - group: 939 + - template: jinja + - defaults: + REDISMERGED: {{ REDISMERGED }} + +redis_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://redis/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +redis_sbin_jinja: + file.recurse: + - name: /usr/sbin + - source: salt://redis/tools/sbin_jinja + - user: 939 + - group: 939 + - file_mode: 755 + - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/redis/defaults.yaml b/salt/redis/defaults.yaml index ede78ad6b..913ebe7a0 100644 --- a/salt/redis/defaults.yaml +++ b/salt/redis/defaults.yaml @@ -1,4 +1,5 @@ redis: + enabled: False config: bind: '0.0.0.0' protected-mode: 'yes' diff --git a/salt/redis/disabled.sls b/salt/redis/disabled.sls new file mode 100644 index 000000000..09cb9f1fd --- /dev/null +++ b/salt/redis/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - redis.sostatus + +so-redis: + docker_container.absent: + - force: True + +so-redis_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-redis$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/redis/enabled.sls b/salt/redis/enabled.sls new file mode 100644 index 000000000..26f95e59f --- /dev/null +++ b/salt/redis/enabled.sls @@ -0,0 +1,62 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - redis.config + - redis.sostatus + +so-redis: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} + - hostname: so-redis + - user: socore + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-redis'].ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-redis'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - binds: + - /opt/so/log/redis:/var/log/redis:rw + - /opt/so/conf/redis/etc/redis.conf:/usr/local/etc/redis/redis.conf:ro + - /opt/so/conf/redis/working:/redis:rw + - /etc/pki/redis.crt:/certs/redis.crt:ro + - /etc/pki/redis.key:/certs/redis.key:ro + {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} + - /etc/pki/ca.crt:/certs/ca.crt:ro + {% else %} + - /etc/ssl/certs/intca.crt:/certs/ca.crt:ro + {% endif %} + - entrypoint: "redis-server /usr/local/etc/redis/redis.conf" + - watch: + - file: /opt/so/conf/redis/etc + - require: + - file: redisconf + - x509: redis_crt + - x509: redis_key + {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} + - x509: pki_public_ca_crt + {% else %} + - x509: trusttheca + {% endif %} + +delete_so-redis_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-redis$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/redis/etc/redis.conf.jinja b/salt/redis/etc/redis.conf.jinja index c3291c3e8..cb6d8abd8 100644 --- a/salt/redis/etc/redis.conf.jinja +++ b/salt/redis/etc/redis.conf.jinja @@ -1,5 +1,7 @@ -{%- import_yaml 'redis/defaults.yaml' as REDISDEFAULTS %} -{%- set REDISMERGED = salt['pillar.get']('redis', default=REDISDEFAULTS.redis, merge=true) %} +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} {%- for k, v in REDISMERGED.config.items() %} {%- if v is iterable and v is not string %} diff --git a/salt/redis/init.sls b/salt/redis/init.sls index 5806d99f3..2f7f38dcc 100644 --- a/salt/redis/init.sls +++ b/salt/redis/init.sls @@ -3,106 +3,11 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'redis/map.jinja' import REDISMERGED %} include: - - ssl - -# Redis Setup -redisconfdir: - file.directory: - - name: /opt/so/conf/redis/etc - - user: 939 - - group: 939 - - makedirs: True - -redisworkdir: - file.directory: - - name: /opt/so/conf/redis/working - - user: 939 - - group: 939 - - makedirs: True - -redislogdir: - file.directory: - - name: /opt/so/log/redis - - user: 939 - - group: 939 - - makedirs: True - -redisconf: - file.managed: - - name: /opt/so/conf/redis/etc/redis.conf - - source: salt://redis/etc/redis.conf.jinja - - user: 939 - - group: 939 - - template: jinja - -redis_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://redis/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -redis_sbin_jinja: - file.recurse: - - name: /usr/sbin - - source: salt://redis/tools/sbin_jinja - - user: 939 - - group: 939 - - file_mode: 755 - - template: jinja - -so-redis: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} - - hostname: so-redis - - user: socore - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-redis'].ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-redis'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - binds: - - /opt/so/log/redis:/var/log/redis:rw - - /opt/so/conf/redis/etc/redis.conf:/usr/local/etc/redis/redis.conf:ro - - /opt/so/conf/redis/working:/redis:rw - - /etc/pki/redis.crt:/certs/redis.crt:ro - - /etc/pki/redis.key:/certs/redis.key:ro - {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} - - /etc/pki/ca.crt:/certs/ca.crt:ro - {% else %} - - /etc/ssl/certs/intca.crt:/certs/ca.crt:ro - {% endif %} - - entrypoint: "redis-server /usr/local/etc/redis/redis.conf" - - watch: - - file: /opt/so/conf/redis/etc - - require: - - file: redisconf - - x509: redis_crt - - x509: redis_key - {% if grains['role'] in ['so-manager', 'so-helix', 'so-managersearch', 'so-standalone', 'so-import'] %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - -append_so-redis_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-redis - +{% if REDISMERGED.enabled %} + - redis.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - redis.disabled {% endif %} diff --git a/salt/redis/map.jinja b/salt/redis/map.jinja new file mode 100644 index 000000000..576a7c658 --- /dev/null +++ b/salt/redis/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'redis/defaults.yaml' as REDISDEFAULTS %} +{% set REDISMERGED = salt['pillar.get']('redis', REDISDEFAULTS.redis, merge=True) %} diff --git a/salt/redis/soc_redis.yaml b/salt/redis/soc_redis.yaml index 5f5ac3da5..45c63ffd3 100644 --- a/salt/redis/soc_redis.yaml +++ b/salt/redis/soc_redis.yaml @@ -1,4 +1,7 @@ redis: + enabled: + description: You can enable or disable Redis. + helpLink: redis.html config: bind: description: The IP address to bind to. diff --git a/salt/redis/sostatus.sls b/salt/redis/sostatus.sls new file mode 100644 index 000000000..8ac26250c --- /dev/null +++ b/salt/redis/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-redis_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-redis + - unless: grep -q so-redis /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/registry/config.sls b/salt/registry/config.sls new file mode 100644 index 000000000..098633829 --- /dev/null +++ b/salt/registry/config.sls @@ -0,0 +1,46 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - ssl + +# Create the config directory for the docker registry +dockerregistryconfdir: + file.directory: + - name: /opt/so/conf/docker-registry/etc + - user: 939 + - group: 939 + - makedirs: True + +dockerregistrydir: + file.directory: + - name: /nsm/docker-registry/docker + - user: 939 + - group: 939 + - makedirs: True + +dockerregistrylogdir: + file.directory: + - name: /opt/so/log/docker-registry + - user: 939 + - group: 939 + - makedirs: true + +# Copy the config +dockerregistryconf: + file.managed: + - name: /opt/so/conf/docker-registry/etc/config.yml + - source: salt://registry/etc/config.yml + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/registry/defaults.yaml b/salt/registry/defaults.yaml new file mode 100644 index 000000000..f6d2b2946 --- /dev/null +++ b/salt/registry/defaults.yaml @@ -0,0 +1,2 @@ +registry: + enabled: False diff --git a/salt/registry/disabled.sls b/salt/registry/disabled.sls new file mode 100644 index 000000000..ac0a56d95 --- /dev/null +++ b/salt/registry/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - registry.sostatus + +so-dockerregistry: + docker_container.absent: + - force: True + +so-dockerregistry_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-dockerregistry$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/registry/enabled.sls b/salt/registry/enabled.sls new file mode 100644 index 000000000..0ce3ee318 --- /dev/null +++ b/salt/registry/enabled.sls @@ -0,0 +1,55 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - registry.config + - registry.sostatus + +# Install the registry container +so-dockerregistry: + docker_container.running: + - image: ghcr.io/security-onion-solutions/registry:latest + - hostname: so-registry + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-dockerregistry'].ip }} + - restart_policy: always + - port_bindings: + {% for BINDING in DOCKER.containers['so-dockerregistry'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - binds: + - /opt/so/conf/docker-registry/etc/config.yml:/etc/docker/registry/config.yml:ro + - /opt/so/conf/docker-registry:/var/lib/registry:rw + - /nsm/docker-registry/docker:/var/lib/registry/docker:rw + - /etc/pki/registry.crt:/etc/pki/registry.crt:ro + - /etc/pki/registry.key:/etc/pki/registry.key:ro + - client_timeout: 180 + - environment: + - HOME=/root + - retry: + attempts: 5 + interval: 30 + - require: + - file: dockerregistryconf + - x509: registry_crt + - x509: registry_key + +delete_so-dockerregistry_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-dockerregistry$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/registry/init.sls b/salt/registry/init.sls index cb8035e44..b2b5912f2 100644 --- a/salt/registry/init.sls +++ b/salt/registry/init.sls @@ -1,77 +1,14 @@ -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'registry/map.jinja' import REGISTRYMERGED %} include: - - ssl - -# Create the config directory for the docker registry -dockerregistryconfdir: - file.directory: - - name: /opt/so/conf/docker-registry/etc - - user: 939 - - group: 939 - - makedirs: True - -dockerregistrydir: - file.directory: - - name: /nsm/docker-registry/docker - - user: 939 - - group: 939 - - makedirs: True - -dockerregistrylogdir: - file.directory: - - name: /opt/so/log/docker-registry - - user: 939 - - group: 939 - - makedirs: true - -# Copy the config -dockerregistryconf: - file.managed: - - name: /opt/so/conf/docker-registry/etc/config.yml - - source: salt://registry/etc/config.yml - -# Install the registry container -so-dockerregistry: - docker_container.running: - - image: ghcr.io/security-onion-solutions/registry:latest - - hostname: so-registry - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-dockerregistry'].ip }} - - restart_policy: always - - port_bindings: - {% for BINDING in DOCKER.containers['so-dockerregistry'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - binds: - - /opt/so/conf/docker-registry/etc/config.yml:/etc/docker/registry/config.yml:ro - - /opt/so/conf/docker-registry:/var/lib/registry:rw - - /nsm/docker-registry/docker:/var/lib/registry/docker:rw - - /etc/pki/registry.crt:/etc/pki/registry.crt:ro - - /etc/pki/registry.key:/etc/pki/registry.key:ro - - client_timeout: 180 - - environment: - - HOME=/root - - retry: - attempts: 5 - interval: 30 - - require: - - file: dockerregistryconf - - x509: registry_crt - - x509: registry_key - -append_so-dockerregistry_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-dockerregistry - +{% if REGISTRYMERGED.enabled %} + - registry.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - registry.disabled {% endif %} diff --git a/salt/registry/map.jinja b/salt/registry/map.jinja new file mode 100644 index 000000000..d8b18b231 --- /dev/null +++ b/salt/registry/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'registry/defaults.yaml' as REGISTRYDEFAULTS with context %} +{% set REGISTRYMERGED = salt['pillar.get']('registry', REGISTRYDEFAULTS.registry, merge=True) %} diff --git a/salt/registry/soc_registry.yaml b/salt/registry/soc_registry.yaml new file mode 100644 index 000000000..7fc3a161f --- /dev/null +++ b/salt/registry/soc_registry.yaml @@ -0,0 +1,4 @@ +registry: + enabled: + description: You can enable or disable the registry. + advanced: True diff --git a/salt/registry/sostatus.sls b/salt/registry/sostatus.sls new file mode 100644 index 000000000..ddfd187fd --- /dev/null +++ b/salt/registry/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-dockerregistry_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-dockerregistry + - unless: grep -q so-dockerregistry /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/sensoroni/config.sls b/salt/sensoroni/config.sls new file mode 100644 index 000000000..0024ca962 --- /dev/null +++ b/salt/sensoroni/config.sls @@ -0,0 +1,60 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +sensoroniconfdir: + file.directory: + - name: /opt/so/conf/sensoroni + - user: 939 + - group: 939 + - makedirs: True + +sensoroniagentconf: + file.managed: + - name: /opt/so/conf/sensoroni/sensoroni.json + - source: salt://sensoroni/files/sensoroni.json + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + +analyzersdir: + file.directory: + - name: /opt/so/conf/sensoroni/analyzers + - user: 939 + - group: 939 + - makedirs: True + +sensoronilog: + file.directory: + - name: /opt/so/log/sensoroni + - user: 939 + - group: 939 + - makedirs: True + +analyzerscripts: + file.recurse: + - name: /opt/so/conf/sensoroni/analyzers + - user: 939 + - group: 939 + - file_mode: 755 + - template: jinja + - source: salt://sensoroni/files/analyzers + +sensoroni_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://sensoroni/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#sensoroni_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://sensoroni/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja diff --git a/salt/sensoroni/defaults.yaml b/salt/sensoroni/defaults.yaml new file mode 100644 index 000000000..b29b8cebf --- /dev/null +++ b/salt/sensoroni/defaults.yaml @@ -0,0 +1,11 @@ +sensoroni: + enabled: False + config: + analyze: + enabled: False + timeout_ms: 900000 + parallel_limit: 5 + node_checkin_interval_ms: 10000 + node_description: '' + sensoronikey: + soc_host: diff --git a/salt/sensoroni/disabled.sls b/salt/sensoroni/disabled.sls new file mode 100644 index 000000000..4822406f9 --- /dev/null +++ b/salt/sensoroni/disabled.sls @@ -0,0 +1,16 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +include: + - sensoroni.sostatus + +so-sensoroni: + docker_container.absent: + - force: True + +so-sensoroni_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-sensoroni$ diff --git a/salt/sensoroni/enabled.sls b/salt/sensoroni/enabled.sls new file mode 100644 index 000000000..e506de49d --- /dev/null +++ b/salt/sensoroni/enabled.sls @@ -0,0 +1,32 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - sensoroni.config + - sensoroni.sostatus + +so-sensoroni: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soc:{{ GLOBALS.so_version }} + - network_mode: host + - binds: + - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw + - /nsm/pcap:/nsm/pcap:rw + - /nsm/import:/nsm/import:rw + - /nsm/pcapout:/nsm/pcapout:rw + - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro + - /opt/so/conf/sensoroni/analyzers:/opt/sensoroni/analyzers:rw + - /opt/so/log/sensoroni:/opt/sensoroni/logs:rw + - watch: + - file: /opt/so/conf/sensoroni/sensoroni.json + - require: + - file: sensoroniagentconf + +delete_so-sensoroni_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-sensoroni$ diff --git a/salt/sensoroni/files/sensoroni.json b/salt/sensoroni/files/sensoroni.json index 4b545f5e0..59ce500e3 100644 --- a/salt/sensoroni/files/sensoroni.json +++ b/salt/sensoroni/files/sensoroni.json @@ -1,43 +1,29 @@ -{%- from 'vars/globals.map.jinja' import GLOBALS -%} -{%- set ANALYZE_TIMEOUT_MS = salt['pillar.get']('sensoroni:analyze_timeout_ms', 900000) %} -{%- set ANALYZE_PARALLEL_LIMIT = salt['pillar.get']('sensoroni:analyze_parallel_limit', 5) %} -{%- set CHECKININTERVALMS = salt['pillar.get']('sensoroni:node_checkin_interval_ms', 10000) %} -{%- set ROLE = grains.id.split('_') | last %} -{%- if ROLE in ['eval', 'standalone', 'sensor', 'heavynode'] %} -{%- set STENODEFAULT = True %} -{%- else %} -{%- set STENODEFAULT = False %} -{%- endif %} -{%- set STENOENABLED = salt['pillar.get']('steno:enabled', STENODEFAULT) %} -{%- if ROLE in ['eval', 'standalone', 'import', 'manager', 'managersearch'] %} -{%- set ANALYZEDEFAULT = True %} -{%- else %} -{%- set ANALYZEDEFAULT = False %} -{%- endif %} -{%- set ANALYZEENABLED = salt['pillar.get']('sensoroni:analyze_enabled', ANALYZEDEFAULT) %} +{%- from 'vars/globals.map.jinja' import GLOBALS %} +{%- from 'sensoroni/map.jinja' import SENSORONIMERGED %} +{%- from 'pcap/config.map.jinja' import PCAPMERGED %} { "logFilename": "/opt/sensoroni/logs/sensoroni.log", "logLevel":"info", "agent": { "nodeId": "{{ GLOBALS.hostname | lower }}", "role": "{{ GLOBALS.role }}", - "description": {{ GLOBALS.description | tojson }}, + "description": {{ SENSORONIMERGED.config.node_description | tojson }}, "address": "{{ GLOBALS.node_ip }}", "model": "{{ GLOBALS.so_model }}", - "pollIntervalMs": {{ CHECKININTERVALMS if CHECKININTERVALMS else 10000 }}, + "pollIntervalMs": {{ SENSORONIMERGED.config.node_checkin_interval_ms }}, "serverUrl": "https://{{ GLOBALS.url_base }}/sensoroniagents", "verifyCert": false, "modules": { -{%- if ANALYZEENABLED %} +{%- if SENSORONIMERGED.config.analyze.enabled %} "analyze": { - "timeoutMs": {{ ANALYZE_TIMEOUT_MS }}, - "parallelLimit": {{ ANALYZE_PARALLEL_LIMIT }} + "timeoutMs": {{ SENSORONIMERGED.config.analyze.timeout_ms }}, + "parallelLimit": {{ SENSORONIMERGED.config.analyze.parallel_limit }} }, {%- endif %} "importer": {}, "statickeyauth": { "apiKey": "{{ GLOBALS.sensoroni_key }}" -{%- if STENOENABLED %} +{%- if PCAPMERGED.enabled %} }, "stenoquery": { "executablePath": "/opt/sensoroni/scripts/stenoquery.sh", diff --git a/salt/sensoroni/init.sls b/salt/sensoroni/init.sls index df6b99948..98d13ca15 100644 --- a/salt/sensoroni/init.sls +++ b/salt/sensoroni/init.sls @@ -1,79 +1,13 @@ -{% from 'vars/globals.map.jinja' import GLOBALS %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. -sensoroniconfdir: - file.directory: - - name: /opt/so/conf/sensoroni - - user: 939 - - group: 939 - - makedirs: True +{% from 'sensoroni/map.jinja' import SENSORONIMERGED %} -sensoroniagentconf: - file.managed: - - name: /opt/so/conf/sensoroni/sensoroni.json - - source: salt://sensoroni/files/sensoroni.json - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - -analyzersdir: - file.directory: - - name: /opt/so/conf/sensoroni/analyzers - - user: 939 - - group: 939 - - makedirs: True - -sensoronilog: - file.directory: - - name: /opt/so/log/sensoroni - - user: 939 - - group: 939 - - makedirs: True - -analyzerscripts: - file.recurse: - - name: /opt/so/conf/sensoroni/analyzers - - user: 939 - - group: 939 - - file_mode: 755 - - template: jinja - - source: salt://sensoroni/files/analyzers - -sensoroni_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://sensoroni/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#sensoroni_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://sensoroni/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -so-sensoroni: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soc:{{ GLOBALS.so_version }} - - network_mode: host - - binds: - - /opt/so/conf/steno/certs:/etc/stenographer/certs:rw - - /nsm/pcap:/nsm/pcap:rw - - /nsm/import:/nsm/import:rw - - /nsm/pcapout:/nsm/pcapout:rw - - /opt/so/conf/sensoroni/sensoroni.json:/opt/sensoroni/sensoroni.json:ro - - /opt/so/conf/sensoroni/analyzers:/opt/sensoroni/analyzers:rw - - /opt/so/log/sensoroni:/opt/sensoroni/logs:rw - - watch: - - file: /opt/so/conf/sensoroni/sensoroni.json - - require: - - file: sensoroniagentconf - -append_so-sensoroni_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-sensoroni +include: +{% if SENSORONIMERGED.enabled %} + - sensoroni.enabled +{% else %} + - sensoroni.disabled +{% endif %} diff --git a/salt/sensoroni/map.jinja b/salt/sensoroni/map.jinja new file mode 100644 index 000000000..228daa910 --- /dev/null +++ b/salt/sensoroni/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'sensoroni/defaults.yaml' as SENSORONIDEFAULTS %} +{% set SENSORONIMERGED = salt['pillar.get']('sensoroni', SENSORONIDEFAULTS.sensoroni, merge=True) %} diff --git a/salt/sensoroni/soc_sensoroni.yaml b/salt/sensoroni/soc_sensoroni.yaml index 6f6a75452..859a60d0c 100644 --- a/salt/sensoroni/soc_sensoroni.yaml +++ b/salt/sensoroni/soc_sensoroni.yaml @@ -1,19 +1,37 @@ sensoroni: - node_checkin_interval_ms: - description: Interval in ms to checkin to the soc_host. + enabled: + description: Enable or disable Sensoroni. advanced: True helpLink: sensoroni.html - node_description: - description: Description of the specific node. - helpLink: sensoroni.html - sensoronikey: - description: Shared key for sensoroni authentication. - helpLink: sensoroni.html - global: True - sensitive: True - advanced: True - soc_host: - description: Host for sensoroni agents to connect to. - helpLink: sensoroni.html - global: True - advanced: True \ No newline at end of file + config: + analyze: + enabled: + description: Enable or disable the analyzer. + advanced: True + helpLink: sensoroni.html + timeout_ms: + description: Timeout period for the analyzer. + advanced: True + helpLink: sensoroni.html + parallel_limit: + description: Parallel limit for the analyzer. + advanced: True + helpLink: sensoroni.html + node_checkin_interval_ms: + description: Interval in ms to checkin to the soc_host. + advanced: True + helpLink: sensoroni.html + node_description: + description: Description of the specific node. + helpLink: sensoroni.html + sensoronikey: + description: Shared key for sensoroni authentication. + helpLink: sensoroni.html + global: True + sensitive: True + advanced: True + soc_host: + description: Host for sensoroni agents to connect to. + helpLink: sensoroni.html + global: True + advanced: True diff --git a/salt/sensoroni/sostatus.sls b/salt/sensoroni/sostatus.sls new file mode 100644 index 000000000..fac2dac4d --- /dev/null +++ b/salt/sensoroni/sostatus.sls @@ -0,0 +1,10 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +append_so-sensoroni_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-sensoroni + - unless: grep -q so-sensoroni /opt/so/conf/so-status/so-status.conf diff --git a/salt/soc/config.sls b/salt/soc/config.sls new file mode 100644 index 000000000..399ff72cd --- /dev/null +++ b/salt/soc/config.sls @@ -0,0 +1,115 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - manager.sync_es_users + +socdir: + file.directory: + - name: /opt/so/conf/soc + - user: 939 + - group: 939 + - makedirs: True + +socdatadir: + file.directory: + - name: /nsm/soc/jobs + - user: 939 + - group: 939 + - makedirs: True + +soclogdir: + file.directory: + - name: /opt/so/log/soc + - user: 939 + - group: 939 + - makedirs: True + +socsaltdir: + file.directory: + - name: /opt/so/conf/soc/salt + - user: 939 + - group: 939 + - makedirs: True + +socconfig: + file.managed: + - name: /opt/so/conf/soc/soc.json + - source: salt://soc/files/soc/soc.json.jinja + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + - show_changes: False + +socmotd: + file.managed: + - name: /opt/so/conf/soc/motd.md + - source: salt://soc/files/soc/motd.md + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + +socbanner: + file.managed: + - name: /opt/so/conf/soc/banner.md + - source: salt://soc/files/soc/banner.md + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + +soc_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://soc/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#soc_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://soc/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +soccustom: + file.managed: + - name: /opt/so/conf/soc/custom.js + - source: salt://soc/files/soc/custom.js + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + +soccustomroles: + file.managed: + - name: /opt/so/conf/soc/custom_roles + - source: salt://soc/files/soc/custom_roles + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + +socusersroles: + file.exists: + - name: /opt/so/conf/soc/soc_users_roles + - require: + - sls: manager.sync_es_users + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soc/defaults.map.jinja b/salt/soc/defaults.map.jinja index 85db938cc..d816752c0 100644 --- a/salt/soc/defaults.map.jinja +++ b/salt/soc/defaults.map.jinja @@ -1,3 +1,8 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% import_yaml 'soc/defaults.yaml' as SOCDEFAULTS %} {% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'docker/docker.map.jinja' import DOCKER -%} @@ -5,28 +10,28 @@ {% import_text 'influxdb/metrics_link.txt' as METRICS_LINK %} {% for module, application_url in GLOBALS.application_urls.items() %} -{% do SOCDEFAULTS.soc.server.modules[module].update({'hostUrl': application_url}) %} +{% do SOCDEFAULTS.soc.config.server.modules[module].update({'hostUrl': application_url}) %} {% endfor %} {# add nodes from the logstash:nodes pillar to soc.server.modules.elastic.remoteHostUrls #} {% for node_type, minions in salt['pillar.get']('logstash:nodes', {}).items() %} {% for m in minions.keys() %} -{% do SOCDEFAULTS.soc.server.modules.elastic.remoteHostUrls.append(m) %} +{% do SOCDEFAULTS.soc.config.server.modules.elastic.remoteHostUrls.append(m) %} {% endfor %} {% endfor %} -{% do SOCDEFAULTS.soc.server.modules.elastic.update({'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'password': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}) %} +{% do SOCDEFAULTS.soc.config.server.modules.elastic.update({'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'password': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}) %} -{% do SOCDEFAULTS.soc.server.modules.influxdb.update({'hostUrl': 'https://' ~ GLOBALS.influxdb_host ~ ':8086'}) %} -{% do SOCDEFAULTS.soc.server.modules.influxdb.update({'token': INFLUXDB_TOKEN}) %} -{% for tool in SOCDEFAULTS.soc.server.client.tools %} +{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'hostUrl': 'https://' ~ GLOBALS.influxdb_host ~ ':8086'}) %} +{% do SOCDEFAULTS.soc.config.server.modules.influxdb.update({'token': INFLUXDB_TOKEN}) %} +{% for tool in SOCDEFAULTS.soc.config.server.client.tools %} {% if tool.name == "toolInfluxDb" and METRICS_LINK | length > 0 %} {% do tool.update({'link': METRICS_LINK}) %} {% endif %} {% endfor %} -{% do SOCDEFAULTS.soc.server.modules.statickeyauth.update({'anonymousCidr': DOCKER.sorange, 'apiKey': pillar.sensoroni.sensoronikey}) %} +{% do SOCDEFAULTS.soc.config.server.modules.statickeyauth.update({'anonymousCidr': DOCKER.sorange, 'apiKey': pillar.sensoroni.config.sensoronikey}) %} -{% do SOCDEFAULTS.soc.server.client.case.update({'analyzerNodeId': GLOBALS.hostname}) %} +{% do SOCDEFAULTS.soc.config.server.client.case.update({'analyzerNodeId': GLOBALS.hostname}) %} {% set SOCDEFAULTS = SOCDEFAULTS.soc %} diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 8572ed7ce..adbadc57f 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1,1746 +1,1748 @@ soc: - logFilename: /opt/sensoroni/logs/sensoroni-server.log - logLevel: info - actions: - - name: actionHunt - description: actionHuntHelp - icon: fa-crosshairs - target: - links: - - '/#/hunt?q="{value|escape}" | groupby event.module* event.dataset' - - name: actionCorrelate - description: actionCorrelateHelp - icon: fab fa-searchengin - target: '' - links: - - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* event.dataset' - - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}") | groupby event.module* event.dataset' - - '/#/hunt?q=("{:log.id.fuid}" OR "{:network.community_id}") | groupby event.module* event.dataset' - - '/#/hunt?q=("{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* event.dataset' - - '/#/hunt?q="{:log.id.fuid}" | groupby event.module* event.dataset' - - '/#/hunt?q="{:log.id.uid}" | groupby event.module* event.dataset' - - '/#/hunt?q="{:network.community_id}" | groupby event.module* event.dataset' - - name: actionPcap - description: actionPcapHelp - icon: fa-stream - target: '' - links: - - '/joblookup?esid={:soc_id}&time={:@timestamp}' - - '/joblookup?ncid={:network.community_id}&time={:@timestamp}' - categories: - - hunt - - alerts - - dashboards - - name: actionCyberChef - description: actionCyberChefHelp - icon: fas fa-bread-slice - target: _blank - links: - - '/cyberchef/#input={value|base64}' - - name: actionGoogle - description: actionGoogleHelp - icon: fab fa-google - target: _blank - links: - - 'https://www.google.com/search?q={value}' - - name: actionVirusTotal - description: actionVirusTotalHelp - icon: fa-external-link-alt - target: _blank - links: - - 'https://www.virustotal.com/gui/search/{value}' - eventFields: - default: - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - log.id.uid - - network.community_id - - event.dataset - ':kratos:audit': - - soc_timestamp - - http_request.headers.x-real-ip - - identity_id - - http_request.headers.user-agent - '::conn': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - network.transport - - network.protocol - - log.id.uid - - network.community_id - '::dce_rpc': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - dce_rpc.endpoint - - dce_rpc.named_pipe - - dce_rpc.operation - - log.id.uid - '::dhcp': - - soc_timestamp - - client.address - - server.address - - host.domain - - host.hostname - - dhcp.message_types - - log.id.uid - '::dnp3': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - dnp3.fc_reply - - log.id.uid - '::dnp3_control': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - dnp3.function_code - - dnp3.block_type - - log.id.uid - '::dnp3_objects': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - dnp3.function_code - - dnp3.object_type - - log.id.uid - '::dns': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - network.transport - - dns.query.name - - dns.query.type_name - - dns.response.code_name - - log.id.uid - - network.community_id - '::dpd': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - network.protocol - - observer.analyser - - error.reason - - log.id.uid - '::file': - - soc_timestamp - - source.ip - - destination.ip - - file.name - - file.mime_type - - file.source - - file.bytes.total - - log.id.fuid - - log.id.uid - '::ftp': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - ftp.user - - ftp.command - - ftp.argument - - ftp.reply_code - - file.size - - log.id.uid - '::http': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - http.method - - http.virtual_host - - http.status_code - - http.status_message - - http.request.body.length - - http.response.body.length - - log.id.uid - - network.community_id - '::intel': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - intel.indicator - - intel.indicator_type - - intel.seen_where - - log.id.uid - '::irc': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - irc.username - - irc.nickname - - irc.command.type - - irc.command.value - - irc.command.info - - log.id.uid - '::kerberos': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - kerberos.client - - kerberos.service - - kerberos.request_type - - log.id.uid - '::modbus': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - modbus.function - - log.id.uid - '::mysql': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - mysql.command - - mysql.argument - - mysql.success - - mysql.response - - log.id.uid - '::notice': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - notice.note - - notice.message - - log.id.fuid - - log.id.uid - - network.community_id - '::ntlm': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - ntlm.name - - ntlm.success - - ntlm.server.dns.name - - ntlm.server.nb.name - - ntlm.server.tree.name - - log.id.uid - '::pe': - - soc_timestamp - - file.is_64bit - - file.is_exe - - file.machine - - file.os - - file.subsystem - - log.id.fuid - '::radius': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - log.id.uid - - username - - radius.framed_address - - radius.reply_message - - radius.result - '::rdp': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - rdp.client_build - - client_name - - rdp.cookie - - rdp.encryption_level - - rdp.encryption_method - - rdp.keyboard_layout - - rdp.result - - rdp.security_protocol - - log.id.uid - '::rfb': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - rfb.authentication.method - - rfb.authentication.success - - rfb.share_flag - - rfb.desktop.name - - log.id.uid - '::signatures': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - note - - signature_id - - event_message - - sub_message - - signature_count - - host.count - - log.id.uid - '::sip': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - sip.method - - sip.uri - - sip.request.from - - sip.request.to - - sip.response.from - - sip.response.to - - sip.call_id - - sip.subject - - sip.user_agent - - sip.status_code - - log.id.uid - '::smb_files': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - log.id.fuid - - file.action - - file.path - - file.name - - file.size - - file.prev_name - - log.id.uid - '::smb_mapping': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - smb.path - - smb.service - - smb.share_type - - log.id.uid - '::smtp': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - smtp.from - - smtp.recipient_to - - smtp.subject - - smtp.useragent - - log.id.uid - - network.community_id - '::snmp': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - snmp.community - - snmp.version - - log.id.uid - '::socks': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - socks.name - - socks.request.host - - socks.request.port - - socks.status - - log.id.uid - '::software': - - soc_timestamp - - source.ip - - software.name - - software.type - '::ssh': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - ssh.version - - ssh.hassh_version - - ssh.direction - - ssh.client - - ssh.server - - log.id.uid - '::ssl': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - ssl.server_name - - ssl.certificate.subject - - ssl.validation_status - - ssl.version - - log.id.uid - ':zeek:syslog': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - syslog.facility - - network.protocol - - syslog.severity - - log.id.uid - '::tunnels': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - tunnel_type - - action - - log.id.uid - '::weird': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - weird.name - - log.id.uid - '::x509': - - soc_timestamp - - x509.certificate.subject - - x509.certificate.key.type - - x509.certificate.key.length - - x509.certificate.issuer - - log.id.fuid - '::firewall': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - network.transport - - network.direction - - interface.name - - rule.action - - rule.reason - - network.community_id - ':osquery:': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - source.hostname - - event.dataset - - process.executable - - user.name - ':ossec:': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - rule.name - - rule.level - - rule.category - - process.name - - user.name - - user.escalated - - location - ':strelka:file': - - soc_timestamp - - file.name - - file.size - - hash.md5 - - file.source - - file.mime_type - - log.id.fuid - ':suricata:': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - rule.name - - rule.category - - event.severity_label - - log.id.uid - - network.community_id - ':windows_eventlog:': - - soc_timestamp - - user.name - ':elasticsearch:': - - soc_timestamp - - agent.name - - message - - log.level - - metadata.version - - metadata.pipeline - - event.dataset - ':kibana:': - - soc_timestamp - - host.name - - message - - kibana.log.meta.req.headers.x-real-ip - - event.dataset - '::rootcheck': - - soc_timestamp - - host.name - - metadata.ip_address - - log.full - - event.dataset - - event.module - '::ossec': - - soc_timestamp - - host.name - - metadata.ip_address - - log.full - - event.dataset - - event.module - '::syscollector': - - soc_timestamp - - host.name - - metadata.ip_address - - wazuh.data.type - - log.full - - event.dataset - - event.module - ':syslog:syslog': - - soc_timestamp - - host.name - - metadata.ip_address - - real_message - - syslog.priority - - syslog.application - ':aws:': - - soc_timestamp - - aws.cloudtrail.event_category - - aws.cloudtrail.event_type - - event.provider - - event.action - - event.outcome - - cloud.region - - user.name - - source.ip - - source.geo.region_iso_code - ':squid:': - - soc_timestamp - - url.original - - destination.ip - - destination.geo.country_iso_code - - user.name - - source.ip - ':windows.sysmon_operational:': - - soc_timestamp - - event.action - - process.executable - - user.name - - file.target - - dns.question.name - - winlog.event_data.TargetObject - '::network_connection': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - source.hostname - - event.dataset - - process.executable - - user.name - '::process_terminated': - - soc_timestamp - - process.executable - - process.pid - - winlog.computer_name - '::file_create': - - soc_timestamp - - file.target - - process.executable - - process.pid - - winlog.computer_name - '::registry_value_set': - - soc_timestamp - - winlog.event_data.TargetObject - - process.executable - - process.pid - - winlog.computer_name - '::process_creation': - - soc_timestamp - - process.command_line - - process.pid - - process.parent.executable - - process.working_directory - '::registry_create_delete': - - soc_timestamp - - winlog.event_data.TargetObject - - process.executable - - process.pid - - winlog.computer_name - '::dns_query': - - soc_timestamp - - dns.query.name - - dns.answers.name - - process.executable - - winlog.computer_name - '::file_create_stream_hash': - - soc_timestamp - - file.target - - hash.md5 - - hash.sha256 - - process.executable - - process.pid - - winlog.computer_name - '::bacnet': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - bacnet.bclv.function - - bacnet.result.code - - log.id.uid - '::bacnet_discovery': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - bacnet.vendor - - bacnet.pdu.service - - log.id.uid - '::bacnet_property': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - bacnet.property - - bacnet.pdu.service - - log.id.uid - '::bsap_ip_header': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - bsap.message.type - - bsap.number.messages - - log.id.uid - '::bsap_ip_rdb': - - soc_timestamp - - bsap.application.function - - bsap.application.sub.function - - bsap.vector.variables - - log.id.uid - '::bsap_serial_header': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - bsap.source.function - - bsap.destination.function - - bsap.message.type - - log.id.uid - '::bsap_serial_rdb': - - soc_timestamp - - bsap.rdb.function - - bsap.vector.variables - - log.id.uid - '::cip': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - cip.service - - cip.status_code - - log.id.uid - - event.dataset - '::cip_identity': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - cip.device.type.name - - cip.vendor.name - - log.id.uid - '::cip_io': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - cip.connection.id - - cip.io.data - - log.id.uid - '::cotp': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - cotp.pdu.name - - log.id.uid - '::ecat_arp_info': - - soc_timestamp - - source.ip - - destination.ip - - source.mac - - destination.mac - - ecat.arp.type - '::ecat_aoe_info': - - soc_timestamp - - source.mac - - source.port - - destination.mac - - destination.port - - ecat.command - '::ecat_coe_info': - - soc_timestamp - - ecat.message.number - - ecat.message.type - - ecat.request.response.type - - ecat.index - - ecat.sub.index - '::ecat_dev_info': - - soc_timestamp - - ecat.device.type - - ecat.features - - ecat.ram.size - - ecat.revision - - ecat.slave.address - '::ecat_log_address': - - soc_timestamp - - source.mac - - destination.mac - - ecat.command - '::ecat_registers': - - soc_timestamp - - source.mac - - destination.mac - - ecat.command - - ecat.register.type - '::enip': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - enip.command - - enip.status_code - - log.id.uid - - event.dataset - '::modbus_detailed': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - modbus.function - - log.id.uid - '::opcua_binary': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.identifier_string - - opcua.message_type - - log.id.uid - '::opcua_binary_activate_session': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.link_id - - opcua.identifier_string - - opcua.user_name - - log.id.uid - '::opcua_binary_activate_session_diagnostic_info': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.activate_session_diag_info_link_id - - opcua.diag_info_link_id - - log.id.uid - '::opcua_binary_activate_session_locale_id': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.local_id - - opcua.locale_link_id - - log.id.uid - '::opcua_binary_browse': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.link_id - - opcua.service_type - - log.id.uid - '::opcua_binary_browse_description': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - log.id.uid - '::opcua_binary_browse_response_references': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.node_class - - opcua.display_name_text - - log.id.uid - '::opcua_binary_browse_result': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.response_link_id - - log.id.uid - '::opcua_binary_create_session': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.link_id - - log.id.uid - '::opcua_binary_create_session_endpoints': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.endpoint_link_id - - opcua.endpoint_url - - log.id.uid - '::opcua_binary_create_session_user_token': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.user_token_link_id - - log.id.uid - '::opcua_binary_create_subscription': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.link_id - - log.id.uid - '::opcua_binary_get_endpoints': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.endpoint_url - - opcua.link_id - - log.id.uid - '::opcua_binary_get_endpoints_description': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.endpoint_description_link_id - - opcua.endpoint_uri - - log.id.uid - '::opcua_binary_get_endpoints_user_token': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.user_token_link_id - - opcua.user_token_type - - log.id.uid - '::opcua_binary_read': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.link_id - - opcua.read_results_link_id - - log.id.uid - '::opcua_binary_status_code_detail': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - opcua.info_type_string - - opcua.source_string - - log.id.uid - '::profinet': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - profinet.index - - profinet.operation_type - - log.id.uid - '::profinet_dce_rpc': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - profinet.operation - - log.id.uid - '::s7comm': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - s7.ros.control.name - - s7.function.name - - log.id.uid - '::s7comm_plus': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - s7.opcode.name - - s7.version - - log.id.uid - '::s7comm_read_szl': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - s7.szl_id_name - - s7.return_code_name - - log.id.uid - '::s7comm_upload_download': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - s7.ros.control.name - - s7.function_code - - log.id.uid - '::tds': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - tds.command - - log.id.uid - - event.dataset - '::tds_rpc': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - tds.procedure_name - - log.id.uid - - event.dataset - '::tds_sql_batch': - - soc_timestamp - - source.ip - - source.port - - destination.ip - - destination.port - - tds.header_type - - log.id.uid - - event.dataset - server: - bindAddress: 0.0.0.0:9822 - baseUrl: / - maxPacketCount: 5000 - htmlDir: html - airgapEnabled: false - modules: - cases: soc - filedatastore: - jobDir: jobs - kratos: - hostUrl: - elastic: - hostUrl: - remoteHostUrls: [] - username: - password: - index: '*:so-*,*:endgame-*,*:logs-*' - cacheMs: 300000 - verifyCert: false + enabled: False + config: + logFilename: /opt/sensoroni/logs/sensoroni-server.log + logLevel: info + actions: + - name: actionHunt + description: actionHuntHelp + icon: fa-crosshairs + target: + links: + - '/#/hunt?q="{value|escape}" | groupby event.module* event.dataset' + - name: actionCorrelate + description: actionCorrelateHelp + icon: fab fa-searchengin + target: '' + links: + - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* event.dataset' + - '/#/hunt?q=("{:log.id.fuid}" OR "{:log.id.uid}") | groupby event.module* event.dataset' + - '/#/hunt?q=("{:log.id.fuid}" OR "{:network.community_id}") | groupby event.module* event.dataset' + - '/#/hunt?q=("{:log.id.uid}" OR "{:network.community_id}") | groupby event.module* event.dataset' + - '/#/hunt?q="{:log.id.fuid}" | groupby event.module* event.dataset' + - '/#/hunt?q="{:log.id.uid}" | groupby event.module* event.dataset' + - '/#/hunt?q="{:network.community_id}" | groupby event.module* event.dataset' + - name: actionPcap + description: actionPcapHelp + icon: fa-stream + target: '' + links: + - '/joblookup?esid={:soc_id}&time={:@timestamp}' + - '/joblookup?ncid={:network.community_id}&time={:@timestamp}' + categories: + - hunt + - alerts + - dashboards + - name: actionCyberChef + description: actionCyberChefHelp + icon: fas fa-bread-slice + target: _blank + links: + - '/cyberchef/#input={value|base64}' + - name: actionGoogle + description: actionGoogleHelp + icon: fab fa-google + target: _blank + links: + - 'https://www.google.com/search?q={value}' + - name: actionVirusTotal + description: actionVirusTotalHelp + icon: fa-external-link-alt + target: _blank + links: + - 'https://www.virustotal.com/gui/search/{value}' + eventFields: + default: + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - log.id.uid + - network.community_id + - event.dataset + ':kratos:audit': + - soc_timestamp + - http_request.headers.x-real-ip + - identity_id + - http_request.headers.user-agent + '::conn': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - network.transport + - network.protocol + - log.id.uid + - network.community_id + '::dce_rpc': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - dce_rpc.endpoint + - dce_rpc.named_pipe + - dce_rpc.operation + - log.id.uid + '::dhcp': + - soc_timestamp + - client.address + - server.address + - host.domain + - host.hostname + - dhcp.message_types + - log.id.uid + '::dnp3': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - dnp3.fc_reply + - log.id.uid + '::dnp3_control': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - dnp3.function_code + - dnp3.block_type + - log.id.uid + '::dnp3_objects': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - dnp3.function_code + - dnp3.object_type + - log.id.uid + '::dns': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - network.transport + - dns.query.name + - dns.query.type_name + - dns.response.code_name + - log.id.uid + - network.community_id + '::dpd': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - network.protocol + - observer.analyser + - error.reason + - log.id.uid + '::file': + - soc_timestamp + - source.ip + - destination.ip + - file.name + - file.mime_type + - file.source + - file.bytes.total + - log.id.fuid + - log.id.uid + '::ftp': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - ftp.user + - ftp.command + - ftp.argument + - ftp.reply_code + - file.size + - log.id.uid + '::http': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - http.method + - http.virtual_host + - http.status_code + - http.status_message + - http.request.body.length + - http.response.body.length + - log.id.uid + - network.community_id + '::intel': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - intel.indicator + - intel.indicator_type + - intel.seen_where + - log.id.uid + '::irc': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - irc.username + - irc.nickname + - irc.command.type + - irc.command.value + - irc.command.info + - log.id.uid + '::kerberos': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - kerberos.client + - kerberos.service + - kerberos.request_type + - log.id.uid + '::modbus': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - modbus.function + - log.id.uid + '::mysql': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - mysql.command + - mysql.argument + - mysql.success + - mysql.response + - log.id.uid + '::notice': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - notice.note + - notice.message + - log.id.fuid + - log.id.uid + - network.community_id + '::ntlm': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - ntlm.name + - ntlm.success + - ntlm.server.dns.name + - ntlm.server.nb.name + - ntlm.server.tree.name + - log.id.uid + '::pe': + - soc_timestamp + - file.is_64bit + - file.is_exe + - file.machine + - file.os + - file.subsystem + - log.id.fuid + '::radius': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - log.id.uid + - username + - radius.framed_address + - radius.reply_message + - radius.result + '::rdp': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - rdp.client_build + - client_name + - rdp.cookie + - rdp.encryption_level + - rdp.encryption_method + - rdp.keyboard_layout + - rdp.result + - rdp.security_protocol + - log.id.uid + '::rfb': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - rfb.authentication.method + - rfb.authentication.success + - rfb.share_flag + - rfb.desktop.name + - log.id.uid + '::signatures': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - note + - signature_id + - event_message + - sub_message + - signature_count + - host.count + - log.id.uid + '::sip': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - sip.method + - sip.uri + - sip.request.from + - sip.request.to + - sip.response.from + - sip.response.to + - sip.call_id + - sip.subject + - sip.user_agent + - sip.status_code + - log.id.uid + '::smb_files': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - log.id.fuid + - file.action + - file.path + - file.name + - file.size + - file.prev_name + - log.id.uid + '::smb_mapping': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - smb.path + - smb.service + - smb.share_type + - log.id.uid + '::smtp': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - smtp.from + - smtp.recipient_to + - smtp.subject + - smtp.useragent + - log.id.uid + - network.community_id + '::snmp': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - snmp.community + - snmp.version + - log.id.uid + '::socks': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - socks.name + - socks.request.host + - socks.request.port + - socks.status + - log.id.uid + '::software': + - soc_timestamp + - source.ip + - software.name + - software.type + '::ssh': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - ssh.version + - ssh.hassh_version + - ssh.direction + - ssh.client + - ssh.server + - log.id.uid + '::ssl': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - ssl.server_name + - ssl.certificate.subject + - ssl.validation_status + - ssl.version + - log.id.uid + ':zeek:syslog': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - syslog.facility + - network.protocol + - syslog.severity + - log.id.uid + '::tunnels': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - tunnel_type + - action + - log.id.uid + '::weird': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - weird.name + - log.id.uid + '::x509': + - soc_timestamp + - x509.certificate.subject + - x509.certificate.key.type + - x509.certificate.key.length + - x509.certificate.issuer + - log.id.fuid + '::firewall': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - network.transport + - network.direction + - interface.name + - rule.action + - rule.reason + - network.community_id + ':osquery:': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - source.hostname + - event.dataset + - process.executable + - user.name + ':ossec:': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - rule.name + - rule.level + - rule.category + - process.name + - user.name + - user.escalated + - location + ':strelka:file': + - soc_timestamp + - file.name + - file.size + - hash.md5 + - file.source + - file.mime_type + - log.id.fuid + ':suricata:': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - rule.name + - rule.category + - event.severity_label + - log.id.uid + - network.community_id + ':windows_eventlog:': + - soc_timestamp + - user.name + ':elasticsearch:': + - soc_timestamp + - agent.name + - message + - log.level + - metadata.version + - metadata.pipeline + - event.dataset + ':kibana:': + - soc_timestamp + - host.name + - message + - kibana.log.meta.req.headers.x-real-ip + - event.dataset + '::rootcheck': + - soc_timestamp + - host.name + - metadata.ip_address + - log.full + - event.dataset + - event.module + '::ossec': + - soc_timestamp + - host.name + - metadata.ip_address + - log.full + - event.dataset + - event.module + '::syscollector': + - soc_timestamp + - host.name + - metadata.ip_address + - wazuh.data.type + - log.full + - event.dataset + - event.module + ':syslog:syslog': + - soc_timestamp + - host.name + - metadata.ip_address + - real_message + - syslog.priority + - syslog.application + ':aws:': + - soc_timestamp + - aws.cloudtrail.event_category + - aws.cloudtrail.event_type + - event.provider + - event.action + - event.outcome + - cloud.region + - user.name + - source.ip + - source.geo.region_iso_code + ':squid:': + - soc_timestamp + - url.original + - destination.ip + - destination.geo.country_iso_code + - user.name + - source.ip + ':windows.sysmon_operational:': + - soc_timestamp + - event.action + - process.executable + - user.name + - file.target + - dns.question.name + - winlog.event_data.TargetObject + '::network_connection': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - source.hostname + - event.dataset + - process.executable + - user.name + '::process_terminated': + - soc_timestamp + - process.executable + - process.pid + - winlog.computer_name + '::file_create': + - soc_timestamp + - file.target + - process.executable + - process.pid + - winlog.computer_name + '::registry_value_set': + - soc_timestamp + - winlog.event_data.TargetObject + - process.executable + - process.pid + - winlog.computer_name + '::process_creation': + - soc_timestamp + - process.command_line + - process.pid + - process.parent.executable + - process.working_directory + '::registry_create_delete': + - soc_timestamp + - winlog.event_data.TargetObject + - process.executable + - process.pid + - winlog.computer_name + '::dns_query': + - soc_timestamp + - dns.query.name + - dns.answers.name + - process.executable + - winlog.computer_name + '::file_create_stream_hash': + - soc_timestamp + - file.target + - hash.md5 + - hash.sha256 + - process.executable + - process.pid + - winlog.computer_name + '::bacnet': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - bacnet.bclv.function + - bacnet.result.code + - log.id.uid + '::bacnet_discovery': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - bacnet.vendor + - bacnet.pdu.service + - log.id.uid + '::bacnet_property': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - bacnet.property + - bacnet.pdu.service + - log.id.uid + '::bsap_ip_header': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - bsap.message.type + - bsap.number.messages + - log.id.uid + '::bsap_ip_rdb': + - soc_timestamp + - bsap.application.function + - bsap.application.sub.function + - bsap.vector.variables + - log.id.uid + '::bsap_serial_header': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - bsap.source.function + - bsap.destination.function + - bsap.message.type + - log.id.uid + '::bsap_serial_rdb': + - soc_timestamp + - bsap.rdb.function + - bsap.vector.variables + - log.id.uid + '::cip': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - cip.service + - cip.status_code + - log.id.uid + - event.dataset + '::cip_identity': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - cip.device.type.name + - cip.vendor.name + - log.id.uid + '::cip_io': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - cip.connection.id + - cip.io.data + - log.id.uid + '::cotp': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - cotp.pdu.name + - log.id.uid + '::ecat_arp_info': + - soc_timestamp + - source.ip + - destination.ip + - source.mac + - destination.mac + - ecat.arp.type + '::ecat_aoe_info': + - soc_timestamp + - source.mac + - source.port + - destination.mac + - destination.port + - ecat.command + '::ecat_coe_info': + - soc_timestamp + - ecat.message.number + - ecat.message.type + - ecat.request.response.type + - ecat.index + - ecat.sub.index + '::ecat_dev_info': + - soc_timestamp + - ecat.device.type + - ecat.features + - ecat.ram.size + - ecat.revision + - ecat.slave.address + '::ecat_log_address': + - soc_timestamp + - source.mac + - destination.mac + - ecat.command + '::ecat_registers': + - soc_timestamp + - source.mac + - destination.mac + - ecat.command + - ecat.register.type + '::enip': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - enip.command + - enip.status_code + - log.id.uid + - event.dataset + '::modbus_detailed': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - modbus.function + - log.id.uid + '::opcua_binary': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.identifier_string + - opcua.message_type + - log.id.uid + '::opcua_binary_activate_session': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.link_id + - opcua.identifier_string + - opcua.user_name + - log.id.uid + '::opcua_binary_activate_session_diagnostic_info': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.activate_session_diag_info_link_id + - opcua.diag_info_link_id + - log.id.uid + '::opcua_binary_activate_session_locale_id': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.local_id + - opcua.locale_link_id + - log.id.uid + '::opcua_binary_browse': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.link_id + - opcua.service_type + - log.id.uid + '::opcua_binary_browse_description': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - log.id.uid + '::opcua_binary_browse_response_references': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.node_class + - opcua.display_name_text + - log.id.uid + '::opcua_binary_browse_result': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.response_link_id + - log.id.uid + '::opcua_binary_create_session': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.link_id + - log.id.uid + '::opcua_binary_create_session_endpoints': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.endpoint_link_id + - opcua.endpoint_url + - log.id.uid + '::opcua_binary_create_session_user_token': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.user_token_link_id + - log.id.uid + '::opcua_binary_create_subscription': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.link_id + - log.id.uid + '::opcua_binary_get_endpoints': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.endpoint_url + - opcua.link_id + - log.id.uid + '::opcua_binary_get_endpoints_description': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.endpoint_description_link_id + - opcua.endpoint_uri + - log.id.uid + '::opcua_binary_get_endpoints_user_token': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.user_token_link_id + - opcua.user_token_type + - log.id.uid + '::opcua_binary_read': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.link_id + - opcua.read_results_link_id + - log.id.uid + '::opcua_binary_status_code_detail': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - opcua.info_type_string + - opcua.source_string + - log.id.uid + '::profinet': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - profinet.index + - profinet.operation_type + - log.id.uid + '::profinet_dce_rpc': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - profinet.operation + - log.id.uid + '::s7comm': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - s7.ros.control.name + - s7.function.name + - log.id.uid + '::s7comm_plus': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - s7.opcode.name + - s7.version + - log.id.uid + '::s7comm_read_szl': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - s7.szl_id_name + - s7.return_code_name + - log.id.uid + '::s7comm_upload_download': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - s7.ros.control.name + - s7.function_code + - log.id.uid + '::tds': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - tds.command + - log.id.uid + - event.dataset + '::tds_rpc': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - tds.procedure_name + - log.id.uid + - event.dataset + '::tds_sql_batch': + - soc_timestamp + - source.ip + - source.port + - destination.ip + - destination.port + - tds.header_type + - log.id.uid + - event.dataset + server: + bindAddress: 0.0.0.0:9822 + baseUrl: / + maxPacketCount: 5000 + htmlDir: html + airgapEnabled: false + modules: + cases: soc + filedatastore: + jobDir: jobs + kratos: + hostUrl: + elastic: + hostUrl: + remoteHostUrls: [] + username: + password: + index: '*:so-*,*:endgame-*,*:logs-*' + cacheMs: 300000 + verifyCert: false + casesEnabled: true + extractCommonObservables: + - source.ip + - destination.ip + timeoutMs: 300000 + timeShiftMs: 120000 + defaultDurationMs: 1800000 + esSearchOffsetMs: 1800000 + maxLogLength: 1024 + asyncThreshold: 10 + influxdb: + hostUrl: + token: + org: Security Onion + bucket: telegraf/so_short_term + verifyCert: false + salt: + saltPipe: /opt/sensoroni/salt/pipe + sostatus: + refreshIntervalMs: 30000 + offlineThresholdMs: 900000 + statickeyauth: + anonymousCidr: + apiKey: + staticrbac: + roleFiles: + - rbac/permissions + - rbac/roles + - rbac/custom_roles + userFiles: + - rbac/users_roles + client: + docsUrl: /docs/ + cheatsheetUrl: /docs/cheatsheet.pdf + releaseNotesUrl: /docs/release-notes.html + apiTimeoutMs: 300000 + webSocketTimeoutMs: 15000 + tipTimeoutMs: 6000 + cacheExpirationMs: 300000 casesEnabled: true - extractCommonObservables: - - source.ip - - destination.ip - timeoutMs: 300000 - timeShiftMs: 120000 - defaultDurationMs: 1800000 - esSearchOffsetMs: 1800000 - maxLogLength: 1024 - asyncThreshold: 10 - influxdb: - hostUrl: - token: - org: Security Onion - bucket: telegraf/so_short_term - verifyCert: false - salt: - saltPipe: /opt/sensoroni/salt/pipe - sostatus: - refreshIntervalMs: 30000 - offlineThresholdMs: 900000 - statickeyauth: - anonymousCidr: - apiKey: - staticrbac: - roleFiles: - - rbac/permissions - - rbac/roles - - rbac/custom_roles - userFiles: - - rbac/users_roles - client: - docsUrl: /docs/ - cheatsheetUrl: /docs/cheatsheet.pdf - releaseNotesUrl: /docs/release-notes.html - apiTimeoutMs: 300000 - webSocketTimeoutMs: 15000 - tipTimeoutMs: 6000 - cacheExpirationMs: 300000 - casesEnabled: true - inactiveTools: ['toolUnused'] - tools: - - name: toolKibana - description: toolKibanaHelp - icon: fa-external-link-alt - target: so-kibana - link: /kibana/ - - name: toolElasticFleet - description: toolElasticFleet - icon: fa-external-link-alt - target: so-elastic-fleet - link: /kibana/app/fleet/agents - - name: toolOsqueryManager - description: toolOsqueryManager - icon: fa-external-link-alt - target: so-osquery-manager - link: /kibana/app/osquery/live_queries - - name: toolInfluxDb - description: toolInfluxDbHelp - icon: fa-external-link-alt - target: so-influxdb - link: /influxdb - - name: toolCyberchef - description: toolCyberchefHelp - icon: fa-external-link-alt - target: so-cyberchef - link: /cyberchef/ - - name: toolPlaybook - description: toolPlaybookHelp - icon: fa-external-link-alt - target: so-playbook - link: /playbook/projects/detection-playbooks/issues/ - - name: toolNavigator - description: toolNavigatorHelp - icon: fa-external-link-alt - target: so-navigator - link: /navigator/ - hunt: - advanced: true - aggregationActionsEnabled: true - groupItemsPerPage: 10 - groupFetchLimit: 10 - eventItemsPerPage: 10 - eventFetchLimit: 100 - relativeTimeValue: 24 - relativeTimeUnit: 30 - mostRecentlyUsedLimit: 5 - ackEnabled: false - escalateEnabled: true - escalateRelatedEventsEnabled: true - queryBaseFilter: '' - queryToggleFilters: - - name: caseExcludeToggle - filter: 'NOT _index:"*:so-case*"' - enabled: true - queries: - - name: Default Query - description: Show all events grouped by the observer host - query: '* | groupby observer.name' - showSubtitle: true - - name: Log Type - description: Show all events grouped by module and dataset - query: '* | groupby event.module* event.dataset' - showSubtitle: true - - name: SOC - Auth - description: Users authenticated to SOC grouped by IP address and identity - query: 'event.module:kratos AND event.dataset:audit AND msg:authenticated | groupby http_request.headers.x-real-ip identity_id' - showSubtitle: true - - name: SOC - App - description: Logs generated by the Security Onion Console (SOC) server and modules - query: 'event.module: "soc" | groupby event.module* event.dataset* log.level* | groupby agent.name | groupby event.action* | groupby "http.request.method" | groupby "url.path"' - showSubtitle: true - - name: Elastalerts - description: '' - query: '_type:elastalert | groupby rule.name' - showSubtitle: true - - name: Alerts - description: Show all alerts grouped by alert source - query: 'event.dataset: alert | groupby event.module' - showSubtitle: true - - name: NIDS Alerts - description: Show all NIDS alerts grouped by alert - query: 'event.category: network AND event.dataset: alert | groupby rule.category rule.gid rule.uuid rule.name' - showSubtitle: true - - name: Osquery - Live Query - description: Show all Osquery Live Query results - query: 'event.dataset: osquery_manager.result | groupby action_data.id action_data.query | groupby host.hostname' - showSubtitle: true - - name: Sysmon Events - description: Show all Sysmon logs grouped by event type - query: 'event.dataset: windows.sysmon_operational | groupby event.action' - showSubtitle: true - - name: Sysmon Usernames - description: Show all Sysmon logs grouped by username - query: 'event.dataset: windows.sysmon_operational | groupby event.action, user.name.keyword' - showSubtitle: true - - name: Strelka - description: Show all Strelka logs grouped by file type - query: 'event.module:strelka | groupby file.mime_type' - showSubtitle: true - - name: Zeek Notice - description: Show notices from Zeek - query: 'event.dataset:notice | groupby notice.note notice.message' - showSubtitle: true - - name: Connections - description: Connections grouped by IP and Port - query: 'event.dataset:conn | groupby source.ip destination.ip network.protocol destination.port' - showSubtitle: true - - name: Connections - description: Connections grouped by Service - query: 'event.dataset:conn | groupby network.protocol destination.port' - showSubtitle: true - - name: Connections - description: Connections grouped by destination country - query: 'event.dataset:conn | groupby destination.geo.country_name' - showSubtitle: true - - name: Connections - description: Connections grouped by source country - query: 'event.dataset:conn | groupby source.geo.country_name' - showSubtitle: true - - name: DCE_RPC - description: DCE_RPC grouped by operation - query: 'event.dataset:dce_rpc | groupby dce_rpc.operation' - showSubtitle: true - - name: DHCP - description: DHCP leases - query: 'event.dataset:dhcp | groupby host.hostname client.address' - showSubtitle: true - - name: DHCP - description: DHCP grouped by message type - query: 'event.dataset:dhcp | groupby dhcp.message_types' - showSubtitle: true - - name: DNP3 - description: DNP3 grouped by reply - query: 'event.dataset:dnp3 | groupby dnp3.fc_reply' - showSubtitle: true - - name: DNS - description: DNS queries grouped by port - query: 'event.dataset:dns | groupby dns.query.name destination.port' - showSubtitle: true - - name: DNS - description: DNS queries grouped by type - query: 'event.dataset:dns | groupby dns.query.type_name destination.port' - showSubtitle: true - - name: DNS - description: DNS queries grouped by response code - query: 'event.dataset:dns | groupby dns.response.code_name destination.port' - showSubtitle: true - - name: DNS - description: DNS highest registered domain - query: 'event.dataset:dns | groupby dns.highest_registered_domain.keyword destination.port' - showSubtitle: true - - name: DNS - description: DNS grouped by parent domain - query: 'event.dataset:dns | groupby dns.parent_domain.keyword destination.port' - showSubtitle: true - - name: DPD - description: Dynamic Protocol Detection errors - query: 'event.dataset:dpd | groupby error.reason' - showSubtitle: true - - name: Files - description: Files grouped by mimetype - query: 'event.dataset:file | groupby file.mime_type source.ip' - showSubtitle: true - - name: Files - description: Files grouped by source - query: 'event.dataset:file | groupby file.source source.ip' - showSubtitle: true - - name: FTP - description: FTP grouped by command and argument - query: 'event.dataset:ftp | groupby ftp.command ftp.argument' - showSubtitle: true - - name: FTP - description: FTP grouped by username and argument - query: 'event.dataset:ftp | groupby ftp.user ftp.argument' - showSubtitle: true - - name: HTTP - description: HTTP grouped by destination port - query: 'event.dataset:http | groupby destination.port' - showSubtitle: true - - name: HTTP - description: HTTP grouped by status code and message - query: 'event.dataset:http | groupby http.status_code http.status_message' - showSubtitle: true - - name: HTTP - description: HTTP grouped by method and user agent - query: 'event.dataset:http | groupby http.method http.useragent' - showSubtitle: true - - name: HTTP - description: HTTP grouped by virtual host - query: 'event.dataset:http | groupby http.virtual_host' - showSubtitle: true - - name: HTTP - description: HTTP with exe downloads - query: 'event.dataset:http AND (file.resp_mime_types:dosexec OR file.resp_mime_types:executable) | groupby http.virtual_host' - showSubtitle: true - - name: Intel - description: Intel framework hits grouped by indicator - query: 'event.dataset:intel | groupby intel.indicator.keyword' - showSubtitle: true - - name: IRC - description: IRC grouped by command - query: 'event.dataset:irc | groupby irc.command.type' - showSubtitle: true - - name: KERBEROS - description: KERBEROS grouped by service - query: 'event.dataset:kerberos | groupby kerberos.service' - showSubtitle: true - - name: MODBUS - description: MODBUS grouped by function - query: 'event.dataset:modbus | groupby modbus.function' - showSubtitle: true - - name: MYSQL - description: MYSQL grouped by command - query: 'event.dataset:mysql | groupby mysql.command' - showSubtitle: true - - name: NOTICE - description: Zeek notice logs grouped by note and message - query: 'event.dataset:notice | groupby notice.note notice.message' - showSubtitle: true - - name: NTLM - description: NTLM grouped by computer name - query: 'event.dataset:ntlm | groupby ntlm.server.dns.name' - showSubtitle: true - - name: PE - description: PE files list - query: 'event.dataset:pe | groupby file.machine file.os file.subsystem' - showSubtitle: true - - name: RADIUS - description: RADIUS grouped by username - query: 'event.dataset:radius | groupby user.name.keyword' - showSubtitle: true - - name: RDP - description: RDP grouped by client name - query: 'event.dataset:rdp | groupby client.name' - showSubtitle: true - - name: RFB - description: RFB grouped by desktop name - query: 'event.dataset:rfb | groupby rfb.desktop.name.keyword' - showSubtitle: true - - name: Signatures - description: Zeek signatures grouped by signature id - query: 'event.dataset:signatures | groupby signature_id' - showSubtitle: true - - name: SIP - description: SIP grouped by user agent - query: 'event.dataset:sip | groupby client.user_agent' - showSubtitle: true - - name: SMB_Files - description: SMB files grouped by action - query: 'event.dataset:smb_files | groupby file.action' - showSubtitle: true - - name: SMB_Mapping - description: SMB mapping grouped by path - query: 'event.dataset:smb_mapping | groupby smb.path' - showSubtitle: true - - name: SMTP - description: SMTP grouped by subject - query: 'event.dataset:smtp | groupby smtp.subject' - showSubtitle: true - - name: SNMP - description: SNMP grouped by version and string - query: 'event.dataset:snmp | groupby snmp.community snmp.version' - showSubtitle: true - - name: Software - description: List of software seen on the network - query: 'event.dataset:software | groupby software.type software.name' - showSubtitle: true - - name: SSH - description: SSH grouped by version and client - query: 'event.dataset:ssh | groupby ssh.version ssh.client' - showSubtitle: true - - name: SSL - description: SSL grouped by version and server name - query: 'event.dataset:ssl | groupby ssl.version ssl.server_name' - showSubtitle: true - - name: SYSLOG - description: 'SYSLOG grouped by severity and facility ' - query: 'event.dataset:syslog | groupby syslog.severity_label syslog.facility_label' - showSubtitle: true - - name: Tunnel - description: Tunnels grouped by type and action - query: 'event.dataset:tunnel | groupby tunnel.type event.action' - showSubtitle: true - - name: Weird - description: Zeek weird log grouped by name - query: 'event.dataset:weird | groupby weird.name' - showSubtitle: true - - name: x509 - description: x.509 grouped by key length and name - query: 'event.dataset:x509 | groupby x509.certificate.key.length x509.san_dns' - showSubtitle: true - - name: x509 - description: x.509 grouped by name and issuer - query: 'event.dataset:x509 | groupby x509.san_dns x509.certificate.issuer' - showSubtitle: true - - name: x509 - description: x.509 grouped by name and subject - query: 'event.dataset:x509 | groupby x509.san_dns x509.certificate.subject' - showSubtitle: true - - name: Firewall - description: Firewall events grouped by action - query: 'event.dataset:firewall | groupby rule.action' - showSubtitle: true - dashboards: - advanced: true - groupItemsPerPage: 10 - groupFetchLimit: 10 - eventItemsPerPage: 10 - eventFetchLimit: 100 - relativeTimeValue: 24 - relativeTimeUnit: 30 - mostRecentlyUsedLimit: 0 - ackEnabled: false - escalateEnabled: true - escalateRelatedEventsEnabled: true - aggregationActionsEnabled: false - queryBaseFilter: '' - queryToggleFilters: - - name: caseExcludeToggle - filter: 'NOT _index:"*:so-case*"' - enabled: true - queries: - - name: Overview - description: Overview of all events - query: '* | groupby -sankey event.dataset event.category* | groupby -pie event.category | groupby -bar event.module* | groupby event.dataset | groupby event.module* | groupby event.category | groupby observer.name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: SOC Auth - description: SOC (Security Onion Console) authentication logs - query: 'event.module:kratos AND event.dataset:audit AND msg:authenticated | groupby -sankey http_request.headers.x-real-ip identity_id | groupby http_request.headers.x-real-ip | groupby identity_id | groupby http_request.headers.user-agent' - - name: Elastalerts - description: Elastalert logs - query: '_index: "*:elastalert*" | groupby rule_name | groupby alert_info.type' - - name: Alerts - description: Overview of all alerts - query: 'event.dataset:alert | groupby event.module* | groupby rule.name | groupby event.severity | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: NIDS Alerts - description: NIDS (Network Intrusion Detection System) alerts - query: 'event.category:network AND event.dataset:alert | groupby rule.category | groupby -sankey source.ip destination.ip | groupby rule.name | groupby rule.uuid | groupby rule.gid | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Sysmon Overview - description: Overview of all Sysmon data types - query: 'event.dataset:windows.sysmon_operational | groupby -sankey event.action host.name | groupby -sankey host.name user.name | groupby host.name | groupby event.category event.action | groupby user.name | groupby dns.question.name | groupby process.executable | groupby winlog.event_data.TargetObject | groupby file.name | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Host Overview - description: Overview of all host data types - query: '((event.category:registry OR event.category:host OR event.category:process OR event.category:driver OR event.category:configuration) OR (event.category:file AND _exists_:process.executable) OR (event.category:network AND _exists_:host.name)) | groupby event.dataset* event.category* event.action* | groupby event.type | groupby host.name | groupby user.name | groupby file.name | groupby process.executable' - - name: Host Registry Changes - description: Windows Registry changes - query: 'event.category: registry | groupby -sankey event.action host.name | groupby event.dataset event.action | groupby host.name | groupby process.executable | groupby registry.path | groupby process.executable registry.path' - - name: Host DNS & Process Mappings - description: DNS queries mapped to originating processes - query: 'event.category: network AND _exists_:process.executable AND (_exists_:dns.question.name OR _exists_:dns.answers.data) | groupby -sankey host.name dns.question.name | groupby event.dataset event.type | groupby host.name | groupby process.executable | groupby dns.question.name | groupby dns.answers.data' - - name: Host Process Activity - description: Process activity captured on an endpoint - query: 'event.category:process | groupby -sankey host.name user.name* | groupby event.dataset event.action | groupby host.name | groupby user.name | groupby process.working_directory | groupby process.executable | groupby process.command_line | groupby process.parent.executable | groupby process.parent.command_line | groupby -sankey process.parent.executable process.executable' - - name: Host File Activity - description: File activity captured on an endpoint - query: 'event.category: file AND _exists_:process.executable | groupby -sankey host.name process.executable | groupby host.name | groupby event.dataset event.action event.type | groupby file.name | groupby process.executable' - - name: Host Network & Process Mappings - description: Network activity mapped to originating processes - query: 'event.category: network AND _exists_:process.executable | groupby -sankey event.action host.name | groupby -sankey host.name user.name | groupby event.dataset* event.type* event.action* | groupby host.name | groupby user.name | groupby dns.question.name | groupby process.executable | groupby winlog.event_data.TargetObject | groupby process.name | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Strelka - description: Strelka file analysis - query: 'event.module:strelka | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.name' - - name: Zeek Notice - description: Zeek notice logs - query: 'event.dataset:notice | groupby -sankey notice.note destination.ip | groupby notice.note | groupby notice.message | groupby notice.sub_message | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Connections - description: Network connection metadata - query: 'event.dataset:conn | groupby source.ip | groupby destination.ip | groupby destination.port | groupby -sankey destination.port network.protocol | groupby network.protocol | groupby network.transport | groupby connection.history | groupby connection.state | groupby connection.state_description | groupby source.geo.country_name | groupby destination.geo.country_name | groupby client.ip_bytes | groupby server.ip_bytes | groupby client.oui' - - name: DCE_RPC - description: DCE_RPC (Distributed Computing Environment / Remote Procedure Calls) network metadata - query: 'event.dataset:dce_rpc | groupby -sankey dce_rpc.endpoint dce_rpc.operation | groupby dce_rpc.endpoint | groupby dce_rpc.operation | groupby dce_rpc.named_pipe | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: DHCP - description: DHCP (Dynamic Host Configuration Protocol) leases - query: 'event.dataset:dhcp | groupby host.hostname | groupby dhcp.message_types | groupby -sankey client.address server.address | groupby client.address | groupby server.address | groupby host.domain' - - name: DNS - description: DNS (Domain Name System) queries - query: 'event.dataset:dns | groupby dns.query.name | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby -sankey source.ip destination.ip | groupby dns.answers.name | groupby dns.query.type_name | groupby dns.response.code_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: DPD - description: DPD (Dynamic Protocol Detection) errors - query: 'event.dataset:dpd | groupby error.reason | groupby network.protocol | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Files - description: Files seen in network traffic - query: 'event.dataset:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination_geo.organization_name' - - name: FTP - description: FTP (File Transfer Protocol) network metadata - query: 'event.dataset:ftp | groupby -sankey ftp.command destination.ip | groupby ftp.command | groupby ftp.argument | groupby ftp.user | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: HTTP - description: HTTP (Hyper Text Transport Protocol) network metadata - query: 'event.dataset:http | groupby http.method | groupby -sankey http.method http.virtual_host | groupby http.virtual_host | groupby http.uri | groupby http.useragent | groupby http.status_code | groupby http.status_message | groupby file.resp_mime_types | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Intel - description: Zeek Intel framework hits - query: 'event.dataset:intel | groupby intel.indicator | groupby -sankey source.ip intel.indicator | groupby intel.indicator_type | groupby intel.seen_where | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: IRC - description: IRC (Internet Relay Chat) network metadata - query: 'event.dataset:irc | groupby irc.command.type | groupby -sankey irc.command.type irc.username | groupby irc.username | groupby irc.nickname | groupby irc.command.value | groupby irc.command.info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Kerberos - description: Kerberos network metadata - query: 'event.dataset:kerberos | groupby kerberos.service | groupby -sankey kerberos.service destination.ip | groupby kerberos.client | groupby kerberos.request_type | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: MySQL - description: MySQL network metadata - query: 'event.dataset:mysql | groupby mysql.command | groupby -sankey mysql.command destination.ip | groupby mysql.argument | groupby mysql.success | groupby mysql.response | groupby mysql.rows | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: NTLM - description: NTLM (New Technology LAN Manager) network metadata - query: 'event.dataset:ntlm | groupby ntlm.server.dns.name | groupby ntlm.server.nb.name | groupby -sankey source.ip destination.ip | groupby ntlm.server.tree.name | groupby ntlm.success | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: PE - description: PE (Portable Executable) files transferred via network traffic - query: 'event.dataset:pe | groupby file.machine | groupby -sankey file.machine file.os | groupby file.os | groupby file.subsystem | groupby file.section_names | groupby file.is_exe | groupby file.is_64bit' - - name: RADIUS - description: RADIUS (Remote Authentication Dial-In User Service) network metadata - query: 'event.dataset:radius | groupby -sankey user.name.keyword destination.ip | groupby user.name.keyword | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: RDP - description: RDP (Remote Desktop Protocol) network metadata - query: 'event.dataset:rdp | groupby client.name | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: RFB - description: RFB (Remote Frame Buffer) network metadata - query: 'event.dataset:rfb | groupby rfb.desktop.name.keyword | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: Signatures - description: Zeek signatures - query: 'event.dataset:signatures | groupby signature_id' - - name: SIP - description: SIP (Session Initiation Protocol) network metadata - query: 'event.dataset:sip | groupby client.user_agent | groupby sip.method | groupby sip.uri | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: SMB_Files - description: Files transferred via SMB (Server Message Block) - query: 'event.dataset:smb_files | groupby file.action | groupby file.path | groupby file.name | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: SMB_Mapping - description: SMB (Server Message Block) mapping network metadata - query: 'event.dataset:smb_mapping | groupby smb.share_type | groupby smb.path | groupby smb.service | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: SMTP - description: SMTP (Simple Mail Transfer Protocol) network metadata - query: 'event.dataset:smtp | groupby smtp.from | groupby smtp.recipient_to | groupby -sankey source.ip destination.ip | groupby smtp.subject | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: SNMP - description: SNMP (Simple Network Management Protocol) network metadat - query: 'event.dataset:snmp | groupby snmp.community | groupby snmp.version | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Software - description: Software seen by Zeek via network traffic - query: 'event.dataset:software | groupby -sankey software.type source.ip | groupby software.type | groupby software.name | groupby source.ip' - - name: SSH - description: SSH (Secure Shell) connections seen by Zeek - query: 'event.dataset:ssh | groupby ssh.client | groupby ssh.server | groupby -sankey source.ip destination.ip | groupby ssh.direction | groupby ssh.version | groupby ssh.hassh_version | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: SSL - description: SSL/TLS network metadata - query: 'event.dataset:ssl | groupby ssl.version | groupby ssl.validation_status | groupby -sankey source.ip ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby ssl.certificate.issuer | groupby ssl.certificate.subject' - - name: STUN - description: STUN (Session Traversal Utilities for NAT) network metadata - query: 'event.dataset:stun* | groupby -sankey source.ip destination.ip | groupby destination.geo.country_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby event.dataset' - - name: Syslog - description: Syslog logs - query: 'event.dataset:syslog | groupby syslog.severity_label | groupby syslog.facility_label | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby network.protocol' - - name: TDS - description: TDS (Tabular Data Stream) network metadata - query: 'event.dataset:tds* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby tds.command | groupby tds.header_type | groupby tds.procedure_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby tds.query' - - name: Tunnel - description: Tunnels seen by Zeek - query: 'event.dataset:tunnel | groupby -sankey source.ip destination.ip | groupby tunnel.type | groupby event.action | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name' - - name: Weird - description: Weird network traffic seen by Zeek - query: 'event.dataset:weird | groupby -sankey weird.name destination.ip | groupby weird.name | groupby weird.additional_info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' - - name: WireGuard - description: WireGuard VPN network metadata - query: 'event.dataset:wireguard | groupby -sankey source.ip destination.ip | groupby destination.geo.country_name | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: x509 - description: x.509 certificates seen by Zeek - query: 'event.dataset:x509 | groupby -sankey x509.certificate.key.length x509.san_dns | groupby x509.certificate.key.length | groupby x509.san_dns | groupby x509.certificate.key.type | groupby x509.certificate.subject | groupby x509.certificate.issuer' - - name: ICS Overview - description: Overview of ICS (Industrial Control Systems) network metadata - query: 'tags:ics | groupby event.dataset | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby source.mac | groupby destination.mac' - - name: ICS BACnet - description: BACnet (Building Automation and Control Networks) network metadata - query: 'event.dataset:bacnet* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS BSAP - description: BSAP (Bristol Standard Asynchronous Protocol) network metadata - query: 'event.dataset:bsap* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS CIP - description: CIP (Common Industrial Protocol) network metadata - query: 'event.dataset:cip* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS COTP - description: COTP (Connection Oriented Transport Protocol) network metadata - query: 'event.dataset:cotp* | groupby -sankey source.ip destination.ip | groupby cotp.pdu.name | groupby cotp.pdu.code | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS DNP3 - description: DNP3 (Distributed Network Protocol) network metadata - query: 'event.dataset:dnp3* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby dnp3.function_code | groupby dnp3.object_type | groupby dnp3.fc_request | groupby dnp3.fc_reply | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS ECAT - description: ECAT (Ethernet for Control Automation Technology) network metadata - query: 'event.dataset:ecat* | groupby -sankey event.dataset source.mac destination.mac | groupby event.dataset | groupby source.mac | groupby destination.mac | groupby ecat.command | groupby ecat.register.type' - - name: ICS ENIP - description: ENIP (Ethernet Industrial Protocol) network metadata - query: 'event.dataset:enip* | groupby -sankey source.ip destination.ip | groupby enip.command | groupby enip.status_code | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS Modbus - description: Modbus network metadata - query: 'event.dataset:modbus* | groupby -sankey event.dataset modbus.function | groupby event.dataset | groupby modbus.function | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS OPC UA - description: OPC UA (Unified Architecture) network metadata - query: 'event.dataset:opcua* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS Profinet - description: Profinet (Process Field Network) network metadata - query: 'event.dataset:profinet* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: ICS S7 - description: S7 (Siemens) network metadata - query: 'event.dataset:s7* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Firewall - description: Firewall logs - query: 'event.dataset:firewall | groupby -sankey rule.action interface.name | groupby rule.action | groupby interface.name | groupby network.transport | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: VLAN - description: VLAN (Virtual Local Area Network) tagged logs - query: '* AND _exists_:network.vlan.id | groupby network.vlan.id | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby event.dataset | groupby event.module | groupby observer.name | groupby source.geo.country_name | groupby destination.geo.country_name' - - name: GeoIP - Destination Countries - description: GeoIP tagged logs visualized by destination countries - query: '* AND _exists_:destination.geo.country_name | groupby destination.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby event.dataset | groupby event.module' - - name: GeoIP - Destination Organizations - description: GeoIP tagged logs visualized by destination organizations - query: '* AND _exists_:destination_geo.organization_name | groupby destination_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby event.dataset | groupby event.module' - - name: GeoIP - Source Countries - description: GeoIP tagged logs visualized by source countries - query: '* AND _exists_:source.geo.country_name | groupby source.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source_geo.organization_name | groupby event.dataset | groupby event.module' - - name: GeoIP - Source Organizations - description: GeoIP tagged logs visualized by source organizations - query: '* AND _exists_:source_geo.organization_name | groupby source_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.geo.country_name | groupby event.dataset | groupby event.module' - job: - alerts: - advanced: false - groupItemsPerPage: 50 - groupFetchLimit: 500 - eventItemsPerPage: 50 - eventFetchLimit: 500 - relativeTimeValue: 24 - relativeTimeUnit: 30 - mostRecentlyUsedLimit: 5 - ackEnabled: true - escalateEnabled: true - escalateRelatedEventsEnabled: true - aggregationActionsEnabled: true - eventFields: - default: - - soc_timestamp - - rule.name - - event.severity_label - - source.ip - - source.port - - destination.ip - - destination.port - - rule.gid - - rule.uuid - - rule.category - - rule.rev - ':ossec:': - - soc_timestamp - - rule.name - - event.severity_label - - source.ip - - source.port - - destination.ip - - destination.port - - rule.level - - rule.category - - process.name - - user.name - - user.escalated - - location - - process.name - queryBaseFilter: event.dataset:alert - queryToggleFilters: - - name: acknowledged - filter: event.acknowledged:true - enabled: false - exclusive: true - - name: escalated - filter: event.escalated:true - enabled: false - exclusive: true - enablesToggles: - - acknowledged - queries: - - name: 'Group By Name, Module' - query: '* | groupby rule.name event.module* event.severity_label' - - name: 'Group By Sensor, Source IP/Port, Destination IP/Port, Name' - query: '* | groupby observer.name source.ip source.port destination.ip destination.port rule.name network.community_id event.severity_label' - - name: 'Group By Source IP, Name' - query: '* | groupby source.ip rule.name event.severity_label' - - name: 'Group By Source Port, Name' - query: '* | groupby source.port rule.name event.severity_label' - - name: 'Group By Destination IP, Name' - query: '* | groupby destination.ip rule.name event.severity_label' - - name: 'Group By Destination Port, Name' - query: '* | groupby destination.port rule.name event.severity_label' - - name: Ungroup - query: '*' - cases: - advanced: false - aggregationActionsEnabled: false - groupItemsPerPage: 50 - groupFetchLimit: 100 - eventItemsPerPage: 50 - eventFetchLimit: 500 - relativeTimeValue: 12 - relativeTimeUnit: 60 - mostRecentlyUsedLimit: 5 - ackEnabled: false - escalateEnabled: false - escalateRelatedEventsEnabled: false - viewEnabled: true - createLink: /case/create - eventFields: - default: - - soc_timestamp - - so_case.title - - so_case.status - - so_case.severity - - so_case.assigneeId - - so_case.createTime - queryBaseFilter: '_index:"*:so-case" AND so_kind:case' - queryToggleFilters: [] - queries: - - name: Open Cases - query: 'NOT so_case.status:closed AND NOT so_case.category:template' - - name: Closed Cases - query: 'so_case.status:closed AND NOT so_case.category:template' - - name: My Open Cases - query: 'NOT so_case.status:closed AND NOT so_case.category:template AND so_case.assigneeId:{myId}' - - name: My Closed Cases - query: 'so_case.status:closed AND NOT so_case.category:template AND so_case.assigneeId:{myId}' - - name: Templates - query: 'so_case.category:template' - case: - analyzerNodeId: - mostRecentlyUsedLimit: 5 - renderAbbreviatedCount: 30 - presets: - artifactType: - labels: - - autonomous-system - - domain - - file - - filename - - fqdn - - hash - - ip - - mail - - mail_subject - - other - - regexp - - registry - - uri_path - - url - - user-agent - customEnabled: true - category: - labels: - - general - - template - customEnabled: true - pap: - labels: - - white - - green - - amber - - red - customEnabled: false - severity: - labels: - - low - - medium - - high - - critical - customEnabled: false - status: - labels: - - new - - in progress - - closed - customEnabled: false - tags: - labels: - - false-positive - - confirmed - - pending - customEnabled: true - tlp: - labels: - - clear - - green - - amber - - amber+strict - - red - customEnabled: false + inactiveTools: ['toolUnused'] + tools: + - name: toolKibana + description: toolKibanaHelp + icon: fa-external-link-alt + target: so-kibana + link: /kibana/ + - name: toolElasticFleet + description: toolElasticFleet + icon: fa-external-link-alt + target: so-elastic-fleet + link: /kibana/app/fleet/agents + - name: toolOsqueryManager + description: toolOsqueryManager + icon: fa-external-link-alt + target: so-osquery-manager + link: /kibana/app/osquery/live_queries + - name: toolInfluxDb + description: toolInfluxDbHelp + icon: fa-external-link-alt + target: so-influxdb + link: /influxdb + - name: toolCyberchef + description: toolCyberchefHelp + icon: fa-external-link-alt + target: so-cyberchef + link: /cyberchef/ + - name: toolPlaybook + description: toolPlaybookHelp + icon: fa-external-link-alt + target: so-playbook + link: /playbook/projects/detection-playbooks/issues/ + - name: toolNavigator + description: toolNavigatorHelp + icon: fa-external-link-alt + target: so-navigator + link: /navigator/ + hunt: + advanced: true + aggregationActionsEnabled: true + groupItemsPerPage: 10 + groupFetchLimit: 10 + eventItemsPerPage: 10 + eventFetchLimit: 100 + relativeTimeValue: 24 + relativeTimeUnit: 30 + mostRecentlyUsedLimit: 5 + ackEnabled: false + escalateEnabled: true + escalateRelatedEventsEnabled: true + queryBaseFilter: '' + queryToggleFilters: + - name: caseExcludeToggle + filter: 'NOT _index:"*:so-case*"' + enabled: true + queries: + - name: Default Query + description: Show all events grouped by the observer host + query: '* | groupby observer.name' + showSubtitle: true + - name: Log Type + description: Show all events grouped by module and dataset + query: '* | groupby event.module* event.dataset' + showSubtitle: true + - name: SOC - Auth + description: Users authenticated to SOC grouped by IP address and identity + query: 'event.module:kratos AND event.dataset:audit AND msg:authenticated | groupby http_request.headers.x-real-ip identity_id' + showSubtitle: true + - name: SOC - App + description: Logs generated by the Security Onion Console (SOC) server and modules + query: 'event.module: "soc" | groupby event.module* event.dataset* log.level* | groupby agent.name | groupby event.action* | groupby "http.request.method" | groupby "url.path"' + showSubtitle: true + - name: Elastalerts + description: '' + query: '_type:elastalert | groupby rule.name' + showSubtitle: true + - name: Alerts + description: Show all alerts grouped by alert source + query: 'event.dataset: alert | groupby event.module' + showSubtitle: true + - name: NIDS Alerts + description: Show all NIDS alerts grouped by alert + query: 'event.category: network AND event.dataset: alert | groupby rule.category rule.gid rule.uuid rule.name' + showSubtitle: true + - name: Osquery - Live Query + description: Show all Osquery Live Query results + query: 'event.dataset: osquery_manager.result | groupby action_data.id action_data.query | groupby host.hostname' + showSubtitle: true + - name: Sysmon Events + description: Show all Sysmon logs grouped by event type + query: 'event.dataset: windows.sysmon_operational | groupby event.action' + showSubtitle: true + - name: Sysmon Usernames + description: Show all Sysmon logs grouped by username + query: 'event.dataset: windows.sysmon_operational | groupby event.action, user.name.keyword' + showSubtitle: true + - name: Strelka + description: Show all Strelka logs grouped by file type + query: 'event.module:strelka | groupby file.mime_type' + showSubtitle: true + - name: Zeek Notice + description: Show notices from Zeek + query: 'event.dataset:notice | groupby notice.note notice.message' + showSubtitle: true + - name: Connections + description: Connections grouped by IP and Port + query: 'event.dataset:conn | groupby source.ip destination.ip network.protocol destination.port' + showSubtitle: true + - name: Connections + description: Connections grouped by Service + query: 'event.dataset:conn | groupby network.protocol destination.port' + showSubtitle: true + - name: Connections + description: Connections grouped by destination country + query: 'event.dataset:conn | groupby destination.geo.country_name' + showSubtitle: true + - name: Connections + description: Connections grouped by source country + query: 'event.dataset:conn | groupby source.geo.country_name' + showSubtitle: true + - name: DCE_RPC + description: DCE_RPC grouped by operation + query: 'event.dataset:dce_rpc | groupby dce_rpc.operation' + showSubtitle: true + - name: DHCP + description: DHCP leases + query: 'event.dataset:dhcp | groupby host.hostname client.address' + showSubtitle: true + - name: DHCP + description: DHCP grouped by message type + query: 'event.dataset:dhcp | groupby dhcp.message_types' + showSubtitle: true + - name: DNP3 + description: DNP3 grouped by reply + query: 'event.dataset:dnp3 | groupby dnp3.fc_reply' + showSubtitle: true + - name: DNS + description: DNS queries grouped by port + query: 'event.dataset:dns | groupby dns.query.name destination.port' + showSubtitle: true + - name: DNS + description: DNS queries grouped by type + query: 'event.dataset:dns | groupby dns.query.type_name destination.port' + showSubtitle: true + - name: DNS + description: DNS queries grouped by response code + query: 'event.dataset:dns | groupby dns.response.code_name destination.port' + showSubtitle: true + - name: DNS + description: DNS highest registered domain + query: 'event.dataset:dns | groupby dns.highest_registered_domain.keyword destination.port' + showSubtitle: true + - name: DNS + description: DNS grouped by parent domain + query: 'event.dataset:dns | groupby dns.parent_domain.keyword destination.port' + showSubtitle: true + - name: DPD + description: Dynamic Protocol Detection errors + query: 'event.dataset:dpd | groupby error.reason' + showSubtitle: true + - name: Files + description: Files grouped by mimetype + query: 'event.dataset:file | groupby file.mime_type source.ip' + showSubtitle: true + - name: Files + description: Files grouped by source + query: 'event.dataset:file | groupby file.source source.ip' + showSubtitle: true + - name: FTP + description: FTP grouped by command and argument + query: 'event.dataset:ftp | groupby ftp.command ftp.argument' + showSubtitle: true + - name: FTP + description: FTP grouped by username and argument + query: 'event.dataset:ftp | groupby ftp.user ftp.argument' + showSubtitle: true + - name: HTTP + description: HTTP grouped by destination port + query: 'event.dataset:http | groupby destination.port' + showSubtitle: true + - name: HTTP + description: HTTP grouped by status code and message + query: 'event.dataset:http | groupby http.status_code http.status_message' + showSubtitle: true + - name: HTTP + description: HTTP grouped by method and user agent + query: 'event.dataset:http | groupby http.method http.useragent' + showSubtitle: true + - name: HTTP + description: HTTP grouped by virtual host + query: 'event.dataset:http | groupby http.virtual_host' + showSubtitle: true + - name: HTTP + description: HTTP with exe downloads + query: 'event.dataset:http AND (file.resp_mime_types:dosexec OR file.resp_mime_types:executable) | groupby http.virtual_host' + showSubtitle: true + - name: Intel + description: Intel framework hits grouped by indicator + query: 'event.dataset:intel | groupby intel.indicator.keyword' + showSubtitle: true + - name: IRC + description: IRC grouped by command + query: 'event.dataset:irc | groupby irc.command.type' + showSubtitle: true + - name: KERBEROS + description: KERBEROS grouped by service + query: 'event.dataset:kerberos | groupby kerberos.service' + showSubtitle: true + - name: MODBUS + description: MODBUS grouped by function + query: 'event.dataset:modbus | groupby modbus.function' + showSubtitle: true + - name: MYSQL + description: MYSQL grouped by command + query: 'event.dataset:mysql | groupby mysql.command' + showSubtitle: true + - name: NOTICE + description: Zeek notice logs grouped by note and message + query: 'event.dataset:notice | groupby notice.note notice.message' + showSubtitle: true + - name: NTLM + description: NTLM grouped by computer name + query: 'event.dataset:ntlm | groupby ntlm.server.dns.name' + showSubtitle: true + - name: PE + description: PE files list + query: 'event.dataset:pe | groupby file.machine file.os file.subsystem' + showSubtitle: true + - name: RADIUS + description: RADIUS grouped by username + query: 'event.dataset:radius | groupby user.name.keyword' + showSubtitle: true + - name: RDP + description: RDP grouped by client name + query: 'event.dataset:rdp | groupby client.name' + showSubtitle: true + - name: RFB + description: RFB grouped by desktop name + query: 'event.dataset:rfb | groupby rfb.desktop.name.keyword' + showSubtitle: true + - name: Signatures + description: Zeek signatures grouped by signature id + query: 'event.dataset:signatures | groupby signature_id' + showSubtitle: true + - name: SIP + description: SIP grouped by user agent + query: 'event.dataset:sip | groupby client.user_agent' + showSubtitle: true + - name: SMB_Files + description: SMB files grouped by action + query: 'event.dataset:smb_files | groupby file.action' + showSubtitle: true + - name: SMB_Mapping + description: SMB mapping grouped by path + query: 'event.dataset:smb_mapping | groupby smb.path' + showSubtitle: true + - name: SMTP + description: SMTP grouped by subject + query: 'event.dataset:smtp | groupby smtp.subject' + showSubtitle: true + - name: SNMP + description: SNMP grouped by version and string + query: 'event.dataset:snmp | groupby snmp.community snmp.version' + showSubtitle: true + - name: Software + description: List of software seen on the network + query: 'event.dataset:software | groupby software.type software.name' + showSubtitle: true + - name: SSH + description: SSH grouped by version and client + query: 'event.dataset:ssh | groupby ssh.version ssh.client' + showSubtitle: true + - name: SSL + description: SSL grouped by version and server name + query: 'event.dataset:ssl | groupby ssl.version ssl.server_name' + showSubtitle: true + - name: SYSLOG + description: 'SYSLOG grouped by severity and facility ' + query: 'event.dataset:syslog | groupby syslog.severity_label syslog.facility_label' + showSubtitle: true + - name: Tunnel + description: Tunnels grouped by type and action + query: 'event.dataset:tunnel | groupby tunnel.type event.action' + showSubtitle: true + - name: Weird + description: Zeek weird log grouped by name + query: 'event.dataset:weird | groupby weird.name' + showSubtitle: true + - name: x509 + description: x.509 grouped by key length and name + query: 'event.dataset:x509 | groupby x509.certificate.key.length x509.san_dns' + showSubtitle: true + - name: x509 + description: x.509 grouped by name and issuer + query: 'event.dataset:x509 | groupby x509.san_dns x509.certificate.issuer' + showSubtitle: true + - name: x509 + description: x.509 grouped by name and subject + query: 'event.dataset:x509 | groupby x509.san_dns x509.certificate.subject' + showSubtitle: true + - name: Firewall + description: Firewall events grouped by action + query: 'event.dataset:firewall | groupby rule.action' + showSubtitle: true + dashboards: + advanced: true + groupItemsPerPage: 10 + groupFetchLimit: 10 + eventItemsPerPage: 10 + eventFetchLimit: 100 + relativeTimeValue: 24 + relativeTimeUnit: 30 + mostRecentlyUsedLimit: 0 + ackEnabled: false + escalateEnabled: true + escalateRelatedEventsEnabled: true + aggregationActionsEnabled: false + queryBaseFilter: '' + queryToggleFilters: + - name: caseExcludeToggle + filter: 'NOT _index:"*:so-case*"' + enabled: true + queries: + - name: Overview + description: Overview of all events + query: '* | groupby -sankey event.dataset event.category* | groupby -pie event.category | groupby -bar event.module* | groupby event.dataset | groupby event.module* | groupby event.category | groupby observer.name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: SOC Auth + description: SOC (Security Onion Console) authentication logs + query: 'event.module:kratos AND event.dataset:audit AND msg:authenticated | groupby -sankey http_request.headers.x-real-ip identity_id | groupby http_request.headers.x-real-ip | groupby identity_id | groupby http_request.headers.user-agent' + - name: Elastalerts + description: Elastalert logs + query: '_index: "*:elastalert*" | groupby rule_name | groupby alert_info.type' + - name: Alerts + description: Overview of all alerts + query: 'event.dataset:alert | groupby event.module* | groupby rule.name | groupby event.severity | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: NIDS Alerts + description: NIDS (Network Intrusion Detection System) alerts + query: 'event.category:network AND event.dataset:alert | groupby rule.category | groupby -sankey source.ip destination.ip | groupby rule.name | groupby rule.uuid | groupby rule.gid | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Sysmon Overview + description: Overview of all Sysmon data types + query: 'event.dataset:windows.sysmon_operational | groupby -sankey event.action host.name | groupby -sankey host.name user.name | groupby host.name | groupby event.category event.action | groupby user.name | groupby dns.question.name | groupby process.executable | groupby winlog.event_data.TargetObject | groupby file.name | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Host Overview + description: Overview of all host data types + query: '((event.category:registry OR event.category:host OR event.category:process OR event.category:driver OR event.category:configuration) OR (event.category:file AND _exists_:process.executable) OR (event.category:network AND _exists_:host.name)) | groupby event.dataset* event.category* event.action* | groupby event.type | groupby host.name | groupby user.name | groupby file.name | groupby process.executable' + - name: Host Registry Changes + description: Windows Registry changes + query: 'event.category: registry | groupby -sankey event.action host.name | groupby event.dataset event.action | groupby host.name | groupby process.executable | groupby registry.path | groupby process.executable registry.path' + - name: Host DNS & Process Mappings + description: DNS queries mapped to originating processes + query: 'event.category: network AND _exists_:process.executable AND (_exists_:dns.question.name OR _exists_:dns.answers.data) | groupby -sankey host.name dns.question.name | groupby event.dataset event.type | groupby host.name | groupby process.executable | groupby dns.question.name | groupby dns.answers.data' + - name: Host Process Activity + description: Process activity captured on an endpoint + query: 'event.category:process | groupby -sankey host.name user.name* | groupby event.dataset event.action | groupby host.name | groupby user.name | groupby process.working_directory | groupby process.executable | groupby process.command_line | groupby process.parent.executable | groupby process.parent.command_line | groupby -sankey process.parent.executable process.executable' + - name: Host File Activity + description: File activity captured on an endpoint + query: 'event.category: file AND _exists_:process.executable | groupby -sankey host.name process.executable | groupby host.name | groupby event.dataset event.action event.type | groupby file.name | groupby process.executable' + - name: Host Network & Process Mappings + description: Network activity mapped to originating processes + query: 'event.category: network AND _exists_:process.executable | groupby -sankey event.action host.name | groupby -sankey host.name user.name | groupby event.dataset* event.type* event.action* | groupby host.name | groupby user.name | groupby dns.question.name | groupby process.executable | groupby winlog.event_data.TargetObject | groupby process.name | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Strelka + description: Strelka file analysis + query: 'event.module:strelka | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.name' + - name: Zeek Notice + description: Zeek notice logs + query: 'event.dataset:notice | groupby -sankey notice.note destination.ip | groupby notice.note | groupby notice.message | groupby notice.sub_message | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Connections + description: Network connection metadata + query: 'event.dataset:conn | groupby source.ip | groupby destination.ip | groupby destination.port | groupby -sankey destination.port network.protocol | groupby network.protocol | groupby network.transport | groupby connection.history | groupby connection.state | groupby connection.state_description | groupby source.geo.country_name | groupby destination.geo.country_name | groupby client.ip_bytes | groupby server.ip_bytes | groupby client.oui' + - name: DCE_RPC + description: DCE_RPC (Distributed Computing Environment / Remote Procedure Calls) network metadata + query: 'event.dataset:dce_rpc | groupby -sankey dce_rpc.endpoint dce_rpc.operation | groupby dce_rpc.endpoint | groupby dce_rpc.operation | groupby dce_rpc.named_pipe | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: DHCP + description: DHCP (Dynamic Host Configuration Protocol) leases + query: 'event.dataset:dhcp | groupby host.hostname | groupby dhcp.message_types | groupby -sankey client.address server.address | groupby client.address | groupby server.address | groupby host.domain' + - name: DNS + description: DNS (Domain Name System) queries + query: 'event.dataset:dns | groupby dns.query.name | groupby dns.highest_registered_domain | groupby dns.parent_domain | groupby -sankey source.ip destination.ip | groupby dns.answers.name | groupby dns.query.type_name | groupby dns.response.code_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: DPD + description: DPD (Dynamic Protocol Detection) errors + query: 'event.dataset:dpd | groupby error.reason | groupby network.protocol | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Files + description: Files seen in network traffic + query: 'event.dataset:file | groupby file.mime_type | groupby -sankey file.mime_type file.source | groupby file.source | groupby file.bytes.total | groupby source.ip | groupby destination.ip | groupby destination_geo.organization_name' + - name: FTP + description: FTP (File Transfer Protocol) network metadata + query: 'event.dataset:ftp | groupby -sankey ftp.command destination.ip | groupby ftp.command | groupby ftp.argument | groupby ftp.user | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: HTTP + description: HTTP (Hyper Text Transport Protocol) network metadata + query: 'event.dataset:http | groupby http.method | groupby -sankey http.method http.virtual_host | groupby http.virtual_host | groupby http.uri | groupby http.useragent | groupby http.status_code | groupby http.status_message | groupby file.resp_mime_types | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Intel + description: Zeek Intel framework hits + query: 'event.dataset:intel | groupby intel.indicator | groupby -sankey source.ip intel.indicator | groupby intel.indicator_type | groupby intel.seen_where | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: IRC + description: IRC (Internet Relay Chat) network metadata + query: 'event.dataset:irc | groupby irc.command.type | groupby -sankey irc.command.type irc.username | groupby irc.username | groupby irc.nickname | groupby irc.command.value | groupby irc.command.info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Kerberos + description: Kerberos network metadata + query: 'event.dataset:kerberos | groupby kerberos.service | groupby -sankey kerberos.service destination.ip | groupby kerberos.client | groupby kerberos.request_type | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: MySQL + description: MySQL network metadata + query: 'event.dataset:mysql | groupby mysql.command | groupby -sankey mysql.command destination.ip | groupby mysql.argument | groupby mysql.success | groupby mysql.response | groupby mysql.rows | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: NTLM + description: NTLM (New Technology LAN Manager) network metadata + query: 'event.dataset:ntlm | groupby ntlm.server.dns.name | groupby ntlm.server.nb.name | groupby -sankey source.ip destination.ip | groupby ntlm.server.tree.name | groupby ntlm.success | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: PE + description: PE (Portable Executable) files transferred via network traffic + query: 'event.dataset:pe | groupby file.machine | groupby -sankey file.machine file.os | groupby file.os | groupby file.subsystem | groupby file.section_names | groupby file.is_exe | groupby file.is_64bit' + - name: RADIUS + description: RADIUS (Remote Authentication Dial-In User Service) network metadata + query: 'event.dataset:radius | groupby -sankey user.name.keyword destination.ip | groupby user.name.keyword | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: RDP + description: RDP (Remote Desktop Protocol) network metadata + query: 'event.dataset:rdp | groupby client.name | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: RFB + description: RFB (Remote Frame Buffer) network metadata + query: 'event.dataset:rfb | groupby rfb.desktop.name.keyword | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: Signatures + description: Zeek signatures + query: 'event.dataset:signatures | groupby signature_id' + - name: SIP + description: SIP (Session Initiation Protocol) network metadata + query: 'event.dataset:sip | groupby client.user_agent | groupby sip.method | groupby sip.uri | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: SMB_Files + description: Files transferred via SMB (Server Message Block) + query: 'event.dataset:smb_files | groupby file.action | groupby file.path | groupby file.name | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: SMB_Mapping + description: SMB (Server Message Block) mapping network metadata + query: 'event.dataset:smb_mapping | groupby smb.share_type | groupby smb.path | groupby smb.service | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: SMTP + description: SMTP (Simple Mail Transfer Protocol) network metadata + query: 'event.dataset:smtp | groupby smtp.from | groupby smtp.recipient_to | groupby -sankey source.ip destination.ip | groupby smtp.subject | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: SNMP + description: SNMP (Simple Network Management Protocol) network metadat + query: 'event.dataset:snmp | groupby snmp.community | groupby snmp.version | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Software + description: Software seen by Zeek via network traffic + query: 'event.dataset:software | groupby -sankey software.type source.ip | groupby software.type | groupby software.name | groupby source.ip' + - name: SSH + description: SSH (Secure Shell) connections seen by Zeek + query: 'event.dataset:ssh | groupby ssh.client | groupby ssh.server | groupby -sankey source.ip destination.ip | groupby ssh.direction | groupby ssh.version | groupby ssh.hassh_version | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: SSL + description: SSL/TLS network metadata + query: 'event.dataset:ssl | groupby ssl.version | groupby ssl.validation_status | groupby -sankey source.ip ssl.server_name | groupby ssl.server_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby ssl.certificate.issuer | groupby ssl.certificate.subject' + - name: STUN + description: STUN (Session Traversal Utilities for NAT) network metadata + query: 'event.dataset:stun* | groupby -sankey source.ip destination.ip | groupby destination.geo.country_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby event.dataset' + - name: Syslog + description: Syslog logs + query: 'event.dataset:syslog | groupby syslog.severity_label | groupby syslog.facility_label | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby network.protocol' + - name: TDS + description: TDS (Tabular Data Stream) network metadata + query: 'event.dataset:tds* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby tds.command | groupby tds.header_type | groupby tds.procedure_name | groupby source.ip | groupby destination.ip | groupby destination.port | groupby tds.query' + - name: Tunnel + description: Tunnels seen by Zeek + query: 'event.dataset:tunnel | groupby -sankey source.ip destination.ip | groupby tunnel.type | groupby event.action | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name' + - name: Weird + description: Weird network traffic seen by Zeek + query: 'event.dataset:weird | groupby -sankey weird.name destination.ip | groupby weird.name | groupby weird.additional_info | groupby source.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name' + - name: WireGuard + description: WireGuard VPN network metadata + query: 'event.dataset:wireguard | groupby -sankey source.ip destination.ip | groupby destination.geo.country_name | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: x509 + description: x.509 certificates seen by Zeek + query: 'event.dataset:x509 | groupby -sankey x509.certificate.key.length x509.san_dns | groupby x509.certificate.key.length | groupby x509.san_dns | groupby x509.certificate.key.type | groupby x509.certificate.subject | groupby x509.certificate.issuer' + - name: ICS Overview + description: Overview of ICS (Industrial Control Systems) network metadata + query: 'tags:ics | groupby event.dataset | groupby -sankey source.ip destination.ip | groupby source.ip | groupby destination.ip | groupby destination.port | groupby source.mac | groupby destination.mac' + - name: ICS BACnet + description: BACnet (Building Automation and Control Networks) network metadata + query: 'event.dataset:bacnet* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS BSAP + description: BSAP (Bristol Standard Asynchronous Protocol) network metadata + query: 'event.dataset:bsap* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS CIP + description: CIP (Common Industrial Protocol) network metadata + query: 'event.dataset:cip* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS COTP + description: COTP (Connection Oriented Transport Protocol) network metadata + query: 'event.dataset:cotp* | groupby -sankey source.ip destination.ip | groupby cotp.pdu.name | groupby cotp.pdu.code | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS DNP3 + description: DNP3 (Distributed Network Protocol) network metadata + query: 'event.dataset:dnp3* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby dnp3.function_code | groupby dnp3.object_type | groupby dnp3.fc_request | groupby dnp3.fc_reply | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS ECAT + description: ECAT (Ethernet for Control Automation Technology) network metadata + query: 'event.dataset:ecat* | groupby -sankey event.dataset source.mac destination.mac | groupby event.dataset | groupby source.mac | groupby destination.mac | groupby ecat.command | groupby ecat.register.type' + - name: ICS ENIP + description: ENIP (Ethernet Industrial Protocol) network metadata + query: 'event.dataset:enip* | groupby -sankey source.ip destination.ip | groupby enip.command | groupby enip.status_code | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS Modbus + description: Modbus network metadata + query: 'event.dataset:modbus* | groupby -sankey event.dataset modbus.function | groupby event.dataset | groupby modbus.function | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS OPC UA + description: OPC UA (Unified Architecture) network metadata + query: 'event.dataset:opcua* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS Profinet + description: Profinet (Process Field Network) network metadata + query: 'event.dataset:profinet* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: ICS S7 + description: S7 (Siemens) network metadata + query: 'event.dataset:s7* | groupby -sankey event.dataset source.ip destination.ip | groupby event.dataset | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: Firewall + description: Firewall logs + query: 'event.dataset:firewall | groupby -sankey rule.action interface.name | groupby rule.action | groupby interface.name | groupby network.transport | groupby source.ip | groupby destination.ip | groupby destination.port' + - name: VLAN + description: VLAN (Virtual Local Area Network) tagged logs + query: '* AND _exists_:network.vlan.id | groupby network.vlan.id | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby event.dataset | groupby event.module | groupby observer.name | groupby source.geo.country_name | groupby destination.geo.country_name' + - name: GeoIP - Destination Countries + description: GeoIP tagged logs visualized by destination countries + query: '* AND _exists_:destination.geo.country_name | groupby destination.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination_geo.organization_name | groupby event.dataset | groupby event.module' + - name: GeoIP - Destination Organizations + description: GeoIP tagged logs visualized by destination organizations + query: '* AND _exists_:destination_geo.organization_name | groupby destination_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby destination.geo.country_name | groupby event.dataset | groupby event.module' + - name: GeoIP - Source Countries + description: GeoIP tagged logs visualized by source countries + query: '* AND _exists_:source.geo.country_name | groupby source.geo.country_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source_geo.organization_name | groupby event.dataset | groupby event.module' + - name: GeoIP - Source Organizations + description: GeoIP tagged logs visualized by source organizations + query: '* AND _exists_:source_geo.organization_name | groupby source_geo.organization_name | groupby source.ip | groupby -sankey source.ip destination.ip | groupby destination.ip | groupby destination.port | groupby source.geo.country_name | groupby event.dataset | groupby event.module' + job: + alerts: + advanced: false + groupItemsPerPage: 50 + groupFetchLimit: 500 + eventItemsPerPage: 50 + eventFetchLimit: 500 + relativeTimeValue: 24 + relativeTimeUnit: 30 + mostRecentlyUsedLimit: 5 + ackEnabled: true + escalateEnabled: true + escalateRelatedEventsEnabled: true + aggregationActionsEnabled: true + eventFields: + default: + - soc_timestamp + - rule.name + - event.severity_label + - source.ip + - source.port + - destination.ip + - destination.port + - rule.gid + - rule.uuid + - rule.category + - rule.rev + ':ossec:': + - soc_timestamp + - rule.name + - event.severity_label + - source.ip + - source.port + - destination.ip + - destination.port + - rule.level + - rule.category + - process.name + - user.name + - user.escalated + - location + - process.name + queryBaseFilter: event.dataset:alert + queryToggleFilters: + - name: acknowledged + filter: event.acknowledged:true + enabled: false + exclusive: true + - name: escalated + filter: event.escalated:true + enabled: false + exclusive: true + enablesToggles: + - acknowledged + queries: + - name: 'Group By Name, Module' + query: '* | groupby rule.name event.module* event.severity_label' + - name: 'Group By Sensor, Source IP/Port, Destination IP/Port, Name' + query: '* | groupby observer.name source.ip source.port destination.ip destination.port rule.name network.community_id event.severity_label' + - name: 'Group By Source IP, Name' + query: '* | groupby source.ip rule.name event.severity_label' + - name: 'Group By Source Port, Name' + query: '* | groupby source.port rule.name event.severity_label' + - name: 'Group By Destination IP, Name' + query: '* | groupby destination.ip rule.name event.severity_label' + - name: 'Group By Destination Port, Name' + query: '* | groupby destination.port rule.name event.severity_label' + - name: Ungroup + query: '*' + cases: + advanced: false + aggregationActionsEnabled: false + groupItemsPerPage: 50 + groupFetchLimit: 100 + eventItemsPerPage: 50 + eventFetchLimit: 500 + relativeTimeValue: 12 + relativeTimeUnit: 60 + mostRecentlyUsedLimit: 5 + ackEnabled: false + escalateEnabled: false + escalateRelatedEventsEnabled: false + viewEnabled: true + createLink: /case/create + eventFields: + default: + - soc_timestamp + - so_case.title + - so_case.status + - so_case.severity + - so_case.assigneeId + - so_case.createTime + queryBaseFilter: '_index:"*:so-case" AND so_kind:case' + queryToggleFilters: [] + queries: + - name: Open Cases + query: 'NOT so_case.status:closed AND NOT so_case.category:template' + - name: Closed Cases + query: 'so_case.status:closed AND NOT so_case.category:template' + - name: My Open Cases + query: 'NOT so_case.status:closed AND NOT so_case.category:template AND so_case.assigneeId:{myId}' + - name: My Closed Cases + query: 'so_case.status:closed AND NOT so_case.category:template AND so_case.assigneeId:{myId}' + - name: Templates + query: 'so_case.category:template' + case: + analyzerNodeId: + mostRecentlyUsedLimit: 5 + renderAbbreviatedCount: 30 + presets: + artifactType: + labels: + - autonomous-system + - domain + - file + - filename + - fqdn + - hash + - ip + - mail + - mail_subject + - other + - regexp + - registry + - uri_path + - url + - user-agent + customEnabled: true + category: + labels: + - general + - template + customEnabled: true + pap: + labels: + - white + - green + - amber + - red + customEnabled: false + severity: + labels: + - low + - medium + - high + - critical + customEnabled: false + status: + labels: + - new + - in progress + - closed + customEnabled: false + tags: + labels: + - false-positive + - confirmed + - pending + customEnabled: true + tlp: + labels: + - clear + - green + - amber + - amber+strict + - red + customEnabled: false diff --git a/salt/soc/disabled.sls b/salt/soc/disabled.sls new file mode 100644 index 000000000..70b03596f --- /dev/null +++ b/salt/soc/disabled.sls @@ -0,0 +1,31 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - soc.sostatus + +so-soc: + docker_container.absent: + - force: True + +so-soc_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-soc$ + +salt-relay: + cron.absent: + - identifier: salt-relay + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soc/enabled.sls b/salt/soc/enabled.sls new file mode 100644 index 000000000..2e4528080 --- /dev/null +++ b/salt/soc/enabled.sls @@ -0,0 +1,68 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'soc/merged.map.jinja' import DOCKER_EXTRA_HOSTS %} + +include: + - soc.config + - soc.sostatus + +so-soc: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soc:{{ GLOBALS.so_version }} + - hostname: soc + - name: so-soc + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-soc'].ip }} + - binds: + - /nsm/soc/jobs:/opt/sensoroni/jobs:rw + - /opt/so/log/soc/:/opt/sensoroni/logs/:rw + - /opt/so/conf/soc/soc.json:/opt/sensoroni/sensoroni.json:ro + - /opt/so/conf/soc/motd.md:/opt/sensoroni/html/motd.md:ro + - /opt/so/conf/soc/banner.md:/opt/sensoroni/html/login/banner.md:ro + - /opt/so/conf/soc/custom.js:/opt/sensoroni/html/js/custom.js:ro + - /opt/so/conf/soc/custom_roles:/opt/sensoroni/rbac/custom_roles:ro + - /opt/so/conf/soc/soc_users_roles:/opt/sensoroni/rbac/users_roles:rw + - /opt/so/conf/soc/salt:/opt/sensoroni/salt:rw + - /opt/so/saltstack:/opt/so/saltstack:rw + - extra_hosts: {{ DOCKER_EXTRA_HOSTS }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-soc'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - watch: + - file: /opt/so/conf/soc/* + - require: + - file: socdatadir + - file: soclogdir + - file: socconfig + - file: socmotd + - file: socbanner + - file: soccustom + - file: soccustomroles + - file: socusersroles + +delete_so-soc_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-soc$ + +salt-relay: + cron.present: + - name: 'ps -ef | grep salt-relay.sh | grep -v grep > /dev/null 2>&1 || /opt/so/saltstack/default/salt/soc/files/bin/salt-relay.sh >> /opt/so/log/soc/salt-relay.log 2>&1 &' + - identifier: salt-relay + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soc/files/soc/soc.json.jinja b/salt/soc/files/soc/soc.json.jinja index 101959758..91c96d58f 100644 --- a/salt/soc/files/soc/soc.json.jinja +++ b/salt/soc/files/soc/soc.json.jinja @@ -1,2 +1,2 @@ {% from 'soc/merged.map.jinja' import SOCMERGED -%} -{{ SOCMERGED | json(sort_keys=True, indent=4 * ' ') }} +{{ SOCMERGED.config | json(sort_keys=True, indent=4 * ' ') }} diff --git a/salt/soc/init.sls b/salt/soc/init.sls index 8c3ed5104..64531d814 100644 --- a/salt/soc/init.sls +++ b/salt/soc/init.sls @@ -1,160 +1,13 @@ -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'soc/merged.map.jinja' import DOCKER_EXTRA_HOSTS %} +{% from 'soc/merged.map.jinja' import SOCMERGED %} include: - - manager.sync_es_users - -socdir: - file.directory: - - name: /opt/so/conf/soc - - user: 939 - - group: 939 - - makedirs: True - -socdatadir: - file.directory: - - name: /nsm/soc/jobs - - user: 939 - - group: 939 - - makedirs: True - -soclogdir: - file.directory: - - name: /opt/so/log/soc - - user: 939 - - group: 939 - - makedirs: True - -socsaltdir: - file.directory: - - name: /opt/so/conf/soc/salt - - user: 939 - - group: 939 - - makedirs: True - -socconfig: - file.managed: - - name: /opt/so/conf/soc/soc.json - - source: salt://soc/files/soc/soc.json.jinja - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - - show_changes: False - -socmotd: - file.managed: - - name: /opt/so/conf/soc/motd.md - - source: salt://soc/files/soc/motd.md - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - -socbanner: - file.managed: - - name: /opt/so/conf/soc/banner.md - - source: salt://soc/files/soc/banner.md - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - -soc_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://soc/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#soc_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://soc/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -soccustom: - file.managed: - - name: /opt/so/conf/soc/custom.js - - source: salt://soc/files/soc/custom.js - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - -soccustomroles: - file.managed: - - name: /opt/so/conf/soc/custom_roles - - source: salt://soc/files/soc/custom_roles - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - -socusersroles: - file.exists: - - name: /opt/so/conf/soc/soc_users_roles - - require: - - sls: manager.sync_es_users - -salt-relay: - cron.present: - - name: 'ps -ef | grep salt-relay.sh | grep -v grep > /dev/null 2>&1 || /opt/so/saltstack/default/salt/soc/files/bin/salt-relay.sh >> /opt/so/log/soc/salt-relay.log 2>&1 &' - - identifier: salt-relay - -so-soc: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soc:{{ GLOBALS.so_version }} - - hostname: soc - - name: so-soc - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-soc'].ip }} - - binds: - - /nsm/soc/jobs:/opt/sensoroni/jobs:rw - - /opt/so/log/soc/:/opt/sensoroni/logs/:rw - - /opt/so/conf/soc/soc.json:/opt/sensoroni/sensoroni.json:ro - - /opt/so/conf/soc/motd.md:/opt/sensoroni/html/motd.md:ro - - /opt/so/conf/soc/banner.md:/opt/sensoroni/html/login/banner.md:ro - - /opt/so/conf/soc/custom.js:/opt/sensoroni/html/js/custom.js:ro - - /opt/so/conf/soc/custom_roles:/opt/sensoroni/rbac/custom_roles:ro - - /opt/so/conf/soc/soc_users_roles:/opt/sensoroni/rbac/users_roles:rw - - /opt/so/conf/soc/salt:/opt/sensoroni/salt:rw - - /opt/so/saltstack:/opt/so/saltstack:rw - - extra_hosts: {{ DOCKER_EXTRA_HOSTS }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-soc'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - watch: - - file: /opt/so/conf/soc/* - - require: - - file: socdatadir - - file: soclogdir - - file: socconfig - - file: socmotd - - file: socbanner - - file: soccustom - - file: soccustomroles - - file: socusersroles - -append_so-soc_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-soc - +{% if SOCMERGED.enabled %} + - soc.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - soc.disabled {% endif %} diff --git a/salt/soc/merged.map.jinja b/salt/soc/merged.map.jinja index 9589e9897..dc2f889bb 100644 --- a/salt/soc/merged.map.jinja +++ b/salt/soc/merged.map.jinja @@ -1,3 +1,8 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'soc/defaults.map.jinja' import SOCDEFAULTS with context %} {% from 'logstash/map.jinja' import LOGSTASH_NODES %} @@ -6,14 +11,14 @@ {% set SOCMERGED = salt['pillar.get']('soc', SOCDEFAULTS, merge=true) %} -{# if SOCMERGED.server.modules.cases == httpcase details come from the soc pillar #} -{% if SOCMERGED.server.modules.cases != 'soc' %} -{% do SOCMERGED.server.modules.elastic.update({'casesEnabled': false}) %} -{% do SOCMERGED.server.client.update({'casesEnabled': false}) %} -{% do SOCMERGED.server.client.hunt.update({'escalateRelatedEventsEnabled': false}) %} -{% do SOCMERGED.server.client.alerts.update({'escalateRelatedEventsEnabled': false}) %} -{% if SOCMERGED.server.modules.cases == 'elasticcases' %} -{% do SOCMERGED.server.modules.update({ +{# if SOCMERGED.config.server.modules.cases == httpcase details come from the soc pillar #} +{% if SOCMERGED.config.server.modules.cases != 'soc' %} +{% do SOCMERGED.config.server.modules.elastic.update({'casesEnabled': false}) %} +{% do SOCMERGED.config.server.client.update({'casesEnabled': false}) %} +{% do SOCMERGED.config.server.client.hunt.update({'escalateRelatedEventsEnabled': false}) %} +{% do SOCMERGED.config.server.client.alerts.update({'escalateRelatedEventsEnabled': false}) %} +{% if SOCMERGED.config.server.modules.cases == 'elasticcases' %} +{% do SOCMERGED.config.server.modules.update({ 'elasticcases': { 'hostUrl': 'https://' ~ GLOBALS.manager_ip ~ ':5601', 'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, @@ -23,13 +28,13 @@ {% endif %} {% endif %} {# since cases is not a valid soc config item and only used for the map files, remove it from being placed in the config #} -{% do SOCMERGED.server.modules.pop('cases') %} +{% do SOCMERGED.config.server.modules.pop('cases') %} {% if pillar.manager.playbook == 0 %} -{% do SOCMERGED.server.client.inactiveTools.append('toolPlaybook') %} +{% do SOCMERGED.config.server.client.inactiveTools.append('toolPlaybook') %} {% endif %} -{% set standard_actions = SOCMERGED.pop('actions') %} +{% set standard_actions = SOCMERGED.config.pop('actions') %} {% if pillar.global.endgamehost is defined %} {% set endgame_dict = { "name": "Endgame", @@ -42,12 +47,12 @@ {% do standard_actions.append(endgame_dict) %} {% endif %} -{% do SOCMERGED.server.client.hunt.update({'actions': standard_actions}) %} -{% do SOCMERGED.server.client.dashboards.update({'actions': standard_actions}) %} -{% do SOCMERGED.server.client.update({'job': {'actions': standard_actions}}) %} -{% do SOCMERGED.server.client.alerts.update({'actions': standard_actions}) %} -{% do SOCMERGED.server.client.cases.update({'actions': standard_actions}) %} +{% do SOCMERGED.config.server.client.hunt.update({'actions': standard_actions}) %} +{% do SOCMERGED.config.server.client.dashboards.update({'actions': standard_actions}) %} +{% do SOCMERGED.config.server.client.update({'job': {'actions': standard_actions}}) %} +{% do SOCMERGED.config.server.client.alerts.update({'actions': standard_actions}) %} +{% do SOCMERGED.config.server.client.cases.update({'actions': standard_actions}) %} -{% set standard_eventFields = SOCMERGED.pop('eventFields') %} -{% do SOCMERGED.server.client.hunt.update({'eventFields': standard_eventFields}) %} -{% do SOCMERGED.server.client.dashboards.update({'eventFields': standard_eventFields}) %} +{% set standard_eventFields = SOCMERGED.config.pop('eventFields') %} +{% do SOCMERGED.config.server.client.hunt.update({'eventFields': standard_eventFields}) %} +{% do SOCMERGED.config.server.client.dashboards.update({'eventFields': standard_eventFields}) %} diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 17737abe4..6551b632b 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -1,224 +1,228 @@ soc: - licenseKey: - title: License Key - description: Optional Security Onion license key to unlock enterprise features. - global: True - logLevel: - title: Log Level - description: The SOC log level, useful for enabling debug logging for advanced troubleshooting. Allowed values are debug, info, warn, error. The SOC log is available at /opt/so/log/soc/sensoroni-server.log. - global: True - regex: ^(info|debug|warn|error)$ - files: - soc: - banner__md: - title: Login Banner - description: Customize the login page with a specific markdown-formatted message. - file: True - global: True - syntax: md - helpLink: soc-customization.html - motd__md: - title: Overview Page - description: Customize the overview page with specific markdown-formatted content. Images can be used but must be hosted from another host that is accessible by the user's browser. - file: True - global: True - syntax: md - helpLink: soc-customization.html - custom__js: - title: Custom Javascript - description: Customize SOC UI behavior with custom Javascript code. Custom Javascript not provided by Security Onion Solutions is unsupported, and should be removed prior to requesting support and prior to performing upgrades. - file: True - global: True - advanced: True - helpLink: soc-customization.html - custom_roles: - title: Custom Roles - description: Customize role and permission mappings. Changing this setting requires a complete understanding of the SOC RBAC system. - file: True - global: True - advanced: True - helpLink: soc-customization.html - actions: - description: A list of actions a user can take from the SOC UI against a hunt, alert, and other records. The action must be defined in JSON object format, and contain a "name" key and "links" key. The links is a list of URLs, where the most suitable URL in the list will be the selected URL when the user clicks the action. - global: True - eventFields: - default: - description: The list of fields to show as columns in the Hunt/Dashboards event table, when no other specific mapping applies. Mappings are defined by the format ":event.module:event.dataset". + enabled: + description: You can enable or disable SOC. + advanced: True + config: + licenseKey: + title: License Key + description: Optional Security Onion license key to unlock enterprise features. global: True - advanced: True - server: - srvKey: - description: Unique key for protecting the integrity of user submitted data via the web browser. + logLevel: + title: Log Level + description: The SOC log level, useful for enabling debug logging for advanced troubleshooting. Allowed values are debug, info, warn, error. The SOC log is available at /opt/so/log/soc/sensoroni-server.log. global: True - sensitive: True - advanced: True - maxPacketCount: - description: Maximum number of packets to show in the PCAP viewer. Larger values can cause more resource utilization on both the SOC server and the browser. - global: True - advanced: True - modules: - elastic: - index: - description: Comma-separated list of indices or index patterns (wildcard "*" supported) that SOC will search for records. + regex: ^(info|debug|warn|error)$ + files: + soc: + banner__md: + title: Login Banner + description: Customize the login page with a specific markdown-formatted message. + file: True + global: True + syntax: md + helpLink: soc-customization.html + motd__md: + title: Overview Page + description: Customize the overview page with specific markdown-formatted content. Images can be used but must be hosted from another host that is accessible by the user's browser. + file: True + global: True + syntax: md + helpLink: soc-customization.html + custom__js: + title: Custom Javascript + description: Customize SOC UI behavior with custom Javascript code. Custom Javascript not provided by Security Onion Solutions is unsupported, and should be removed prior to requesting support and prior to performing upgrades. + file: True global: True advanced: True - cacheMs: - description: Duration (in milliseconds) to cache the Elasticsearch index field data to minimize repeated requests for this typically static information. + helpLink: soc-customization.html + custom_roles: + title: Custom Roles + description: Customize role and permission mappings. Changing this setting requires a complete understanding of the SOC RBAC system. + file: True global: True advanced: True - timeoutMs: - description: Duration (in milliseconds) to wait for a response from the Elasticsearch host before giving up and showing an error on the SOC UI. + helpLink: soc-customization.html + actions: + description: A list of actions a user can take from the SOC UI against a hunt, alert, and other records. The action must be defined in JSON object format, and contain a "name" key and "links" key. The links is a list of URLs, where the most suitable URL in the list will be the selected URL when the user clicks the action. + global: True + eventFields: + default: + description: The list of fields to show as columns in the Hunt/Dashboards event table, when no other specific mapping applies. Mappings are defined by the format ":event.module:event.dataset". + global: True + advanced: True + server: + srvKey: + description: Unique key for protecting the integrity of user submitted data via the web browser. + global: True + sensitive: True + advanced: True + maxPacketCount: + description: Maximum number of packets to show in the PCAP viewer. Larger values can cause more resource utilization on both the SOC server and the browser. + global: True + advanced: True + modules: + elastic: + index: + description: Comma-separated list of indices or index patterns (wildcard "*" supported) that SOC will search for records. + global: True + advanced: True + cacheMs: + description: Duration (in milliseconds) to cache the Elasticsearch index field data to minimize repeated requests for this typically static information. + global: True + advanced: True + timeoutMs: + description: Duration (in milliseconds) to wait for a response from the Elasticsearch host before giving up and showing an error on the SOC UI. + global: True + advanced: True + casesEnabled: + description: Set to true if the SOC case management module, natively integrated with Elasticsearch, should be enabled. + global: True + advanced: True + extractCommonObservables: + description: List of indexed fields to automatically extract into a case observable, when attaching related events to a case. + global: True + timeShiftMs: + description: Duration (in milliseconds) to further expand the PCAP time range when querying PCAP data related to an event. This duration is added to the normal duration value (see defaultDurationMs). + global: True + advanced: True + defaultDurationMs: + description: Duration (in milliseconds) to add before and after the event's timestamp, when querying PCAP data related to the event. If the PCAP-related event record itself has an event.duration value, it will be used instead of this default. + global: True + advanced: True + esSearchOffsetMs: + description: Duration (in milliseconds) to add before and after the selected event's timestamp, when looking up PCAP-related events in order to pivot to PCAP. + global: True + advanced: True + maxLogLength: + description: The maximum length of an Elasticsearch related log line that is output to the Sensoroni log file. This prevents massive Elasticsearch responses from being dumped into the text log file on disk. + global: True + advanced: True + asyncThreshold: + description: Maximum number of events that can be acknowledged synchronously. When acknowledging large numbers of events, where the count exceeds this value, the acknowledge update will be performed in the background, as it can take several minutes to complete. + global: True + advanced: True + sostatus: + refreshIntervalMs: + description: Duration (in milliseconds) between refreshes of the grid status. Shortening this duration may not have expected results, as the backend systems feeding this sostatus data will continue their updates as scheduled. + global: True + advanced: True + offlineThresholdMs: + description: Duration (in milliseconds) that must elapse after a grid node fails to check-in before the node will be marked offline (fault). + global: True + advanced: True + client: + apiTimeoutMs: + description: Duration (in milliseconds) to wait for a response from the SOC server API before giving up and showing an error on the SOC UI. + global: True + advanced: True + webSocketTimeoutMs: + description: Duration (in milliseconds) to wait for a response from the SOC server websocket before giving up and reconnecting. + global: True + advanced: True + tipTimeoutMs: + description: Duration (in milliseconds) to show the popup tips, which typically indicate a successful operation. + global: True + cacheExpirationMs: + description: Duration (in milliseconds) of cached data within the browser, including users and settings. global: True advanced: True casesEnabled: - description: Set to true if the SOC case management module, natively integrated with Elasticsearch, should be enabled. + description: Set to true to enable case management in SOC. + global: True + inactiveTools: + description: List of external tools to remove from the SOC UI. + global: True + tools: + description: List of available external tools visible in the SOC UI. Each tool is defined in JSON object notation, and must include the "name" key and "link" key, where the link is the tool's URL. global: True advanced: True - extractCommonObservables: - description: List of indexed fields to automatically extract into a case observable, when attaching related events to a case. - global: True - timeShiftMs: - description: Duration (in milliseconds) to further expand the PCAP time range when querying PCAP data related to an event. This duration is added to the normal duration value (see defaultDurationMs). - global: True - advanced: True - defaultDurationMs: - description: Duration (in milliseconds) to add before and after the event's timestamp, when querying PCAP data related to the event. If the PCAP-related event record itself has an event.duration value, it will be used instead of this default. - global: True - advanced: True - esSearchOffsetMs: - description: Duration (in milliseconds) to add before and after the selected event's timestamp, when looking up PCAP-related events in order to pivot to PCAP. - global: True - advanced: True - maxLogLength: - description: The maximum length of an Elasticsearch related log line that is output to the Sensoroni log file. This prevents massive Elasticsearch responses from being dumped into the text log file on disk. - global: True - advanced: True - asyncThreshold: - description: Maximum number of events that can be acknowledged synchronously. When acknowledging large numbers of events, where the count exceeds this value, the acknowledge update will be performed in the background, as it can take several minutes to complete. - global: True - advanced: True - sostatus: - refreshIntervalMs: - description: Duration (in milliseconds) between refreshes of the grid status. Shortening this duration may not have expected results, as the backend systems feeding this sostatus data will continue their updates as scheduled. - global: True - advanced: True - offlineThresholdMs: - description: Duration (in milliseconds) that must elapse after a grid node fails to check-in before the node will be marked offline (fault). - global: True - advanced: True - client: - apiTimeoutMs: - description: Duration (in milliseconds) to wait for a response from the SOC server API before giving up and showing an error on the SOC UI. - global: True - advanced: True - webSocketTimeoutMs: - description: Duration (in milliseconds) to wait for a response from the SOC server websocket before giving up and reconnecting. - global: True - advanced: True - tipTimeoutMs: - description: Duration (in milliseconds) to show the popup tips, which typically indicate a successful operation. - global: True - cacheExpirationMs: - description: Duration (in milliseconds) of cached data within the browser, including users and settings. - global: True - advanced: True - casesEnabled: - description: Set to true to enable case management in SOC. - global: True - inactiveTools: - description: List of external tools to remove from the SOC UI. - global: True - tools: - description: List of available external tools visible in the SOC UI. Each tool is defined in JSON object notation, and must include the "name" key and "link" key, where the link is the tool's URL. - global: True - advanced: True - hunt: &appSettings - groupItemsPerPage: - description: Default number of aggregations to show per page. Larger values consume more vertical area in the SOC UI. - global: True - groupFetchLimit: - description: Default maximum number of aggregations to retrieve per search. Larger values consume more bandwidth and server resources. - global: True - eventItemsPerPage: - description: Default number of items to show per page. Larger values consume more vertical area in the SOC UI. - global: True - eventFetchLimit: - description: Default maximum number of items to retrieve per search. Larger values consume more bandwidth and server resources. - global: True - relativeTimeValue: - description: The duration of time to look backwards when searching for items. Used in combination with the relativeTimeUnit setting. - global: True - relativeTimeUnit: - description: The unit of time for the relativeTimeValue setting. Possible values are 10 (seconds), 20 (minutes), 30 (hours), 40 (days), 50 (weeks), and 60 (months). - global: True - mostRecentlyUsedLimit: - description: Number of items to show in the most recently used queries list. Larger values cause default queries to be located further down the list. - global: True - queries: - description: List of default queries to show in the query list. Each query is represented in JSON object notation, and must include the "name" key and "query" key. - global: True - alerts: *appSettings - cases: *appSettings - dashboards: *appSettings - case: - analyzerNodeId: - description: The node ID on which analyzers will be executed. - global: True - advanced: True - mostRecentlyUsedLimit: - description: Number of items to show in the most recently used queries list. Larger values cause default queries to be located further down the list. - global: True - renderAbbreviatedCount: - description: When the number of case related items exceeds this number, the middle section of the results will be hidden from view, avoiding unnecessary scrolling. - global: True - advanced: True - presets: - artifactType: - labels: - description: List of available artifact types. Some of these default types have special characteristics and related functionality, built into SOC. - global: True - customEnabled: - description: Set to true to allow users add their own artifact types directly in the SOC UI. - global: True - category: - labels: - description: List of available case categories. - global: True - customEnabled: - description: Set to true to allow users add their own categories directly in the SOC UI. - global: True - pap: - labels: - description: List of available PAP (Permissible Actions Protocol) values. - global: True - customEnabled: - description: Set to true to allow users add their own PAP values directly in the SOC UI. - global: True - severity: - labels: - description: List of available case severities. - global: True - customEnabled: - description: Set to true to allow users add their own severities directly in the SOC UI. - global: True - status: - labels: - description: List of available case statuses. Some statuses have specifial characteristics and related functionality built into SOC. - global: True - customEnabled: - description: Set to true to allow users add their own case statuses directly in the SOC UI. - global: True - tags: - labels: - description: List of available tags. - global: True - customEnabled: - description: Set to true to allow users add their own tags directly in the SOC UI. - global: True - tlp: - labels: - description: List of available TLP (Traffic Light Protocol) values. - global: True - customEnabled: - description: Set to true to allow users add their own TLP values directly in the SOC UI. - global: True + hunt: &appSettings + groupItemsPerPage: + description: Default number of aggregations to show per page. Larger values consume more vertical area in the SOC UI. + global: True + groupFetchLimit: + description: Default maximum number of aggregations to retrieve per search. Larger values consume more bandwidth and server resources. + global: True + eventItemsPerPage: + description: Default number of items to show per page. Larger values consume more vertical area in the SOC UI. + global: True + eventFetchLimit: + description: Default maximum number of items to retrieve per search. Larger values consume more bandwidth and server resources. + global: True + relativeTimeValue: + description: The duration of time to look backwards when searching for items. Used in combination with the relativeTimeUnit setting. + global: True + relativeTimeUnit: + description: The unit of time for the relativeTimeValue setting. Possible values are 10 (seconds), 20 (minutes), 30 (hours), 40 (days), 50 (weeks), and 60 (months). + global: True + mostRecentlyUsedLimit: + description: Number of items to show in the most recently used queries list. Larger values cause default queries to be located further down the list. + global: True + queries: + description: List of default queries to show in the query list. Each query is represented in JSON object notation, and must include the "name" key and "query" key. + global: True + alerts: *appSettings + cases: *appSettings + dashboards: *appSettings + case: + analyzerNodeId: + description: The node ID on which analyzers will be executed. + global: True + advanced: True + mostRecentlyUsedLimit: + description: Number of items to show in the most recently used queries list. Larger values cause default queries to be located further down the list. + global: True + renderAbbreviatedCount: + description: When the number of case related items exceeds this number, the middle section of the results will be hidden from view, avoiding unnecessary scrolling. + global: True + advanced: True + presets: + artifactType: + labels: + description: List of available artifact types. Some of these default types have special characteristics and related functionality, built into SOC. + global: True + customEnabled: + description: Set to true to allow users add their own artifact types directly in the SOC UI. + global: True + category: + labels: + description: List of available case categories. + global: True + customEnabled: + description: Set to true to allow users add their own categories directly in the SOC UI. + global: True + pap: + labels: + description: List of available PAP (Permissible Actions Protocol) values. + global: True + customEnabled: + description: Set to true to allow users add their own PAP values directly in the SOC UI. + global: True + severity: + labels: + description: List of available case severities. + global: True + customEnabled: + description: Set to true to allow users add their own severities directly in the SOC UI. + global: True + status: + labels: + description: List of available case statuses. Some statuses have specifial characteristics and related functionality built into SOC. + global: True + customEnabled: + description: Set to true to allow users add their own case statuses directly in the SOC UI. + global: True + tags: + labels: + description: List of available tags. + global: True + customEnabled: + description: Set to true to allow users add their own tags directly in the SOC UI. + global: True + tlp: + labels: + description: List of available TLP (Traffic Light Protocol) values. + global: True + customEnabled: + description: Set to true to allow users add their own TLP values directly in the SOC UI. + global: True diff --git a/salt/soc/sostatus.sls b/salt/soc/sostatus.sls new file mode 100644 index 000000000..67640ea4d --- /dev/null +++ b/salt/soc/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-soc_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-soc + - unless: grep -q so-soc /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soctopus/config.sls b/salt/soctopus/config.sls new file mode 100644 index 000000000..35b55d296 --- /dev/null +++ b/salt/soctopus/config.sls @@ -0,0 +1,88 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - nginx.config + +soctopusdir: + file.directory: + - name: /opt/so/conf/soctopus/sigma-import + - user: 939 + - group: 939 + - makedirs: True + +soctopus-sync: + file.recurse: + - name: /opt/so/conf/soctopus/templates + - source: salt://soctopus/files/templates + - user: 939 + - group: 939 + - template: jinja + - defaults: + GLOBALS: {{ GLOBALS }} + +soctopusconf: + file.managed: + - name: /opt/so/conf/soctopus/SOCtopus.conf + - source: salt://soctopus/files/SOCtopus.conf + - user: 939 + - group: 939 + - mode: 600 + - template: jinja + - show_changes: False + - defaults: + GLOBALS: {{ GLOBALS }} + +soctopuslogdir: + file.directory: + - name: /opt/so/log/soctopus + - user: 939 + - group: 939 + +playbookrulesdir: + file.directory: + - name: /opt/so/rules/elastalert/playbook + - user: 939 + - group: 939 + - makedirs: True + +playbookrulessync: + file.recurse: + - name: /opt/so/rules/elastalert/playbook + - source: salt://soctopus/files/templates + - user: 939 + - group: 939 + - template: jinja + - defaults: + GLOBALS: {{ GLOBALS }} + +soctopus_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://soctopus/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#soctopus_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://soctopus/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soctopus/defaults.yaml b/salt/soctopus/defaults.yaml new file mode 100644 index 000000000..cb7f286ae --- /dev/null +++ b/salt/soctopus/defaults.yaml @@ -0,0 +1,2 @@ +soctopus: + enabled: False diff --git a/salt/soctopus/disabled.sls b/salt/soctopus/disabled.sls new file mode 100644 index 000000000..9293a9d71 --- /dev/null +++ b/salt/soctopus/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - soctopus.sostatus + +so-soctopus: + docker_container.absent: + - force: True + +so-soctopus_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-soctopus$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soctopus/enabled.sls b/salt/soctopus/enabled.sls new file mode 100644 index 000000000..9c2ee4de7 --- /dev/null +++ b/salt/soctopus/enabled.sls @@ -0,0 +1,54 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'docker/docker.map.jinja' import DOCKER %} + +include: + - soctopus.config + - soctopus.sostatus + +so-soctopus: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soctopus:{{ GLOBALS.so_version }} + - hostname: soctopus + - name: so-soctopus + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-soctopus'].ip }} + - binds: + - /opt/so/conf/soctopus/SOCtopus.conf:/SOCtopus/SOCtopus.conf:ro + - /opt/so/log/soctopus/:/var/log/SOCtopus/:rw + - /opt/so/rules/elastalert/playbook:/etc/playbook-rules:rw + - /opt/so/conf/navigator/nav_layer_playbook.json:/etc/playbook/nav_layer_playbook.json:rw + - /opt/so/conf/soctopus/sigma-import/:/SOCtopus/sigma-import/:rw + {% if GLOBALS.airgap %} + - /nsm/repo/rules/sigma:/soctopus/sigma + {% endif %} + - port_bindings: + {% for BINDING in DOCKER.containers['so-soctopus'].port_bindings %} + - {{ BINDING }} + {% endfor %} + - extra_hosts: + - {{GLOBALS.url_base}}:{{GLOBALS.manager_ip}} + - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} + - require: + - file: soctopusconf + - file: navigatordefaultlayer + +delete_so-soctopus_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-soctopus$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/soctopus/init.sls b/salt/soctopus/init.sls index 6470d1163..c9359a68c 100644 --- a/salt/soctopus/init.sls +++ b/salt/soctopus/init.sls @@ -1,117 +1,13 @@ -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'soctopus/map.jinja' import SOCTOPUSMERGED %} include: - - nginx - -soctopusdir: - file.directory: - - name: /opt/so/conf/soctopus/sigma-import - - user: 939 - - group: 939 - - makedirs: True - -soctopus-sync: - file.recurse: - - name: /opt/so/conf/soctopus/templates - - source: salt://soctopus/files/templates - - user: 939 - - group: 939 - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - -soctopusconf: - file.managed: - - name: /opt/so/conf/soctopus/SOCtopus.conf - - source: salt://soctopus/files/SOCtopus.conf - - user: 939 - - group: 939 - - mode: 600 - - template: jinja - - show_changes: False - - defaults: - GLOBALS: {{ GLOBALS }} - -soctopuslogdir: - file.directory: - - name: /opt/so/log/soctopus - - user: 939 - - group: 939 - -playbookrulesdir: - file.directory: - - name: /opt/so/rules/elastalert/playbook - - user: 939 - - group: 939 - - makedirs: True - -playbookrulessync: - file.recurse: - - name: /opt/so/rules/elastalert/playbook - - source: salt://soctopus/files/templates - - user: 939 - - group: 939 - - template: jinja - - defaults: - GLOBALS: {{ GLOBALS }} - -soctopus_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://soctopus/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#soctopus_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://soctopus/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -so-soctopus: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-soctopus:{{ GLOBALS.so_version }} - - hostname: soctopus - - name: so-soctopus - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-soctopus'].ip }} - - binds: - - /opt/so/conf/soctopus/SOCtopus.conf:/SOCtopus/SOCtopus.conf:ro - - /opt/so/log/soctopus/:/var/log/SOCtopus/:rw - - /opt/so/rules/elastalert/playbook:/etc/playbook-rules:rw - - /opt/so/conf/navigator/nav_layer_playbook.json:/etc/playbook/nav_layer_playbook.json:rw - - /opt/so/conf/soctopus/sigma-import/:/SOCtopus/sigma-import/:rw - {% if GLOBALS.airgap %} - - /nsm/repo/rules/sigma:/soctopus/sigma - {% endif %} - - port_bindings: - {% for BINDING in DOCKER.containers['so-soctopus'].port_bindings %} - - {{ BINDING }} - {% endfor %} - - extra_hosts: - - {{GLOBALS.url_base}}:{{GLOBALS.manager_ip}} - - {{ GLOBALS.manager }}:{{ GLOBALS.manager_ip }} - - require: - - file: soctopusconf - - file: navigatordefaultlayer - -append_so-soctopus_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-soctopus - +{% if SOCTOPUSMERGED.enabled %} + - soctopus.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - soctopus.disabled {% endif %} diff --git a/salt/soctopus/map.jinja b/salt/soctopus/map.jinja new file mode 100644 index 000000000..07df21dbb --- /dev/null +++ b/salt/soctopus/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'soctopus/defaults.yaml' as SOCTOPUSDEFAULTS %} +{% set SOCTOPUSMERGED = salt['pillar.get']('soctopus', SOCTOPUSDEFAULTS.soctopus, merge=True) %} diff --git a/salt/soctopus/soc_soctopus.yaml b/salt/soctopus/soc_soctopus.yaml index 033405345..51a3a5c52 100644 --- a/salt/soctopus/soc_soctopus.yaml +++ b/salt/soctopus/soc_soctopus.yaml @@ -1,7 +1,10 @@ soctopus: + enabled: + description: You can enable or disable SOCtopus. + helpLink: soctopus.html playbook: rulesets: description: List of playbook rulesets. advanced: True helplink: soctopus.html - global: True \ No newline at end of file + global: True diff --git a/salt/soctopus/sostatus.sls b/salt/soctopus/sostatus.sls new file mode 100644 index 000000000..8a888235e --- /dev/null +++ b/salt/soctopus/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-soctopus_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-soctopus + - unless: grep -q so-soctopus /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index ec807e6aa..e077d55d0 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -35,6 +35,8 @@ include: {% set ca_server = global_ca_server[0] %} {% endif %} + + # Trust the CA trusttheca: x509.pem_managed: diff --git a/salt/strelka/backend/config.sls b/salt/strelka/backend/config.sls new file mode 100644 index 000000000..d51debb1b --- /dev/null +++ b/salt/strelka/backend/config.sls @@ -0,0 +1,69 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: + - strelka.config + - strelka.backend.sostatus + +backend_backend_config: + file.managed: + - name: /opt/so/conf/strelka/backend/backend.yaml + - source: salt://strelka/backend/files/backend.yaml.jinja + - template: jinja + - user: 939 + - group: 939 + - makedirs: True + - defaults: + BACKENDCONFIG: {{ STRELKAMERGED.backend.config.backend }} + +backend_logging_config: + file.managed: + - name: /opt/so/conf/strelka/backend/logging.yaml + - source: salt://strelka/backend/files/logging.yaml.jinja + - template: jinja + - user: 939 + - group: 939 + - defaults: + LOGGINGCONFIG: {{ STRELKAMERGED.backend.config.logging }} + +backend_passwords: + file.managed: + - name: /opt/so/conf/strelka/backend/passwords.dat + - source: salt://strelka/backend/files/passwords.dat.jinja + - template: jinja + - user: 939 + - group: 939 + - defaults: + PASSWORDS: {{ STRELKAMERGED.backend.config.passwords }} + +backend_taste: + file.managed: + - name: /opt/so/conf/strelka/backend/taste/taste.yara + - source: salt://strelka/backend/files/taste/taste.yara + - makedirs: True + - user: 939 + - group: 939 + +{% if STRELKAMERGED.rules.enabled %} +strelkarules: + file.recurse: + - name: /opt/so/conf/strelka/rules + - source: salt://strelka/rules + - user: 939 + - group: 939 + - clean: True +{% endif %} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/backend/disabled.sls b/salt/strelka/backend/disabled.sls new file mode 100644 index 000000000..fcf9136c6 --- /dev/null +++ b/salt/strelka/backend/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.backend.sostatus + +so-strelka-backend: + docker_container.absent: + - force: True + +so-strelka-backend_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-backend$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/backend/enabled.sls b/salt/strelka/backend/enabled.sls new file mode 100644 index 000000000..2ba998e30 --- /dev/null +++ b/salt/strelka/backend/enabled.sls @@ -0,0 +1,41 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.backend.config + - strelka.backend.sostatus + +strelka_backend: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-backend:{{ GLOBALS.so_version }} + - binds: + - /opt/so/conf/strelka/backend/:/etc/strelka/:ro + - /opt/so/conf/strelka/rules/:/etc/yara/:ro + - name: so-strelka-backend + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-backend'].ip }} + - command: strelka-backend + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - restart_policy: on-failure + +delete_so-strelka-backend_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-backend$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/files/backend/backend.yaml.jinja b/salt/strelka/backend/files/backend.yaml.jinja similarity index 100% rename from salt/strelka/files/backend/backend.yaml.jinja rename to salt/strelka/backend/files/backend.yaml.jinja diff --git a/salt/strelka/files/backend/logging.yaml.jinja b/salt/strelka/backend/files/logging.yaml.jinja similarity index 100% rename from salt/strelka/files/backend/logging.yaml.jinja rename to salt/strelka/backend/files/logging.yaml.jinja diff --git a/salt/strelka/files/backend/passwords.dat.jinja b/salt/strelka/backend/files/passwords.dat.jinja similarity index 100% rename from salt/strelka/files/backend/passwords.dat.jinja rename to salt/strelka/backend/files/passwords.dat.jinja diff --git a/salt/strelka/files/backend/taste/taste.yara b/salt/strelka/backend/files/taste/taste.yara similarity index 100% rename from salt/strelka/files/backend/taste/taste.yara rename to salt/strelka/backend/files/taste/taste.yara diff --git a/salt/strelka/backend/init.sls b/salt/strelka/backend/init.sls new file mode 100644 index 000000000..253544c98 --- /dev/null +++ b/salt/strelka/backend/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.backend.enabled %} + - strelka.backend.enabled +{% else %} + - strelka.backend.disabled +{% endif %} diff --git a/salt/strelka/backend/sostatus.sls b/salt/strelka/backend/sostatus.sls new file mode 100644 index 000000000..6de50cfdc --- /dev/null +++ b/salt/strelka/backend/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-backend_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-backend + - unless: grep -q so-strelka-backend /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/config.sls b/salt/strelka/config.sls new file mode 100644 index 000000000..aa51e4b03 --- /dev/null +++ b/salt/strelka/config.sls @@ -0,0 +1,61 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +# Strelka config +strelkaconfdir: + file.directory: + - name: /opt/so/conf/strelka + - user: 939 + - group: 939 + - makedirs: True + +strelkarulesdir: + file.directory: + - name: /opt/so/conf/strelka/rules + - user: 939 + - group: 939 + - makedirs: True + +strelkadatadir: + file.directory: + - name: /nsm/strelka + - user: 939 + - group: 939 + - makedirs: True + +strelkalogdir: + file.directory: + - name: /nsm/strelka/log + - user: 939 + - group: 939 + - makedirs: True + +strelka_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://strelka/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#strelka_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://strelka/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/coordinator/config.sls b/salt/strelka/coordinator/config.sls new file mode 100644 index 000000000..55cb4239c --- /dev/null +++ b/salt/strelka/coordinator/config.sls @@ -0,0 +1,19 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.config + - strelka.coordinator.sostatus + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/coordinator/disabled.sls b/salt/strelka/coordinator/disabled.sls new file mode 100644 index 000000000..4ac20fe0f --- /dev/null +++ b/salt/strelka/coordinator/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.coordinator.sostatus + +so-strelka-coordinator: + docker_container.absent: + - force: True + +so-strelka-coordinator_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-coordinator$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/coordinator/enabled.sls b/salt/strelka/coordinator/enabled.sls new file mode 100644 index 000000000..9f2627344 --- /dev/null +++ b/salt/strelka/coordinator/enabled.sls @@ -0,0 +1,41 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.coordinator.config + - strelka.coordinator.sostatus + +strelka_coordinator: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} + - name: so-strelka-coordinator + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-coordinator'].ip }} + - entrypoint: redis-server --save "" --appendonly no + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-strelka-coordinator'].port_bindings %} + - {{ BINDING }} + {% endfor %} + +delete_so-strelka-coordinator_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-coordinator$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/coordinator/init.sls b/salt/strelka/coordinator/init.sls new file mode 100644 index 000000000..bad4c0a48 --- /dev/null +++ b/salt/strelka/coordinator/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.coordinator.enabled %} + - strelka.coordinator.enabled +{% else %} + - strelka.coordinator.disabled +{% endif %} diff --git a/salt/strelka/coordinator/sostatus.sls b/salt/strelka/coordinator/sostatus.sls new file mode 100644 index 000000000..dbc124993 --- /dev/null +++ b/salt/strelka/coordinator/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-coordinator_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-coordinator + - unless: grep -q so-strelka-coordinator /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/defaults.yaml b/salt/strelka/defaults.yaml index 8ef162779..2379bd012 100644 --- a/salt/strelka/defaults.yaml +++ b/salt/strelka/defaults.yaml @@ -1,6 +1,7 @@ strelka: - config: - backend: + backend: + enabled: False + config: backend: logging_cfg: '/etc/strelka/logging.yaml' limits: @@ -493,7 +494,9 @@ strelka: passwords: - infected - password - filestream: + filestream: + enabled: False + config: conn: server: 'HOST:57314' cert: '' @@ -514,7 +517,9 @@ strelka: report: 5s delta: 5s staging: '/nsm/strelka/staging' - frontend: + frontend: + enabled: False + config: server: ":57314" coordinator: addr: 'HOST:6380' @@ -525,10 +530,16 @@ strelka: ttl: 1h response: log: "/var/log/strelka/strelka.log" - manager: + manager: + enabled: False + config: coordinator: addr: 'HOST:6380' db: 0 + coordinator: + enabled: False + gatekeeper: + enabled: False rules: enabled: True repos: diff --git a/salt/strelka/filestream/config.sls b/salt/strelka/filestream/config.sls new file mode 100644 index 000000000..a215967ee --- /dev/null +++ b/salt/strelka/filestream/config.sls @@ -0,0 +1,108 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} +{% from 'strelka/map.jinja' import filecheck_runas %} + +include: + - strelka.config + - strelka.filestream.sostatus + +strelkaprocessed: + file.directory: + - name: /nsm/strelka/processed + - user: 939 + - group: 939 + - makedirs: True + +strelkastaging: + file.directory: + - name: /nsm/strelka/staging + - user: 939 + - group: 939 + - makedirs: True + +strelkaunprocessed: + file.directory: + - name: /nsm/strelka/unprocessed + - user: 939 + - group: 939 + - mode: 775 + - makedirs: True + +filestream_config: + file.managed: + - name: /opt/so/conf/strelka/filestream/filestream.yaml + - source: salt://strelka/filestream/files/filestream.yaml.jinja + - template: jinja + - user: 939 + - group: 939 + - makedirs: True + - defaults: + FILESTREAMCONFIG: {{ STRELKAMERGED.filestream.config }} + +# Filecheck Section +filecheck_logdir: + file.directory: + - name: /opt/so/log/strelka + - user: 939 + - group: 939 + - mode: 775 + - makedirs: True + +filecheck_history: + file.directory: + - name: /nsm/strelka/history + - user: 939 + - group: 939 + - mode: 775 + - makedirs: True + +filecheck_conf: + file.managed: + - name: /opt/so/conf/strelka/filecheck.yaml + - source: salt://strelka/filecheck/filecheck.yaml.jinja + - template: jinja + - defaults: + FILECHECKCONFIG: {{ STRELKAMERGED.filecheck }} + +filecheck_script: + file.managed: + - name: /opt/so/conf/strelka/filecheck + - source: salt://strelka/filecheck/filecheck + - user: 939 + - group: 939 + - mode: 755 + +filecheck_restart: + cmd.run: + - name: pkill -f "python3 /opt/so/conf/strelka/filecheck" + - hide_output: True + - success_retcodes: [0,1] + - onchanges: + - file: filecheck_script + +filecheck_run: + cron.present: + - name: 'ps -ef | grep filecheck | grep -v grep > /dev/null 2>&1 || python3 /opt/so/conf/strelka/filecheck >> /opt/so/log/strelka/filecheck_stdout.log 2>&1 &' + - identifier: filecheck_run + - user: {{ filecheck_runas }} + +filcheck_history_clean: + cron.present: + - name: '/usr/bin/find /nsm/strelka/history/ -type f -mtime +2 -exec rm {} + > /dev/null 2>&1' + - identifier: filecheck_history_clean + - minute: '33' +# End Filecheck Section + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/filestream/disabled.sls b/salt/strelka/filestream/disabled.sls new file mode 100644 index 000000000..162e310a9 --- /dev/null +++ b/salt/strelka/filestream/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.filestream.sostatus + +so-strelka-filestream: + docker_container.absent: + - force: True + +so-strelka-filestream_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-filestream$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/filestream/enabled.sls b/salt/strelka/filestream/enabled.sls new file mode 100644 index 000000000..6c6ee0b97 --- /dev/null +++ b/salt/strelka/filestream/enabled.sls @@ -0,0 +1,40 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.filestream.config + - strelka.filestream.sostatus + +strelka_filestream: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-filestream:{{ GLOBALS.so_version }} + - binds: + - /opt/so/conf/strelka/filestream/:/etc/strelka/:ro + - /nsm/strelka:/nsm/strelka + - name: so-strelka-filestream + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-filestream'].ip }} + - command: strelka-filestream + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + +delete_so-strelka-filestream_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-filestream$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/files/filestream/filestream.yaml.jinja b/salt/strelka/filestream/files/filestream.yaml.jinja similarity index 100% rename from salt/strelka/files/filestream/filestream.yaml.jinja rename to salt/strelka/filestream/files/filestream.yaml.jinja diff --git a/salt/strelka/filestream/init.sls b/salt/strelka/filestream/init.sls new file mode 100644 index 000000000..79b471891 --- /dev/null +++ b/salt/strelka/filestream/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.filestream.enabled %} + - strelka.filestream.enabled +{% else %} + - strelka.filestream.disabled +{% endif %} diff --git a/salt/strelka/filestream/sostatus.sls b/salt/strelka/filestream/sostatus.sls new file mode 100644 index 000000000..cb292a459 --- /dev/null +++ b/salt/strelka/filestream/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-filestream_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-filestream + - unless: grep -q so-strelka-filestream /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/frontend/config.sls b/salt/strelka/frontend/config.sls new file mode 100644 index 000000000..e06994b10 --- /dev/null +++ b/salt/strelka/frontend/config.sls @@ -0,0 +1,36 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: + - strelka.config + - strelka.frontend.sostatus + +# Check to see if Strelka frontend port is available +strelkaportavailable: + cmd.run: + - name: netstat -utanp | grep ":57314" | grep -qvE 'docker|TIME_WAIT' && PROCESS=$(netstat -utanp | grep ":57314" | uniq) && echo "Another process ($PROCESS) appears to be using port 57314. Please terminate this process, or reboot to ensure a clean state so that Strelka can start properly." && exit 1 || exit 0 + +frontend_config: + file.managed: + - name: /opt/so/conf/strelka/frontend/frontend.yaml + - source: salt://strelka/frontend/files/frontend.yaml.jinja + - template: jinja + - user: 939 + - group: 939 + - makedirs: True + - defaults: + FRONTENDCONFIG: {{ STRELKAMERGED.frontend.config }} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/frontend/disabled.sls b/salt/strelka/frontend/disabled.sls new file mode 100644 index 000000000..66f6c898c --- /dev/null +++ b/salt/strelka/frontend/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.frontend.sostatus + +so-strelka-frontend: + docker_container.absent: + - force: True + +so-strelka-frontend_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-frontend$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/frontend/enabled.sls b/salt/strelka/frontend/enabled.sls new file mode 100644 index 000000000..28b7dc19c --- /dev/null +++ b/salt/strelka/frontend/enabled.sls @@ -0,0 +1,45 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.frontend.config + - strelka.frontend.sostatus + +strelka_frontend: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-frontend:{{ GLOBALS.so_version }} + - binds: + - /opt/so/conf/strelka/frontend/:/etc/strelka/:ro + - /nsm/strelka/log/:/var/log/strelka/:rw + - privileged: True + - name: so-strelka-frontend + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-frontend'].ip }} + - command: strelka-frontend + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-strelka-frontend'].port_bindings %} + - {{ BINDING }} + {% endfor %} + +delete_so-strelka-frontend_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-frontend$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/files/frontend/frontend.yaml.jinja b/salt/strelka/frontend/files/frontend.yaml.jinja similarity index 100% rename from salt/strelka/files/frontend/frontend.yaml.jinja rename to salt/strelka/frontend/files/frontend.yaml.jinja diff --git a/salt/strelka/frontend/init.sls b/salt/strelka/frontend/init.sls new file mode 100644 index 000000000..980746dfd --- /dev/null +++ b/salt/strelka/frontend/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.frontend.enabled %} + - strelka.frontend.enabled +{% else %} + - strelka.frontend.disabled +{% endif %} diff --git a/salt/strelka/frontend/sostatus.sls b/salt/strelka/frontend/sostatus.sls new file mode 100644 index 000000000..a1ab76312 --- /dev/null +++ b/salt/strelka/frontend/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-frontend_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-frontend + - unless: grep -q so-strelka-frontend /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/gatekeeper/config.sls b/salt/strelka/gatekeeper/config.sls new file mode 100644 index 000000000..069813f9d --- /dev/null +++ b/salt/strelka/gatekeeper/config.sls @@ -0,0 +1,19 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.config + - strelka.gatekeeper.sostatus + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/gatekeeper/disabled.sls b/salt/strelka/gatekeeper/disabled.sls new file mode 100644 index 000000000..8f49d383c --- /dev/null +++ b/salt/strelka/gatekeeper/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.gatekeeper.sostatus + +so-strelka-gatekeeper: + docker_container.absent: + - force: True + +so-strelka-gatekeeper_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-gatekeeper$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/gatekeeper/enabled.sls b/salt/strelka/gatekeeper/enabled.sls new file mode 100644 index 000000000..326fb752f --- /dev/null +++ b/salt/strelka/gatekeeper/enabled.sls @@ -0,0 +1,41 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.gatekeeper.config + - strelka.gatekeeper.sostatus + +strelka_gatekeeper: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} + - name: so-strelka-gatekeeper + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-gatekeeper'].ip }} + - entrypoint: redis-server --save "" --appendonly no --maxmemory-policy allkeys-lru + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + - port_bindings: + {% for BINDING in DOCKER.containers['so-strelka-gatekeeper'].port_bindings %} + - {{ BINDING }} + {% endfor %} + +delete_so-strelka-gatekeeper_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-gatekeeper$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/gatekeeper/init.sls b/salt/strelka/gatekeeper/init.sls new file mode 100644 index 000000000..33ece563a --- /dev/null +++ b/salt/strelka/gatekeeper/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.gatekeeper.enabled %} + - strelka.gatekeeper.enabled +{% else %} + - strelka.gatekeeper.disabled +{% endif %} diff --git a/salt/strelka/gatekeeper/sostatus.sls b/salt/strelka/gatekeeper/sostatus.sls new file mode 100644 index 000000000..db6c6416e --- /dev/null +++ b/salt/strelka/gatekeeper/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-gatekeeper_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-gatekeeper + - unless: grep -q so-strelka-gatekeeper /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/init.sls b/salt/strelka/init.sls index 6b7a2bbd2..a60612087 100644 --- a/salt/strelka/init.sls +++ b/salt/strelka/init.sls @@ -3,361 +3,41 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'docker/docker.map.jinja' import DOCKER %} -{% from 'vars/globals.map.jinja' import GLOBALS %} - {% from 'strelka/map.jinja' import STRELKAMERGED %} -{% from 'strelka/map.jinja' import filecheck_runas %} - -# Strelka config -strelkaconfdir: - file.directory: - - name: /opt/so/conf/strelka - - user: 939 - - group: 939 - - makedirs: True - -strelkarulesdir: - file.directory: - - name: /opt/so/conf/strelka/rules - - user: 939 - - group: 939 - - makedirs: True - -backend_backend_config: - file.managed: - - name: /opt/so/conf/strelka/backend/backend.yaml - - source: salt://strelka/files/backend/backend.yaml.jinja - - template: jinja - - user: 939 - - group: 939 - - makedirs: True - - defaults: - BACKENDCONFIG: {{ STRELKAMERGED.config.backend.backend }} - -backend_logging_config: - file.managed: - - name: /opt/so/conf/strelka/backend/logging.yaml - - source: salt://strelka/files/backend/logging.yaml.jinja - - template: jinja - - user: 939 - - group: 939 - - defaults: - LOGGINGCONFIG: {{ STRELKAMERGED.config.backend.logging }} - -backend_passwords: - file.managed: - - name: /opt/so/conf/strelka/backend/passwords.dat - - source: salt://strelka/files/backend/passwords.dat.jinja - - template: jinja - - user: 939 - - group: 939 - - defaults: - PASSWORDS: {{ STRELKAMERGED.config.backend.passwords }} - -strelka_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://strelka/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#strelka_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://strelka/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -backend_taste: - file.managed: - - name: /opt/so/conf/strelka/backend/taste/taste.yara - - source: salt://strelka/files/backend/taste/taste.yara - - makedirs: True - - user: 939 - - group: 939 - -filestream_config: - file.managed: - - name: /opt/so/conf/strelka/filestream/filestream.yaml - - source: salt://strelka/files/filestream/filestream.yaml.jinja - - template: jinja - - user: 939 - - group: 939 - - makedirs: True - - defaults: - FILESTREAMCONFIG: {{ STRELKAMERGED.config.filestream }} - -frontend_config: - file.managed: - - name: /opt/so/conf/strelka/frontend/frontend.yaml - - source: salt://strelka/files/frontend/frontend.yaml.jinja - - template: jinja - - user: 939 - - group: 939 - - makedirs: True - - defaults: - FRONTENDCONFIG: {{ STRELKAMERGED.config.frontend }} - -manager_config: - file.managed: - - name: /opt/so/conf/strelka/manager/manager.yaml - - source: salt://strelka/files/manager/manager.yaml.jinja - - template: jinja - - user: 939 - - group: 939 - - makedirs: True - - defaults: - MANAGERCONFIG: {{ STRELKAMERGED.config.manager }} - -{% if STRELKAMERGED.rules.enabled %} - -strelkarules: - file.recurse: - - name: /opt/so/conf/strelka/rules - - source: salt://strelka/rules - - user: 939 - - group: 939 - - clean: True - -{% if grains['role'] in GLOBALS.manager_roles %} -strelkarepos: - file.managed: - - name: /opt/so/conf/strelka/repos.txt - - source: salt://strelka/rules/repos.txt.jinja - - template: jinja - - defaults: - STRELKAREPOS: {{ STRELKAMERGED.rules.repos }} - -{% endif %} -{% endif %} - -strelkadatadir: - file.directory: - - name: /nsm/strelka - - user: 939 - - group: 939 - - makedirs: True - -strelkalogdir: - file.directory: - - name: /nsm/strelka/log - - user: 939 - - group: 939 - - makedirs: True - -strelkaprocessed: - file.directory: - - name: /nsm/strelka/processed - - user: 939 - - group: 939 - - makedirs: True - -strelkastaging: - file.directory: - - name: /nsm/strelka/staging - - user: 939 - - group: 939 - - makedirs: True - -strelkaunprocessed: - file.directory: - - name: /nsm/strelka/unprocessed - - user: 939 - - group: 939 - - mode: 775 - - makedirs: True - -# Check to see if Strelka frontend port is available -strelkaportavailable: - cmd.run: - - name: netstat -utanp | grep ":57314" | grep -qvE 'docker|TIME_WAIT' && PROCESS=$(netstat -utanp | grep ":57314" | uniq) && echo "Another process ($PROCESS) appears to be using port 57314. Please terminate this process, or reboot to ensure a clean state so that Strelka can start properly." && exit 1 || exit 0 - -# Filecheck Section -filecheck_logdir: - file.directory: - - name: /opt/so/log/strelka - - user: 939 - - group: 939 - - mode: 775 - - makedirs: True - -filecheck_history: - file.directory: - - name: /nsm/strelka/history - - user: 939 - - group: 939 - - mode: 775 - - makedirs: True - -filecheck_conf: - file.managed: - - name: /opt/so/conf/strelka/filecheck.yaml - - source: salt://strelka/filecheck/filecheck.yaml.jinja - - template: jinja - - defaults: - FILECHECKCONFIG: {{ STRELKAMERGED.filecheck }} - -filecheck_script: - file.managed: - - name: /opt/so/conf/strelka/filecheck - - source: salt://strelka/filecheck/filecheck - - user: 939 - - group: 939 - - mode: 755 - -filecheck_restart: - cmd.run: - - name: pkill -f "python3 /opt/so/conf/strelka/filecheck" - - hide_output: True - - success_retcodes: [0,1] - - onchanges: - - file: filecheck_script - -filecheck_run: - cron.present: - - name: 'ps -ef | grep filecheck | grep -v grep > /dev/null 2>&1 || python3 /opt/so/conf/strelka/filecheck >> /opt/so/log/strelka/filecheck_stdout.log 2>&1 &' - - identifier: filecheck_run - - user: {{ filecheck_runas }} - -filcheck_history_clean: - cron.present: - - name: '/usr/bin/find /nsm/strelka/history/ -type f -mtime +2 -exec rm {} + > /dev/null 2>&1' - - identifier: filecheck_history_clean - - minute: '33' -# End Filecheck Section - - -strelka_coordinator: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} - - name: so-strelka-coordinator - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-coordinator'].ip }} - - entrypoint: redis-server --save "" --appendonly no - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-coordinator'].port_bindings %} - - {{ BINDING }} - {% endfor %} - -append_so-strelka-coordinator_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-coordinator - -strelka_gatekeeper: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-redis:{{ GLOBALS.so_version }} - - name: so-strelka-gatekeeper - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-gatekeeper'].ip }} - - entrypoint: redis-server --save "" --appendonly no --maxmemory-policy allkeys-lru - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-gatekeeper'].port_bindings %} - - {{ BINDING }} - {% endfor %} - -append_so-strelka-gatekeeper_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-gatekeeper - -strelka_frontend: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-frontend:{{ GLOBALS.so_version }} - - binds: - - /opt/so/conf/strelka/frontend/:/etc/strelka/:ro - - /nsm/strelka/log/:/var/log/strelka/:rw - - privileged: True - - name: so-strelka-frontend - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-frontend'].ip }} - - command: strelka-frontend - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - port_bindings: - {% for BINDING in DOCKER.containers['so-strelka-frontend'].port_bindings %} - - {{ BINDING }} - {% endfor %} - -append_so-strelka-frontend_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-frontend - -strelka_backend: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-backend:{{ GLOBALS.so_version }} - - binds: - - /opt/so/conf/strelka/backend/:/etc/strelka/:ro - - /opt/so/conf/strelka/rules/:/etc/yara/:ro - - name: so-strelka-backend - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-backend'].ip }} - - command: strelka-backend - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - - restart_policy: on-failure - -append_so-strelka-backend_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-backend - -strelka_manager: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} - - binds: - - /opt/so/conf/strelka/manager/:/etc/strelka/:ro - - name: so-strelka-manager - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-manager'].ip }} - - command: strelka-manager - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - -append_so-strelka-manager_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-manager - -strelka_filestream: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-filestream:{{ GLOBALS.so_version }} - - binds: - - /opt/so/conf/strelka/filestream/:/etc/strelka/:ro - - /nsm/strelka:/nsm/strelka - - name: so-strelka-filestream - - networks: - - sobridge: - - ipv4_address: {{ DOCKER.containers['so-strelka-filestream'].ip }} - - command: strelka-filestream - - extra_hosts: - - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} - -append_so-strelka-filestream_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-strelka-filestream +include: +{% if STRELKAMERGED.coordinator.enabled %} + - strelka.coordinator.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - strelka.coordinator.disabled +{% endif %} + +{% if STRELKAMERGED.gatekeeper.enabled %} + - strelka.gatekeeper.enabled +{% else %} + - strelka.gatekeeper.disabled +{% endif %} + +{% if STRELKAMERGED.frontend.enabled %} + - strelka.frontend.enabled +{% else %} + - strelka.frontend.disabled +{% endif %} + +{% if STRELKAMERGED.backend.enabled %} + - strelka.backend.enabled +{% else %} + - strelka.backend.disabled +{% endif %} + +{% if STRELKAMERGED.manager.enabled %} + - strelka.manager.enabled +{% else %} + - strelka.manager.disabled +{% endif %} + +{% if STRELKAMERGED.filestream.enabled %} + - strelka.filestream.enabled +{% else %} + - strelka.filestream.disabled {% endif %} diff --git a/salt/strelka/manager/config.sls b/salt/strelka/manager/config.sls new file mode 100644 index 000000000..a99bdb27a --- /dev/null +++ b/salt/strelka/manager/config.sls @@ -0,0 +1,31 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: + - strelka.config + - strelka.manager.sostatus + +manager_config: + file.managed: + - name: /opt/so/conf/strelka/manager/manager.yaml + - source: salt://strelka/manager/files/manager.yaml.jinja + - template: jinja + - user: 939 + - group: 939 + - makedirs: True + - defaults: + MANAGERCONFIG: {{ STRELKAMERGED.manager.config }} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/manager/disabled.sls b/salt/strelka/manager/disabled.sls new file mode 100644 index 000000000..0826166ad --- /dev/null +++ b/salt/strelka/manager/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - strelka.manager.sostatus + +so-strelka-manager: + docker_container.absent: + - force: True + +so-strelka-manager_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-manager$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/manager/enabled.sls b/salt/strelka/manager/enabled.sls new file mode 100644 index 000000000..0c78c9dcb --- /dev/null +++ b/salt/strelka/manager/enabled.sls @@ -0,0 +1,39 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'docker/docker.map.jinja' import DOCKER %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - strelka.manager.config + - strelka.manager.sostatus + +strelka_manager: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-strelka-manager:{{ GLOBALS.so_version }} + - binds: + - /opt/so/conf/strelka/manager/:/etc/strelka/:ro + - name: so-strelka-manager + - networks: + - sobridge: + - ipv4_address: {{ DOCKER.containers['so-strelka-manager'].ip }} + - command: strelka-manager + - extra_hosts: + - {{ GLOBALS.hostname }}:{{ GLOBALS.node_ip }} + +delete_so-strelka-manager_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-strelka-manager$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/files/manager/manager.yaml.jinja b/salt/strelka/manager/files/manager.yaml.jinja similarity index 100% rename from salt/strelka/files/manager/manager.yaml.jinja rename to salt/strelka/manager/files/manager.yaml.jinja diff --git a/salt/strelka/manager/init.sls b/salt/strelka/manager/init.sls new file mode 100644 index 000000000..2b479751c --- /dev/null +++ b/salt/strelka/manager/init.sls @@ -0,0 +1,13 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'strelka/map.jinja' import STRELKAMERGED %} + +include: +{% if STRELKAMERGED.manager.enabled %} + - strelka.manager.enabled +{% else %} + - strelka.manager.disabled +{% endif %} diff --git a/salt/strelka/manager/sostatus.sls b/salt/strelka/manager/sostatus.sls new file mode 100644 index 000000000..5e42093f5 --- /dev/null +++ b/salt/strelka/manager/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-strelka-manager_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-strelka-manager + - unless: grep -q so-strelka-manager /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/strelka/map.jinja b/salt/strelka/map.jinja index 5df15aa59..646f7a746 100644 --- a/salt/strelka/map.jinja +++ b/salt/strelka/map.jinja @@ -1,21 +1,26 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% from 'vars/globals.map.jinja' import GLOBALS %} {% import_yaml 'strelka/defaults.yaml' as STRELKADEFAULTS %} {% set HOST = GLOBALS.hostname %} -{% set backend_coordinator_port = STRELKADEFAULTS.strelka.config.backend.backend.coordinator.addr.split(':')[1] %} -{% do STRELKADEFAULTS.strelka.config.backend.backend.coordinator.update({'addr': HOST ~ ':' ~ backend_coordinator_port}) %} +{% set backend_coordinator_port = STRELKADEFAULTS.strelka.backend.config.backend.coordinator.addr.split(':')[1] %} +{% do STRELKADEFAULTS.strelka.backend.config.backend.coordinator.update({'addr': HOST ~ ':' ~ backend_coordinator_port}) %} -{% set filestream_conn_port = STRELKADEFAULTS.strelka.config.filestream.conn.server.split(':')[1] %} -{% do STRELKADEFAULTS.strelka.config.filestream.conn.update({'server': HOST ~ ':' ~ filestream_conn_port}) %} +{% set filestream_conn_port = STRELKADEFAULTS.strelka.filestream.config.conn.server.split(':')[1] %} +{% do STRELKADEFAULTS.strelka.filestream.config.conn.update({'server': HOST ~ ':' ~ filestream_conn_port}) %} -{% set frontend_coordinator_port = STRELKADEFAULTS.strelka.config.frontend.coordinator.addr.split(':')[1] %} -{% do STRELKADEFAULTS.strelka.config.frontend.coordinator.update({'addr': HOST ~ ':' ~ frontend_coordinator_port}) %} +{% set frontend_coordinator_port = STRELKADEFAULTS.strelka.frontend.config.coordinator.addr.split(':')[1] %} +{% do STRELKADEFAULTS.strelka.frontend.config.coordinator.update({'addr': HOST ~ ':' ~ frontend_coordinator_port}) %} -{% set frontend_gatekeeper_port = STRELKADEFAULTS.strelka.config.frontend.gatekeeper.addr.split(':')[1] %} -{% do STRELKADEFAULTS.strelka.config.frontend.gatekeeper.update({'addr': HOST ~ ':' ~ frontend_gatekeeper_port}) %} +{% set frontend_gatekeeper_port = STRELKADEFAULTS.strelka.frontend.config.gatekeeper.addr.split(':')[1] %} +{% do STRELKADEFAULTS.strelka.frontend.config.gatekeeper.update({'addr': HOST ~ ':' ~ frontend_gatekeeper_port}) %} -{% set manager_coordinator_port = STRELKADEFAULTS.strelka.config.manager.coordinator.addr.split(':')[1] %} -{% do STRELKADEFAULTS.strelka.config.manager.coordinator.update({'addr': HOST ~ ':' ~ manager_coordinator_port}) %} +{% set manager_coordinator_port = STRELKADEFAULTS.strelka.manager.config.coordinator.addr.split(':')[1] %} +{% do STRELKADEFAULTS.strelka.manager.config.coordinator.update({'addr': HOST ~ ':' ~ manager_coordinator_port}) %} {% if GLOBALS.md_engine == "SURICATA" %} {% set extract_path = '/nsm/suricata/extracted' %} diff --git a/salt/strelka/soc_strelka.yaml b/salt/strelka/soc_strelka.yaml index dbe949817..5cdf442d5 100644 --- a/salt/strelka/soc_strelka.yaml +++ b/salt/strelka/soc_strelka.yaml @@ -1,6 +1,9 @@ strelka: - config: - backend: + backend: + enabled: + description: You can enable or disable Strelka backend. + helpLink: strelka.html + config: backend: logging_cfg: description: Path to the Python logging configuration. @@ -398,7 +401,11 @@ strelka: global: False helpLink: strelka.html multiline: True - filestream: + filestream: + enabled: + description: You can enable or disable Strelka filestream. + helpLink: strelka.html + config: conn: server: description: Network address of the frontend server. @@ -488,7 +495,11 @@ strelka: global: False helpLink: strelka.html advanced: True - frontend: + frontend: + enabled: + description: You can enable or disable Strelka frontend. + helpLink: strelka.html + config: server: description: Network address of the frontend server. readonly: False @@ -534,7 +545,11 @@ strelka: global: False helpLink: strelka.html advanced: True - manager: + manager: + enabled: + description: You can enable or disable Strelka manager. + helpLink: strelka.html + config: coordinator: addr: description: Network address of the coordinator. @@ -548,6 +563,14 @@ strelka: global: False helpLink: strelka.html advanced: True + coordinator: + enabled: + description: You can enable or disable Strelka coordinator. + helpLink: strelka.html + gatekeeper: + enabled: + description: You can enable or disable Strelka gatekeeper. + helpLink: strelka.html rules: enabled: description: Boolean that determines if yara rules sync from the Salt manager to the backend nodes. diff --git a/salt/telegraf/config.map.jinja b/salt/telegraf/config.map.jinja deleted file mode 100644 index 4ac4597a4..000000000 --- a/salt/telegraf/config.map.jinja +++ /dev/null @@ -1,3 +0,0 @@ -{% import_yaml 'telegraf/defaults.yaml' as TGDEFAULTS %} - -{% set TGMERGED = salt['pillar.get']('telegraf', TGDEFAULTS.telegraf, merge=True) %} diff --git a/salt/telegraf/config.sls b/salt/telegraf/config.sls new file mode 100644 index 000000000..1cc7ceed0 --- /dev/null +++ b/salt/telegraf/config.sls @@ -0,0 +1,91 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'telegraf/map.jinja' import TELEGRAFMERGED %} + +include: + - ssl + +# add Telegraf to monitor all the things +tgraflogdir: + file.directory: + - name: /opt/so/log/telegraf + - makedirs: True + - user: 939 + - group: 939 + - recurse: + - user + - group + +tgrafetcdir: + file.directory: + - name: /opt/so/conf/telegraf/etc + - makedirs: True + +tgrafetsdir: + file.directory: + - name: /opt/so/conf/telegraf/scripts + - makedirs: True + +tgrafsyncscripts: + file.recurse: + - name: /opt/so/conf/telegraf/scripts + - user: root + - group: 939 + - file_mode: 770 + - template: jinja + - source: salt://telegraf/scripts + {% if GLOBALS.md_engine == 'SURICATA' %} + - exclude_pat: zeekcaptureloss.sh + {% endif %} + +telegraf_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://telegraf/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#telegraf_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://telegraf/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +tgrafconf: + file.managed: + - name: /opt/so/conf/telegraf/etc/telegraf.conf + - user: 939 + - group: 939 + - mode: 660 + - template: jinja + - source: salt://telegraf/etc/telegraf.conf + - show_changes: False + - defaults: + GLOBALS: {{ GLOBALS }} + TELEGRAFMERGED: {{ TELEGRAFMERGED }} + +# this file will be read by telegraf to send node details (management interface, monitor interface, etc) +# into influx +node_config: + file.managed: + - name: /opt/so/conf/telegraf/node_config.json + - source: salt://telegraf/node_config.json.jinja + - template: jinja + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/telegraf/defaults.yaml b/salt/telegraf/defaults.yaml index a0cc8095f..63d437763 100644 --- a/salt/telegraf/defaults.yaml +++ b/salt/telegraf/defaults.yaml @@ -1,4 +1,5 @@ telegraf: + enabled: False config: interval: '30s' metric_batch_size: 1000 diff --git a/salt/telegraf/disabled.sls b/salt/telegraf/disabled.sls new file mode 100644 index 000000000..004d3d928 --- /dev/null +++ b/salt/telegraf/disabled.sls @@ -0,0 +1,27 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - telegraf.sostatus + +so-telegraf: + docker_container.absent: + - force: True + +so-telegraf_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-telegraf$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/telegraf/enabled.sls b/salt/telegraf/enabled.sls new file mode 100644 index 000000000..04459d7ff --- /dev/null +++ b/salt/telegraf/enabled.sls @@ -0,0 +1,76 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - telegraf.config + - telegraf.sostatus + +so-telegraf: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-telegraf:{{ GLOBALS.so_version }} + - user: 939 + - group_add: 939,920 + - environment: + - HOST_PROC=/host/proc + - HOST_ETC=/host/etc + - HOST_SYS=/host/sys + - HOST_MOUNT_PREFIX=/host + - GODEBUG=x509ignoreCN=0 + - network_mode: host + - init: True + - binds: + - /opt/so/log/telegraf:/var/log/telegraf:rw + - /opt/so/conf/telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro + - /opt/so/conf/telegraf/node_config.json:/etc/telegraf/node_config.json:ro + - /var/run/utmp:/var/run/utmp:ro + - /var/run/docker.sock:/var/run/docker.sock:ro + - /:/host/root:ro + - /sys:/host/sys:ro + - /proc:/host/proc:ro + - /nsm:/host/nsm:ro + - /etc:/host/etc:ro + {% if GLOBALS.role in ['so-manager', 'so-eval', 'so-managersearch' ] %} + - /etc/pki/ca.crt:/etc/telegraf/ca.crt:ro + {% else %} + - /etc/ssl/certs/intca.crt:/etc/telegraf/ca.crt:ro + {% endif %} + - /etc/pki/influxdb.crt:/etc/telegraf/telegraf.crt:ro + - /etc/pki/influxdb.key:/etc/telegraf/telegraf.key:ro + - /opt/so/conf/telegraf/scripts:/scripts:ro + - /opt/so/log/stenographer:/var/log/stenographer:ro + - /opt/so/log/suricata:/var/log/suricata:ro + - /opt/so/log/raid:/var/log/raid:ro + - /opt/so/log/sostatus:/var/log/sostatus:ro + - watch: + - file: tgrafconf + - file: tgrafsyncscripts + - file: node_config + - require: + - file: tgrafconf + - file: node_config + {% if GLOBALS.role in ['so-manager', 'so-eval', 'so-managersearch' ] %} + - x509: pki_public_ca_crt + {% else %} + - x509: trusttheca + {% endif %} + - x509: influxdb_crt + - x509: influxdb_key + +delete_so-telegraf_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-telegraf$ + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/telegraf/etc/telegraf.conf b/salt/telegraf/etc/telegraf.conf index f2a89baf4..596f40b88 100644 --- a/salt/telegraf/etc/telegraf.conf +++ b/salt/telegraf/etc/telegraf.conf @@ -14,7 +14,7 @@ # Configuration for telegraf agent [agent] ## Default data collection interval for all inputs - interval = "{{ TGMERGED.config.interval }}" + interval = "{{ TELEGRAFMERGED.config.interval }}" ## Rounds collection interval to 'interval' ## ie, if interval="10s" then always collect on :00, :10, :20, etc. round_interval = true @@ -22,27 +22,27 @@ ## Telegraf will send metrics to outputs in batches of at most ## metric_batch_size metrics. ## This controls the size of writes that Telegraf sends to output plugins. - metric_batch_size = {{ TGMERGED.config.metric_batch_size }} + metric_batch_size = {{ TELEGRAFMERGED.config.metric_batch_size }} ## For failed writes, telegraf will cache metric_buffer_limit metrics for each ## output, and will flush this buffer on a successful write. Oldest metrics ## are dropped first when this buffer fills. ## This buffer only fills when writes fail to output plugin(s). - metric_buffer_limit = {{ TGMERGED.config.metric_buffer_limit }} + metric_buffer_limit = {{ TELEGRAFMERGED.config.metric_buffer_limit }} ## Collection jitter is used to jitter the collection by a random amount. ## Each plugin will sleep for a random time within jitter before collecting. ## This can be used to avoid many plugins querying things like sysfs at the ## same time, which can have a measurable effect on the system. - collection_jitter = "{{ TGMERGED.config.collection_jitter }}" + collection_jitter = "{{ TELEGRAFMERGED.config.collection_jitter }}" ## Default flushing interval for all outputs. Maximum flush_interval will be ## flush_interval + flush_jitter - flush_interval = "{{ TGMERGED.config.flush_interval }}" + flush_interval = "{{ TELEGRAFMERGED.config.flush_interval }}" ## Jitter the flush interval by a random amount. This is primarily to avoid ## large write spikes for users running a large number of telegraf instances. ## ie, a jitter of 5s and interval 10s means flushes will happen every 10-15s - flush_jitter = "{{ TGMERGED.config.flush_jitter }}" + flush_jitter = "{{ TELEGRAFMERGED.config.flush_jitter }}" ## By default or when set to "0s", precision will be set to the same ## timestamp order as the collection interval, with the maximum being 1s. @@ -55,7 +55,7 @@ ## Logging configuration: ## Run telegraf with debug log messages. - debug = {{ TGMERGED.config.debug }} + debug = {{ TELEGRAFMERGED.config.debug }} ## Run telegraf in quiet mode (error log messages only). quiet = false ## Specify the log file name. The empty string means to log to stderr. diff --git a/salt/telegraf/init.sls b/salt/telegraf/init.sls index f14ef14e4..ef5a600ab 100644 --- a/salt/telegraf/init.sls +++ b/salt/telegraf/init.sls @@ -1,141 +1,13 @@ -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} -{% from 'vars/globals.map.jinja' import GLOBALS %} -{% from 'telegraf/config.map.jinja' import TGMERGED %} +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'telegraf/map.jinja' import TELEGRAFMERGED %} include: - - ssl - -# add Telegraf to monitor all the things -tgraflogdir: - file.directory: - - name: /opt/so/log/telegraf - - makedirs: True - - user: 939 - - group: 939 - - recurse: - - user - - group - -tgrafetcdir: - file.directory: - - name: /opt/so/conf/telegraf/etc - - makedirs: True - -tgrafetsdir: - file.directory: - - name: /opt/so/conf/telegraf/scripts - - makedirs: True - -tgrafsyncscripts: - file.recurse: - - name: /opt/so/conf/telegraf/scripts - - user: root - - group: 939 - - file_mode: 770 - - template: jinja - - source: salt://telegraf/scripts -{% if GLOBALS.md_engine == 'SURICATA' %} - - exclude_pat: zeekcaptureloss.sh -{% endif %} - -telegraf_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://telegraf/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#telegraf_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://telegraf/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -tgrafconf: - file.managed: - - name: /opt/so/conf/telegraf/etc/telegraf.conf - - user: 939 - - group: 939 - - mode: 660 - - template: jinja - - source: salt://telegraf/etc/telegraf.conf - - show_changes: False - - defaults: - GLOBALS: {{ GLOBALS }} - TGMERGED: {{ TGMERGED }} - -# this file will be read by telegraf to send node details (management interface, monitor interface, etc) -# into influx -node_config: - file.managed: - - name: /opt/so/conf/telegraf/node_config.json - - source: salt://telegraf/node_config.json.jinja - - template: jinja - -so-telegraf: - docker_container.running: - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-telegraf:{{ GLOBALS.so_version }} - - user: 939 - - group_add: 939,920 - - environment: - - HOST_PROC=/host/proc - - HOST_ETC=/host/etc - - HOST_SYS=/host/sys - - HOST_MOUNT_PREFIX=/host - - GODEBUG=x509ignoreCN=0 - - network_mode: host - - init: True - - binds: - - /opt/so/log/telegraf:/var/log/telegraf:rw - - /opt/so/conf/telegraf/etc/telegraf.conf:/etc/telegraf/telegraf.conf:ro - - /opt/so/conf/telegraf/node_config.json:/etc/telegraf/node_config.json:ro - - /var/run/utmp:/var/run/utmp:ro - - /var/run/docker.sock:/var/run/docker.sock:ro - - /:/host/root:ro - - /sys:/host/sys:ro - - /proc:/host/proc:ro - - /nsm:/host/nsm:ro - - /etc:/host/etc:ro - {% if grains['role'] == 'so-manager' or grains['role'] == 'so-eval' or grains['role'] == 'so-managersearch' %} - - /etc/pki/ca.crt:/etc/telegraf/ca.crt:ro - {% else %} - - /etc/ssl/certs/intca.crt:/etc/telegraf/ca.crt:ro - {% endif %} - - /etc/pki/influxdb.crt:/etc/telegraf/telegraf.crt:ro - - /etc/pki/influxdb.key:/etc/telegraf/telegraf.key:ro - - /opt/so/conf/telegraf/scripts:/scripts:ro - - /opt/so/log/stenographer:/var/log/stenographer:ro - - /opt/so/log/suricata:/var/log/suricata:ro - - /opt/so/log/raid:/var/log/raid:ro - - /opt/so/log/sostatus:/var/log/sostatus:ro - - watch: - - file: tgrafconf - - file: tgrafsyncscripts - - file: node_config - - require: - - file: tgrafconf - - file: node_config - {% if grains['role'] == 'so-manager' or grains['role'] == 'so-eval' or grains['role'] == 'so-managersearch' %} - - x509: pki_public_ca_crt - {% else %} - - x509: trusttheca - {% endif %} - - x509: influxdb_crt - - x509: influxdb_key -append_so-telegraf_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-telegraf - +{% if TELEGRAFMERGED.enabled %} + - telegraf.enabled {% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - telegraf.disabled {% endif %} diff --git a/salt/telegraf/map.jinja b/salt/telegraf/map.jinja new file mode 100644 index 000000000..f1412d3ac --- /dev/null +++ b/salt/telegraf/map.jinja @@ -0,0 +1,7 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + +{% import_yaml 'telegraf/defaults.yaml' as TELEGRAFDEFAULTS %} +{% set TELEGRAFMERGED = salt['pillar.get']('telegraf', TELEGRAFDEFAULTS.telegraf, merge=True) %} diff --git a/salt/telegraf/soc_telegraf.yaml b/salt/telegraf/soc_telegraf.yaml index f64811632..a688ea2a3 100644 --- a/salt/telegraf/soc_telegraf.yaml +++ b/salt/telegraf/soc_telegraf.yaml @@ -1,4 +1,7 @@ telegraf: + enabled: + description: You can enable or disable Telegraf. + helpLink: telegraf.html config: interval: description: Data collection interval. diff --git a/salt/telegraf/sostatus.sls b/salt/telegraf/sostatus.sls new file mode 100644 index 000000000..2eb69cf5e --- /dev/null +++ b/salt/telegraf/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-telegraf_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-telegraf + - unless: grep -q so-telegraf /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/top.sls b/salt/top.sls index 0c644d6bd..229557575 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -3,15 +3,6 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. - -{% set ZEEKVER = salt['pillar.get']('global:mdengine', '') %} -{% set PLAYBOOK = salt['pillar.get']('manager:playbook', '0') %} -{% set ELASTALERT = salt['pillar.get']('elastalert:enabled', True) %} -{% set ELASTICSEARCH = salt['pillar.get']('elasticsearch:enabled', True) %} -{% set KIBANA = salt['pillar.get']('kibana:enabled', True) %} -{% set LOGSTASH = salt['pillar.get']('logstash:enabled', True) %} -{% set REDIS = salt['pillar.get']('redis:enabled', True) %} -{% set STRELKA = salt['pillar.get']('strelka:enabled', '0') %} {% import_yaml 'salt/minion.defaults.yaml' as saltversion %} {% set saltversion = saltversion.salt.minion.version %} {% set INSTALLEDSALTVERSION = grains.saltversion %} @@ -52,12 +43,8 @@ base: - pcap - suricata - healthcheck - {%- if ZEEKVER != 'SURICATA' %} - zeek - {%- endif %} - {%- if STRELKA %} - strelka - {%- endif %} - docker_clean - elasticfleet.install_agent_grid @@ -80,31 +67,19 @@ base: - suricata.manager - healthcheck - mysql - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if KIBANA %} - elastic-fleet-package-registry - - kibana.so_savedobjects_defaults - {%- endif %} + - kibana - pcap - suricata - {%- if ZEEKVER != 'SURICATA' %} - zeek - {%- endif %} - {%- if STRELKA %} - strelka - {%- endif %} - curator - {%- if ELASTALERT %} - elastalert - {%- endif %} - utility - soctopus - {%- if PLAYBOOK != 0 %} - playbook - redis - {%- endif %} - elasticfleet - docker_clean @@ -126,23 +101,13 @@ base: - idstools - suricata.manager - mysql - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if LOGSTASH %} - logstash - {%- endif %} - {%- if REDIS %} - redis - {%- endif %} - {%- if KIBANA %} - elastic-fleet-package-registry - - kibana.so_savedobjects_defaults - {%- endif %} + - kibana - curator - {%- if ELASTALERT %} - elastalert - {%- endif %} - utility - soctopus - playbook @@ -168,31 +133,17 @@ base: - suricata.manager - healthcheck - mysql - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if LOGSTASH %} - logstash - {%- endif %} - {%- if REDIS %} - redis - {%- endif %} - {%- if KIBANA %} - elastic-fleet-package-registry - - kibana.so_savedobjects_defaults - {%- endif %} + - kibana - pcap - suricata - {%- if ZEEKVER != 'SURICATA' %} - zeek - {%- endif %} - {%- if STRELKA %} - strelka - {%- endif %} - curator - {%- if ELASTALERT %} - elastalert - {%- endif %} - utility - soctopus - playbook @@ -206,12 +157,8 @@ base: - nginx - telegraf - firewall - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if LOGSTASH %} - logstash - {%- endif %} - elasticfleet.install_agent_grid - docker_clean @@ -233,23 +180,13 @@ base: - idstools - suricata.manager - mysql - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if LOGSTASH %} - logstash - {%- endif %} - {%- if REDIS %} - redis - {%- endif %} - curator - {%- if KIBANA %} - elastic-fleet-package-registry - - kibana.so_savedobjects_defaults - {%- endif %} - {%- if ELASTALERT %} + - kibana - elastalert - {%- endif %} - utility - soctopus - playbook @@ -263,24 +200,14 @@ base: - nginx - telegraf - firewall - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if LOGSTASH %} - logstash - {%- endif %} - {%- if REDIS %} - redis - {%- endif %} - curator - {%- if STRELKA %} - strelka - {%- endif %} - pcap - suricata - {%- if ZEEKVER != 'SURICATA' %} - zeek - {%- endif %} - elasticfleet.install_agent_grid - docker_clean @@ -301,13 +228,9 @@ base: - idstools - suricata.manager - pcap - {%- if ELASTICSEARCH %} - elasticsearch - {%- endif %} - {%- if KIBANA %} - elastic-fleet-package-registry - - kibana.so_savedobjects_defaults - {%- endif %} + - kibana - utility - suricata - zeek @@ -320,12 +243,8 @@ base: - sensoroni - telegraf - firewall - {%- if LOGSTASH %} - logstash - {%- endif %} - {%- if REDIS %} - redis - {%- endif %} - elasticfleet.install_agent_grid - docker_clean diff --git a/salt/vars/globals.map.jinja b/salt/vars/globals.map.jinja index 578432799..a56fad571 100644 --- a/salt/vars/globals.map.jinja +++ b/salt/vars/globals.map.jinja @@ -26,8 +26,7 @@ 'so_docker_range': DOCKER.sorange, 'url_base': INIT.PILLAR.global.url_base, 'so_model': INIT.GRAINS.get('sosmodel',''), - 'description': INIT.PILLAR.sensoroni.get('node_description',''), - 'sensoroni_key': INIT.PILLAR.sensoroni.sensoronikey, + 'sensoroni_key': INIT.PILLAR.sensoroni.config.sensoronikey, 'os': INIT.GRAINS.os, 'application_urls': {}, 'manager_roles': [ diff --git a/salt/zeek/config.map.jinja b/salt/zeek/config.map.jinja index 181666227..58f927c11 100644 --- a/salt/zeek/config.map.jinja +++ b/salt/zeek/config.map.jinja @@ -1,28 +1,19 @@ +{# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one + or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at + https://securityonion.net/license; you may not use this file except in compliance with the + Elastic License 2.0. #} + {% from 'vars/sensor.map.jinja' import ROLE_GLOBALS %} -{% import_yaml 'zeek/defaults.yaml' as zeek_defaults with context %} -{% set ZEEKMERGED = salt['pillar.get']('zeek', zeek_defaults.zeek, merge=True) %} +{% import_yaml 'zeek/defaults.yaml' as ZEEKDEFAULTS with context %} +{% set ZEEKMERGED = salt['pillar.get']('zeek', ZEEKDEFAULTS.zeek, merge=True) %} {% do ZEEKMERGED.config.node.update({'interface': ROLE_GLOBALS.sensor.interface}) %} +{# we have to add the @ sign for the config since we remove it from defaults for the UI #} {% if ZEEKMERGED.config.local.load is defined %} {% set LOCALLOAD = ZEEKMERGED.config.local.pop('load') %} {% do ZEEKMERGED.config.local.update({'@load': LOCALLOAD}) %} {% endif %} - {% if ZEEKMERGED.config.local['load-sigs'] is defined %} {% set LOCALLOADSIGS = ZEEKMERGED.config.local.pop('load-sigs') %} {% do ZEEKMERGED.config.local.update({'@load-sigs': LOCALLOADSIGS}) %} {% endif %} - -{% set ZEEKOPTIONS = {} %} -{% set ENABLED = salt['pillar.get']('zeek:enabled', True) %} - -# don't start the docker container if it is an import node or disabled via pillar -{% if grains.id.split('_')|last == 'import' or not ENABLED %} - {% do ZEEKOPTIONS.update({'start': False}) %} - {% do ZEEKOPTIONS.update({'pl_cron_state': 'absent'}) %} - {% do ZEEKOPTIONS.update({'status': 'absent'}) %} -{% else %} - {% do ZEEKOPTIONS.update({'start': True}) %} - {% do ZEEKOPTIONS.update({'pl_cron_state': 'present'}) %} - {% do ZEEKOPTIONS.update({'status': 'running'}) %} -{% endif %} diff --git a/salt/zeek/config.sls b/salt/zeek/config.sls new file mode 100644 index 000000000..703da8d85 --- /dev/null +++ b/salt/zeek/config.sls @@ -0,0 +1,195 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from "zeek/config.map.jinja" import ZEEKMERGED %} +{% from 'bpf/zeek.map.jinja' import ZEEKBPF %} +{% set BPF_STATUS = 0 %} + +# Add Zeek group +zeekgroup: + group.present: + - name: zeek + - gid: 937 + +# Add Zeek User +zeek: + user.present: + - uid: 937 + - gid: 937 + - home: /home/zeek + +# Create some directories +zeekpolicydir: + file.directory: + - name: /opt/so/conf/zeek/policy + - user: 937 + - group: 939 + - makedirs: True + +# Zeek Log Directory +zeeklogdir: + file.directory: + - name: /nsm/zeek/logs + - user: 937 + - group: 939 + - makedirs: True + +# Zeek Spool Directory +zeekspooldir: + file.directory: + - name: /nsm/zeek/spool/manager + - user: 937 + - makedirs: True + +# Zeek extracted +zeekextractdir: + file.directory: + - name: /nsm/zeek/extracted + - user: 937 + - group: 939 + - mode: 770 + - makedirs: True + +zeekextractcompletedir: + file.directory: + - name: /nsm/zeek/extracted/complete + - user: 937 + - group: 939 + - mode: 770 + - makedirs: True + +# Sync the policies +zeekpolicysync: + file.recurse: + - name: /opt/so/conf/zeek/policy + - source: salt://zeek/policy + - user: 937 + - group: 939 + - template: jinja + - defaults: + FILE_EXTRACTION: {{ ZEEKMERGED.file_extraction }} + +# Ensure the zeek spool tree (and state.db) ownership is correct +zeekspoolownership: + file.directory: + - name: /nsm/zeek/spool + - user: 937 +zeekstatedbownership: + file.managed: + - name: /nsm/zeek/spool/state.db + - user: 937 + - replace: False + - create: False + +zeek_sbin: + file.recurse: + - name: /usr/sbin + - source: salt://zeek/tools/sbin + - user: 939 + - group: 939 + - file_mode: 755 + +#zeek_sbin_jinja: +# file.recurse: +# - name: /usr/sbin +# - source: salt://zeek/tools/sbin_jinja +# - user: 939 +# - group: 939 +# - file_mode: 755 +# - template: jinja + +# Sync Intel +zeekintelloadsync: + file.managed: + - name: /opt/so/conf/policy/intel/__load__.zeek + - source: salt://zeek/policy/intel/__load__.zeek + - user: 937 + - group: 939 + - makedirs: True + +zeekctlcfg: + file.managed: + - name: /opt/so/conf/zeek/zeekctl.cfg + - source: salt://zeek/files/zeekctl.cfg.jinja + - user: 937 + - group: 939 + - template: jinja + - defaults: + ZEEKCTL: {{ ZEEKMERGED.config.zeekctl | tojson }} + +# Sync node.cfg +nodecfg: + file.managed: + - name: /opt/so/conf/zeek/node.cfg + - source: salt://zeek/files/node.cfg.jinja + - user: 937 + - group: 939 + - template: jinja + - defaults: + NODE: {{ ZEEKMERGED.config.node }} + +networkscfg: + file.managed: + - name: /opt/so/conf/zeek/networks.cfg + - source: salt://zeek/files/networks.cfg.jinja + - user: 937 + - group: 939 + - template: jinja + - defaults: + NETWORKS: {{ ZEEKMERGED.config.networks }} + +plcronscript: + file.managed: + - name: /usr/local/bin/packetloss.sh + - source: salt://zeek/cron/packetloss.sh + - mode: 755 + +# BPF compilation and configuration +{% if ZEEKBPF %} + {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %} + {% 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: {{ ZEEKBPF }} +{% else %} + - contents: + - "ip or not ip" +{% endif %} + +localzeek: + file.managed: + - name: /opt/so/conf/zeek/local.zeek + - source: salt://zeek/files/local.zeek.jinja + - user: 937 + - group: 939 + - template: jinja + - defaults: + LOCAL: {{ ZEEKMERGED.config.local | tojson }} + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/zeek/defaults.yaml b/salt/zeek/defaults.yaml index b2629ab66..ca3168b8b 100644 --- a/salt/zeek/defaults.yaml +++ b/salt/zeek/defaults.yaml @@ -1,4 +1,5 @@ zeek: + enabled: False config: node: lb_procs: 0 diff --git a/salt/zeek/disabled.sls b/salt/zeek/disabled.sls new file mode 100644 index 000000000..5011331bf --- /dev/null +++ b/salt/zeek/disabled.sls @@ -0,0 +1,32 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +include: + - zeek.sostatus + +so-zeek: + docker_container.absent: + - force: True + +so-zeek_so-status.disabled: + file.comment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-zeek$ + +zeekpacketlosscron: + cron.absent: + - identifier: zeekpacketlosscron + - user: root + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/zeek/enabled.sls b/salt/zeek/enabled.sls new file mode 100644 index 000000000..611402fbc --- /dev/null +++ b/salt/zeek/enabled.sls @@ -0,0 +1,71 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} + +include: + - zeek.config + - zeek.sostatus + +so-zeek: + docker_container.running: + - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-zeek:{{ GLOBALS.so_version }} + - start: True + - privileged: True + - ulimits: + - core=0 + - nofile=1048576:1048576 + - binds: + - /nsm/zeek/logs:/nsm/zeek/logs:rw + - /nsm/zeek/spool:/nsm/zeek/spool:rw + - /nsm/zeek/extracted:/nsm/zeek/extracted:rw + - /opt/so/conf/zeek/local.zeek:/opt/zeek/share/zeek/site/local.zeek:ro + - /opt/so/conf/zeek/node.cfg:/opt/zeek/etc/node.cfg:ro + - /opt/so/conf/zeek/networks.cfg:/opt/zeek/etc/networks.cfg:ro + - /opt/so/conf/zeek/zeekctl.cfg:/opt/zeek/etc/zeekctl.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 + - /opt/so/conf/zeek/bpf:/opt/zeek/etc/bpf:ro + - network_mode: host + - watch: + - file: /opt/so/conf/zeek/local.zeek + - file: /opt/so/conf/zeek/node.cfg + - file: /opt/so/conf/zeek/networks.cfg + - file: /opt/so/conf/zeek/zeekctl.cfg + - file: /opt/so/conf/zeek/policy + - file: /opt/so/conf/zeek/bpf + - require: + - file: localzeek + - file: nodecfg + - file: zeekctlcfg + - file: zeekbpf + +delete_so-zeek_so-status.disabled: + file.uncomment: + - name: /opt/so/conf/so-status/so-status.conf + - regex: ^so-zeek$ + +zeekpacketlosscron: + cron.present: + - name: /usr/local/bin/packetloss.sh + - identifier: zeekpacketlosscron + - user: root + - minute: '*/10' + - hour: '*' + - daymonth: '*' + - month: '*' + - dayweek: '*' + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/salt/zeek/init.sls b/salt/zeek/init.sls index ce5996888..b2ba36ab1 100644 --- a/salt/zeek/init.sls +++ b/salt/zeek/init.sls @@ -3,281 +3,15 @@ # https://securityonion.net/license; you may not use this file except in compliance with the # Elastic License 2.0. -{% from 'allowed_states.map.jinja' import allowed_states %} -{% if sls in allowed_states %} +{% from 'vars/globals.map.jinja' import GLOBALS %} +{% from 'zeek/config.map.jinja' import ZEEKMERGED %} -{% from 'vars/globals.map.jinja' import GLOBALS with context %} -{% from "zeek/config.map.jinja" import ZEEKOPTIONS with context %} -{% from "zeek/config.map.jinja" import ZEEKMERGED with context %} - -{% from 'bpf/zeek.map.jinja' import ZEEKBPF %} - -{% set BPF_STATUS = 0 %} - -# Zeek Salt State - -# Add Zeek group -zeekgroup: - group.present: - - name: zeek - - gid: 937 - -# Add Zeek User -zeek: - user.present: - - uid: 937 - - gid: 937 - - home: /home/zeek - -# Create some directories -zeekpolicydir: - file.directory: - - name: /opt/so/conf/zeek/policy - - user: 937 - - group: 939 - - makedirs: True - -# Zeek Log Directory -zeeklogdir: - file.directory: - - name: /nsm/zeek/logs - - user: 937 - - group: 939 - - makedirs: True - -# Zeek Spool Directory -zeekspooldir: - file.directory: - - name: /nsm/zeek/spool/manager - - user: 937 - - makedirs: True - -# Zeek extracted -zeekextractdir: - file.directory: - - name: /nsm/zeek/extracted - - user: 937 - - group: 939 - - mode: 770 - - makedirs: True - -zeekextractcompletedir: - file.directory: - - name: /nsm/zeek/extracted/complete - - user: 937 - - group: 939 - - mode: 770 - - makedirs: True - -# Sync the policies -zeekpolicysync: - file.recurse: - - name: /opt/so/conf/zeek/policy - - source: salt://zeek/policy - - user: 937 - - group: 939 - - template: jinja - - defaults: - FILE_EXTRACTION: {{ ZEEKMERGED.file_extraction }} - -# Ensure the zeek spool tree (and state.db) ownership is correct -zeekspoolownership: - file.directory: - - name: /nsm/zeek/spool - - user: 937 -zeekstatedbownership: - file.managed: - - name: /nsm/zeek/spool/state.db - - user: 937 - - replace: False - - create: False - -zeek_sbin: - file.recurse: - - name: /usr/sbin - - source: salt://zeek/tools/sbin - - user: 939 - - group: 939 - - file_mode: 755 - -#zeek_sbin_jinja: -# file.recurse: -# - name: /usr/sbin -# - source: salt://zeek/tools/sbin_jinja -# - user: 939 -# - group: 939 -# - file_mode: 755 -# - template: jinja - -# Sync Intel -zeekintelloadsync: - file.managed: - - name: /opt/so/conf/policy/intel/__load__.zeek - - source: salt://zeek/policy/intel/__load__.zeek - - user: 937 - - group: 939 - - makedirs: True - -zeekctlcfg: - file.managed: - - name: /opt/so/conf/zeek/zeekctl.cfg - - source: salt://zeek/files/zeekctl.cfg.jinja - - user: 937 - - group: 939 - - template: jinja - - defaults: - ZEEKCTL: {{ ZEEKMERGED.config.zeekctl | tojson }} - -# Sync node.cfg -nodecfg: - file.managed: - - name: /opt/so/conf/zeek/node.cfg - - source: salt://zeek/files/node.cfg.jinja - - user: 937 - - group: 939 - - template: jinja - - defaults: - NODE: {{ ZEEKMERGED.config.node }} - -networkscfg: - file.managed: - - name: /opt/so/conf/zeek/networks.cfg - - source: salt://zeek/files/networks.cfg.jinja - - user: 937 - - group: 939 - - template: jinja - - defaults: - NETWORKS: {{ ZEEKMERGED.config.networks }} - -#zeekcleanscript: -# file.managed: -# - name: /usr/local/bin/zeek_clean -# - source: salt://zeek/cron/zeek_clean -# - mode: 755 - -#/usr/local/bin/zeek_clean: -# cron.present: -# - user: root -# - minute: '*' -# - hour: '*' -# - daymonth: '*' -# - month: '*' -# - dayweek: '*' - -plcronscript: - file.managed: - - name: /usr/local/bin/packetloss.sh - - source: salt://zeek/cron/packetloss.sh - - mode: 755 - -zeekpacketlosscron: - cron.{{ZEEKOPTIONS.pl_cron_state}}: - - name: /usr/local/bin/packetloss.sh - - user: root - - minute: '*/10' - - hour: '*' - - daymonth: '*' - - month: '*' - - dayweek: '*' - -# BPF compilation and configuration -{% if ZEEKBPF %} - {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %} - {% 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: {{ ZEEKBPF }} +include: +{% if ZEEKMERGED.enabled and GLOBALS.role != 'so-import' and GLOBALS.md_engine != 'SURICATA' %} + - zeek.enabled +{% elif GLOBALS.role == 'so-import' %} + - zeek.config + - zeek.disabled {% else %} - - contents: - - "ip or not ip" -{% endif %} - - -localzeek: - file.managed: - - name: /opt/so/conf/zeek/local.zeek - - source: salt://zeek/files/local.zeek.jinja - - user: 937 - - group: 939 - - template: jinja - - defaults: - LOCAL: {{ ZEEKMERGED.config.local | tojson }} - -so-zeek: - docker_container.{{ ZEEKOPTIONS.status }}: - {% if ZEEKOPTIONS.status == 'running' %} - - image: {{ GLOBALS.registry_host }}:5000/{{ GLOBALS.image_repo }}/so-zeek:{{ GLOBALS.so_version }} - - start: {{ ZEEKOPTIONS.start }} - - privileged: True - - ulimits: - - core=0 - - nofile=1048576:1048576 - - binds: - - /nsm/zeek/logs:/nsm/zeek/logs:rw - - /nsm/zeek/spool:/nsm/zeek/spool:rw - - /nsm/zeek/extracted:/nsm/zeek/extracted:rw - - /opt/so/conf/zeek/local.zeek:/opt/zeek/share/zeek/site/local.zeek:ro - - /opt/so/conf/zeek/node.cfg:/opt/zeek/etc/node.cfg:ro - - /opt/so/conf/zeek/networks.cfg:/opt/zeek/etc/networks.cfg:ro - - /opt/so/conf/zeek/zeekctl.cfg:/opt/zeek/etc/zeekctl.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 - - /opt/so/conf/zeek/bpf:/opt/zeek/etc/bpf:ro - - network_mode: host - - watch: - - file: /opt/so/conf/zeek/local.zeek - - file: /opt/so/conf/zeek/node.cfg - - file: /opt/so/conf/zeek/networks.cfg - - file: /opt/so/conf/zeek/zeekctl.cfg - - file: /opt/so/conf/zeek/policy - - file: /opt/so/conf/zeek/bpf - - require: - - file: localzeek - - file: nodecfg - - file: zeekctlcfg - - file: zeekbpf - {% else %} {# if Zeek isn't enabled, then stop and remove the container #} - - force: True - {% endif %} - -append_so-zeek_so-status.conf: - file.append: - - name: /opt/so/conf/so-status/so-status.conf - - text: so-zeek - - unless: grep -q so-zeek /opt/so/conf/so-status/so-status.conf - - {% if not ZEEKOPTIONS.start %} -so-zeek_so-status.disabled: - file.comment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-zeek$ - {% else %} -delete_so-zeek_so-status.disabled: - file.uncomment: - - name: /opt/so/conf/so-status/so-status.conf - - regex: ^so-zeek$ - {% endif %} - -{% else %} - -{{sls}}_state_not_allowed: - test.fail_without_changes: - - name: {{sls}}_state_not_allowed - + - zeek.disabled {% endif %} diff --git a/salt/zeek/soc_zeek.yaml b/salt/zeek/soc_zeek.yaml index a3ad624b6..8410d4e75 100644 --- a/salt/zeek/soc_zeek.yaml +++ b/salt/zeek/soc_zeek.yaml @@ -1,4 +1,7 @@ zeek: + enabled: + description: You can enable or disable ZEEK on all sensors or a single sensor. + helpLink: zeek.html logging: enabled: description: This is a list of Zeek logs that will be shipped through the pipeline. If you remove a log from this list, it will still persist on the sensor. diff --git a/salt/zeek/sostatus.sls b/salt/zeek/sostatus.sls new file mode 100644 index 000000000..3a75d217e --- /dev/null +++ b/salt/zeek/sostatus.sls @@ -0,0 +1,21 @@ +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +{% from 'allowed_states.map.jinja' import allowed_states %} +{% if sls.split('.')[0] in allowed_states %} + +append_so-zeek_so-status.conf: + file.append: + - name: /opt/so/conf/so-status/so-status.conf + - text: so-zeek + - unless: grep -q so-zeek /opt/so/conf/so-status/so-status.conf + +{% else %} + +{{sls}}_state_not_allowed: + test.fail_without_changes: + - name: {{sls}}_state_not_allowed + +{% endif %} diff --git a/setup/so-functions b/setup/so-functions index 6aae8806b..0bad00cbc 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -892,7 +892,6 @@ create_manager_pillars() { manager_pillar create_global create_sensoroni_pillar - #create_strelka_pillar backup_pillar soctopus_pillar docker_pillar @@ -905,6 +904,7 @@ create_manager_pillars() { logrotate_pillar patch_pillar nginx_pillar + kibana_pillar } create_repo() { @@ -1341,8 +1341,9 @@ idh_pillar() { } kibana_pillar() { - touch $adv_kibana_pillar_file - touch $kibana_pillar_file + logCmd "mkdir -p $local_salt_dir/pillar/kibana" + logCmd "touch $adv_kibana_pillar_file" + logCmd "touch $kibana_pillar_file" } logrotate_pillar() { @@ -1407,8 +1408,9 @@ soc_pillar() { touch $adv_soc_pillar_file printf '%s\n'\ "soc:"\ - " server:"\ - " srvKey: '$SOCSRVKEY'"\ + " config:"\ + " server:"\ + " srvKey: '$SOCSRVKEY'"\ "" > "$soc_pillar_file" } @@ -1502,9 +1504,10 @@ create_sensoroni_pillar() { printf '%s\n'\ "sensoroni:"\ - " node_checkin_interval_ms: $NODE_CHECKIN_INTERVAL_MS"\ - " sensoronikey: '$SENSORONIKEY'"\ - " soc_host: '$REDIRECTIT'" > $sensoroni_pillar_file + " config:"\ + " node_checkin_interval_ms: $NODE_CHECKIN_INTERVAL_MS"\ + " sensoronikey: '$SENSORONIKEY'"\ + " soc_host: '$REDIRECTIT'" > $sensoroni_pillar_file } diff --git a/setup/so-setup b/setup/so-setup index 6051ba742..853809e67 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -650,6 +650,7 @@ if ! [[ -f $install_opt_file ]]; then info "Restarting SOC to pick up initial user" logCmd "so-soc-restart" title "Setting up Elastic Fleet" + logCmd "salt-call state.apply elasticfleet.config" logCmd "so-elastic-fleet-setup" if [[ ! $is_import ]]; then title "Setting up Playbook"