From 9bcba41882c9d2eee1a90320c78f9e5f557408b1 Mon Sep 17 00:00:00 2001 From: Josh Brower Date: Tue, 24 Mar 2020 20:57:24 -0400 Subject: [PATCH] Feature/Fleet-Standalone --- files/master | 4 + pillar/firewall/fleet_nodes.sls | 3 + pillar/top.sls | 7 ++ salt/common/init.sls | 4 + salt/common/nginx/nginx.conf.so-eval | 39 +++--- salt/common/nginx/nginx.conf.so-fleet | 106 ++++++++++++++++ salt/common/nginx/nginx.conf.so-master | 41 ++++--- salt/common/nginx/nginx.conf.so-mastersearch | 43 ++++--- salt/common/tools/sbin/so-allow | 2 +- salt/common/tools/sbin/so-status | 2 + .../init.sls | 0 .../packages/info.txt | 0 salt/filebeat/etc/filebeat.yml | 7 +- salt/filebeat/init.sls | 4 +- salt/firewall/init.sls | 116 +++++++++++++++++- salt/fleet/event_enable-fleet.sls | 9 ++ salt/fleet/event_gen-packages.sls | 10 ++ salt/fleet/files/osquery-packages-sa.html | 107 ++++++++++++++++ salt/fleet/{ => files}/osquery-packages.html | 0 .../fleet/{ => files}/packs/PUT.PACKS.IN.HERE | 0 .../{ => files}/packs/hh/hh-post-login.sh | 0 salt/fleet/{ => files}/packs/hh/hhdefault.yml | 0 salt/fleet/{ => files}/packs/hh/osquery.conf | 0 .../Fleet/Endpoints/MacOS/osquery.yaml | 0 .../Fleet/Endpoints/Windows/osquery.yaml | 0 .../palantir/Fleet/Endpoints/options.yaml | 0 .../Endpoints/packs/performance-metrics.yaml | 0 .../packs/security-tooling-checks.yaml | 0 .../packs/windows-application-security.yaml | 0 .../Endpoints/packs/windows-compliance.yaml | 0 .../packs/windows-registry-monitoring.yaml | 0 .../palantir/Fleet/Servers/Linux/osquery.yaml | 0 .../packs/palantir/Fleet/Servers/options.yaml | 0 .../{ => files}/packs/palantir/LICENSE.md | 0 .../{ => files}/packs/palantir/README.md | 0 salt/fleet/files/scripts/so-fleet-packages | 33 +++++ salt/fleet/files/scripts/so-fleet-setup | 38 ++++++ salt/fleet/init.sls | 80 +++++++++--- salt/fleet/install_package.sls | 13 ++ salt/fleet/packages/info.txt | 1 + salt/fleet/so-fleet-setup.sh | 53 -------- salt/mysql/etc/mypass | 2 +- salt/mysql/init.sls | 25 +++- salt/reactor/fleet.sls | 48 ++++++++ salt/ssl/init.sls | 44 +++++++ salt/top.sls | 61 +++++---- setup/so-functions | 34 ++++- setup/so-setup | 77 +++++++++++- setup/so-whiptail | 6 +- 49 files changed, 854 insertions(+), 165 deletions(-) create mode 100644 pillar/firewall/fleet_nodes.sls create mode 100644 salt/common/nginx/nginx.conf.so-fleet rename salt/{launcher => deprecated-launcher}/init.sls (100%) rename salt/{launcher => deprecated-launcher}/packages/info.txt (100%) create mode 100644 salt/fleet/event_enable-fleet.sls create mode 100644 salt/fleet/event_gen-packages.sls create mode 100644 salt/fleet/files/osquery-packages-sa.html rename salt/fleet/{ => files}/osquery-packages.html (100%) rename salt/fleet/{ => files}/packs/PUT.PACKS.IN.HERE (100%) rename salt/fleet/{ => files}/packs/hh/hh-post-login.sh (100%) rename salt/fleet/{ => files}/packs/hh/hhdefault.yml (100%) rename salt/fleet/{ => files}/packs/hh/osquery.conf (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/Windows/osquery.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/options.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/packs/performance-metrics.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/packs/security-tooling-checks.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/packs/windows-application-security.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/packs/windows-compliance.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Endpoints/packs/windows-registry-monitoring.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Servers/Linux/osquery.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/Fleet/Servers/options.yaml (100%) rename salt/fleet/{ => files}/packs/palantir/LICENSE.md (100%) rename salt/fleet/{ => files}/packs/palantir/README.md (100%) create mode 100644 salt/fleet/files/scripts/so-fleet-packages create mode 100644 salt/fleet/files/scripts/so-fleet-setup create mode 100644 salt/fleet/install_package.sls create mode 100644 salt/fleet/packages/info.txt delete mode 100644 salt/fleet/so-fleet-setup.sh create mode 100644 salt/reactor/fleet.sls diff --git a/files/master b/files/master index 25252da0c..f14c4194c 100644 --- a/files/master +++ b/files/master @@ -57,3 +57,7 @@ pillar_roots: peer: .*: - x509.sign_remote_certificate + +reactor: + - 'so/fleet': + - salt://reactor/fleet.sls diff --git a/pillar/firewall/fleet_nodes.sls b/pillar/firewall/fleet_nodes.sls new file mode 100644 index 000000000..ca2bd1ff3 --- /dev/null +++ b/pillar/firewall/fleet_nodes.sls @@ -0,0 +1,3 @@ +fleet_nodes: + - 127.0.0.1 + diff --git a/pillar/top.sls b/pillar/top.sls index 9b1d60035..f1cde7853 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -56,3 +56,10 @@ base: - logstash - logstash.helix - minions.{{ grains.id }} + + '*_fleet': + - static + - firewall.* + - data.* + - auth + - minions.{{ grains.id }} diff --git a/salt/common/init.sls b/salt/common/init.sls index 934183f5a..13c174265 100644 --- a/salt/common/init.sls +++ b/salt/common/init.sls @@ -1,6 +1,7 @@ {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} {% set GRAFANA = salt['pillar.get']('master:grafana', '0') %} +{% set FLEETMASTER = salt['pillar.get']('static:fleet_master', False) %} # Add socore Group socoregroup: group.present: @@ -142,6 +143,9 @@ so-core: - port_bindings: - 80:80 - 443:443 + {%- if FLEETMASTER %} + - 8090:8090 + {%- endif %} - watch: - file: /opt/so/conf/nginx/nginx.conf diff --git a/salt/common/nginx/nginx.conf.so-eval b/salt/common/nginx/nginx.conf.so-eval index 7cc810a93..e322ab59d 100644 --- a/salt/common/nginx/nginx.conf.so-eval +++ b/salt/common/nginx/nginx.conf.so-eval @@ -1,4 +1,5 @@ {%- set masterip = salt['pillar.get']('master:mainip', '') %} +{%- set FLEET_MASTER = salt['pillar.get']('static:fleet_master') %} # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ @@ -63,6 +64,29 @@ http { return 301 https://$host$request_uri; } +{% if FLEET_MASTER %} + server { + listen 8090 ssl http2 default_server; + server_name _; + root /opt/socore/html; + index blank.html; + + ssl_certificate "/etc/pki/nginx/server.crt"; + ssl_certificate_key "/etc/pki/nginx/server.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location ~ ^/kolide.agent.Api/(RequestEnrollment|RequestConfig|RequestQueries|PublishLogs|PublishResults|CheckHealth)$ { + grpc_pass grpcs://{{ masterip }}:8080; + grpc_set_header Host $host; + grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_buffering off; + } + + } +{% endif %} # Settings for a TLS enabled server. @@ -149,21 +173,8 @@ http { } - location /api/ { - proxy_pass https://{{ masterip }}:8080/api/; - proxy_read_timeout 90; - proxy_connect_timeout 90; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Proxy ""; - - } - location /fleet/ { - proxy_pass https://{{ masterip }}:8080/fleet/; + proxy_pass https://{{ masterip }}:8080; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; diff --git a/salt/common/nginx/nginx.conf.so-fleet b/salt/common/nginx/nginx.conf.so-fleet new file mode 100644 index 000000000..5665fcf4e --- /dev/null +++ b/salt/common/nginx/nginx.conf.so-fleet @@ -0,0 +1,106 @@ +{%- set MAINIP = salt['pillar.get']('node:mainip', '') %} +# For more information on configuration, see: +# * Official English Documentation: http://nginx.org/en/docs/ +# * Official Russian Documentation: http://nginx.org/ru/docs/ + +user nginx; +worker_processes auto; +error_log /var/log/nginx/error.log; +pid /run/nginx.pid; + +# Load dynamic modules. See /usr/share/nginx/README.dynamic. +include /usr/share/nginx/modules/*.conf; + +events { + worker_connections 1024; +} + +http { + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 65; + types_hash_max_size 2048; + + include /etc/nginx/mime.types; + default_type application/octet-stream; + + include /etc/nginx/conf.d/*.conf; + + server { + listen 80 default_server; + server_name _; + return 301 https://$host$request_uri; + } + + server { + listen 8090 ssl http2 default_server; + server_name _; + root /opt/socore/html; + index blank.html; + + ssl_certificate "/etc/pki/nginx/server.crt"; + ssl_certificate_key "/etc/pki/nginx/server.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location ~ ^/kolide.agent.Api/(RequestEnrollment|RequestConfig|RequestQueries|PublishLogs|PublishResults|CheckHealth)$ { + grpc_pass grpcs://{{ MAINIP }}:8080; + grpc_set_header Host $host; + grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_buffering off; + } + + } + + + server { + listen 443 ssl http2 default_server; + server_name _; + root /opt/socore/html; + index index.html; + + ssl_certificate "/etc/pki/nginx/server.crt"; + ssl_certificate_key "/etc/pki/nginx/server.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location /fleet/ { + proxy_pass https://{{ MAINIP }}:8080; + proxy_read_timeout 90; + proxy_connect_timeout 90; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header Proxy ""; + + } + + + error_page 401 = @error401; + + location @error401 { + add_header Set-Cookie "NSREDIRECT=http://{{ MAINIP }}$request_uri;Domain={{ MAINIP }};Path=/;Max-Age=60000"; + return 302 http://{{ MAINIP }}/so-auth/loginpage/; + } + + error_page 404 /404.html; + location = /40x.html { + } + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + } + } + +} diff --git a/salt/common/nginx/nginx.conf.so-master b/salt/common/nginx/nginx.conf.so-master index 4da4b99d6..ed9dfb253 100644 --- a/salt/common/nginx/nginx.conf.so-master +++ b/salt/common/nginx/nginx.conf.so-master @@ -1,4 +1,5 @@ {%- set masterip = salt['pillar.get']('master:mainip', '') %} +{%- set FLEET_MASTER = salt['pillar.get']('static:fleet_master') %} # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ @@ -63,6 +64,29 @@ http { return 301 https://$host$request_uri; } +{% if FLEET_MASTER %} + server { + listen 8090 ssl http2 default_server; + server_name _; + root /opt/socore/html; + index blank.html; + + ssl_certificate "/etc/pki/nginx/server.crt"; + ssl_certificate_key "/etc/pki/nginx/server.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location ~ ^/kolide.agent.Api/(RequestEnrollment|RequestConfig|RequestQueries|PublishLogs|PublishResults|CheckHealth)$ { + grpc_pass grpcs://{{ masterip }}:8080; + grpc_set_header Host $host; + grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_buffering off; + } + + } +{% endif %} # Settings for a TLS enabled server. @@ -148,23 +172,8 @@ http { } - location /api/ { - proxy_pass https://{{ masterip }}:8080/api/; - proxy_read_timeout 90; - proxy_connect_timeout 90; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Proxy ""; - - } - location /fleet/ { - rewrite /fleet/(.*) /$1 break; - auth_request /so-auth/api/auth/; - proxy_pass https://{{ masterip }}:8080/; + proxy_pass https://{{ masterip }}:8080; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; diff --git a/salt/common/nginx/nginx.conf.so-mastersearch b/salt/common/nginx/nginx.conf.so-mastersearch index 1bd0ebd2f..1eb4e8e5c 100644 --- a/salt/common/nginx/nginx.conf.so-mastersearch +++ b/salt/common/nginx/nginx.conf.so-mastersearch @@ -1,4 +1,5 @@ {%- set masterip = salt['pillar.get']('master:mainip', '') %} +{%- set FLEET_MASTER = salt['pillar.get']('static:fleet_master') %} # For more information on configuration, see: # * Official English Documentation: http://nginx.org/en/docs/ # * Official Russian Documentation: http://nginx.org/ru/docs/ @@ -63,6 +64,29 @@ http { return 301 https://$host$request_uri; } +{% if FLEET_MASTER %} + server { + listen 8090 ssl http2 default_server; + server_name _; + root /opt/socore/html; + index blank.html; + + ssl_certificate "/etc/pki/nginx/server.crt"; + ssl_certificate_key "/etc/pki/nginx/server.key"; + ssl_session_cache shared:SSL:1m; + ssl_session_timeout 10m; + ssl_ciphers HIGH:!aNULL:!MD5; + ssl_prefer_server_ciphers on; + + location ~ ^/kolide.agent.Api/(RequestEnrollment|RequestConfig|RequestQueries|PublishLogs|PublishResults|CheckHealth)$ { + grpc_pass grpcs://{{ masterip }}:8080; + grpc_set_header Host $host; + grpc_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_buffering off; + } + + } +{% endif %} # Settings for a TLS enabled server. @@ -135,23 +159,8 @@ http { } - location /api/ { - proxy_pass https://{{ masterip }}:8080/api/; - proxy_read_timeout 90; - proxy_connect_timeout 90; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header Proxy ""; - - } - location /fleet/ { - rewrite /fleet/(.*) /$1 break; - auth_request /so-auth/api/auth/; - proxy_pass https://{{ masterip }}:8080/; + proxy_pass https://{{ masterip }}:8080; proxy_read_timeout 90; proxy_connect_timeout 90; proxy_set_header Host $host; @@ -275,4 +284,4 @@ http { } } -} +} \ No newline at end of file diff --git a/salt/common/tools/sbin/so-allow b/salt/common/tools/sbin/so-allow index 61df47fd0..bede282b3 100755 --- a/salt/common/tools/sbin/so-allow +++ b/salt/common/tools/sbin/so-allow @@ -56,7 +56,7 @@ if [ "$SKIP" -eq 0 ]; then echo "" echo "[a] - Analyst - ports 80/tcp and 443/tcp" echo "[b] - Logstash Beat - port 5044/tcp" - echo "[o] - Osquery endpoint - port 8080/tcp" + echo "[o] - Osquery endpoint - port 8090/tcp" echo "[w] - Wazuh endpoint - port 1514" echo "" echo "Please enter your selection (a - analyst, b - beats, o - osquery, w - wazuh):" diff --git a/salt/common/tools/sbin/so-status b/salt/common/tools/sbin/so-status index 7f6e01eec..551a80fbd 100755 --- a/salt/common/tools/sbin/so-status +++ b/salt/common/tools/sbin/so-status @@ -26,6 +26,8 @@ {%- set pillar_val = 'sensor' -%} {%- elif (salt['grains.get']('role') == 'so-eval') -%} {%- set pillar_val = 'eval' -%} +{%- elif (salt['grains.get']('role') == 'so-fleet') -%} + {%- set pillar_val = 'fleet' -%} {%- elif (salt['grains.get']('role') == 'so-helix') -%} {%- set pillar_val = 'helix' -%} {%- elif (salt['grains.get']('role') == 'so-node') -%} diff --git a/salt/launcher/init.sls b/salt/deprecated-launcher/init.sls similarity index 100% rename from salt/launcher/init.sls rename to salt/deprecated-launcher/init.sls diff --git a/salt/launcher/packages/info.txt b/salt/deprecated-launcher/packages/info.txt similarity index 100% rename from salt/launcher/packages/info.txt rename to salt/deprecated-launcher/packages/info.txt diff --git a/salt/filebeat/etc/filebeat.yml b/salt/filebeat/etc/filebeat.yml index 3aa8fa565..792f0a959 100644 --- a/salt/filebeat/etc/filebeat.yml +++ b/salt/filebeat/etc/filebeat.yml @@ -8,8 +8,9 @@ {%- set HOSTNAME = salt['grains.get']('host', '') %} {%- set BROVER = salt['pillar.get']('static:broversion', 'COMMUNITY') %} {%- set WAZUHENABLED = salt['pillar.get']('static:wazuh_enabled', '1') %} -{%- set FLEETENABLED = salt['pillar.get']('static:fleet_enabled', '1') %} {%- set STRELKAENABLED = salt['pillar.get']('static:strelka_enabled', '1') %} +{%- set FLEETMASTER = salt['pillar.get']('static:fleet_master', False) -%} +{%- set FLEETNODE = salt['pillar.get']('static:fleet_node', False) -%} name: {{ HOSTNAME }} @@ -137,11 +138,11 @@ filebeat.inputs: {%- endif %} -{%- if FLEETENABLED == '1' %} +{%- if FLEETMASTER or FLEETNODE %} - type: log paths: - - /osquery/logs/result.log + - /nsm/osquery/fleet/result.log fields: type: osquery diff --git a/salt/filebeat/init.sls b/salt/filebeat/init.sls index 671530cd1..25fbbdd14 100644 --- a/salt/filebeat/init.sls +++ b/salt/filebeat/init.sls @@ -1,4 +1,4 @@ -# Copyright 2014,2015,2016,2017,2018 Security Onion Solutions, LLC +# Copyright 2014,2015,2016,2017,2018,2019,2020 Security Onion Solutions, LLC # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or @@ -59,7 +59,7 @@ so-filebeat: - /opt/so/log/suricata:/suricata:ro - /opt/so/wazuh/logs/alerts:/wazuh/alerts:ro - /opt/so/wazuh/logs/archives:/wazuh/archives:ro - - /opt/so/log/fleet/:/osquery/logs:ro + - /nsm/osquery/fleet/:/osquery/logs:ro - /opt/so/conf/filebeat/etc/pki/filebeat.crt:/usr/share/filebeat/filebeat.crt:ro - /opt/so/conf/filebeat/etc/pki/filebeat.key:/usr/share/filebeat/filebeat.key:ro - /etc/ssl/certs/intca.crt:/usr/share/filebeat/intraca.crt:ro diff --git a/salt/firewall/init.sls b/salt/firewall/init.sls index 657ff7814..16492dd47 100644 --- a/salt/firewall/init.sls +++ b/salt/firewall/init.sls @@ -5,7 +5,10 @@ {%- set ip = salt['pillar.get']('node:mainip', '') %} {%- elif grains['role'] == 'so-sensor' %} {%- set ip = salt['pillar.get']('sensor:mainip', '') %} +{%- elif grains['role'] == 'so-fleet' %} +{%- set ip = salt['pillar.get']('node:mainip', '') %} {%- endif %} + # Quick Fix for Docker being difficult iptables_fix_docker: iptables.chain_present: @@ -232,14 +235,14 @@ enable_masternode_mysql_3306_{{ip}}: - position: 1 - save: True -enable_master_osquery_8080_{{ip}}: +enable_master_osquery_8090_{{ip}}: iptables.insert: - table: filter - chain: DOCKER-USER - jump: ACCEPT - proto: tcp - source: {{ ip }} - - dport: 8080 + - dport: 8090 - position: 1 - save: True @@ -466,14 +469,14 @@ enable_standard_beats_5044_{{ip}}: # Allow OSQuery Endpoints to send their traffic {% for ip in pillar.get('osquery_endpoint') %} -enable_standard_osquery_8080_{{ip}}: +enable_standard_osquery_8090_{{ip}}: iptables.insert: - table: filter - chain: DOCKER-USER - jump: ACCEPT - proto: tcp - source: {{ ip }} - - dport: 8080 + - dport: 8090 - position: 1 - save: True @@ -702,3 +705,108 @@ enable_forwardnode_beats_5644_{{ip}}: - position: 1 - save: True {% endif %} + + +# Rules if you are a Standalone Fleet node +{% if grains['role'] == 'so-fleet' %} +#This should be more granular +iptables_allow_fleetnode_docker: + iptables.insert: + - table: filter + - chain: INPUT + - jump: ACCEPT + - source: 172.17.0.0/24 + - position: 1 + - save: True + +# Allow Redis +enable_fleetnode_redis_6379_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 6379 + - position: 1 + - save: True + +enable_fleetnode_mysql_3306_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 3306 + - position: 1 + - save: True + +enable_fleet_osquery_8080_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 8080 + - position: 1 + - save: True + + +enable_fleetnodetemp_mysql_3306_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: 127.0.0.1 + - dport: 3306 + - position: 1 + - save: True + +enable_fleettemp_osquery_8080_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: 127.0.0.1 + - dport: 8080 + - position: 1 + - save: True + + +# Allow Analysts to access Fleet WebUI +{% for ip in pillar.get('analyst') %} + +enable_fleetnode_fleet_443_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 443 + - position: 1 + - save: True + +{% endfor %} + +# Needed for osquery endpoints to checkin to Fleet API for mgt +{% for ip in pillar.get('osquery_endpoint') %} + +enable_fleetnode_8090_{{ip}}: + iptables.insert: + - table: filter + - chain: DOCKER-USER + - jump: ACCEPT + - proto: tcp + - source: {{ ip }} + - dport: 8090 + - position: 1 + - save: True + +{% endfor %} + +{% endif %} \ No newline at end of file diff --git a/salt/fleet/event_enable-fleet.sls b/salt/fleet/event_enable-fleet.sls new file mode 100644 index 000000000..8c3426e0d --- /dev/null +++ b/salt/fleet/event_enable-fleet.sls @@ -0,0 +1,9 @@ +{% set ENROLLSECRET = salt['cmd.run']('docker exec so-fleet fleetctl get enroll-secret') %} + +so/fleet: + event.send: + - data: + action: 'enablefleet' + hostname: {{ grains.host }} + role: {{ grains.role }} + enroll-secret: {{ ENROLLSECRET }} \ No newline at end of file diff --git a/salt/fleet/event_gen-packages.sls b/salt/fleet/event_gen-packages.sls new file mode 100644 index 000000000..affc9a72a --- /dev/null +++ b/salt/fleet/event_gen-packages.sls @@ -0,0 +1,10 @@ +{% set ENROLLSECRET = salt['pillar.get']('auth:fleet_enroll-secret') %} + +so/fleet: + event.send: + - data: + action: 'genpackages' + hostname: {{ grains.host }} + role: {{ grains.role }} + mainip: {{ grains.host }} + enroll-secret: {{ ENROLLSECRET }} \ No newline at end of file diff --git a/salt/fleet/files/osquery-packages-sa.html b/salt/fleet/files/osquery-packages-sa.html new file mode 100644 index 000000000..c35449522 --- /dev/null +++ b/salt/fleet/files/osquery-packages-sa.html @@ -0,0 +1,107 @@ + + + +Security Onion - Hybrid Hunter + + + + + + + + +
+ Fleet + Fleet & Osquery Docs +
+ +
+ +

Osquery Packages


+ +

Notes

+ +

Downloads

+ + +

Known Issues

+ +

+
+ + + + diff --git a/salt/fleet/osquery-packages.html b/salt/fleet/files/osquery-packages.html similarity index 100% rename from salt/fleet/osquery-packages.html rename to salt/fleet/files/osquery-packages.html diff --git a/salt/fleet/packs/PUT.PACKS.IN.HERE b/salt/fleet/files/packs/PUT.PACKS.IN.HERE similarity index 100% rename from salt/fleet/packs/PUT.PACKS.IN.HERE rename to salt/fleet/files/packs/PUT.PACKS.IN.HERE diff --git a/salt/fleet/packs/hh/hh-post-login.sh b/salt/fleet/files/packs/hh/hh-post-login.sh similarity index 100% rename from salt/fleet/packs/hh/hh-post-login.sh rename to salt/fleet/files/packs/hh/hh-post-login.sh diff --git a/salt/fleet/packs/hh/hhdefault.yml b/salt/fleet/files/packs/hh/hhdefault.yml similarity index 100% rename from salt/fleet/packs/hh/hhdefault.yml rename to salt/fleet/files/packs/hh/hhdefault.yml diff --git a/salt/fleet/packs/hh/osquery.conf b/salt/fleet/files/packs/hh/osquery.conf similarity index 100% rename from salt/fleet/packs/hh/osquery.conf rename to salt/fleet/files/packs/hh/osquery.conf diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/Windows/osquery.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/Windows/osquery.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/Windows/osquery.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/Windows/osquery.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/options.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/options.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/options.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/options.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/packs/performance-metrics.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/performance-metrics.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/packs/performance-metrics.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/performance-metrics.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/packs/security-tooling-checks.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/security-tooling-checks.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/packs/security-tooling-checks.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/security-tooling-checks.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-application-security.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-application-security.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-application-security.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-application-security.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-compliance.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-compliance.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-compliance.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-compliance.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-registry-monitoring.yaml b/salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-registry-monitoring.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Endpoints/packs/windows-registry-monitoring.yaml rename to salt/fleet/files/packs/palantir/Fleet/Endpoints/packs/windows-registry-monitoring.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Servers/Linux/osquery.yaml b/salt/fleet/files/packs/palantir/Fleet/Servers/Linux/osquery.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Servers/Linux/osquery.yaml rename to salt/fleet/files/packs/palantir/Fleet/Servers/Linux/osquery.yaml diff --git a/salt/fleet/packs/palantir/Fleet/Servers/options.yaml b/salt/fleet/files/packs/palantir/Fleet/Servers/options.yaml similarity index 100% rename from salt/fleet/packs/palantir/Fleet/Servers/options.yaml rename to salt/fleet/files/packs/palantir/Fleet/Servers/options.yaml diff --git a/salt/fleet/packs/palantir/LICENSE.md b/salt/fleet/files/packs/palantir/LICENSE.md similarity index 100% rename from salt/fleet/packs/palantir/LICENSE.md rename to salt/fleet/files/packs/palantir/LICENSE.md diff --git a/salt/fleet/packs/palantir/README.md b/salt/fleet/files/packs/palantir/README.md similarity index 100% rename from salt/fleet/packs/palantir/README.md rename to salt/fleet/files/packs/palantir/README.md diff --git a/salt/fleet/files/scripts/so-fleet-packages b/salt/fleet/files/scripts/so-fleet-packages new file mode 100644 index 000000000..eed4bfb71 --- /dev/null +++ b/salt/fleet/files/scripts/so-fleet-packages @@ -0,0 +1,33 @@ +#!/bin/bash +{% set MAIN_HOSTNAME = salt['grains.get']('host') %} +{% set MAIN_IP = salt['pillar.get']('node:mainip') %} + + +#so-fleet-packages $FleetHostname/IP + +#if [ ! "$(docker ps -q -f name=so-fleet)" ]; then +# echo "so-fleet container not running... Exiting..." +# exit 1 +#fi + +#docker exec so-fleet /bin/ash -c "echo {{ MAIN_IP }} {{ MAIN_HOSTNAME }} >> /etc/hosts" +#esecret=$(docker exec so-fleet fleetctl get enroll-secret) + +#Concat fleet.crt & ca.crt - this is required for launcher connectivity +#cat /etc/pki/fleet.crt /etc/pki/ca.crt > /etc/pki/launcher.crt +#Actually only need to use /etc/ssl/certs/intca.crt + +#Create the output directory +#mkdir /opt/so/conf/fleet/packages + +docker run \ + --rm \ + --mount type=bind,source=/opt/so/conf/fleet/packages,target=/output \ + --mount type=bind,source=/etc/ssl/certs/intca.crt,target=/var/launcher/launcher.crt \ + docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8090 + +cp /opt/so/conf/fleet/packages/launcher.* /opt/so/saltstack/salt/launcher/packages/ + +#Update timestamp on packages webpage +sed -i "s@.*Generated.*@Generated: $(date '+%m%d%Y')@g" /opt/so/conf/fleet/packages/index.html +sed -i "s@.*Generated.*@Generated: $(date '+%m%d%Y')@g" /opt/so/saltstack/salt/fleet/osquery-packages.html \ No newline at end of file diff --git a/salt/fleet/files/scripts/so-fleet-setup b/salt/fleet/files/scripts/so-fleet-setup new file mode 100644 index 000000000..2f6628980 --- /dev/null +++ b/salt/fleet/files/scripts/so-fleet-setup @@ -0,0 +1,38 @@ +#!/bin/bash +{% set MAIN_HOSTNAME = salt['grains.get']('host') %} +{% set MAIN_IP = salt['pillar.get']('node:mainip') %} + +#so-fleet-setup.sh $FleetEmail + +if [ ! "$(docker ps -q -f name=so-fleet)" ]; then + echo "so-fleet container not running... Exiting..." + exit 1 +fi + +initpw=$(date +%s | sha256sum | base64 | head -c 16 ; echo) + +docker exec so-fleet /bin/ash -c "echo {{ MAIN_IP }} {{ MAIN_HOSTNAME }} >> /etc/hosts" +docker exec so-fleet fleetctl config set --address https://{{ MAIN_HOSTNAME }}:443 --tls-skip-verify --url-prefix /fleet +docker exec so-fleet fleetctl setup --email $1 --password $initpw + +docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/options.yaml +docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml +docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/Windows/osquery.yaml +docker exec so-fleet fleetctl apply -f /packs/hh/hhdefault.yml +docker exec so-fleet /bin/sh -c 'for pack in /packs/palantir/Fleet/Endpoints/packs/*.yaml; do fleetctl apply -f "$pack"; done' + + +# Enable Fleet +echo "Enabling Fleet..." +salt-call state.apply fleet.event_enable-fleet queue=True >> /root/fleet-setup.log + +# Generate osquery install packages +echo "Generating osquery install packages - will take some time..." +salt-call state.apply fleet.event_gen-packages queue=True >> /root/fleet-setup.log +sleep 180 + +echo "Installing launcher via salt..." +salt-call state.apply fleet.install_package queue=True >> /root/fleet-setup.log + +echo "Fleet Setup Complete - Login here: https://{{ MAIN_HOSTNAME }}" +echo "Your username is $2 and your password is $initpw" diff --git a/salt/fleet/init.sls b/salt/fleet/init.sls index a27ad9eb6..15f55b594 100644 --- a/salt/fleet/init.sls +++ b/salt/fleet/init.sls @@ -1,8 +1,25 @@ -{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', 'iwonttellyou') %} -{%- set FLEETPASS = salt['pillar.get']('auth:fleet', 'bazinga') -%} -{%- set MASTERIP = salt['pillar.get']('static:masterip', '') -%} +{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', None) -%} +{%- set FLEETPASS = salt['pillar.get']('auth:fleet', None) -%} +{%- set FLEETJWT = salt['pillar.get']('auth:fleet_jwt', None) -%} {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} +{% set MAINIP = salt['pillar.get']('node:mainip') %} +{% set FLEETARCH = salt['grains.get']('role') %} + + +{% if FLEETARCH == "so-fleet" %} + {% set MAINIP = salt['pillar.get']('node:mainip') %} +{% else %} + {% set MAINIP = salt['pillar.get']('static:masterip') %} +{% endif %} + +#{% if grains.id.split('_')|last in ['master', 'eval', 'fleet'] %} +#so/fleet: +# event.send: +# - data: +# action: 'enablefleet' +# hostname: {{ grains.host }} +#{% endif %} # Fleet Setup fleetcdir: @@ -18,11 +35,18 @@ fleetpackcdir: - user: 939 - group: 939 - makedirs: True + +fleetnsmdir: + file.directory: + - name: /nsm/osquery/fleet + - user: 939 + - group: 939 + - makedirs: True fleetpacksync: file.recurse: - name: /opt/so/conf/fleet/packs - - source: salt://fleet/packs + - source: salt://fleet/files/packs - user: 939 - group: 939 @@ -33,24 +57,34 @@ fleetlogdir: - group: 939 - makedirs: True -fleetsetupscript: - file.managed: - - name: /opt/so/conf/fleet/so-fleet-setup.sh - - source: salt://fleet/so-fleet-setup.sh +fleetsetupscripts: + file.recurse: + - name: /usr/sbin + - user: 0 + - group: 0 + - file_mode: 755 + - template: jinja + - source: salt://fleet/files/scripts osquerypackageswebpage: file.managed: - name: /opt/so/conf/fleet/packages/index.html - - source: salt://fleet/osquery-packages.html + - source: salt://fleet/files/osquery-packages.html fleetdb: mysql_database.present: - name: fleet + - connection_host: {{ MAINIP }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} fleetdbuser: mysql_user.present: - host: 172.17.0.0/255.255.0.0 - password: {{ FLEETPASS }} + - connection_host: {{ MAINIP }} + - connection_port: 3306 - connection_user: root - connection_pass: {{ MYSQLPASS }} @@ -60,6 +94,21 @@ fleetdbpriv: - database: fleet.* - user: fleetdbuser - host: 172.17.0.0/255.255.0.0 + - connection_host: {{ MAINIP }} + - connection_port: 3306 + - connection_user: root + - connection_pass: {{ MYSQLPASS }} + + +{% if FLEETPASS == None or FLEETJWT == None %} + +fleet_password_none: + test.configurable_test_state: + - changes: False + - result: False + - comment: "Fleet MySQL Password or JWT Key Error - Not Starting Fleet" + +{% else %} so-fleet: docker_container.running: @@ -68,22 +117,25 @@ so-fleet: - port_bindings: - 0.0.0.0:8080:8080 - environment: - - KOLIDE_MYSQL_ADDRESS={{ MASTERIP }}:3306 + - KOLIDE_MYSQL_ADDRESS={{ MAINIP }}:3306 + - KOLIDE_REDIS_ADDRESS={{ MAINIP }}:6379 - KOLIDE_MYSQL_DATABASE=fleet - KOLIDE_MYSQL_USERNAME=fleetdbuser - KOLIDE_MYSQL_PASSWORD={{ FLEETPASS }} - - KOLIDE_REDIS_ADDRESS={{ MASTERIP }}:6379 - KOLIDE_SERVER_CERT=/ssl/server.cert - KOLIDE_SERVER_KEY=/ssl/server.key - KOLIDE_LOGGING_JSON=true - - KOLIDE_AUTH_JWT_KEY=thisisatest - - KOLIDE_OSQUERY_STATUS_LOG_FILE=/var/log/osquery/status.log + - KOLIDE_AUTH_JWT_KEY= {{ FLEETJWT }} + - KOLIDE_OSQUERY_STATUS_LOG_FILE=/var/log/fleet/status.log - KOLIDE_OSQUERY_RESULT_LOG_FILE=/var/log/osquery/result.log - KOLIDE_SERVER_URL_PREFIX=/fleet - binds: - /etc/pki/fleet.key:/ssl/server.key:ro - /etc/pki/fleet.crt:/ssl/server.cert:ro - - /opt/so/log/fleet:/var/log/osquery + - /opt/so/log/fleet:/var/log/fleet + - /nsm/osquery/fleet:/var/log/osquery - /opt/so/conf/fleet/packs:/packs - watch: - /opt/so/conf/fleet/etc + +{% endif %} diff --git a/salt/fleet/install_package.sls b/salt/fleet/install_package.sls new file mode 100644 index 000000000..7a87a5f92 --- /dev/null +++ b/salt/fleet/install_package.sls @@ -0,0 +1,13 @@ +{%- set FLEETMASTER = salt['pillar.get']('static:fleet_master', False) -%} +{%- set FLEETNODE = salt['pillar.get']('static:fleet_node', False) -%} + +{%- if FLEETMASTER or FLEETNODE %} +launcherpkg: + pkg.installed: + - sources: + {% if grains['os'] == 'CentOS' %} + - launcher-final: salt://fleet/packages/launcher.rpm + {% elif grains['os'] == 'Ubuntu' %} + - launcher-final: salt://fleet/packages/launcher.deb + {% endif %} +{%- endif %} diff --git a/salt/fleet/packages/info.txt b/salt/fleet/packages/info.txt new file mode 100644 index 000000000..726dcf0d7 --- /dev/null +++ b/salt/fleet/packages/info.txt @@ -0,0 +1 @@ +Osquery Packages will be copied to this folder \ No newline at end of file diff --git a/salt/fleet/so-fleet-setup.sh b/salt/fleet/so-fleet-setup.sh deleted file mode 100644 index cd082ff03..000000000 --- a/salt/fleet/so-fleet-setup.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash - -#so-fleet-setup.sh $MasterIP $FleetEmail - -if [ ! "$(docker ps -q -f name=so-fleet)" ]; then - echo "so-fleet container not running... Exiting..." - exit 1 -fi - -initpw=$(date +%s | sha256sum | base64 | head -c 16 ; echo) - -docker exec so-fleet fleetctl config set --address https://$1:443 --tls-skip-verify --url-prefix /fleet -docker exec so-fleet fleetctl setup --email $2 --password $initpw - -docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/options.yaml -docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/MacOS/osquery.yaml -docker exec so-fleet fleetctl apply -f /packs/palantir/Fleet/Endpoints/Windows/osquery.yaml -docker exec so-fleet fleetctl apply -f /packs/hh/hhdefault.yml -docker exec so-fleet /bin/sh -c 'for pack in /packs/palantir/Fleet/Endpoints/packs/*.yaml; do fleetctl apply -f "$pack"; done' - -esecret=$(docker exec so-fleet fleetctl get enroll-secret) - -#Concat fleet.crt & ca.crt - this is required for launcher connectivity -cat /etc/pki/fleet.crt /etc/pki/ca.crt > /etc/pki/launcher.crt - -#Create the output directory -mkdir /opt/so/conf/fleet/packages - -#At some point we should version launcher `latest` to avoid hard pinning here -docker run \ - --rm \ - --mount type=bind,source=/opt/so/conf/fleet/packages,target=/output \ - --mount type=bind,source=/etc/pki/launcher.crt,target=/var/launcher/launcher.crt \ - docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0 "$esecret" "$1":8080 - -cp /opt/so/conf/fleet/packages/launcher.* /opt/so/saltstack/salt/launcher/packages/ -#Update timestamp on packages webpage -sed -i "s@.*Generated.*@Generated: $(date '+%m%d%Y')@g" /opt/so/conf/fleet/packages/index.html -sed -i "s@.*Generated.*@Generated: $(date '+%m%d%Y')@g" /opt/so/saltstack/salt/fleet/osquery-packages.html - -# Enable Fleet on all the other parts of the infrastructure -sed -i 's/fleetsetup: 0/fleetsetup: 1/g' /opt/so/saltstack/pillar/static.sls - -# Install osquery locally -#if cat /etc/os-release | grep -q 'debian'; then -# dpkg -i /opt/so/conf/fleet/packages/launcher.deb -#else -# rpm -i /opt/so/conf/fleet/packages/launcher.rpm -#fi -echo "Installing launcher via salt" -salt-call state.apply launcher queue=True > /root/launcher.log -echo "Fleet Setup Complete - Login here: https://$1" -echo "Your username is $2 and your password is $initpw" diff --git a/salt/mysql/etc/mypass b/salt/mysql/etc/mypass index 85ae1772b..2fb9844db 100644 --- a/salt/mysql/etc/mypass +++ b/salt/mysql/etc/mypass @@ -1,2 +1,2 @@ -{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', 'iwonttellyou') -%} +{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', None) -%} {{ MYSQLPASS }} diff --git a/salt/mysql/init.sls b/salt/mysql/init.sls index ac49953f1..981d27a73 100644 --- a/salt/mysql/init.sls +++ b/salt/mysql/init.sls @@ -1,8 +1,16 @@ -{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', 'iwonttellyou') %} -{%- set FLEETPASS = salt['pillar.get']('auth:fleet', 'bazinga') %} +{%- set MYSQLPASS = salt['pillar.get']('auth:mysql', None) %} {%- set MASTERIP = salt['pillar.get']('static:masterip', '') %} {% set VERSION = salt['pillar.get']('static:soversion', 'HH1.1.4') %} {% set MASTER = salt['grains.get']('master') %} +{% set MAINIP = salt['pillar.get']('node:mainip') %} +{% set FLEETARCH = salt['grains.get']('role') %} + +{% if FLEETARCH == "so-fleet" %} + {% set MAINIP = salt['pillar.get']('node:mainip') %} +{% else %} + {% set MAINIP = salt['pillar.get']('static:masterip') %} +{% endif %} + # MySQL Setup mysqlpkgs: pkg.installed: @@ -50,6 +58,16 @@ mysqldatadir: - group: 939 - makedirs: True +{% 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: {{ MASTER }}:5000/soshybridhunter/so-mysql:{{ VERSION }} @@ -58,7 +76,7 @@ so-mysql: - port_bindings: - 0.0.0.0:3306:3306 - environment: - - MYSQL_ROOT_HOST={{ MASTERIP }} + - MYSQL_ROOT_HOST={{ MAINIP }} - MYSQL_ROOT_PASSWORD=/etc/mypass - binds: - /opt/so/conf/mysql/etc/my.cnf:/etc/my.cnf:ro @@ -67,3 +85,4 @@ so-mysql: - /opt/so/log/mysql:/var/log/mysql:rw - watch: - /opt/so/conf/mysql/etc +{% endif %} \ No newline at end of file diff --git a/salt/reactor/fleet.sls b/salt/reactor/fleet.sls new file mode 100644 index 000000000..83a1d981c --- /dev/null +++ b/salt/reactor/fleet.sls @@ -0,0 +1,48 @@ +#!py + +from time import gmtime, strftime +import fileinput +import logging +import re +import subprocess + +def run(): + MINIONID = data['id'] + ACTION = data['data']['action'] + HOSTNAME = data['data']['hostname'] + ROLE = data['data']['role'] + ESECRET = data['data']['enroll-secret'] + STATICFILE = '/opt/so/saltstack/pillar/static.sls' + AUTHFILE = '/opt/so/saltstack/pillar/auth.sls' + + if MINIONID.split('_')[-1] in ['master','eval','fleet']: + if ACTION == 'enablefleet': + logging.info('so/fleet enablefleet reactor') + + # Enable Fleet + for line in fileinput.input(STATICFILE, inplace=True): + if ROLE == 'so-fleet': + line = re.sub(r'fleet_node: \S*', f"fleet_node: True", line.rstrip()) + else: + line = re.sub(r'fleet_master: \S*', f"fleet_master: True", line.rstrip()) + print(line) + + # Update the enroll secret + for line in fileinput.input(AUTHFILE, inplace=True): + line = re.sub(r'fleet_enroll-secret: \S*', f"fleet_enroll-secret: {ESECRET}", line.rstrip()) + print(line) + + if ACTION == 'genpackages': + logging.info('so/fleet genpackages reactor') + + # Run Docker container that will build the packages + gen_packages = subprocess.run(["docker", "run","--rm", "--mount", "type=bind,source=/opt/so/saltstack/salt/fleet/packages,target=/output", \ + "--mount", "type=bind,source=/etc/ssl/certs/intca.crt,target=/var/launcher/launcher.crt", "docker.io/soshybridhunter/so-fleet-launcher:HH1.1.0", \ + f"{ESECRET}", f"{HOSTNAME}:8090"], stdout=subprocess.PIPE, encoding='ascii') + + # Update the 'packages-built' timestamp on the webpage (stored in the static pillar) + for line in fileinput.input(STATICFILE, inplace=True): + line = re.sub(r'fleet_packages-timestamp: \S*', f"fleet_packages-timestamp: {strftime('%Y-%m-%d-%H:%M', gmtime())}", line.rstrip()) + print(line) + + return {} diff --git a/salt/ssl/init.sls b/salt/ssl/init.sls index dfaf131b9..86fce0fb0 100644 --- a/salt/ssl/init.sls +++ b/salt/ssl/init.sls @@ -1,5 +1,7 @@ {% set master = salt['grains.get']('master') %} {% set masterip = salt['pillar.get']('static:masterip', '') %} +{% set HOSTNAME = salt['grains.get']('host') %} +{% set MAINIP = salt['pillar.get']('node:mainip') %} {% set global_ca_text = [] %} {% set global_ca_server = [] %} @@ -172,3 +174,45 @@ filebeatpkcs: - name: "/usr/bin/openssl pkcs8 -in /opt/so/conf/filebeat/etc/pki/filebeat.key -topk8 -out /opt/so/conf/filebeat/etc/pki/filebeat.p8 -passout pass:" {% endif %} + +{% if grains['role'] == 'so-fleet' %} + +# Create a cert for the reverse proxy +/etc/pki/masterssl.crt: + x509.certificate_managed: + - ca_server: {{ ca_server }} + - signing_policy: masterssl + - public_key: /etc/pki/masterssl.key + - CN: {{ HOSTNAME }} + - days_remaining: 0 + - days_valid: 820 + - backup: True + - managed_private_key: + name: /etc/pki/masterssl.key + bits: 4096 + backup: True + + +# Create a private key and cert for Fleet +/etc/pki/fleet.key: + x509.private_key_managed: + - CN: {{ HOSTNAME }} + - bits: 4096 + - days_remaining: 0 + - days_valid: 820 + - backup: True + +/etc/pki/fleet.crt: + x509.certificate_managed: + - signing_private_key: /etc/pki/fleet.key + - CN: {{ HOSTNAME }} + - subjectAltName: DNS:{{ HOSTNAME }}, IP:{{ MAINIP }} + - days_remaining: 0 + - days_valid: 820 + - backup: True + - managed_private_key: + name: /etc/pki/fleet.key + bits: 4096 + backup: True + +{% endif %} diff --git a/salt/top.sls b/salt/top.sls index 64d353208..5026caffd 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -1,10 +1,12 @@ {%- set BROVER = salt['pillar.get']('static:broversion', 'COMMUNITY') -%} -{%- set OSQUERY = salt['pillar.get']('master:osquery', '0') -%} {%- set WAZUH = salt['pillar.get']('master:wazuh', '0') -%} {%- set THEHIVE = salt['pillar.get']('master:thehive', '0') -%} {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} {%- set FREQSERVER = salt['pillar.get']('master:freq', '0') -%} {%- set DOMAINSTATS = salt['pillar.get']('master:domainstats', '0') -%} +{%- set FLEETMASTER = salt['pillar.get']('static:fleet_master', False) -%} +{%- set FLEETNODE = salt['pillar.get']('static:fleet_node', False) -%} + base: '*': @@ -38,8 +40,8 @@ base: {%- endif %} - wazuh - filebeat - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -53,7 +55,7 @@ base: - firewall - idstools - auth - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - mysql {%- endif %} {%- if WAZUH != 0 %} @@ -67,10 +69,10 @@ base: - zeek - curator - elastalert - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - fleet - redis - - launcher + - fleet.install_package {%- endif %} - utility - schedule @@ -100,7 +102,7 @@ base: - idstools - redis - auth - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - mysql {%- endif %} {%- if WAZUH != 0 %} @@ -113,9 +115,9 @@ base: - filebeat - utility - schedule - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - fleet - - launcher + - fleet.install_package {%- endif %} - soctopus {%- if THEHIVE != 0 %} @@ -138,8 +140,8 @@ base: - common - firewall - logstash - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -150,8 +152,8 @@ base: - logstash - elasticsearch - curator - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -160,8 +162,8 @@ base: - common - firewall - elasticsearch - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -178,8 +180,8 @@ base: - elasticsearch - curator - filebeat - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -189,8 +191,8 @@ base: - sensor - master - auth - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - schedule @@ -206,7 +208,7 @@ base: - idstools - redis - auth - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - mysql {%- endif %} {%- if WAZUH != 0 %} @@ -220,9 +222,9 @@ base: - filebeat - utility - schedule - {%- if OSQUERY != 0 %} + {%- if FLEETMASTER or FLEETNODE %} - fleet - - launcher + - fleet.install_package {%- endif %} - soctopus {%- if THEHIVE != 0 %} @@ -251,8 +253,8 @@ base: - elasticsearch - curator - filebeat - {%- if OSQUERY != 0 %} - - launcher + {%- if FLEETMASTER or FLEETNODE %} + - fleet.install_package {%- endif %} - pcap - suricata @@ -261,3 +263,14 @@ base: {%- endif %} - filebeat - schedule + + '*_fleet': + - ca + - ssl + - common + - firewall + - mysql + - redis + - fleet + - fleet.install_package + - filebeat diff --git a/setup/so-functions b/setup/so-functions index 0d677942d..d7cf4c387 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC +# Copyright 2014,2015,2016,2017,2018,2019,2020 Security Onion Solutions, LLC # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -87,6 +87,8 @@ auth_pillar(){ echo "auth:" >> /opt/so/saltstack/pillar/auth.sls echo " mysql: $MYSQLPASS" >> /opt/so/saltstack/pillar/auth.sls echo " fleet: $FLEETPASS" >> /opt/so/saltstack/pillar/auth.sls + echo " fleet_jwt: $FLEETJWT" >> /opt/so/saltstack/pillar/auth.sls + echo " fleet_enroll-secret: False" >> /opt/so/saltstack/pillar/auth.sls fi } @@ -240,6 +242,9 @@ configure_minion() { elif [ $TYPE == 'helix' ]; then echo "master: $HOSTNAME" > /etc/salt/minion echo "id: $MINION_ID" >> /etc/salt/minion + elif [ $TYPE == 'fleet' ]; then + echo "master: $MSRV" > /etc/salt/minion + echo "id: $MINION_ID" >> /etc/salt/minion else echo "master: $MSRV" > /etc/salt/minion echo "id: $MINION_ID" >> /etc/salt/minion @@ -577,10 +582,23 @@ fireeye_pillar() { } +fleet_pillar() { + + PILLARFILE=$TMP/pillar/minions/$MINION_ID.sls + + # Create the fleet pillar + touch $PILLARFILE + echo "fleet:" >> $PILLARFILE + echo " mainip: $MAINIP" >> $PILLARFILE + echo " master: $MSRV" >> $PILLARFILE + echo "" >> $PILLARFILE +} + generate_passwords(){ # Generate Random Passwords for Things MYSQLPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) FLEETPASS=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) + FLEETJWT=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) HIVEKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) CORTEXKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) CORTEXORGUSERKEY=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1) @@ -760,7 +778,9 @@ master_static() { echo " cortexorgname: SecurityOnion" >> /opt/so/saltstack/pillar/static.sls echo " cortexorguser: soadmin" >> /opt/so/saltstack/pillar/static.sls echo " cortexorguserkey: $CORTEXORGUSERKEY" >> /opt/so/saltstack/pillar/static.sls - echo " fleetsetup: 0" >> /opt/so/saltstack/pillar/static.sls + echo " fleet_master: False" >> /opt/so/saltstack/pillar/static.sls + echo " fleet_node: False" >> /opt/so/saltstack/pillar/static.sls + echo " fleet_packages-timestamp: N/A" >> /opt/so/saltstack/pillar/static.sls echo " sensoronikey: $SENSORONIKEY" >> /opt/so/saltstack/pillar/static.sls if [[ $MASTERUPDATES == 'MASTER' ]]; then echo " masterupdate: 1" >> /opt/so/saltstack/pillar/static.sls @@ -1060,6 +1080,8 @@ EOF if [ $INSTALLTYPE == 'MASTER' ] || [ $INSTALLTYPE == 'EVAL' ] || [ $INSTALLTYPE == 'HELIXSENSOR' ] || [ $INSTALLTYPE == 'MASTERSEARCH' ]; then yum -y install salt-master-2019.2.3 python3 python36-m2crypto salt-minion-2019.2.3 python36-dateutil python36-mysql python36-docker systemctl enable salt-master + elif [ $INSTALLTYPE == 'FLEET' ]; then + yum -y install salt-minion-2019.2.3 python3 python36-m2crypto python36-dateutil python36-docker python36-mysql else yum -y install salt-minion-2019.2.3 python3 python36-m2crypto python36-dateutil python36-docker fi @@ -1132,7 +1154,7 @@ EOF echo "Using apt-key add to add SALTSTACK-GPG-KEY.pub and GPG-KEY-WAZUH" apt-key add $TMP/gpg/SALTSTACK-GPG-KEY.pub apt-key add $TMP/gpg/GPG-KEY-WAZUH - echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/latest $OSVER main" > /etc/apt/sources.list.d/saltstack.list + echo "deb http://repo.saltstack.com/apt/ubuntu/$UVER/amd64/2019.2 $OSVER main" > /etc/apt/sources.list.d/saltstack.list echo "deb https://packages.wazuh.com/3.x/apt/ stable main" | tee /etc/apt/sources.list.d/wazuh.list # Initialize the new repos apt-get update >> $SETUPLOG 2>&1 @@ -1281,7 +1303,7 @@ set_hostname() { echo "::1 localhost localhost.localdomain localhost6 localhost6.localdomain6" >> /etc/hosts echo $HOSTNAME > /etc/hostname HOSTNAME=$(cat /etc/hostname) - if [ $INSTALLTYPE != 'MASTER' || $INSTALLTYPE != 'EVAL' || $INSTALLTYPE == 'HELIXSENSOR' || $INSTALLTYPE == 'MASTERSEARCH' ]; then + if [[ ! $INSTALLTYPE =~ ^(MASTER|EVAL|HELIXSENSOR|MASTERSEARCH)$ ]]; then if [[ $TESTHOST = *"not found"* ]] || [ -z $TESTHOST ] || [[ $TESTHOST = *"connection timed out"* ]]; then if ! grep -q $MSRVIP /etc/hosts; then echo "$MSRVIP $MSRV" >> /etc/hosts @@ -1347,6 +1369,10 @@ set_initial_firewall_policy() { ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/data/addtotab.sh nodestab $MINION_ID $MAINIP $CPUCORES $RANDOMUID $MAININT $FSROOT $FSNSM fi + if [ $INSTALLTYPE == 'FLEET' ]; then + ssh -i /root/.ssh/so.key socore@$MSRV sudo /opt/so/saltstack/pillar/firewall/addfirewall.sh minions $MAINIP + fi + if [ $INSTALLTYPE == 'PARSINGNODE' ]; then echo "blah" fi diff --git a/setup/so-setup b/setup/so-setup index d9d10cf8c..e6a3f4708 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2014,2015,2016,2017,2018,2019 Security Onion Solutions, LLC +# Copyright 2014,2015,2016,2017,2018,2019,2020 Security Onion Solutions, LLC # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -928,12 +928,77 @@ if (whiptail_you_sure) ; then fi +########################### +### Standalone Fleet ### +########################### - - - - - + if [ $INSTALLTYPE == 'FLEET' ]; then + whiptail_management_server + whiptail_master_updates + whiptail_make_changes + set_updates + set_hostname + clear_master + mkdir -p /nsm + get_filesystem_root + get_filesystem_nsm + if [ $INSTALLMETHOD == iso ]; then + add_admin_user + disable_onion_user + fi + copy_ssh_key >> $SETUPLOG 2>&1 + { + sleep 0.5 + echo -e "XXX\n0\nSetting Initial Firewall Policy... \nXXX" + set_initial_firewall_policy >> $SETUPLOG 2>&1 + #echo -e "XXX\n4\nGenerating Fleet Pillar... \nXXX" + fleet_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling mysql dependencies for saltstack... \nXXX" + salt_install_mysql_deps >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 + node_pillar >> $SETUPLOG 2>&1 + echo -e "XXX\n5\nInstalling Salt Components... \nXXX" + saltify >> $SETUPLOG 2>&1 + echo -e "XXX\n20\nInstalling Docker... \nXXX" + docker_install >> $SETUPLOG 2>&1 + echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" + configure_minion fleet >> $SETUPLOG 2>&1 + echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" + copy_minion_tmp_files >> $SETUPLOG 2>&1 + echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" + salt_firstcheckin >> $SETUPLOG 2>&1 + echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" + # Accept the Salt Key + accept_salt_key_remote >> $SETUPLOG 2>&1 + echo -e "XXX\n27\nApplying SSL Certificates... \nXXX" + salt-call state.apply ca >> $SETUPLOG 2>&1 + salt-call state.apply ssl >> $SETUPLOG 2>&1 + echo -e "XXX\n35\nInstalling Core Components... \nXXX" + salt-call state.apply common >> $SETUPLOG 2>&1 + salt-call state.apply firewall >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nInstalling MySQL... \nXXX" + salt-call state.apply mysql >> $SETUPLOG 2>&1 + echo -e "XXX\n50\nInstalling Redis... \nXXX" + salt-call state.apply redis >> $SETUPLOG 2>&1 + echo -e "XXX\n60\nInstalling Fleet... \nXXX" + salt-call state.apply fleet >> $SETUPLOG 2>&1 + checkin_at_boot >> $SETUPLOG 2>&1 + echo -e "XX\n97\nFinishing touches... \nXXX" + filter_unused_nics >> $SETUPLOG 2>&1 + network_setup >> $SETUPLOG 2>&1 + echo -e "XXX\n98\nVerifying Setup... \nXXX" + salt-call state.highstate >> $SETUPLOG 2>&1 + } |whiptail --title "Hybrid Hunter Install" --gauge "Please wait while installing" 6 60 0 + GOODSETUP=$(tail -10 $SETUPLOG | grep Failed | awk '{ print $2}') + if [[ $GOODSETUP == '0' ]]; then + whiptail_setup_complete + shutdown -r now + else + whiptail_setup_failed + shutdown -r now + fi + fi else diff --git a/setup/so-whiptail b/setup/so-whiptail index e828d39dc..2769150cd 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -256,12 +256,12 @@ whiptail_install_type() { "MASTERSEARCH" "Master + Search Node" OFF \ "HEAVYNODE" "Sensor + Search Node" OFF \ "HELIXSENSOR" "Connect this sensor to FireEye Helix" OFF \ - "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF \ + "FLEET" "Dedicated Fleet Osquery Node" OFF \ "HOTNODE" "TODO Add Hot Node (Search Node without Parsing)" OFF \ "WARMNODE" "TODO Add Warm Node to existing Hot or Search node" OFF \ "WAZUH" "TODO Stand Alone Wazuh Node" OFF \ "STRELKA" "TODO Stand Alone Strelka Node" OFF \ - "FLEET" "TODO Stand Alone Fleet OSQuery Node" OFF 3>&1 1>&2 2>&3 ) + "PARSINGNODE" "TODO Add a dedicated Parsing Node" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus @@ -371,7 +371,7 @@ whiptail_management_server() { # See if it resolves. Otherwise prompt to add to host file TESTHOST=$(host $MSRV) - if [[ $TESTHOST = *"not found"* ]] || [[ $TESTHOST = *"connection timed out"* ]]; then + if [[ $TESTHOST = *"not found"* ]] || [ -z $TESTHOST ] || [[ $TESTHOST = *"connection timed out"* ]]; then add_master_hostfile fi