Merge pull request #13278 from Security-Onion-Solutions/issue/13073

Issue/13073 - disable Logstash on heavynodes
This commit is contained in:
Josh Patterson
2024-06-27 14:50:18 -04:00
committed by GitHub
14 changed files with 134 additions and 37 deletions

View File

@@ -0,0 +1,34 @@
{% set node_types = {} %}
{% for minionid, ip in salt.saltutil.runner(
'mine.get',
tgt='elasticsearch:enabled:true',
fun='network.ip_addrs',
tgt_type='pillar') | dictsort()
%}
# only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %}
{% if hostname not in node_types[node_type] %}
{% do node_types[node_type].update({hostname: ip[0]}) %}
{% else %}
{% do node_types[node_type][hostname].update(ip[0]) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
elasticsearch:
nodes:
{% for node_type, values in node_types.items() %}
{{node_type}}:
{% for hostname, ip in values.items() %}
{{hostname}}:
ip: {{ip}}
{% endfor %}
{% endfor %}

View File

@@ -1,16 +1,15 @@
{% set node_types = {} %} {% set node_types = {} %}
{% set cached_grains = salt.saltutil.runner('cache.grains', tgt='*') %}
{% for minionid, ip in salt.saltutil.runner( {% for minionid, ip in salt.saltutil.runner(
'mine.get', 'mine.get',
tgt='G@role:so-manager or G@role:so-managersearch or G@role:so-standalone or G@role:so-searchnode or G@role:so-heavynode or G@role:so-receiver or G@role:so-fleet ', tgt='logstash:enabled:true',
fun='network.ip_addrs', fun='network.ip_addrs',
tgt_type='compound') | dictsort() tgt_type='pillar') | dictsort()
%} %}
# only add a node to the pillar if it returned an ip from the mine # only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%} {% if ip | length > 0%}
{% set hostname = cached_grains[minionid]['host'] %} {% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_')[1] %} {% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %} {% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %} {% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %} {% else %}

34
pillar/redis/nodes.sls Normal file
View File

@@ -0,0 +1,34 @@
{% set node_types = {} %}
{% for minionid, ip in salt.saltutil.runner(
'mine.get',
tgt='redis:enabled:true',
fun='network.ip_addrs',
tgt_type='pillar') | dictsort()
%}
# only add a node to the pillar if it returned an ip from the mine
{% if ip | length > 0%}
{% set hostname = minionid.split('_') | first %}
{% set node_type = minionid.split('_') | last %}
{% if node_type not in node_types.keys() %}
{% do node_types.update({node_type: {hostname: ip[0]}}) %}
{% else %}
{% if hostname not in node_types[node_type] %}
{% do node_types[node_type].update({hostname: ip[0]}) %}
{% else %}
{% do node_types[node_type][hostname].update(ip[0]) %}
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
redis:
nodes:
{% for node_type, values in node_types.items() %}
{{node_type}}:
{% for hostname, ip in values.items() %}
{{hostname}}:
ip: {{ip}}
{% endfor %}
{% endfor %}

View File

@@ -47,10 +47,12 @@ base:
- kibana.adv_kibana - kibana.adv_kibana
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos - kratos.adv_kratos
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
- influxdb.adv_influxdb - influxdb.adv_influxdb
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -147,10 +149,12 @@ base:
- idstools.adv_idstools - idstools.adv_idstools
- kratos.soc_kratos - kratos.soc_kratos
- kratos.adv_kratos - kratos.adv_kratos
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- influxdb.soc_influxdb - influxdb.soc_influxdb
- influxdb.adv_influxdb - influxdb.adv_influxdb
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
- elasticfleet.soc_elasticfleet - elasticfleet.soc_elasticfleet
@@ -215,11 +219,13 @@ base:
- logstash.nodes - logstash.nodes
- logstash.soc_logstash - logstash.soc_logstash
- logstash.adv_logstash - logstash.adv_logstash
- elasticsearch.nodes
- elasticsearch.soc_elasticsearch - elasticsearch.soc_elasticsearch
- elasticsearch.adv_elasticsearch - elasticsearch.adv_elasticsearch
{% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %} {% if salt['file.file_exists']('/opt/so/saltstack/local/pillar/elasticsearch/auth.sls') %}
- elasticsearch.auth - elasticsearch.auth
{% endif %} {% endif %}
- redis.nodes
- redis.soc_redis - redis.soc_redis
- redis.adv_redis - redis.adv_redis
- minions.{{ grains.id }} - minions.{{ grains.id }}

View File

@@ -3,21 +3,30 @@
{% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %} {% set HIGHLANDER = salt['pillar.get']('global:highlander', False) %}
{# ES_LOGSTASH_NODES is the same as LOGSTASH_NODES from logstash/map.jinja but heavynodes and fleet nodes are removed #} {# this is a list of dicts containing hostname:ip for elasticsearch nodes that need to know about each other for cluster #}
{% set ES_LOGSTASH_NODES = [] %} {% set ELASTICSEARCH_SEED_HOSTS = [] %}
{% set node_data = salt['pillar.get']('logstash:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %} {% set node_data = salt['pillar.get']('elasticsearch:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %}
{% for node_type, node_details in node_data.items() | sort %} {% for node_type, node_details in node_data.items() | sort %}
{% if node_type not in ['heavynode', 'fleet'] %} {% if node_type != 'heavynode' %}
{% for hostname in node_data[node_type].keys() %} {% for hostname in node_data[node_type].keys() %}
{% do ES_LOGSTASH_NODES.append({hostname:node_details[hostname].ip}) %} {% do ELASTICSEARCH_SEED_HOSTS.append({hostname:node_details[hostname].ip}) %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% endfor %} {% endfor %}
{# this is a list of dicts containing hostname:ip of all nodes running elasticsearch #}
{% set ELASTICSEARCH_NODES = [] %}
{% set node_data = salt['pillar.get']('elasticsearch:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %}
{% for node_type, node_details in node_data.items() %}
{% for hostname in node_data[node_type].keys() %}
{% do ELASTICSEARCH_NODES.append({hostname:node_details[hostname].ip}) %}
{% endfor %}
{% endfor %}
{% if grains.id.split('_') | last in ['manager','managersearch','standalone'] %} {% if grains.id.split('_') | last in ['manager','managersearch','standalone'] %}
{% if ES_LOGSTASH_NODES | length > 1 %} {% if ELASTICSEARCH_SEED_HOSTS | length > 1 %}
{% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': []}}) %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.update({'discovery': {'seed_hosts': []}}) %}
{% for NODE in ES_LOGSTASH_NODES %} {% for NODE in ELASTICSEARCH_SEED_HOSTS %}
{% do ELASTICSEARCHDEFAULTS.elasticsearch.config.discovery.seed_hosts.append(NODE.keys()|first) %} {% do ELASTICSEARCHDEFAULTS.elasticsearch.config.discovery.seed_hosts.append(NODE.keys()|first) %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}

View File

@@ -7,8 +7,8 @@
{% if sls.split('.')[0] in allowed_states %} {% if sls.split('.')[0] in allowed_states %}
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
{% from 'docker/docker.map.jinja' import DOCKER %} {% from 'docker/docker.map.jinja' import DOCKER %}
{% from 'logstash/map.jinja' import LOGSTASH_NODES %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_NODES %}
{% from 'elasticsearch/config.map.jinja' import ES_LOGSTASH_NODES %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_SEED_HOSTS %}
{% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCHMERGED %}
{% set TEMPLATES = salt['pillar.get']('elasticsearch:templates', {}) %} {% set TEMPLATES = salt['pillar.get']('elasticsearch:templates', {}) %}
{% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS %} {% from 'elasticsearch/template.map.jinja' import ES_INDEX_SETTINGS %}
@@ -27,7 +27,7 @@ so-elasticsearch:
- sobridge: - sobridge:
- ipv4_address: {{ DOCKER.containers['so-elasticsearch'].ip }} - ipv4_address: {{ DOCKER.containers['so-elasticsearch'].ip }}
- extra_hosts: - extra_hosts:
{% for node in LOGSTASH_NODES %} {% for node in ELASTICSEARCH_NODES %}
{% for hostname, ip in node.items() %} {% for hostname, ip in node.items() %}
- {{hostname}}:{{ip}} - {{hostname}}:{{ip}}
{% endfor %} {% endfor %}
@@ -38,7 +38,7 @@ so-elasticsearch:
{% endfor %} {% endfor %}
{% endif %} {% endif %}
- environment: - environment:
{% if ES_LOGSTASH_NODES | length == 1 or GLOBALS.role == 'so-heavynode' %} {% if ELASTICSEARCH_SEED_HOSTS | length == 1 or GLOBALS.role == 'so-heavynode' %}
- discovery.type=single-node - discovery.type=single-node
{% endif %} {% endif %}
- ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true - ES_JAVA_OPTS=-Xms{{ GLOBALS.elasticsearch.es_heap }} -Xmx{{ GLOBALS.elasticsearch.es_heap }} -Des.transport.cname_in_publish_address=true -Dlog4j2.formatMsgNoLookups=true

View File

@@ -4,7 +4,7 @@
# https://securityonion.net/license; you may not use this file except in compliance with the # https://securityonion.net/license; you may not use this file except in compliance with the
# Elastic License 2.0. # Elastic License 2.0.
{%- from 'vars/globals.map.jinja' import GLOBALS %} {%- from 'vars/globals.map.jinja' import GLOBALS %}
{%- set node_data = salt['pillar.get']('logstash:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %} {%- set node_data = salt['pillar.get']('elasticsearch:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %}
. /usr/sbin/so-common . /usr/sbin/so-common

View File

@@ -7,9 +7,7 @@ logstash:
- search - search
receiver: receiver:
- receiver - receiver
heavynode: heavynode: []
- manager
- search
searchnode: searchnode:
- search - search
manager: manager:

View File

@@ -7,23 +7,26 @@
{% import_yaml 'logstash/defaults.yaml' as LOGSTASH_DEFAULTS %} {% import_yaml 'logstash/defaults.yaml' as LOGSTASH_DEFAULTS %}
{% set LOGSTASH_MERGED = salt['pillar.get']('logstash', LOGSTASH_DEFAULTS.logstash, merge=True) %} {% set LOGSTASH_MERGED = salt['pillar.get']('logstash', LOGSTASH_DEFAULTS.logstash, merge=True) %}
{% set REDIS_NODES = [] %} {# used to store the redis nodes that logstash needs to know about to pull from the queue #}
{# LOGSTASH_NODES is the same as ES_LOGSTASH_NODES from elasticsearch/config.map.jinja but heavynodes are present #} {% set LOGSTASH_REDIS_NODES = [] %}
{# stores all logstash nodes #}
{% set LOGSTASH_NODES = [] %} {% set LOGSTASH_NODES = [] %}
{% set node_data = salt['pillar.get']('logstash:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %} {% set logstash_node_data = salt['pillar.get']('logstash:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %}
{% set redis_node_data = salt['pillar.get']('redis:nodes', {GLOBALS.role.split('-')[1]: {GLOBALS.hostname: {'ip': GLOBALS.node_ip}}}) %}
{% for node_type, node_details in node_data.items() | sort %} {% for node_type, node_details in redis_node_data.items() | sort %}
{% if GLOBALS.role in ['so-searchnode', 'so-standalone', 'so-managersearch', 'so-fleet'] %} {% if GLOBALS.role in ['so-searchnode', 'so-standalone', 'so-managersearch', 'so-fleet'] %}
{% if node_type in ['manager', 'managersearch', 'standalone', 'receiver' ] %} {% if node_type in ['manager', 'managersearch', 'standalone', 'receiver' ] %}
{% for hostname in node_data[node_type].keys() %} {% for hostname in redis_node_data[node_type].keys() %}
{% do REDIS_NODES.append({hostname:node_details[hostname].ip}) %} {% do LOGSTASH_REDIS_NODES.append({hostname:node_details[hostname].ip}) %}
{% endfor %} {% endfor %}
{% endif %} {% endif %}
{% else %}
{% do REDIS_NODES.append({GLOBALS.hostname:GLOBALS.node_ip}) %}
{% endif %} {% endif %}
{% endfor %}
{% for hostname in node_data[node_type].keys() %} {% for node_type, node_details in logstash_node_data.items() | sort %}
{% for hostname in logstash_node_data[node_type].keys() %}
{% do LOGSTASH_NODES.append({hostname:node_details[hostname].ip}) %} {% do LOGSTASH_NODES.append({hostname:node_details[hostname].ip}) %}
{% endfor %} {% endfor %}
{% endfor %} {% endfor %}

View File

@@ -1,8 +1,8 @@
{%- from 'logstash/map.jinja' import REDIS_NODES with context %} {%- from 'logstash/map.jinja' import LOGSTASH_REDIS_NODES with context %}
{%- set REDIS_PASS = salt['pillar.get']('redis:config:requirepass') %} {%- set REDIS_PASS = salt['pillar.get']('redis:config:requirepass') %}
{%- for index in range(REDIS_NODES|length) %} {%- for index in range(LOGSTASH_REDIS_NODES|length) %}
{%- for host in REDIS_NODES[index] %} {%- for host in LOGSTASH_REDIS_NODES[index] %}
input { input {
redis { redis {
host => '{{ host }}' host => '{{ host }}'

View File

@@ -528,7 +528,6 @@ function createHEAVYNODE() {
pcapspace pcapspace
add_elasticsearch_to_minion add_elasticsearch_to_minion
add_elastic_agent_to_minion add_elastic_agent_to_minion
add_logstash_to_minion
add_sensor_to_minion add_sensor_to_minion
add_strelka_to_minion add_strelka_to_minion
add_redis_to_minion add_redis_to_minion

View File

@@ -308,6 +308,21 @@ clone_to_tmp() {
fi fi
} }
disable_logstash_heavynodes() {
c=0
printf "\nChecking for heavynodes and disabling Logstash if they exist\n"
for file in /opt/so/saltstack/local/pillar/minions/*.sls; do
if [[ "$file" =~ "_heavynode.sls" && ! "$file" =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then
if [ "$c" -eq 0 ]; then
c=$((c + 1))
FINAL_MESSAGE_QUEUE+=("Logstash has been disabled on all heavynodes. It can be re-enabled via Grid Configuration in SOC.")
fi
echo "Disabling Logstash for: $file"
so-yaml.py replace "$file" logstash.enabled False
fi
done
}
enable_highstate() { enable_highstate() {
echo "Enabling highstate." echo "Enabling highstate."
salt-call state.enable highstate -l info --local salt-call state.enable highstate -l info --local
@@ -485,7 +500,7 @@ post_to_2.4.80() {
} }
post_to_2.4.90() { post_to_2.4.90() {
echo "Nothing to apply" disable_logstash_heavynodes
POSTVERSION=2.4.90 POSTVERSION=2.4.90
} }

View File

@@ -14,7 +14,7 @@
{% endfor %} {% endfor %}
{# add all grid heavy nodes to soc.server.modules.elastic.remoteHostUrls #} {# add all grid heavy nodes to soc.server.modules.elastic.remoteHostUrls #}
{% for node_type, minions in salt['pillar.get']('logstash:nodes', {}).items() %} {% for node_type, minions in salt['pillar.get']('elasticsearch:nodes', {}).items() %}
{% if node_type in ['heavynode'] %} {% if node_type in ['heavynode'] %}
{% for m in minions.keys() %} {% for m in minions.keys() %}
{% do SOCDEFAULTS.soc.config.server.modules.elastic.remoteHostUrls.append('https://' ~ m ~ ':9200') %} {% do SOCDEFAULTS.soc.config.server.modules.elastic.remoteHostUrls.append('https://' ~ m ~ ':9200') %}

View File

@@ -5,9 +5,9 @@
{% from 'vars/globals.map.jinja' import GLOBALS %} {% from 'vars/globals.map.jinja' import GLOBALS %}
{% from 'soc/defaults.map.jinja' import SOCDEFAULTS with context %} {% from 'soc/defaults.map.jinja' import SOCDEFAULTS with context %}
{% from 'logstash/map.jinja' import LOGSTASH_NODES %} {% from 'elasticsearch/config.map.jinja' import ELASTICSEARCH_NODES %}
{% from 'manager/map.jinja' import MANAGERMERGED %} {% from 'manager/map.jinja' import MANAGERMERGED %}
{% set DOCKER_EXTRA_HOSTS = LOGSTASH_NODES %} {% set DOCKER_EXTRA_HOSTS = ELASTICSEARCH_NODES %}
{% do DOCKER_EXTRA_HOSTS.append({GLOBALS.influxdb_host:pillar.node_data[GLOBALS.influxdb_host].ip}) %} {% do DOCKER_EXTRA_HOSTS.append({GLOBALS.influxdb_host:pillar.node_data[GLOBALS.influxdb_host].ip}) %}
{% set SOCMERGED = salt['pillar.get']('soc', SOCDEFAULTS, merge=true) %} {% set SOCMERGED = salt['pillar.get']('soc', SOCDEFAULTS, merge=true) %}