diff --git a/pillar/top.sls b/pillar/top.sls index e8bcabca3..63bcbbaaf 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,6 +1,8 @@ base: '*': - patch.needs_restarting + - ntp.soc_ntp + - ntp.adv_ntp - logrotate - docker.soc_docker - docker.adv_docker diff --git a/salt/elasticsearch/tools/sbin/so-elasticsearch-templates-load b/salt/elasticsearch/tools/sbin/so-elasticsearch-templates-load index cb727a5d3..aa9502396 100755 --- a/salt/elasticsearch/tools/sbin/so-elasticsearch-templates-load +++ b/salt/elasticsearch/tools/sbin/so-elasticsearch-templates-load @@ -58,7 +58,7 @@ echo cd ${ELASTICSEARCH_TEMPLATES}/index echo "Loading Security Onion index templates..." -for i in *; do TEMPLATE=$(echo $i | cut -d '-' -f2); echo "so-$TEMPLATE"; so-elasticsearch-query _index_template/so-$TEMPLATE -d@$i -XPUT 2>/dev/null; echo; done +for i in *; do TEMPLATE=${i::-14}; echo "$TEMPLATE"; so-elasticsearch-query _index_template/$TEMPLATE -d@$i -XPUT 2>/dev/null; echo; done echo cd - >/dev/null diff --git a/salt/grafana/dashboards/common_template.json.jinja b/salt/grafana/dashboards/common_template.json.jinja index 23060a2fb..4c6745c3c 100644 --- a/salt/grafana/dashboards/common_template.json.jinja +++ b/salt/grafana/dashboards/common_template.json.jinja @@ -57,6 +57,8 @@ "title": "{{ TITLE }}", {% if TITLE | lower == 'security onion grid overview' %} "uid": "so_overview", + {% else %} + "uid": "{{ UID }}", {% endif %} "version": 1 } diff --git a/salt/grafana/init.sls b/salt/grafana/init.sls index f71bc3acb..584219906 100644 --- a/salt/grafana/init.sls +++ b/salt/grafana/init.sls @@ -117,6 +117,7 @@ so-grafana-dashboard-folder-delete: TEMPLATES: {{GRAFANA_SETTINGS.dashboards[dashboard].templating.list}} TITLE: {{ GRAFANA_SETTINGS.dashboards[dashboard].get('title', dashboard| capitalize) }} ID: {{ loop.index }} + UID: {{ dashboard }} {% endfor %} so-grafana: diff --git a/salt/nginx/config/ssl.crt b/salt/nginx/config/ssl.crt new file mode 100644 index 000000000..16878f704 --- /dev/null +++ b/salt/nginx/config/ssl.crt @@ -0,0 +1 @@ +# Replace this text with the text from the .crt \ No newline at end of file diff --git a/salt/nginx/config/ssl.key b/salt/nginx/config/ssl.key new file mode 100644 index 000000000..16878f704 --- /dev/null +++ b/salt/nginx/config/ssl.key @@ -0,0 +1 @@ +# Replace this text with the text from the .crt \ No newline at end of file diff --git a/salt/nginx/defaults.yaml b/salt/nginx/defaults.yaml new file mode 100644 index 000000000..cf051274b --- /dev/null +++ b/salt/nginx/defaults.yaml @@ -0,0 +1,3 @@ +nginx: + config: + replace_cert: False \ No newline at end of file diff --git a/salt/nginx/etc/nginx.conf b/salt/nginx/etc/nginx.conf index 623dae701..d09325f0e 100644 --- a/salt/nginx/etc/nginx.conf +++ b/salt/nginx/etc/nginx.conf @@ -1,11 +1,5 @@ +{%- from 'vars/globals.map.jinja' import GLOBALS %} {%- set role = grains.id.split('_') | last %} - -{%- set manager_ip = salt['pillar.get']('global:managerip', '') %} -{%- set url_base = salt['pillar.get']('global:url_base') %} - -{%- set airgap = salt['pillar.get']('global:airgap', 'False') %} - - worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; @@ -42,13 +36,13 @@ http { server { listen 80 default_server; server_name _; - return 307 https://{{ url_base }}$request_uri; + return 307 https://{{ GLOBALS.url_base }}$request_uri; } server { listen 443 ssl http2 default_server; server_name _; - return 307 https://{{ url_base }}$request_uri; + return 307 https://{{ GLOBALS.url_base }}$request_uri; ssl_certificate "/etc/pki/nginx/server.crt"; ssl_certificate_key "/etc/pki/nginx/server.key"; @@ -66,7 +60,7 @@ http { server { listen 7788; - server_name {{ url_base }}; + server_name {{ GLOBALS.url_base }}; root /opt/socore/html/repo; location /rules/ { allow all; @@ -81,7 +75,7 @@ http { server { listen 443 ssl http2; - server_name {{ url_base }}; + server_name {{ GLOBALS.url_base }}; root /opt/socore/html; index index.html; @@ -100,7 +94,7 @@ http { ssl_protocols TLSv1.2; location ~* (^/login/.*|^/js/.*|^/css/.*|^/images/.*) { - proxy_pass http://{{ manager_ip }}:9822; + proxy_pass http://{{ GLOBALS.manager_ip }}:9822; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header x-user-id ""; @@ -117,7 +111,7 @@ http { auth_request /auth/sessions/whoami; auth_request_set $userid $upstream_http_x_kratos_authenticated_identity_id; proxy_set_header x-user-id $userid; - proxy_pass http://{{ manager_ip }}:9822/; + proxy_pass http://{{ GLOBALS.manager_ip }}:9822/; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_set_header Host $host; @@ -131,7 +125,7 @@ http { location ~ ^/auth/.*?(whoami|login|logout|settings) { rewrite /auth/(.*) /$1 break; - proxy_pass http://{{ manager_ip }}:4433; + proxy_pass http://{{ GLOBALS.manager_ip }}:4433; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; @@ -188,7 +182,7 @@ http { location /grafana/ { auth_request /auth/sessions/whoami; rewrite /grafana/(.*) /$1 break; - proxy_pass http://{{ manager_ip }}:3000/; + proxy_pass http://{{ GLOBALS.manager_ip }}:3000/; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; @@ -201,7 +195,7 @@ http { location /kibana/ { auth_request /auth/sessions/whoami; rewrite /kibana/(.*) /$1 break; - proxy_pass http://{{ manager_ip }}:5601/; + proxy_pass http://{{ GLOBALS.manager_ip }}:5601/; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_set_header Host $host; @@ -213,7 +207,7 @@ http { location /nodered/ { auth_request /auth/sessions/whoami; - proxy_pass http://{{ manager_ip }}:1880/; + proxy_pass http://{{ GLOBALS.manager_ip }}:1880/; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; @@ -227,7 +221,7 @@ http { location /playbook/ { auth_request /auth/sessions/whoami; - proxy_pass http://{{ manager_ip }}:3200/playbook/; + proxy_pass http://{{ GLOBALS.manager_ip }}:3200/playbook/; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; @@ -240,7 +234,7 @@ http { location /soctopus/ { auth_request /auth/sessions/whoami; - proxy_pass http://{{ manager_ip }}:7000/; + proxy_pass http://{{ GLOBALS.manager_ip }}:7000/; proxy_read_timeout 300; proxy_connect_timeout 300; proxy_set_header Host $host; @@ -262,7 +256,7 @@ http { if ($http_authorization = "") { return 403; } - proxy_pass http://{{ manager_ip }}:9822/; + proxy_pass http://{{ GLOBALS.manager_ip }}:9822/; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header x-user-id ""; diff --git a/salt/nginx/init.sls b/salt/nginx/init.sls index f5791fdd6..122093337 100644 --- a/salt/nginx/init.sls +++ b/salt/nginx/init.sls @@ -1,11 +1,7 @@ +{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'allowed_states.map.jinja' import allowed_states %} {% if sls in allowed_states %} -{% set MANAGER = salt['grains.get']('master') %} -{% set VERSION = salt['pillar.get']('global:soversion') %} -{% set IMAGEREPO = salt['pillar.get']('global:imagerepo') %} -{% set ISAIRGAP = salt['pillar.get']('global:airgap') %} - include: - ssl @@ -85,7 +81,7 @@ navigatorenterpriseattack: so-nginx: docker_container.running: - - image: {{ MANAGER }}:5000/{{ IMAGEREPO }}/so-nginx:{{ VERSION }} + - image: {{ GLOBALS.manager }}:5000/{{ GLOBALS.image_repo }}/so-nginx:{{ GLOBALS.so_version }} - hostname: so-nginx - binds: - /opt/so/conf/nginx/nginx.conf:/etc/nginx/nginx.conf:ro @@ -108,9 +104,6 @@ so-nginx: - port_bindings: - 80:80 - 443:443 - {% if ISAIRGAP is sameas true %} - - 7788:7788 - {% endif %} - watch: - file: nginxconf - file: nginxconfdir diff --git a/salt/nginx/soc_nginx.yaml b/salt/nginx/soc_nginx.yaml new file mode 100644 index 000000000..d5811654e --- /dev/null +++ b/salt/nginx/soc_nginx.yaml @@ -0,0 +1,19 @@ +nginx: + config: + replace_cert: + description: Replace the Security Onion Certificate with your own? + global: True + advanced: True + title: Replace Default Cert + ssl__key: + description: Paste your .key file here + file: True + title: SSL Key File + advanced: True + global: True + ssl__crt: + description: Paste your .crt file here + file: True + title: SSL Cert File + advanced: True + global: True \ No newline at end of file diff --git a/salt/ntp/chrony.conf b/salt/ntp/chrony.conf new file mode 100644 index 000000000..46432915f --- /dev/null +++ b/salt/ntp/chrony.conf @@ -0,0 +1,11 @@ + +# NTP server list +{%- for SERVER in NTPCONFIG.servers %} +server {{ SERVER }} iburst +{%- endfor %} + +# Config options +driftfile /var/lib/chrony/drift +makestep 1.0 3 +rtcsync +logdir /var/log/chrony diff --git a/salt/ntp/config.map.jinja b/salt/ntp/config.map.jinja new file mode 100644 index 000000000..62714abfc --- /dev/null +++ b/salt/ntp/config.map.jinja @@ -0,0 +1,3 @@ +{% import_yaml 'ntp/defaults.yaml' as NTP with context %} + +{% set NTPCONFIG = salt['pillar.get']('ntp:config', default=NTP.ntp.config, merge=True) %} diff --git a/salt/ntp/defaults.yaml b/salt/ntp/defaults.yaml new file mode 100644 index 000000000..9b58ad380 --- /dev/null +++ b/salt/ntp/defaults.yaml @@ -0,0 +1,5 @@ +ntp: + config: + servers: + - 0.pool.ntp.org + - 1.pool.ntp.org \ No newline at end of file diff --git a/salt/ntp/init.sls b/salt/ntp/init.sls new file mode 100644 index 000000000..42840d6ec --- /dev/null +++ b/salt/ntp/init.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 'ntp/config.map.jinja' import NTPCONFIG %} + +chronyconf: + file.managed: + - name: /etc/chrony.conf + - source: salt://ntp/chrony.conf + - template: jinja + - defaults: + NTPCONFIG: {{ NTPCONFIG }} + +chronyd: + service.running: + - enable: True + - watch: + - file: chronyconf \ No newline at end of file diff --git a/salt/ntp/soc_ntp.yaml b/salt/ntp/soc_ntp.yaml new file mode 100644 index 000000000..01484d714 --- /dev/null +++ b/salt/ntp/soc_ntp.yaml @@ -0,0 +1,5 @@ +ntp: + config: + servers: + description: NTP Server List + title: NTP Servers diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 055bd401b..041a09d0b 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -64,7 +64,7 @@ soc: remoteHostUrls: [] username: password: - index: '*:so-*,*:endgame-*' + index: '*:so-*,*:endgame-*,*:logs-*' cacheMs: 300000 verifyCert: false casesEnabled: true @@ -702,7 +702,7 @@ soc: queryBaseFilter: queryToggleFilters: - name: caseExcludeToggle - filter: NOT _index:\"*:so-case*\" + filter: 'NOT _index:"*:so-case*"' enabled: true queries: - name: Default Query @@ -723,6 +723,9 @@ soc: - 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' + - 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' - name: Wazuh/OSSEC Alerts description: Show all Wazuh alerts at Level 5 or higher grouped by category query: 'event.module:ossec AND event.dataset:alert AND rule.level:>4 | groupby rule.category rule.name' @@ -837,9 +840,6 @@ soc: - name: NTLM description: NTLM grouped by computer name query: 'event.dataset:ntlm | groupby ntlm.server.dns.name' - - name: Osquery Live Queries - description: Osquery Live Query results grouped by computer name - query: 'event.dataset:live_query | groupby host.hostname' - name: PE description: PE files list query: 'event.dataset:pe | groupby file.machine file.os file.subsystem' @@ -1461,7 +1461,7 @@ soc: - winlog.computer_name queryBaseFilter: queryToggleFilters: - - name: caseExcludeToggle, + - name: caseExcludeToggle filter: 'NOT _index:"*:so-case*"' enabled: true queries: @@ -1540,9 +1540,6 @@ soc: - name: NTLM description: NTLM logs query: 'event.dataset:ntlm | groupby ntlm.server.dns.name | groupby ntlm.server.nb.name | groupby ntlm.server.tree.name | groupby ntlm.success | groupby source.ip | groupby destination.ip | groupby destination.port' - - name: Osquery Live Queries - description: Osquery Live Query results - query: 'event.dataset:live_query | groupby host.hostname' - name: PE description: PE files list query: 'event.dataset:pe | groupby file.machine | groupby file.os | groupby file.subsystem | groupby file.section_names | groupby file.is_exe | groupby file.is_64bit' @@ -1687,7 +1684,7 @@ soc: - so_case.severity - so_case.assigneeId - so_case.createTime - queryBaseFilter: '_index:\"*:so-case\" AND so_kind:case' + queryBaseFilter: '_index:"*:so-case" AND so_kind:case' queryToggleFilters: [] queries: - name: Open Cases diff --git a/salt/top.sls b/salt/top.sls index e12a3a22e..481a741b0 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -22,6 +22,7 @@ base: '*': - cron.running - repo.client + - ntp 'not G@saltversion:{{saltversion}}': - match: compound diff --git a/setup/so-variables b/setup/so-variables index 5acbc01bc..f29d9ae55 100644 --- a/setup/so-variables +++ b/setup/so-variables @@ -81,7 +81,7 @@ export whiptail_title mkdir -p $local_salt_dir/pillar/minions -for THEDIR in bpf pcap elasticsearch firewall redis backup strelka sensoroni curator soc soctopus docker zeek suricata nginx filebeat logstash soc manager kratos idstools idh elastalert +for THEDIR in bpf pcap elasticsearch ntp firewall redis backup strelka sensoroni curator soc soctopus docker zeek suricata nginx filebeat logstash soc manager kratos idstools idh elastalert do mkdir -p $local_salt_dir/pillar/$THEDIR touch $local_salt_dir/pillar/$THEDIR/adv_$THEDIR.sls