mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-22 08:53:06 +01:00
Compare commits
73 Commits
8abd4c9c78
...
reyesj2/el
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9345718967 | ||
|
|
6c879cbd13 | ||
|
|
089b5aaf44 | ||
|
|
b61885add5 | ||
|
|
5cb1e284af | ||
|
|
e3a4f0873e | ||
|
|
7977a020ac | ||
|
|
d518f75468 | ||
|
|
04d6cca204 | ||
|
|
5ab6bda639 | ||
|
|
f433de7e12 | ||
|
|
8ef6c2f91d | ||
|
|
7575218697 | ||
|
|
dc945dad00 | ||
|
|
ddcd74ffd2 | ||
|
|
e105bd12e6 | ||
|
|
f5688175b6 | ||
|
|
72a4ba405f | ||
|
|
ba49765312 | ||
|
|
72c8c2371e | ||
|
|
80411ab6cf | ||
|
|
0ff8fa57e7 | ||
|
|
411f28a049 | ||
|
|
0f42233092 | ||
|
|
2dd49f6d9b | ||
|
|
271f545f4f | ||
|
|
c4a70b540e | ||
|
|
bef85772e3 | ||
|
|
a6b19c4a6c | ||
|
|
44f5e6659b | ||
|
|
3f9a9b7019 | ||
|
|
b7ad985c7a | ||
|
|
dba087ae25 | ||
|
|
bbc4b1b502 | ||
|
|
9304513ce8 | ||
|
|
0b127582cb | ||
|
|
6e9b8791c8 | ||
|
|
ef87ad77c3 | ||
|
|
8477420911 | ||
|
|
f5741e318f | ||
|
|
e010b5680a | ||
|
|
8620d3987e | ||
|
|
30487a54c1 | ||
|
|
f15a39c153 | ||
|
|
aed27fa111 | ||
|
|
822c411e83 | ||
|
|
41b3ac7554 | ||
|
|
23575fdf6c | ||
|
|
52f70dc49a | ||
|
|
79c9749ff7 | ||
|
|
8d2701e143 | ||
|
|
877444ac29 | ||
|
|
b0d9426f1b | ||
|
|
18accae47e | ||
|
|
55e3a2c6b6 | ||
|
|
ef092e2893 | ||
|
|
89eb95c077 | ||
|
|
e871ec358e | ||
|
|
271a2f74ad | ||
|
|
d6bd951c37 | ||
|
|
45a8c0acd1 | ||
|
|
cc8fb96047 | ||
|
|
3339b50daf | ||
|
|
415ea07a4f | ||
|
|
b80ec95fa8 | ||
|
|
99cb51482f | ||
|
|
90638f7a43 | ||
|
|
1fb00c8eb6 | ||
|
|
4490ea7635 | ||
|
|
bce7a20d8b | ||
|
|
b52dd53e29 | ||
|
|
a155f45036 | ||
|
|
de4424fab0 |
@@ -85,7 +85,7 @@ function suricata() {
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
-v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \
|
-v /opt/so/conf/suricata/suricata.yaml:/etc/suricata/suricata.yaml:ro \
|
||||||
-v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \
|
-v /opt/so/conf/suricata/threshold.conf:/etc/suricata/threshold.conf:ro \
|
||||||
-v /opt/so/conf/suricata/rules:/etc/suricata/rules:ro \
|
-v /opt/so/rules/suricata/:/etc/suricata/rules:ro \
|
||||||
-v ${LOG_PATH}:/var/log/suricata/:rw \
|
-v ${LOG_PATH}:/var/log/suricata/:rw \
|
||||||
-v ${NSM_PATH}/:/nsm/:rw \
|
-v ${NSM_PATH}/:/nsm/:rw \
|
||||||
-v "$PCAP:/input.pcap:ro" \
|
-v "$PCAP:/input.pcap:ro" \
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ so-elastalert:
|
|||||||
- watch:
|
- watch:
|
||||||
- file: elastaconf
|
- file: elastaconf
|
||||||
- onlyif:
|
- onlyif:
|
||||||
- "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 8" {# only run this state if elasticsearch is version 8 #}
|
- "so-elasticsearch-query / | jq -r '.version.number[0:1]' | grep -q 9" {# only run this state if elasticsearch is version 9 #}
|
||||||
|
|
||||||
delete_so-elastalert_so-status.disabled:
|
delete_so-elastalert_so-status.disabled:
|
||||||
file.uncomment:
|
file.uncomment:
|
||||||
|
|||||||
34
salt/elasticfleet/config.map.jinja
Normal file
34
salt/elasticfleet/config.map.jinja
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{# 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 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||||
|
|
||||||
|
{# advanced config_yaml options for elasticfleet logstash output #}
|
||||||
|
{% set ADV_OUTPUT_LOGSTASH_RAW = ELASTICFLEETMERGED.config.outputs.logstash %}
|
||||||
|
{% set ADV_OUTPUT_LOGSTASH = {} %}
|
||||||
|
{% for k, v in ADV_OUTPUT_LOGSTASH_RAW.items() %}
|
||||||
|
{% if v != "" and v is not none %}
|
||||||
|
{% if k == 'queue_mem_events' %}
|
||||||
|
{# rename queue_mem_events queue.mem.events #}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({'queue.mem.events':v}) %}
|
||||||
|
{% elif k == 'loadbalance' %}
|
||||||
|
{% if v %}
|
||||||
|
{# only include loadbalance config when its True #}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% else %}
|
||||||
|
{% do ADV_OUTPUT_LOGSTASH.update({k:v}) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% set LOGSTASH_CONFIG_YAML_RAW = [] %}
|
||||||
|
{% if ADV_OUTPUT_LOGSTASH %}
|
||||||
|
{% for k, v in ADV_OUTPUT_LOGSTASH.items() %}
|
||||||
|
{% do LOGSTASH_CONFIG_YAML_RAW.append(k ~ ': ' ~ v) %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% set LOGSTASH_CONFIG_YAML = LOGSTASH_CONFIG_YAML_RAW | join('\\n') if LOGSTASH_CONFIG_YAML_RAW else '' %}
|
||||||
@@ -10,6 +10,14 @@ elasticfleet:
|
|||||||
grid_enrollment: ''
|
grid_enrollment: ''
|
||||||
defend_filters:
|
defend_filters:
|
||||||
enable_auto_configuration: False
|
enable_auto_configuration: False
|
||||||
|
outputs:
|
||||||
|
logstash:
|
||||||
|
bulk_max_size: ''
|
||||||
|
worker: ''
|
||||||
|
queue_mem_events: ''
|
||||||
|
timeout: ''
|
||||||
|
loadbalance: False
|
||||||
|
compression_level: ''
|
||||||
subscription_integrations: False
|
subscription_integrations: False
|
||||||
auto_upgrade_integrations: False
|
auto_upgrade_integrations: False
|
||||||
logging:
|
logging:
|
||||||
|
|||||||
@@ -36,12 +36,13 @@ so-elastic-fleet-auto-configure-logstash-outputs:
|
|||||||
{# Separate from above in order to catch elasticfleet-logstash.crt changes and force update to fleet output policy #}
|
{# Separate from above in order to catch elasticfleet-logstash.crt changes and force update to fleet output policy #}
|
||||||
so-elastic-fleet-auto-configure-logstash-outputs-force:
|
so-elastic-fleet-auto-configure-logstash-outputs-force:
|
||||||
cmd.run:
|
cmd.run:
|
||||||
- name: /usr/sbin/so-elastic-fleet-outputs-update --force --certs
|
- name: /usr/sbin/so-elastic-fleet-outputs-update --certs
|
||||||
- retry:
|
- retry:
|
||||||
attempts: 4
|
attempts: 4
|
||||||
interval: 30
|
interval: 30
|
||||||
- onchanges:
|
- onchanges:
|
||||||
- x509: etc_elasticfleet_logstash_crt
|
- x509: etc_elasticfleet_logstash_crt
|
||||||
|
- x509: elasticfleet_kafka_crt
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
# If enabled, automatically update Fleet Server URLs & ES Connection
|
# If enabled, automatically update Fleet Server URLs & ES Connection
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
"package": {
|
"package": {
|
||||||
"name": "endpoint",
|
"name": "endpoint",
|
||||||
"title": "Elastic Defend",
|
"title": "Elastic Defend",
|
||||||
"version": "8.18.1",
|
"version": "9.0.2",
|
||||||
"requires_root": true
|
"requires_root": true
|
||||||
},
|
},
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
'azure_application_insights.app_state': 'azure.app_state',
|
'azure_application_insights.app_state': 'azure.app_state',
|
||||||
'azure_billing.billing': 'azure.billing',
|
'azure_billing.billing': 'azure.billing',
|
||||||
'azure_functions.metrics': 'azure.function',
|
'azure_functions.metrics': 'azure.function',
|
||||||
|
'azure_ai_foundry.metrics': 'azure.ai_foundry',
|
||||||
'azure_metrics.compute_vm_scaleset': 'azure.compute_vm_scaleset',
|
'azure_metrics.compute_vm_scaleset': 'azure.compute_vm_scaleset',
|
||||||
'azure_metrics.compute_vm': 'azure.compute_vm',
|
'azure_metrics.compute_vm': 'azure.compute_vm',
|
||||||
'azure_metrics.container_instance': 'azure.container_instance',
|
'azure_metrics.container_instance': 'azure.container_instance',
|
||||||
@@ -121,6 +122,9 @@
|
|||||||
"phases": {
|
"phases": {
|
||||||
"cold": {
|
"cold": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"allocate":{
|
||||||
|
"number_of_replicas": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 0}
|
"set_priority": {"priority": 0}
|
||||||
},
|
},
|
||||||
"min_age": "60d"
|
"min_age": "60d"
|
||||||
@@ -137,12 +141,31 @@
|
|||||||
"max_age": "30d",
|
"max_age": "30d",
|
||||||
"max_primary_shard_size": "50gb"
|
"max_primary_shard_size": "50gb"
|
||||||
},
|
},
|
||||||
|
"forcemerge":{
|
||||||
|
"max_num_segments": ""
|
||||||
|
},
|
||||||
|
"shrink":{
|
||||||
|
"max_primary_shard_size": "",
|
||||||
|
"method": "COUNT",
|
||||||
|
"number_of_shards": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 100}
|
"set_priority": {"priority": 100}
|
||||||
},
|
},
|
||||||
"min_age": "0ms"
|
"min_age": "0ms"
|
||||||
},
|
},
|
||||||
"warm": {
|
"warm": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"allocate": {
|
||||||
|
"number_of_replicas": ""
|
||||||
|
},
|
||||||
|
"forcemerge": {
|
||||||
|
"max_num_segments": ""
|
||||||
|
},
|
||||||
|
"shrink":{
|
||||||
|
"max_primary_shard_size": "",
|
||||||
|
"method": "COUNT",
|
||||||
|
"number_of_shards": ""
|
||||||
|
},
|
||||||
"set_priority": {"priority": 50}
|
"set_priority": {"priority": 50}
|
||||||
},
|
},
|
||||||
"min_age": "30d"
|
"min_age": "30d"
|
||||||
|
|||||||
@@ -50,6 +50,46 @@ elasticfleet:
|
|||||||
global: True
|
global: True
|
||||||
forcedType: bool
|
forcedType: bool
|
||||||
helpLink: elastic-fleet.html
|
helpLink: elastic-fleet.html
|
||||||
|
outputs:
|
||||||
|
logstash:
|
||||||
|
bulk_max_size:
|
||||||
|
description: The maximum number of events to bulk in a single Logstash request.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
worker:
|
||||||
|
description: The number of workers per configured host publishing events.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: true
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
queue_mem_events:
|
||||||
|
title: queued events
|
||||||
|
description: The number of events the queue can store. This value should be evenly divisible by the smaller of 'bulk_max_size' to avoid sending partial batches to the output.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
timeout:
|
||||||
|
description: The number of seconds to wait for responses from the Logstash server before timing out. Eg 30s
|
||||||
|
regex: ^[0-9]+s$
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
loadbalance:
|
||||||
|
description: If true and multiple Logstash hosts are configured, the output plugin load balances published events onto all Logstash hosts. If false, the output plugin sends all events to one host (determined at random) and switches to another host if the selected one becomes unresponsive.
|
||||||
|
forcedType: bool
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
|
compression_level:
|
||||||
|
description: The gzip compression level. The compression level must be in the range of 1 (best speed) to 9 (best compression).
|
||||||
|
regex: ^[1-9]$
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
global: True
|
||||||
|
helpLink: elastic-fleet.html
|
||||||
server:
|
server:
|
||||||
custom_fqdn:
|
custom_fqdn:
|
||||||
description: Custom FQDN for Agents to connect to. One per line.
|
description: Custom FQDN for Agents to connect to. One per line.
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ if [[ -f $STATE_FILE_SUCCESS ]]; then
|
|||||||
latest_package_list=$(/usr/sbin/so-elastic-fleet-package-list)
|
latest_package_list=$(/usr/sbin/so-elastic-fleet-package-list)
|
||||||
echo '{ "packages" : []}' > $BULK_INSTALL_PACKAGE_LIST
|
echo '{ "packages" : []}' > $BULK_INSTALL_PACKAGE_LIST
|
||||||
rm -f $INSTALLED_PACKAGE_LIST
|
rm -f $INSTALLED_PACKAGE_LIST
|
||||||
echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .savedObject.attributes.install_version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST
|
echo $latest_package_list | jq '{packages: [.items[] | {name: .name, latest_version: .version, installed_version: .installationInfo.version, subscription: .conditions.elastic.subscription }]}' >> $INSTALLED_PACKAGE_LIST
|
||||||
|
|
||||||
while read -r package; do
|
while read -r package; do
|
||||||
# get package details
|
# get package details
|
||||||
|
|||||||
@@ -3,13 +3,16 @@
|
|||||||
# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one
|
# 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
|
# 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.
|
# this file except in compliance with the Elastic License 2.0.
|
||||||
{% from 'vars/globals.map.jinja' import GLOBALS %}
|
{%- from 'vars/globals.map.jinja' import GLOBALS %}
|
||||||
{% from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
{%- from 'elasticfleet/map.jinja' import ELASTICFLEETMERGED %}
|
||||||
|
{%- from 'elasticfleet/config.map.jinja' import LOGSTASH_CONFIG_YAML %}
|
||||||
|
|
||||||
. /usr/sbin/so-common
|
. /usr/sbin/so-common
|
||||||
|
|
||||||
FORCE_UPDATE=false
|
FORCE_UPDATE=false
|
||||||
UPDATE_CERTS=false
|
UPDATE_CERTS=false
|
||||||
|
LOGSTASH_PILLAR_CONFIG_YAML="{{ LOGSTASH_CONFIG_YAML }}"
|
||||||
|
LOGSTASH_PILLAR_STATE_FILE="/opt/so/state/esfleet_logstash_config_pillar"
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
case $1 in
|
case $1 in
|
||||||
@@ -19,6 +22,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
;;
|
;;
|
||||||
-c| --certs)
|
-c| --certs)
|
||||||
UPDATE_CERTS=true
|
UPDATE_CERTS=true
|
||||||
|
FORCE_UPDATE=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
@@ -41,38 +45,45 @@ function update_logstash_outputs() {
|
|||||||
LOGSTASHKEY=$(openssl rsa -in /etc/pki/elasticfleet-logstash.key)
|
LOGSTASHKEY=$(openssl rsa -in /etc/pki/elasticfleet-logstash.key)
|
||||||
LOGSTASHCRT=$(openssl x509 -in /etc/pki/elasticfleet-logstash.crt)
|
LOGSTASHCRT=$(openssl x509 -in /etc/pki/elasticfleet-logstash.crt)
|
||||||
LOGSTASHCA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
LOGSTASHCA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
||||||
|
# Revert escaped \\n to \n for jq
|
||||||
|
LOGSTASH_PILLAR_CONFIG_YAML=$(printf '%b' "$LOGSTASH_PILLAR_CONFIG_YAML")
|
||||||
|
|
||||||
if SECRETS=$(echo "$logstash_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
if SECRETS=$(echo "$logstash_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
||||||
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
# Reuse existing secret
|
# Reuse existing secret
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
--argjson SECRETS "$SECRETS" \
|
--argjson SECRETS "$SECRETS" \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
||||||
else
|
else
|
||||||
# Update certs, creating new secret
|
# Update certs, creating new secret
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
||||||
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
||||||
--arg LOGSTASHCA "$LOGSTASHCA" \
|
--arg LOGSTASHCA "$LOGSTASHCA" \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": {"certificate": $LOGSTASHCRT,"certificate_authorities":[ $LOGSTASHCA ]},"secrets": {"ssl":{"key": $LOGSTASHKEY }}}')
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": {"certificate": $LOGSTASHCRT,"certificate_authorities":[ $LOGSTASHCA ]},"secrets": {"ssl":{"key": $LOGSTASHKEY }}}')
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
# Reuse existing ssl config
|
# Reuse existing ssl config
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": $SSL_CONFIG}')
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": $SSL_CONFIG}')
|
||||||
else
|
else
|
||||||
# Update ssl config
|
# Update ssl config
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg CONFIG_YAML "$LOGSTASH_PILLAR_CONFIG_YAML" \
|
||||||
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
--arg LOGSTASHKEY "$LOGSTASHKEY" \
|
||||||
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
--arg LOGSTASHCRT "$LOGSTASHCRT" \
|
||||||
--arg LOGSTASHCA "$LOGSTASHCA" \
|
--arg LOGSTASHCA "$LOGSTASHCA" \
|
||||||
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":"","ssl": {"certificate": $LOGSTASHCRT,"key": $LOGSTASHKEY,"certificate_authorities":[ $LOGSTASHCA ]}}')
|
'{"name":"grid-logstash","type":"logstash","hosts": $UPDATEDLIST,"is_default":true,"is_default_monitoring":true,"config_yaml":$CONFIG_YAML,"ssl": {"certificate": $LOGSTASHCRT,"key": $LOGSTASHKEY,"certificate_authorities":[ $LOGSTASHCA ]}}')
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@@ -84,7 +95,11 @@ function update_kafka_outputs() {
|
|||||||
# Make sure SSL configuration is included in policy updates for Kafka output. SSL is configured in so-elastic-fleet-setup
|
# Make sure SSL configuration is included in policy updates for Kafka output. SSL is configured in so-elastic-fleet-setup
|
||||||
if kafka_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_kafka" --fail 2>/dev/null); then
|
if kafka_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_kafka" --fail 2>/dev/null); then
|
||||||
SSL_CONFIG=$(echo "$kafka_policy" | jq -r '.item.ssl')
|
SSL_CONFIG=$(echo "$kafka_policy" | jq -r '.item.ssl')
|
||||||
|
KAFKAKEY=$(openssl rsa -in /etc/pki/elasticfleet-kafka.key)
|
||||||
|
KAFKACRT=$(openssl x509 -in /etc/pki/elasticfleet-kafka.crt)
|
||||||
|
KAFKACA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt)
|
||||||
if SECRETS=$(echo "$kafka_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
if SECRETS=$(echo "$kafka_policy" | jq -er '.item.secrets' 2>/dev/null); then
|
||||||
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
# Update policy when fleet has secrets enabled
|
# Update policy when fleet has secrets enabled
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
@@ -92,11 +107,30 @@ function update_kafka_outputs() {
|
|||||||
--argjson SECRETS "$SECRETS" \
|
--argjson SECRETS "$SECRETS" \
|
||||||
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG,"secrets": $SECRETS}')
|
||||||
else
|
else
|
||||||
|
# Update certs, creating new secret
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg KAFKAKEY "$KAFKAKEY" \
|
||||||
|
--arg KAFKACRT "$KAFKACRT" \
|
||||||
|
--arg KAFKACA "$KAFKACA" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": {"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"secrets": {"ssl":{"key": $KAFKAKEY }}}')
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [[ "$UPDATE_CERTS" != "true" ]]; then
|
||||||
# Update policy when fleet has secrets disabled or policy hasn't been force updated
|
# Update policy when fleet has secrets disabled or policy hasn't been force updated
|
||||||
JSON_STRING=$(jq -n \
|
JSON_STRING=$(jq -n \
|
||||||
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
--argjson SSL_CONFIG "$SSL_CONFIG" \
|
||||||
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG}')
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": $SSL_CONFIG}')
|
||||||
|
else
|
||||||
|
# Update ssl config
|
||||||
|
JSON_STRING=$(jq -n \
|
||||||
|
--arg UPDATEDLIST "$NEW_LIST_JSON" \
|
||||||
|
--arg KAFKAKEY "$KAFKAKEY" \
|
||||||
|
--arg KAFKACRT "$KAFKACRT" \
|
||||||
|
--arg KAFKACA "$KAFKACA" \
|
||||||
|
'{"name": "grid-kafka","type": "kafka","hosts": $UPDATEDLIST,"is_default": true,"is_default_monitoring": true,"config_yaml": "","ssl": { "certificate_authorities": [ $KAFKACA ], "certificate": $KAFKACRT, "key": $KAFKAKEY, "verification_mode": "full" }}')
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
# Update Kafka outputs
|
# Update Kafka outputs
|
||||||
curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" | jq
|
curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" | jq
|
||||||
@@ -119,7 +153,7 @@ function update_kafka_outputs() {
|
|||||||
|
|
||||||
# Get the current list of kafka outputs & hash them
|
# Get the current list of kafka outputs & hash them
|
||||||
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
||||||
CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
CURRENT_HASH=$(sha256sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
||||||
|
|
||||||
declare -a NEW_LIST=()
|
declare -a NEW_LIST=()
|
||||||
|
|
||||||
@@ -142,10 +176,19 @@ function update_kafka_outputs() {
|
|||||||
printf "Failed to query for current Logstash Outputs..."
|
printf "Failed to query for current Logstash Outputs..."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
# logstash adv config - compare pillar to last state file value
|
||||||
|
if [[ -f "$LOGSTASH_PILLAR_STATE_FILE" ]]; then
|
||||||
|
PREVIOUS_LOGSTASH_PILLAR_CONFIG_YAML=$(cat "$LOGSTASH_PILLAR_STATE_FILE")
|
||||||
|
if [[ "$LOGSTASH_PILLAR_CONFIG_YAML" != "$PREVIOUS_LOGSTASH_PILLAR_CONFIG_YAML" ]]; then
|
||||||
|
echo "Logstash pillar config has changed - forcing update"
|
||||||
|
FORCE_UPDATE=true
|
||||||
|
fi
|
||||||
|
echo "$LOGSTASH_PILLAR_CONFIG_YAML" > "$LOGSTASH_PILLAR_STATE_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
# Get the current list of Logstash outputs & hash them
|
# Get the current list of Logstash outputs & hash them
|
||||||
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
CURRENT_LIST=$(jq -c -r '.item.hosts' <<< "$RAW_JSON")
|
||||||
CURRENT_HASH=$(sha1sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
CURRENT_HASH=$(sha256sum <<< "$CURRENT_LIST" | awk '{print $1}')
|
||||||
|
|
||||||
declare -a NEW_LIST=()
|
declare -a NEW_LIST=()
|
||||||
|
|
||||||
@@ -194,7 +237,7 @@ function update_kafka_outputs() {
|
|||||||
|
|
||||||
# Sort & hash the new list of Logstash Outputs
|
# Sort & hash the new list of Logstash Outputs
|
||||||
NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}")
|
NEW_LIST_JSON=$(jq --compact-output --null-input '$ARGS.positional' --args -- "${NEW_LIST[@]}")
|
||||||
NEW_HASH=$(sha1sum <<< "$NEW_LIST_JSON" | awk '{print $1}')
|
NEW_HASH=$(sha256sum <<< "$NEW_LIST_JSON" | awk '{print $1}')
|
||||||
|
|
||||||
# Compare the current & new list of outputs - if different, update the Logstash outputs
|
# Compare the current & new list of outputs - if different, update the Logstash outputs
|
||||||
if [[ "$NEW_HASH" = "$CURRENT_HASH" ]] && [[ "$FORCE_UPDATE" != "true" ]]; then
|
if [[ "$NEW_HASH" = "$CURRENT_HASH" ]] && [[ "$FORCE_UPDATE" != "true" ]]; then
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ if ! kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l
|
|||||||
--arg KAFKACA "$KAFKACA" \
|
--arg KAFKACA "$KAFKACA" \
|
||||||
--arg MANAGER_IP "{{ GLOBALS.manager_ip }}:9092" \
|
--arg MANAGER_IP "{{ GLOBALS.manager_ip }}:9092" \
|
||||||
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
||||||
'{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
'{"name":"grid-kafka", "id":"so-manager_kafka","type":"kafka","hosts":[ $MANAGER_IP ],"is_default":false,"is_default_monitoring":false,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||||
)
|
)
|
||||||
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/outputs" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
||||||
echo -e "\nFailed to setup Elastic Fleet output policy for Kafka...\n"
|
echo -e "\nFailed to setup Elastic Fleet output policy for Kafka...\n"
|
||||||
@@ -67,7 +67,7 @@ elif kafka_output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "http://l
|
|||||||
--arg ENABLED_DISABLED "$ENABLED_DISABLED"\
|
--arg ENABLED_DISABLED "$ENABLED_DISABLED"\
|
||||||
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
--arg KAFKA_OUTPUT_VERSION "$KAFKA_OUTPUT_VERSION" \
|
||||||
--argjson HOSTS "$HOSTS" \
|
--argjson HOSTS "$HOSTS" \
|
||||||
'{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topics":[{"topic":"default-securityonion"}],"headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
'{"name":"grid-kafka","type":"kafka","hosts":$HOSTS,"is_default":$ENABLED_DISABLED,"is_default_monitoring":$ENABLED_DISABLED,"config_yaml":"","ssl":{"certificate_authorities":[ $KAFKACA ],"certificate": $KAFKACRT ,"key":"","verification_mode":"full"},"proxy_id":null,"client_id":"Elastic","version": $KAFKA_OUTPUT_VERSION ,"compression":"none","auth_type":"ssl","partition":"round_robin","round_robin":{"group_events":10},"topic":"default-securityonion","headers":[{"key":"","value":""}],"timeout":30,"broker_timeout":30,"required_acks":1,"secrets":{"ssl":{"key": $KAFKAKEY }}}'
|
||||||
)
|
)
|
||||||
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
if ! response=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_kafka" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --fail 2>/dev/null); then
|
||||||
echo -e "\nFailed to force update to Elastic Fleet output policy for Kafka...\n"
|
echo -e "\nFailed to force update to Elastic Fleet output policy for Kafka...\n"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
elasticsearch:
|
elasticsearch:
|
||||||
enabled: false
|
enabled: false
|
||||||
version: 8.18.8
|
version: 9.0.8
|
||||||
index_clean: true
|
index_clean: true
|
||||||
config:
|
config:
|
||||||
action:
|
action:
|
||||||
@@ -72,6 +72,8 @@ elasticsearch:
|
|||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 0
|
priority: 0
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 60d
|
min_age: 60d
|
||||||
delete:
|
delete:
|
||||||
actions:
|
actions:
|
||||||
@@ -84,11 +86,25 @@ elasticsearch:
|
|||||||
max_primary_shard_size: 50gb
|
max_primary_shard_size: 50gb
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 100
|
priority: 100
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 0ms
|
min_age: 0ms
|
||||||
warm:
|
warm:
|
||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
so-case:
|
so-case:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
@@ -245,7 +261,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-detection:
|
so-detection:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -584,7 +599,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-import:
|
so-import:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -932,7 +946,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-hydra:
|
so-hydra:
|
||||||
close: 30
|
close: 30
|
||||||
delete: 365
|
delete: 365
|
||||||
@@ -1043,7 +1056,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-lists:
|
so-lists:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
@@ -1127,6 +1139,8 @@ elasticsearch:
|
|||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 0
|
priority: 0
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
min_age: 60d
|
min_age: 60d
|
||||||
delete:
|
delete:
|
||||||
actions:
|
actions:
|
||||||
@@ -1139,11 +1153,25 @@ elasticsearch:
|
|||||||
max_primary_shard_size: 50gb
|
max_primary_shard_size: 50gb
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 100
|
priority: 100
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 0ms
|
min_age: 0ms
|
||||||
warm:
|
warm:
|
||||||
actions:
|
actions:
|
||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
|
allocate:
|
||||||
|
number_of_replicas: ""
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments: ""
|
||||||
|
shrink:
|
||||||
|
max_primary_shard_size: ""
|
||||||
|
method: COUNT
|
||||||
|
number_of_shards: ""
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
so-logs-detections_x_alerts:
|
so-logs-detections_x_alerts:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
@@ -3123,7 +3151,6 @@ elasticsearch:
|
|||||||
set_priority:
|
set_priority:
|
||||||
priority: 50
|
priority: 50
|
||||||
min_age: 30d
|
min_age: 30d
|
||||||
warm: 7
|
|
||||||
so-logs-system_x_application:
|
so-logs-system_x_application:
|
||||||
index_sorting: false
|
index_sorting: false
|
||||||
index_template:
|
index_template:
|
||||||
|
|||||||
@@ -131,6 +131,47 @@ elasticsearch:
|
|||||||
description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index.
|
description: Maximum primary shard size. Once an index reaches this limit, it will be rolled over into a new index.
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
forcedType: string
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
cold:
|
cold:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
||||||
@@ -144,6 +185,12 @@ elasticsearch:
|
|||||||
description: Used for index recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities.
|
description: Used for index recovery after a node restart. Indices with higher priorities are recovered before indices with lower priorities.
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
warm:
|
warm:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
||||||
@@ -158,6 +205,52 @@ elasticsearch:
|
|||||||
forcedType: int
|
forcedType: int
|
||||||
global: True
|
global: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
delete:
|
delete:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
||||||
@@ -287,6 +380,47 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
forcedType: string
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
warm:
|
warm:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
description: Minimum age of index. ex. 30d - This determines when the index should be moved to the warm tier. Nodes in the warm tier generally don’t need to be as fast as those in the hot tier. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and warm min_age set to 30 then there will be 30 days from index creation to rollover and then an additional 30 days before moving to warm tier.
|
||||||
@@ -314,6 +448,52 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
shrink:
|
||||||
|
method:
|
||||||
|
description: Shrink the index to a new index with fewer primary shards. Shrink operation is by count or size.
|
||||||
|
options:
|
||||||
|
- COUNT
|
||||||
|
- SIZE
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
|
number_of_shards:
|
||||||
|
title: shard count
|
||||||
|
description: Desired shard count. Note that this value is only used when the shrink method selected is 'COUNT'.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
max_primary_shard_size:
|
||||||
|
title: max shard size
|
||||||
|
description: Desired shard size in gb/tb/pb eg. 100gb. Note that this value is only used when the shrink method selected is 'SIZE'.
|
||||||
|
regex: ^[0-9]+(?:gb|tb|pb)$
|
||||||
|
global: True
|
||||||
|
forcedType: string
|
||||||
|
advanced: True
|
||||||
|
allow_write_after_shrink:
|
||||||
|
description: Allow writes after shrink.
|
||||||
|
global: True
|
||||||
|
forcedType: bool
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
forcemerge:
|
||||||
|
max_num_segments:
|
||||||
|
description: Reduce the number of segments in each index shard and clean up deleted documents.
|
||||||
|
global: True
|
||||||
|
forcedType: int
|
||||||
|
advanced: True
|
||||||
|
index_codec:
|
||||||
|
title: compression
|
||||||
|
description: Use higher compression for stored fields at the cost of slower performance.
|
||||||
|
forcedType: bool
|
||||||
|
global: True
|
||||||
|
default: False
|
||||||
|
advanced: True
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
cold:
|
cold:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
description: Minimum age of index. ex. 60d - This determines when the index should be moved to the cold tier. While still searchable, this tier is typically optimized for lower storage costs rather than search speed. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and cold min_age set to 60 then there will be 30 days from index creation to rollover and then an additional 60 days before moving to cold tier.
|
||||||
@@ -330,6 +510,12 @@ elasticsearch:
|
|||||||
global: True
|
global: True
|
||||||
advanced: True
|
advanced: True
|
||||||
helpLink: elasticsearch.html
|
helpLink: elasticsearch.html
|
||||||
|
allocate:
|
||||||
|
number_of_replicas:
|
||||||
|
description: Set the number of replicas. Remains the same as the previous phase by default.
|
||||||
|
forcedType: int
|
||||||
|
global: True
|
||||||
|
advanced: True
|
||||||
delete:
|
delete:
|
||||||
min_age:
|
min_age:
|
||||||
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
description: Minimum age of index. ex. 90d - This determines when the index should be deleted. It’s important to note that this is calculated relative to the rollover date (NOT the original creation date of the index). For example, if you have an index that is set to rollover after 30 days and delete min_age set to 90 then there will be 30 days from index creation to rollover and then an additional 90 days before deletion.
|
||||||
|
|||||||
@@ -61,5 +61,55 @@
|
|||||||
{% do settings.index_template.template.settings.index.pop('sort') %}
|
{% do settings.index_template.template.settings.index.pop('sort') %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
{# advanced ilm actions #}
|
||||||
|
{% if settings.policy is defined and settings.policy.phases is defined %}
|
||||||
|
{% set PHASE_NAMES = ["hot", "warm", "cold"] %}
|
||||||
|
{% for P in PHASE_NAMES %}
|
||||||
|
{% if settings.policy.phases[P] is defined and settings.policy.phases[P].actions is defined %}
|
||||||
|
{% set PHASE = settings.policy.phases[P].actions %}
|
||||||
|
{# remove allocate action if number_of_replicas isn't configured #}
|
||||||
|
{% if PHASE.allocate is defined %}
|
||||||
|
{% if PHASE.allocate.number_of_replicas is not defined or PHASE.allocate.number_of_replicas == "" %}
|
||||||
|
{% do PHASE.pop('allocate', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# start shrink action #}
|
||||||
|
{% if PHASE.shrink is defined %}
|
||||||
|
{% if PHASE.shrink.method is defined %}
|
||||||
|
{% if PHASE.shrink.method == 'COUNT' and PHASE.shrink.number_of_shards is defined and PHASE.shrink.number_of_shards %}
|
||||||
|
{# remove max_primary_shard_size value when doing shrink operation by count vs size #}
|
||||||
|
{% do PHASE.shrink.pop('max_primary_shard_size', none) %}
|
||||||
|
{% elif PHASE.shrink.method == 'SIZE' and PHASE.shrink.max_primary_shard_size is defined and PHASE.shrink.max_primary_shard_size %}
|
||||||
|
{# remove number_of_shards value when doing shrink operation by size vs count #}
|
||||||
|
{% do PHASE.shrink.pop('number_of_shards', none) %}
|
||||||
|
{% else %}
|
||||||
|
{# method isn't defined or missing a required config number_of_shards/max_primary_shard_size #}
|
||||||
|
{% do PHASE.pop('shrink', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# always remove shrink method since its only used for SOC config, not in the actual ilm policy #}
|
||||||
|
{% if PHASE.shrink is defined %}
|
||||||
|
{% do PHASE.shrink.pop('method', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{# end shrink action #}
|
||||||
|
{# start force merge #}
|
||||||
|
{% if PHASE.forcemerge is defined %}
|
||||||
|
{% if PHASE.forcemerge.index_codec is defined and PHASE.forcemerge.index_codec %}
|
||||||
|
{% do PHASE.forcemerge.update({'index_codec': 'best_compression'}) %}
|
||||||
|
{% else %}
|
||||||
|
{% do PHASE.forcemerge.pop('index_codec', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% if PHASE.forcemerge.max_num_segments is not defined or not PHASE.forcemerge.max_num_segments %}
|
||||||
|
{# max_num_segments is empty, drop it #}
|
||||||
|
{% do PHASE.pop('forcemerge', none) %}
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
{# end force merge #}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% do ES_INDEX_SETTINGS.update({index | replace("_x_", "."): ES_INDEX_SETTINGS_GLOBAL_OVERRIDES[index]}) %}
|
{% do ES_INDEX_SETTINGS.update({index | replace("_x_", "."): ES_INDEX_SETTINGS_GLOBAL_OVERRIDES[index]}) %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ set -e
|
|||||||
if [ ! -f /opt/so/saltstack/local/salt/elasticsearch/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:$ELASTIC_AGENT_TARBALL_VERSION -keystore /usr/share/elasticsearch/jdk/lib/security/cacerts -alias SOSCA -import -file /etc/ssl/ca.crt -storepass changeit -noprompt
|
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:$ELASTIC_AGENT_TARBALL_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/elasticsearch/cacerts
|
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 cp so-elasticsearchca:/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||||
docker rm so-elasticsearchca
|
docker rm so-elasticsearchca
|
||||||
echo "" >> /opt/so/saltstack/local/salt/elasticsearch/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
|
echo "sosca" >> /opt/so/saltstack/local/salt/elasticsearch/tls-ca-bundle.pem
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ logstash:
|
|||||||
settings:
|
settings:
|
||||||
lsheap: 500m
|
lsheap: 500m
|
||||||
config:
|
config:
|
||||||
http_x_host: 0.0.0.0
|
api_x_http_x_host: 0.0.0.0
|
||||||
path_x_logs: /var/log/logstash
|
path_x_logs: /var/log/logstash
|
||||||
pipeline_x_workers: 1
|
pipeline_x_workers: 1
|
||||||
pipeline_x_batch_x_size: 125
|
pipeline_x_batch_x_size: 125
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ input {
|
|||||||
codec => es_bulk
|
codec => es_bulk
|
||||||
request_headers_target_field => client_headers
|
request_headers_target_field => client_headers
|
||||||
remote_host_target_field => client_host
|
remote_host_target_field => client_host
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
||||||
ssl_certificate => "/usr/share/logstash/filebeat.crt"
|
ssl_certificate => "/usr/share/logstash/filebeat.crt"
|
||||||
ssl_key => "/usr/share/logstash/filebeat.key"
|
ssl_key => "/usr/share/logstash/filebeat.key"
|
||||||
ssl_verify_mode => "peer"
|
ssl_client_authentication => "required"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ input {
|
|||||||
elastic_agent {
|
elastic_agent {
|
||||||
port => 5055
|
port => 5055
|
||||||
tags => [ "elastic-agent", "input-{{ GLOBALS.hostname }}" ]
|
tags => [ "elastic-agent", "input-{{ GLOBALS.hostname }}" ]
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
ssl_certificate_authorities => ["/usr/share/filebeat/ca.crt"]
|
||||||
ssl_certificate => "/usr/share/logstash/elasticfleet-logstash.crt"
|
ssl_certificate => "/usr/share/logstash/elasticfleet-logstash.crt"
|
||||||
ssl_key => "/usr/share/logstash/elasticfleet-logstash.key"
|
ssl_key => "/usr/share/logstash/elasticfleet-logstash.key"
|
||||||
ssl_verify_mode => "force_peer"
|
ssl_client_authentication => "required"
|
||||||
ecs_compatibility => v8
|
ecs_compatibility => v8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ input {
|
|||||||
elastic_agent {
|
elastic_agent {
|
||||||
port => 5056
|
port => 5056
|
||||||
tags => [ "elastic-agent", "fleet-lumberjack-input" ]
|
tags => [ "elastic-agent", "fleet-lumberjack-input" ]
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate => "/usr/share/logstash/elasticfleet-lumberjack.crt"
|
ssl_certificate => "/usr/share/logstash/elasticfleet-lumberjack.crt"
|
||||||
ssl_key => "/usr/share/logstash/elasticfleet-lumberjack.key"
|
ssl_key => "/usr/share/logstash/elasticfleet-lumberjack.key"
|
||||||
ecs_compatibility => v8
|
ecs_compatibility => v8
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ output {
|
|||||||
document_id => "%{[metadata][_id]}"
|
document_id => "%{[metadata][_id]}"
|
||||||
index => "so-ip-mappings"
|
index => "so-ip-mappings"
|
||||||
silence_errors_in_log => ["version_conflict_engine_exception"]
|
silence_errors_in_log => ["version_conflict_engine_exception"]
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_verification => false
|
ssl_verification_mode => "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -25,8 +25,8 @@ output {
|
|||||||
document_id => "%{[metadata][_id]}"
|
document_id => "%{[metadata][_id]}"
|
||||||
pipeline => "%{[metadata][pipeline]}"
|
pipeline => "%{[metadata][pipeline]}"
|
||||||
silence_errors_in_log => ["version_conflict_engine_exception"]
|
silence_errors_in_log => ["version_conflict_engine_exception"]
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_verification => false
|
ssl_verification_mode => "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -37,8 +37,8 @@ output {
|
|||||||
user => "{{ ES_USER }}"
|
user => "{{ ES_USER }}"
|
||||||
password => "{{ ES_PASS }}"
|
password => "{{ ES_PASS }}"
|
||||||
pipeline => "%{[metadata][pipeline]}"
|
pipeline => "%{[metadata][pipeline]}"
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_verification => false
|
ssl_verification_mode => "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,8 +49,8 @@ output {
|
|||||||
data_stream => true
|
data_stream => true
|
||||||
user => "{{ ES_USER }}"
|
user => "{{ ES_USER }}"
|
||||||
password => "{{ ES_PASS }}"
|
password => "{{ ES_PASS }}"
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_verification => false
|
ssl_verification_mode=> "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ output {
|
|||||||
user => "{{ ES_USER }}"
|
user => "{{ ES_USER }}"
|
||||||
password => "{{ ES_PASS }}"
|
password => "{{ ES_PASS }}"
|
||||||
index => "endgame-%{+YYYY.MM.dd}"
|
index => "endgame-%{+YYYY.MM.dd}"
|
||||||
ssl => true
|
ssl_enabled => true
|
||||||
ssl_certificate_verification => false
|
ssl_verification_mode => "none"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ logstash:
|
|||||||
helpLink: logstash.html
|
helpLink: logstash.html
|
||||||
global: False
|
global: False
|
||||||
config:
|
config:
|
||||||
http_x_host:
|
api_x_http_x_host:
|
||||||
description: Host interface to listen to connections.
|
description: Host interface to listen to connections.
|
||||||
helpLink: logstash.html
|
helpLink: logstash.html
|
||||||
readonly: True
|
readonly: True
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ git_config_set_safe_dirs:
|
|||||||
|
|
||||||
surinsmrulesdir:
|
surinsmrulesdir:
|
||||||
file.directory:
|
file.directory:
|
||||||
- name: /nsm/rules/suricata
|
- name: /nsm/rules/suricata/etopen
|
||||||
- user: 939
|
- user: 939
|
||||||
- group: 939
|
- group: 939
|
||||||
- makedirs: True
|
- makedirs: True
|
||||||
|
|||||||
@@ -25,13 +25,11 @@
|
|||||||
{% set index_settings = es.get('index_settings', {}) %}
|
{% set index_settings = es.get('index_settings', {}) %}
|
||||||
{% set input = index_settings.get('so-logs', {}) %}
|
{% set input = index_settings.get('so-logs', {}) %}
|
||||||
{% for k in matched_integration_names %}
|
{% for k in matched_integration_names %}
|
||||||
{% if k not in index_settings %}
|
{% do index_settings.update({k: input}) %}
|
||||||
{% set _ = index_settings.update({k: input}) %}
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for k in addon_integration_keys %}
|
{% for k in addon_integration_keys %}
|
||||||
{% if k not in matched_integration_names and k in index_settings %}
|
{% if k not in matched_integration_names and k in index_settings %}
|
||||||
{% set _ = index_settings.pop(k) %}
|
{% do index_settings.pop(k) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ data }}
|
{{ data }}
|
||||||
@@ -45,14 +43,12 @@
|
|||||||
{% set es = data.get('elasticsearch', {}) %}
|
{% set es = data.get('elasticsearch', {}) %}
|
||||||
{% set index_settings = es.get('index_settings', {}) %}
|
{% set index_settings = es.get('index_settings', {}) %}
|
||||||
{% for k in matched_integration_names %}
|
{% for k in matched_integration_names %}
|
||||||
{% if k not in index_settings %}
|
|
||||||
{% set input = ADDON_INTEGRATION_DEFAULTS[k] %}
|
{% set input = ADDON_INTEGRATION_DEFAULTS[k] %}
|
||||||
{% set _ = index_settings.update({k: input})%}
|
{% do index_settings.update({k: input})%}
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for k in addon_integration_keys %}
|
{% for k in addon_integration_keys %}
|
||||||
{% if k not in matched_integration_names and k in index_settings %}
|
{% if k not in matched_integration_names and k in index_settings %}
|
||||||
{% set _ = index_settings.pop(k) %}
|
{% do index_settings.pop(k) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{{ data }}
|
{{ data }}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ def showUsage(args):
|
|||||||
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]), file=sys.stderr)
|
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]), file=sys.stderr)
|
||||||
print(' General commands:', file=sys.stderr)
|
print(' General commands:', file=sys.stderr)
|
||||||
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||||
|
print(' removelistitem - Remove a list item from a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.', file=sys.stderr)
|
||||||
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.', file=sys.stderr)
|
||||||
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
print(' get - Displays (to stdout) the value stored in the given key. Requires KEY arg.', file=sys.stderr)
|
||||||
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.', file=sys.stderr)
|
||||||
@@ -57,6 +58,24 @@ def appendItem(content, key, listItem):
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def removeListItem(content, key, listItem):
|
||||||
|
pieces = key.split(".", 1)
|
||||||
|
if len(pieces) > 1:
|
||||||
|
removeListItem(content[pieces[0]], pieces[1], listItem)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
if not isinstance(content[key], list):
|
||||||
|
raise AttributeError("Value is not a list")
|
||||||
|
if listItem in content[key]:
|
||||||
|
content[key].remove(listItem)
|
||||||
|
except (AttributeError, TypeError):
|
||||||
|
print("The existing value for the given key is not a list. No action was taken on the file.", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
except KeyError:
|
||||||
|
print("The key provided does not exist. No action was taken on the file.", file=sys.stderr)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
def convertType(value):
|
def convertType(value):
|
||||||
if isinstance(value, str) and value.startswith("file:"):
|
if isinstance(value, str) and value.startswith("file:"):
|
||||||
path = value[5:] # Remove "file:" prefix
|
path = value[5:] # Remove "file:" prefix
|
||||||
@@ -103,6 +122,23 @@ def append(args):
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def removelistitem(args):
|
||||||
|
if len(args) != 3:
|
||||||
|
print('Missing filename, key arg, or list item to remove', file=sys.stderr)
|
||||||
|
showUsage(None)
|
||||||
|
return 1
|
||||||
|
|
||||||
|
filename = args[0]
|
||||||
|
key = args[1]
|
||||||
|
listItem = args[2]
|
||||||
|
|
||||||
|
content = loadYaml(filename)
|
||||||
|
removeListItem(content, key, convertType(listItem))
|
||||||
|
writeYaml(filename, content)
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
def addKey(content, key, value):
|
def addKey(content, key, value):
|
||||||
pieces = key.split(".", 1)
|
pieces = key.split(".", 1)
|
||||||
if len(pieces) > 1:
|
if len(pieces) > 1:
|
||||||
@@ -211,6 +247,7 @@ def main():
|
|||||||
"help": showUsage,
|
"help": showUsage,
|
||||||
"add": add,
|
"add": add,
|
||||||
"append": append,
|
"append": append,
|
||||||
|
"removelistitem": removelistitem,
|
||||||
"get": get,
|
"get": get,
|
||||||
"remove": remove,
|
"remove": remove,
|
||||||
"replace": replace,
|
"replace": replace,
|
||||||
|
|||||||
@@ -457,3 +457,126 @@ class TestRemove(unittest.TestCase):
|
|||||||
self.assertEqual(result, 1)
|
self.assertEqual(result, 1)
|
||||||
self.assertIn("Missing filename or key arg", mock_stderr.getvalue())
|
self.assertIn("Missing filename or key arg", mock_stderr.getvalue())
|
||||||
sysmock.assert_called_once_with(1)
|
sysmock.assert_called_once_with(1)
|
||||||
|
|
||||||
|
|
||||||
|
class TestRemoveListItem(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_removelistitem_missing_arg(self):
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "help"]
|
||||||
|
soyaml.removelistitem(["file", "key"])
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertIn("Missing filename, key arg, or list item to remove", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: abc }, key2: false, key3: [a,b,c]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key3", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2: abc\nkey2: false\nkey3:\n- a\n- c\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_nested(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: [a,b,c] }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1.child2", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2:\n - a\n - c\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_nested_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1.child2.deep2", "b"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2:\n - a\n - c\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_item_not_in_list(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: [a,b,c]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
soyaml.removelistitem([filename, "key1", "d"])
|
||||||
|
|
||||||
|
file = open(filename, "r")
|
||||||
|
actual = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
expected = "key1:\n- a\n- b\n- c\n"
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_removelistitem_key_noexist(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key4", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_noexist_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1.child2.deep3", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The key provided does not exist. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_nonlist(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|
||||||
|
def test_removelistitem_key_nonlist_deep(self):
|
||||||
|
filename = "/tmp/so-yaml_test-removelistitem.yaml"
|
||||||
|
file = open(filename, "w")
|
||||||
|
file.write("{key1: { child1: 123, child2: { deep1: 45, deep2: [a,b,c] } }, key2: false, key3: [e,f,g]}")
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||||
|
with patch('sys.stderr', new=StringIO()) as mock_stderr:
|
||||||
|
sys.argv = ["cmd", "removelistitem", filename, "key1.child2.deep1", "h"]
|
||||||
|
soyaml.main()
|
||||||
|
sysmock.assert_called()
|
||||||
|
self.assertEqual("The existing value for the given key is not a list. No action was taken on the file.\n", mock_stderr.getvalue())
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ check_err() {
|
|||||||
113)
|
113)
|
||||||
echo 'No route to host'
|
echo 'No route to host'
|
||||||
;;
|
;;
|
||||||
|
160)
|
||||||
|
echo 'Incompatiable Elasticsearch upgrade'
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo 'Unhandled error'
|
echo 'Unhandled error'
|
||||||
echo "$err_msg"
|
echo "$err_msg"
|
||||||
@@ -427,6 +430,7 @@ preupgrade_changes() {
|
|||||||
[[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180
|
[[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180
|
||||||
[[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190
|
[[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190
|
||||||
[[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200
|
[[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200
|
||||||
|
[[ "$INSTALLEDVERSION" == 2.4.200 ]] && up_to_2.4.210
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,6 +463,7 @@ postupgrade_changes() {
|
|||||||
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
[[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180
|
||||||
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
[[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190
|
||||||
[[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200
|
[[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200
|
||||||
|
[[ "$POSTVERSION" == 2.4.200 ]] && post_to_2.4.210
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -615,9 +620,6 @@ post_to_2.4.180() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
post_to_2.4.190() {
|
post_to_2.4.190() {
|
||||||
echo "Regenerating Elastic Agent Installers"
|
|
||||||
/sbin/so-elastic-agent-gen-installers
|
|
||||||
|
|
||||||
# Only need to update import / eval nodes
|
# Only need to update import / eval nodes
|
||||||
if [[ "$MINION_ROLE" == "import" ]] || [[ "$MINION_ROLE" == "eval" ]]; then
|
if [[ "$MINION_ROLE" == "import" ]] || [[ "$MINION_ROLE" == "eval" ]]; then
|
||||||
update_import_fleet_output
|
update_import_fleet_output
|
||||||
@@ -645,6 +647,13 @@ post_to_2.4.200() {
|
|||||||
POSTVERSION=2.4.200
|
POSTVERSION=2.4.200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
post_to_2.4.210() {
|
||||||
|
echo "Regenerating Elastic Agent Installers"
|
||||||
|
/sbin/so-elastic-agent-gen-installers
|
||||||
|
|
||||||
|
POSTVERSION=2.4.210
|
||||||
|
}
|
||||||
|
|
||||||
repo_sync() {
|
repo_sync() {
|
||||||
echo "Sync the local repo."
|
echo "Sync the local repo."
|
||||||
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync."
|
||||||
@@ -906,9 +915,7 @@ up_to_2.4.180() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
up_to_2.4.190() {
|
up_to_2.4.190() {
|
||||||
# Elastic Update for this release, so download Elastic Agent files
|
echo "Nothing to do for 2.4.190"
|
||||||
determine_elastic_agent_upgrade
|
|
||||||
|
|
||||||
INSTALLEDVERSION=2.4.190
|
INSTALLEDVERSION=2.4.190
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -916,9 +923,18 @@ up_to_2.4.200() {
|
|||||||
echo "Backing up idstools config..."
|
echo "Backing up idstools config..."
|
||||||
suricata_idstools_removal_pre
|
suricata_idstools_removal_pre
|
||||||
|
|
||||||
|
touch /opt/so/state/esfleet_logstash_config_pillar
|
||||||
|
|
||||||
INSTALLEDVERSION=2.4.200
|
INSTALLEDVERSION=2.4.200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
up_to_2.4.210() {
|
||||||
|
# Elastic Update for this release, so download Elastic Agent files
|
||||||
|
determine_elastic_agent_upgrade
|
||||||
|
|
||||||
|
INSTALLEDVERSION=2.4.210
|
||||||
|
}
|
||||||
|
|
||||||
add_hydra_pillars() {
|
add_hydra_pillars() {
|
||||||
mkdir -p /opt/so/saltstack/local/pillar/hydra
|
mkdir -p /opt/so/saltstack/local/pillar/hydra
|
||||||
touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls
|
touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls
|
||||||
@@ -1111,9 +1127,13 @@ suricata_idstools_removal_pre() {
|
|||||||
install -d -o 939 -g 939 -m 755 /opt/so/conf/soc/fingerprints
|
install -d -o 939 -g 939 -m 755 /opt/so/conf/soc/fingerprints
|
||||||
install -o 939 -g 939 -m 644 /dev/null /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
install -o 939 -g 939 -m 644 /dev/null /opt/so/conf/soc/fingerprints/suricataengine.syncBlock
|
||||||
cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF
|
cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF
|
||||||
Suricata ruleset sync is blocked until this file is removed. Make sure that you have manually added any custom Suricata rulesets via SOC config - review the documentation for more details: securityonion.net/docs
|
Suricata ruleset sync is blocked until this file is removed. **CRITICAL** Make sure that you have manually added any custom Suricata rulesets via SOC config before removing this file - review the documentation for more details: https://docs.securityonion.net/en/2.4/nids.html#sync-block
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
# Remove possible symlink & create salt local rules dir
|
||||||
|
[ -L /opt/so/saltstack/local/salt/suricata/rules ] && rm -f /opt/so/saltstack/local/salt/suricata/rules
|
||||||
|
install -d -o 939 -g 939 /opt/so/saltstack/local/salt/suricata/rules/ || echo "Failed to create Suricata local rules directory"
|
||||||
|
|
||||||
# Backup custom rules & overrides
|
# Backup custom rules & overrides
|
||||||
mkdir -p /nsm/backup/detections-migration/2-4-200
|
mkdir -p /nsm/backup/detections-migration/2-4-200
|
||||||
cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200
|
cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200
|
||||||
@@ -1125,6 +1145,7 @@ if [[ -f /opt/so/conf/soc/so-detections-backup.py ]]; then
|
|||||||
# Verify backup by comparing counts
|
# Verify backup by comparing counts
|
||||||
echo "Verifying detection overrides backup..."
|
echo "Verifying detection overrides backup..."
|
||||||
es_override_count=$(/sbin/so-elasticsearch-query 'so-detection/_count' \
|
es_override_count=$(/sbin/so-elasticsearch-query 'so-detection/_count' \
|
||||||
|
--retry 5 --retry-delay 10 --retry-all-errors \
|
||||||
-d '{"query": {"bool": {"must": [{"exists": {"field": "so_detection.overrides"}}]}}}' | jq -r '.count') || {
|
-d '{"query": {"bool": {"must": [{"exists": {"field": "so_detection.overrides"}}]}}}' | jq -r '.count') || {
|
||||||
echo " Error: Failed to query Elasticsearch for override count"
|
echo " Error: Failed to query Elasticsearch for override count"
|
||||||
exit 1
|
exit 1
|
||||||
@@ -1179,14 +1200,39 @@ hash_normalized_file() {
|
|||||||
"$file" | sha256sum | awk '{print $1}'
|
"$file" | sha256sum | awk '{print $1}'
|
||||||
}
|
}
|
||||||
|
|
||||||
# Known-default hashes
|
# Known-default hashes for so-rule-update (ETOPEN ruleset)
|
||||||
KNOWN_SO_RULE_UPDATE_HASHES=(
|
KNOWN_SO_RULE_UPDATE_HASHES=(
|
||||||
"8f1fe1cb65c08aab78830315b952785c7ccdcc108c5c0474f427e29d4e39ee5f" # non-Airgap
|
# 2.4.100+ (suricata 7.0.3, non-airgap)
|
||||||
"d23ac5a962c709dcb888103effb71444df72b46009b6c426e280dbfbc7d74d40" # Airgap
|
"5fbd067ced86c8ec72ffb7e1798aa624123b536fb9d78f4b3ad8d3b45db1eae7" # 2.4.100-2.4.190 non-Airgap
|
||||||
|
# 2.4.90+ airgap (same for 2.4.90 and 2.4.100+)
|
||||||
|
"61f632c55791338c438c071040f1490066769bcce808b595b5cc7974a90e653a" # 2.4.90+ Airgap
|
||||||
|
# 2.4.90 (suricata 6.0, non-airgap, comment inside proxy block)
|
||||||
|
"0380ec52a05933244ab0f0bc506576e1d838483647b40612d5fe4b378e47aedd" # 2.4.90 non-Airgap
|
||||||
|
# 2.4.10-2.4.80 (suricata 6.0, non-airgap, comment outside proxy block)
|
||||||
|
"b6e4d1b5a78d57880ad038a9cd2cc6978aeb2dd27d48ea1a44dd866a2aee7ff4" # 2.4.10-2.4.80 non-Airgap
|
||||||
|
# 2.4.10-2.4.80 airgap
|
||||||
|
"b20146526ace2b142fde4664f1386a9a1defa319b3a1d113600ad33a1b037dad" # 2.4.10-2.4.80 Airgap
|
||||||
|
# 2.4.5 and earlier (no pidof check, non-airgap)
|
||||||
|
"d04f5e4015c348133d28a7840839e82d60009781eaaa1c66f7f67747703590dc" # 2.4.5 non-Airgap
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Known-default hashes for rulecat.conf
|
||||||
KNOWN_RULECAT_CONF_HASHES=(
|
KNOWN_RULECAT_CONF_HASHES=(
|
||||||
"17fc663a83b30d4ba43ac6643666b0c96343c5ea6ea833fe6a8362fe415b666b" # default
|
# 2.4.100+ (suricata 7.0.3)
|
||||||
|
"302e75dca9110807f09ade2eec3be1fcfc8b2bf6cf2252b0269bb72efeefe67e" # 2.4.100-2.4.190 without SURICATA md_engine
|
||||||
|
"8029b7718c324a9afa06a5cf180afde703da1277af4bdd30310a6cfa3d6398cb" # 2.4.100-2.4.190 with SURICATA md_engine
|
||||||
|
# 2.4.80-2.4.90 (suricata 6.0, with --suricata-version and --output)
|
||||||
|
"4d8b318e6950a6f60b02f307cf27c929efd39652990c1bd0c8820aa8a307e1e7" # 2.4.80-2.4.90 without SURICATA md_engine
|
||||||
|
"a1ddf264c86c4e91c81c5a317f745a19466d4311e4533ec3a3c91fed04c11678" # 2.4.80-2.4.90 with SURICATA md_engine
|
||||||
|
# 2.4.50-2.4.70 (/suri/ path, no --suricata-version)
|
||||||
|
"86e3afb8d0f00c62337195602636864c98580a13ca9cc85029661a539deae6ae" # 2.4.50-2.4.70 without SURICATA md_engine
|
||||||
|
"5a97604ca5b820a10273a2d6546bb5e00c5122ca5a7dfe0ba0bfbce5fc026f4b" # 2.4.50-2.4.70 with SURICATA md_engine
|
||||||
|
# 2.4.20-2.4.40 (/nids/ path without /suri/)
|
||||||
|
"d098ea9ecd94b5cca35bf33543f8ea8f48066a0785221fabda7fef43d2462c29" # 2.4.20-2.4.40 without SURICATA md_engine
|
||||||
|
"9dbc60df22ae20d65738ba42e620392577857038ba92278e23ec182081d191cd" # 2.4.20-2.4.40 with SURICATA md_engine
|
||||||
|
# 2.4.5-2.4.10 (/sorules/ path for extraction/filters)
|
||||||
|
"490f6843d9fca759ee74db3ada9c702e2440b8393f2cfaf07bbe41aaa6d955c3" # 2.4.5-2.4.10 with SURICATA md_engine
|
||||||
|
# Note: 2.4.5-2.4.10 without SURICATA md_engine has same hash as 2.4.20-2.4.40 without SURICATA md_engine
|
||||||
)
|
)
|
||||||
|
|
||||||
# Check a config file against known hashes
|
# Check a config file against known hashes
|
||||||
@@ -1270,8 +1316,14 @@ if [ -n "$(docker ps -q -f name=^so-idstools$)" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Removing idstools symlink and scripts..."
|
echo "Removing idstools symlink and scripts..."
|
||||||
rm /opt/so/saltstack/local/salt/suricata/rules
|
|
||||||
rm -rf /usr/sbin/so-idstools*
|
rm -rf /usr/sbin/so-idstools*
|
||||||
|
sed -i '/^#\?so-idstools$/d' /opt/so/conf/so-status/so-status.conf
|
||||||
|
|
||||||
|
# Backup the salt master config & manager pillar before editing it
|
||||||
|
cp /opt/so/saltstack/local/pillar/minions/$MINIONID.sls /nsm/backup/detections-migration/2-4-200/
|
||||||
|
cp /etc/salt/master /nsm/backup/detections-migration/2-4-200/
|
||||||
|
so-yaml.py remove /opt/so/saltstack/local/pillar/minions/$MINIONID.sls idstools
|
||||||
|
so-yaml.py removelistitem /etc/salt/master file_roots.base /opt/so/rules/nids
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1321,7 +1373,7 @@ unmount_update() {
|
|||||||
|
|
||||||
update_airgap_rules() {
|
update_airgap_rules() {
|
||||||
# Copy the rules over to update them for airgap.
|
# Copy the rules over to update them for airgap.
|
||||||
rsync -a $UPDATE_DIR/agrules/suricata/* /nsm/rules/suricata/
|
rsync -a --delete $UPDATE_DIR/agrules/suricata/ /nsm/rules/suricata/etopen/
|
||||||
rsync -a $UPDATE_DIR/agrules/detect-sigma/* /nsm/rules/detect-sigma/
|
rsync -a $UPDATE_DIR/agrules/detect-sigma/* /nsm/rules/detect-sigma/
|
||||||
rsync -a $UPDATE_DIR/agrules/detect-yara/* /nsm/rules/detect-yara/
|
rsync -a $UPDATE_DIR/agrules/detect-yara/* /nsm/rules/detect-yara/
|
||||||
# Copy the securityonion-resorces repo over for SOC Detection Summaries and checkout the published summaries branch
|
# Copy the securityonion-resorces repo over for SOC Detection Summaries and checkout the published summaries branch
|
||||||
@@ -1570,6 +1622,69 @@ verify_latest_update_script() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verify_es_version_compatibility() {
|
||||||
|
|
||||||
|
# supported upgrade paths for SO-ES versions
|
||||||
|
declare -A es_upgrade_map=(
|
||||||
|
["8.14.3"]="8.17.3 8.18.4 8.18.6 8.18.8"
|
||||||
|
["8.17.3"]="8.18.4 8.18.6 8.18.8"
|
||||||
|
["8.18.4"]="8.18.6 8.18.8 9.0.8"
|
||||||
|
["8.18.6"]="8.18.8 9.0.8"
|
||||||
|
["8.18.8"]="9.0.8"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Elasticsearch MUST upgrade through these versions
|
||||||
|
declare -A es_to_so_version=(
|
||||||
|
["8.18.8"]="2.4.190-20251024"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get current Elasticsearch version
|
||||||
|
if es_version_raw=$(so-elasticsearch-query / --fail --retry 5 --retry-delay 10); then
|
||||||
|
es_version=$(echo "$es_version_raw" | jq -r '.version.number' )
|
||||||
|
else
|
||||||
|
echo "Could not determine current Elasticsearch version to validate compatibility with post soup Elasticsearch version."
|
||||||
|
exit 160
|
||||||
|
fi
|
||||||
|
|
||||||
|
if ! target_es_version=$(so-yaml.py get $UPDATE_DIR/salt/elasticsearch/defaults.yaml elasticsearch.version | sed -n '1p'); then
|
||||||
|
# so-yaml.py failed to get the ES version from upgrade versions elasticsearch/defaults.yaml file. Likely they are upgrading to an SO version older than 2.4.110 prior to the ES version pinning and should be OKAY to continue with the upgrade.
|
||||||
|
|
||||||
|
# if so-yaml.py failed to get the ES version AND the version we are upgrading to is newer than 2.4.110 then we should bail
|
||||||
|
if [[ $(cat $UPDATE_DIR/VERSION | cut -d'.' -f3) > 110 ]]; then
|
||||||
|
echo "Couldn't determine the target Elasticsearch version (post soup version) to ensure compatibility with current Elasticsearch version. Exiting"
|
||||||
|
exit 160
|
||||||
|
fi
|
||||||
|
|
||||||
|
# allow upgrade to version < 2.4.110 without checking ES version compatibility
|
||||||
|
return 0
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
if [[ " ${es_upgrade_map[$es_version]} " =~ " $target_es_version " ]]; then
|
||||||
|
# supported upgrade
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
compatible_versions=${es_upgrade_map[$es_version]}
|
||||||
|
next_step_so_version=${es_to_so_version[${compatible_versions##* }]}
|
||||||
|
echo -e "\n##############################################################################################################################\n"
|
||||||
|
echo -e "You are currently running Security Onion $INSTALLEDVERSION. You will need to update to version $next_step_so_version before updating to $(cat $UPDATE_DIR/VERSION).\n"
|
||||||
|
|
||||||
|
if [[ $is_airgap -eq 0 ]]; then
|
||||||
|
echo "You can download the $next_step_so_version ISO image from https://download.securityonion.net/file/securityonion/securityonion-$next_step_so_version.iso"
|
||||||
|
else
|
||||||
|
echo "You can use the following soup command to upgrade to $next_step_so_version;"
|
||||||
|
echo -e " sudo BRANCH=$next_step_so_version soup\n"
|
||||||
|
|
||||||
|
fi
|
||||||
|
echo "*** Once you have updated to $next_step_so_version, you can then run soup again to update to $(cat $UPDATE_DIR/VERSION). ***"
|
||||||
|
echo -e "\n###############################################################################################################################\n"
|
||||||
|
exit 160
|
||||||
|
fi
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
# Keeping this block in case we need to do a hotfix that requires salt update
|
# Keeping this block in case we need to do a hotfix that requires salt update
|
||||||
apply_hotfix() {
|
apply_hotfix() {
|
||||||
if [[ "$INSTALLEDVERSION" == "2.4.20" ]] ; then
|
if [[ "$INSTALLEDVERSION" == "2.4.20" ]] ; then
|
||||||
@@ -1666,6 +1781,8 @@ main() {
|
|||||||
echo "Verifying we have the latest soup script."
|
echo "Verifying we have the latest soup script."
|
||||||
verify_latest_update_script
|
verify_latest_update_script
|
||||||
|
|
||||||
|
verify_es_version_compatibility
|
||||||
|
|
||||||
echo "Let's see if we need to update Security Onion."
|
echo "Let's see if we need to update Security Onion."
|
||||||
upgrade_check
|
upgrade_check
|
||||||
upgrade_space
|
upgrade_space
|
||||||
|
|||||||
@@ -1622,12 +1622,11 @@ soc:
|
|||||||
sourceType: directory
|
sourceType: directory
|
||||||
airgap:
|
airgap:
|
||||||
- name: Emerging-Threats
|
- name: Emerging-Threats
|
||||||
description: "Emerging Threats ruleset - To enable ET Pro, enter your license key below. Leave empty for ET Open (free) rules."
|
description: "Emerging Threats ruleset - To enable ET Pro on Airgap, review the documentation at https://docs.securityonion.net/suricata"
|
||||||
licenseKey: ""
|
licenseKey: ""
|
||||||
enabled: true
|
enabled: true
|
||||||
sourceType: url
|
sourceType: directory
|
||||||
sourcePath: 'https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz'
|
sourcePath: /nsm/rules/suricata/etopen/
|
||||||
urlHash: "https://rules.emergingthreats.net/open/suricata/emerging.rules.tar.gz.md5"
|
|
||||||
license: "BSD"
|
license: "BSD"
|
||||||
excludeFiles:
|
excludeFiles:
|
||||||
- "*deleted*"
|
- "*deleted*"
|
||||||
@@ -2653,12 +2652,6 @@ soc:
|
|||||||
thresholdColorRatioMed: 0.75
|
thresholdColorRatioMed: 0.75
|
||||||
thresholdColorRatioMax: 1
|
thresholdColorRatioMax: 1
|
||||||
availableModels:
|
availableModels:
|
||||||
- id: sonnet-4
|
|
||||||
displayName: Claude Sonnet 4
|
|
||||||
contextLimitSmall: 200000
|
|
||||||
contextLimitLarge: 1000000
|
|
||||||
lowBalanceColorAlert: 500000
|
|
||||||
enabled: true
|
|
||||||
- id: sonnet-4.5
|
- id: sonnet-4.5
|
||||||
displayName: Claude Sonnet 4.5
|
displayName: Claude Sonnet 4.5
|
||||||
contextLimitSmall: 200000
|
contextLimitSmall: 200000
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
{# Define the Detections custom ruleset that should always be present #}
|
{# Define the Detections custom ruleset that should always be present #}
|
||||||
{% set CUSTOM_RULESET = {
|
{% set CUSTOM_RULESET = {
|
||||||
'name': 'custom',
|
'name': '__custom__',
|
||||||
'description': 'User-created custom rules created via the Detections module in the SOC UI',
|
'description': 'User-created custom rules created via the Detections module in the SOC UI',
|
||||||
'sourceType': 'elasticsearch',
|
'sourceType': 'elasticsearch',
|
||||||
'sourcePath': 'so_detection.ruleset:__custom__',
|
'sourcePath': 'so_detection.ruleset:__custom__',
|
||||||
@@ -83,7 +83,7 @@
|
|||||||
{# Always append the custom ruleset to suricataengine.rulesetSources if not already present #}
|
{# Always append the custom ruleset to suricataengine.rulesetSources if not already present #}
|
||||||
{% if SOCMERGED.config.server.modules.suricataengine is defined and SOCMERGED.config.server.modules.suricataengine.rulesetSources is defined %}
|
{% if SOCMERGED.config.server.modules.suricataengine is defined and SOCMERGED.config.server.modules.suricataengine.rulesetSources is defined %}
|
||||||
{% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is not mapping %}
|
{% if SOCMERGED.config.server.modules.suricataengine.rulesetSources is not mapping %}
|
||||||
{% set custom_names = SOCMERGED.config.server.modules.suricataengine.rulesetSources | selectattr('name', 'equalto', 'custom') | list %}
|
{% set custom_names = SOCMERGED.config.server.modules.suricataengine.rulesetSources | selectattr('name', 'equalto', '__custom__') | list %}
|
||||||
{% if custom_names | length == 0 %}
|
{% if custom_names | length == 0 %}
|
||||||
{% do SOCMERGED.config.server.modules.suricataengine.rulesetSources.append(CUSTOM_RULESET) %}
|
{% do SOCMERGED.config.server.modules.suricataengine.rulesetSources.append(CUSTOM_RULESET) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -108,6 +108,14 @@
|
|||||||
{% if ruleset.name == 'Emerging-Threats' %}
|
{% if ruleset.name == 'Emerging-Threats' %}
|
||||||
{% if ruleset.licenseKey and ruleset.licenseKey != '' %}
|
{% if ruleset.licenseKey and ruleset.licenseKey != '' %}
|
||||||
{# License key is defined - transform to ETPRO #}
|
{# License key is defined - transform to ETPRO #}
|
||||||
|
{% if ruleset.sourceType == 'directory' %}
|
||||||
|
{# Airgap mode - update directory path #}
|
||||||
|
{% do ruleset.update({
|
||||||
|
'name': 'ETPRO',
|
||||||
|
'sourcePath': '/nsm/rules/custom-local-repos/local-etpro-suricata/etpro.rules.tar.gz',
|
||||||
|
'license': 'Commercial'
|
||||||
|
}) %}
|
||||||
|
{% else %}
|
||||||
{# Engine Version is hardcoded in the URL - this does not change often: https://community.emergingthreats.net/t/supported-engines/71 #}
|
{# Engine Version is hardcoded in the URL - this does not change often: https://community.emergingthreats.net/t/supported-engines/71 #}
|
||||||
{% do ruleset.update({
|
{% do ruleset.update({
|
||||||
'name': 'ETPRO',
|
'name': 'ETPRO',
|
||||||
@@ -115,8 +123,17 @@
|
|||||||
'urlHash': 'https://rules.emergingthreatspro.com/' ~ ruleset.licenseKey ~ '/suricata-7.0.3/etpro.rules.tar.gz.md5',
|
'urlHash': 'https://rules.emergingthreatspro.com/' ~ ruleset.licenseKey ~ '/suricata-7.0.3/etpro.rules.tar.gz.md5',
|
||||||
'license': 'Commercial'
|
'license': 'Commercial'
|
||||||
}) %}
|
}) %}
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
{# No license key - explicitly set to ETOPEN #}
|
{# No license key - explicitly set to ETOPEN #}
|
||||||
|
{% if ruleset.sourceType == 'directory' %}
|
||||||
|
{# Airgap mode - update directory path #}
|
||||||
|
{% do ruleset.update({
|
||||||
|
'name': 'ETOPEN',
|
||||||
|
'sourcePath': '/nsm/rules/suricata/etopen/',
|
||||||
|
'license': 'BSD'
|
||||||
|
}) %}
|
||||||
|
{% else %}
|
||||||
{% do ruleset.update({
|
{% do ruleset.update({
|
||||||
'name': 'ETOPEN',
|
'name': 'ETOPEN',
|
||||||
'sourcePath': 'https://rules.emergingthreats.net/open/suricata-7.0.3/emerging.rules.tar.gz',
|
'sourcePath': 'https://rules.emergingthreats.net/open/suricata-7.0.3/emerging.rules.tar.gz',
|
||||||
@@ -125,6 +142,7 @@
|
|||||||
}) %}
|
}) %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -608,6 +608,18 @@ soc:
|
|||||||
label: Delete Unreferenced (Deletes rules that are no longer referenced by ruleset source)
|
label: Delete Unreferenced (Deletes rules that are no longer referenced by ruleset source)
|
||||||
forcedType: bool
|
forcedType: bool
|
||||||
required: False
|
required: False
|
||||||
|
- field: proxyURL
|
||||||
|
label: HTTP/HTTPS proxy URL for downloading the ruleset.
|
||||||
|
required: False
|
||||||
|
- field: proxyUsername
|
||||||
|
label: Proxy authentication username.
|
||||||
|
required: False
|
||||||
|
- field: proxyPassword
|
||||||
|
label: Proxy authentication password.
|
||||||
|
required: False
|
||||||
|
- field: proxyCACert
|
||||||
|
label: Path to CA certificate file for MITM proxy verification.
|
||||||
|
required: False
|
||||||
airgap: *serulesetSources
|
airgap: *serulesetSources
|
||||||
navigator:
|
navigator:
|
||||||
intervalMinutes:
|
intervalMinutes:
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ surirulesync:
|
|||||||
- name: /opt/so/rules/suricata/
|
- name: /opt/so/rules/suricata/
|
||||||
- source: salt://suricata/rules/
|
- source: salt://suricata/rules/
|
||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 939
|
||||||
- show_changes: False
|
- show_changes: False
|
||||||
|
|
||||||
surilogscript:
|
surilogscript:
|
||||||
@@ -160,7 +160,6 @@ surithresholding:
|
|||||||
- source: salt://suricata/files/threshold.conf
|
- source: salt://suricata/files/threshold.conf
|
||||||
- user: 940
|
- user: 940
|
||||||
- group: 940
|
- group: 940
|
||||||
- onlyif: salt://suricata/files/threshold.conf
|
|
||||||
|
|
||||||
suriclassifications:
|
suriclassifications:
|
||||||
file.managed:
|
file.managed:
|
||||||
@@ -178,6 +177,14 @@ so-suricata-eve-clean:
|
|||||||
- template: jinja
|
- template: jinja
|
||||||
- source: salt://suricata/cron/so-suricata-eve-clean
|
- source: salt://suricata/cron/so-suricata-eve-clean
|
||||||
|
|
||||||
|
so-suricata-rulestats:
|
||||||
|
file.managed:
|
||||||
|
- name: /usr/sbin/so-suricata-rulestats
|
||||||
|
- user: root
|
||||||
|
- group: root
|
||||||
|
- mode: 755
|
||||||
|
- source: salt://suricata/cron/so-suricata-rulestats
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
39
salt/suricata/cron/so-suricata-rulestats
Normal file
39
salt/suricata/cron/so-suricata-rulestats
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# Query Suricata for ruleset stats and reload time, write to JSON file for Telegraf to consume
|
||||||
|
|
||||||
|
OUTFILE="/opt/so/log/suricata/rulestats.json"
|
||||||
|
SURICATASC="docker exec so-suricata /opt/suricata/bin/suricatasc"
|
||||||
|
SOCKET="/var/run/suricata/suricata-command.socket"
|
||||||
|
|
||||||
|
query() {
|
||||||
|
timeout 10 $SURICATASC -c "$1" "$SOCKET" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
STATS=$(query "ruleset-stats")
|
||||||
|
RELOAD=$(query "ruleset-reload-time")
|
||||||
|
[ -z "$RELOAD" ] && RELOAD='{}'
|
||||||
|
|
||||||
|
# Outputs valid JSON on success, empty on failure
|
||||||
|
OUTPUT=$(jq -n \
|
||||||
|
--argjson stats "$STATS" \
|
||||||
|
--argjson reload "$RELOAD" \
|
||||||
|
'if $stats.return == "OK" and ($stats.message[0].rules_loaded | type) == "number" and ($stats.message[0].rules_failed | type) == "number" then
|
||||||
|
{
|
||||||
|
rules_loaded: $stats.message[0].rules_loaded,
|
||||||
|
rules_failed: $stats.message[0].rules_failed,
|
||||||
|
last_reload: ($reload.message[0].last_reload // ""),
|
||||||
|
return: "OK"
|
||||||
|
}
|
||||||
|
else empty end' 2>/dev/null)
|
||||||
|
|
||||||
|
if [ -n "$OUTPUT" ]; then
|
||||||
|
echo "$OUTPUT" > "$OUTFILE"
|
||||||
|
else
|
||||||
|
echo '{"return":"FAIL"}' > "$OUTFILE"
|
||||||
|
fi
|
||||||
@@ -23,6 +23,11 @@ clean_suricata_eve_files:
|
|||||||
cron.absent:
|
cron.absent:
|
||||||
- identifier: clean_suricata_eve_files
|
- identifier: clean_suricata_eve_files
|
||||||
|
|
||||||
|
# Remove rulestats cron
|
||||||
|
rulestats:
|
||||||
|
cron.absent:
|
||||||
|
- identifier: suricata_rulestats
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
@@ -90,6 +90,18 @@ clean_suricata_eve_files:
|
|||||||
- month: '*'
|
- month: '*'
|
||||||
- dayweek: '*'
|
- dayweek: '*'
|
||||||
|
|
||||||
|
# Add rulestats cron - runs every minute to query Suricata for rule load status
|
||||||
|
suricata_rulestats:
|
||||||
|
cron.present:
|
||||||
|
- name: /usr/sbin/so-suricata-rulestats > /dev/null 2>&1
|
||||||
|
- identifier: suricata_rulestats
|
||||||
|
- user: root
|
||||||
|
- minute: '*'
|
||||||
|
- hour: '*'
|
||||||
|
- daymonth: '*'
|
||||||
|
- month: '*'
|
||||||
|
- dayweek: '*'
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{{sls}}_state_not_allowed:
|
{{sls}}_state_not_allowed:
|
||||||
|
|||||||
2
salt/suricata/files/threshold.conf
Normal file
2
salt/suricata/files/threshold.conf
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# Threshold configuration generated by Security Onion
|
||||||
|
# This file is automatically generated - do not edit manually
|
||||||
@@ -21,6 +21,7 @@ telegraf:
|
|||||||
- sostatus.sh
|
- sostatus.sh
|
||||||
- stenoloss.sh
|
- stenoloss.sh
|
||||||
- suriloss.sh
|
- suriloss.sh
|
||||||
|
- surirules.sh
|
||||||
- zeekcaptureloss.sh
|
- zeekcaptureloss.sh
|
||||||
- zeekloss.sh
|
- zeekloss.sh
|
||||||
standalone:
|
standalone:
|
||||||
@@ -36,6 +37,7 @@ telegraf:
|
|||||||
- sostatus.sh
|
- sostatus.sh
|
||||||
- stenoloss.sh
|
- stenoloss.sh
|
||||||
- suriloss.sh
|
- suriloss.sh
|
||||||
|
- surirules.sh
|
||||||
- zeekcaptureloss.sh
|
- zeekcaptureloss.sh
|
||||||
- zeekloss.sh
|
- zeekloss.sh
|
||||||
- features.sh
|
- features.sh
|
||||||
@@ -81,6 +83,7 @@ telegraf:
|
|||||||
- sostatus.sh
|
- sostatus.sh
|
||||||
- stenoloss.sh
|
- stenoloss.sh
|
||||||
- suriloss.sh
|
- suriloss.sh
|
||||||
|
- surirules.sh
|
||||||
- zeekcaptureloss.sh
|
- zeekcaptureloss.sh
|
||||||
- zeekloss.sh
|
- zeekloss.sh
|
||||||
- features.sh
|
- features.sh
|
||||||
@@ -95,6 +98,7 @@ telegraf:
|
|||||||
- sostatus.sh
|
- sostatus.sh
|
||||||
- stenoloss.sh
|
- stenoloss.sh
|
||||||
- suriloss.sh
|
- suriloss.sh
|
||||||
|
- surirules.sh
|
||||||
- zeekcaptureloss.sh
|
- zeekcaptureloss.sh
|
||||||
- zeekloss.sh
|
- zeekloss.sh
|
||||||
idh:
|
idh:
|
||||||
|
|||||||
34
salt/telegraf/scripts/surirules.sh
Normal file
34
salt/telegraf/scripts/surirules.sh
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
# Read Suricata ruleset stats from JSON file written by so-suricata-rulestats cron job
|
||||||
|
# JSON format: {"rules_loaded":45879,"rules_failed":1,"last_reload":"2025-12-04T14:10:57+0000","return":"OK"}
|
||||||
|
# or on failure: {"return":"FAIL"}
|
||||||
|
|
||||||
|
# if this script isn't already running
|
||||||
|
if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then
|
||||||
|
|
||||||
|
STATSFILE="/var/log/suricata/rulestats.json"
|
||||||
|
|
||||||
|
# Check file exists, is less than 90 seconds old, and has valid data
|
||||||
|
if [ -f "$STATSFILE" ] && [ $(($(date +%s) - $(stat -c %Y "$STATSFILE"))) -lt 90 ] && jq -e '.return == "OK" and .rules_loaded != null and .rules_failed != null' "$STATSFILE" > /dev/null 2>&1; then
|
||||||
|
LOADED=$(jq -r '.rules_loaded' "$STATSFILE")
|
||||||
|
FAILED=$(jq -r '.rules_failed' "$STATSFILE")
|
||||||
|
RELOAD_TIME=$(jq -r 'if .last_reload then .last_reload else "" end' "$STATSFILE")
|
||||||
|
|
||||||
|
if [ -n "$RELOAD_TIME" ]; then
|
||||||
|
echo "surirules loaded=${LOADED}i,failed=${FAILED}i,reload_time=\"${RELOAD_TIME}\",status=\"ok\""
|
||||||
|
else
|
||||||
|
echo "surirules loaded=${LOADED}i,failed=${FAILED}i,status=\"ok\""
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "surirules loaded=0i,failed=0i,status=\"unknown\""
|
||||||
|
fi
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
exit 0
|
||||||
@@ -656,11 +656,11 @@ check_requirements() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $total_mem_hr -lt $req_mem ]]; then
|
if [[ $total_mem_hr -lt $req_mem ]]; then
|
||||||
whiptail_requirements_error "memory" "${total_mem_hr} GB" "${req_mem} GB"
|
|
||||||
if [[ $is_standalone || $is_heavynode ]]; then
|
if [[ $is_standalone || $is_heavynode ]]; then
|
||||||
echo "This install type will fail with less than $req_mem GB of memory. Exiting setup."
|
echo "This install type will fail with less than $req_mem GB of memory. Exiting setup."
|
||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
whiptail_requirements_error "memory" "${total_mem_hr} GB" "${req_mem} GB"
|
||||||
fi
|
fi
|
||||||
if [[ $is_standalone || $is_heavynode ]]; then
|
if [[ $is_standalone || $is_heavynode ]]; then
|
||||||
if [[ $total_mem_hr -gt 15 && $total_mem_hr -lt 24 ]]; then
|
if [[ $total_mem_hr -gt 15 && $total_mem_hr -lt 24 ]]; then
|
||||||
@@ -1598,16 +1598,21 @@ proxy_validate() {
|
|||||||
|
|
||||||
reserve_group_ids() {
|
reserve_group_ids() {
|
||||||
# This is a hack to fix OS from taking group IDs that we need
|
# This is a hack to fix OS from taking group IDs that we need
|
||||||
|
logCmd "groupadd -g 920 docker"
|
||||||
logCmd "groupadd -g 928 kratos"
|
logCmd "groupadd -g 928 kratos"
|
||||||
logCmd "groupadd -g 930 elasticsearch"
|
logCmd "groupadd -g 930 elasticsearch"
|
||||||
logCmd "groupadd -g 931 logstash"
|
logCmd "groupadd -g 931 logstash"
|
||||||
logCmd "groupadd -g 932 kibana"
|
logCmd "groupadd -g 932 kibana"
|
||||||
logCmd "groupadd -g 933 elastalert"
|
logCmd "groupadd -g 933 elastalert"
|
||||||
logCmd "groupadd -g 937 zeek"
|
logCmd "groupadd -g 937 zeek"
|
||||||
|
logCmd "groupadd -g 938 salt"
|
||||||
|
logCmd "groupadd -g 939 socore"
|
||||||
logCmd "groupadd -g 940 suricata"
|
logCmd "groupadd -g 940 suricata"
|
||||||
|
logCmd "groupadd -g 948 elastic-agent-pr"
|
||||||
|
logCmd "groupadd -g 949 elastic-agent"
|
||||||
logCmd "groupadd -g 941 stenographer"
|
logCmd "groupadd -g 941 stenographer"
|
||||||
logCmd "groupadd -g 945 ossec"
|
logCmd "groupadd -g 947 elastic-fleet"
|
||||||
logCmd "groupadd -g 946 cyberchef"
|
logCmd "groupadd -g 960 kafka"
|
||||||
}
|
}
|
||||||
|
|
||||||
reserve_ports() {
|
reserve_ports() {
|
||||||
|
|||||||
@@ -682,6 +682,8 @@ if ! [[ -f $install_opt_file ]]; then
|
|||||||
fi
|
fi
|
||||||
info "Reserving ports"
|
info "Reserving ports"
|
||||||
reserve_ports
|
reserve_ports
|
||||||
|
info "Reserving group ids"
|
||||||
|
reserve_group_ids
|
||||||
info "Setting Paths"
|
info "Setting Paths"
|
||||||
# Set the paths
|
# Set the paths
|
||||||
set_path
|
set_path
|
||||||
@@ -840,7 +842,10 @@ if ! [[ -f $install_opt_file ]]; then
|
|||||||
if [[ $monints ]]; then
|
if [[ $monints ]]; then
|
||||||
configure_network_sensor
|
configure_network_sensor
|
||||||
fi
|
fi
|
||||||
|
info "Reserving ports"
|
||||||
reserve_ports
|
reserve_ports
|
||||||
|
info "Reserving group ids"
|
||||||
|
reserve_group_ids
|
||||||
# Set the version
|
# Set the version
|
||||||
mark_version
|
mark_version
|
||||||
# Disable the setup from prompting at login
|
# Disable the setup from prompting at login
|
||||||
|
|||||||
Reference in New Issue
Block a user