mirror of
https://github.com/Security-Onion-Solutions/securityonion.git
synced 2025-12-10 11:12:51 +01:00
Merge remote-tracking branch 'origin/2.4/dev' into 2.4/soup-playbook
This commit is contained in:
@@ -27,6 +27,15 @@ repo_log_dir:
|
||||
- user
|
||||
- group
|
||||
|
||||
agents_log_dir:
|
||||
file.directory:
|
||||
- name: /opt/so/log/agents
|
||||
- user: root
|
||||
- group: root
|
||||
- recurse:
|
||||
- user
|
||||
- group
|
||||
|
||||
yara_log_dir:
|
||||
file.directory:
|
||||
- name: /opt/so/log/yarasync
|
||||
@@ -101,6 +110,17 @@ so-repo-sync:
|
||||
- hour: '{{ MANAGERMERGED.reposync.hour }}'
|
||||
- minute: '{{ MANAGERMERGED.reposync.minute }}'
|
||||
|
||||
so_fleetagent_status:
|
||||
cron.present:
|
||||
- name: /usr/sbin/so-elasticagent-status > /opt/so/log/agents/agentstatus.log 2>&1
|
||||
- identifier: so_fleetagent_status
|
||||
- user: root
|
||||
- minute: '*/5'
|
||||
- hour: '*'
|
||||
- daymonth: '*'
|
||||
- month: '*'
|
||||
- dayweek: '*'
|
||||
|
||||
socore_own_saltstack:
|
||||
file.directory:
|
||||
- name: /opt/so/saltstack
|
||||
|
||||
10
salt/manager/tools/sbin/so-elasticagent-status
Normal file
10
salt/manager/tools/sbin/so-elasticagent-status
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/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.
|
||||
|
||||
. /usr/sbin/so-common
|
||||
|
||||
curl -s -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/agent_status" | jq .
|
||||
@@ -17,13 +17,16 @@ def showUsage(args):
|
||||
print('Usage: {} <COMMAND> <YAML_FILE> [ARGS...]'.format(sys.argv[0]))
|
||||
print(' General commands:')
|
||||
print(' append - Append a list item to a yaml key, if it exists and is a list. Requires KEY and LISTITEM args.')
|
||||
print(' add - Add a new key and set its value. Fails if key already exists. Requires KEY and VALUE args.')
|
||||
print(' remove - Removes a yaml key, if it exists. Requires KEY arg.')
|
||||
print(' replace - Replaces (or adds) a new key and set its value. Requires KEY and VALUE args.')
|
||||
print(' help - Prints this usage information.')
|
||||
print('')
|
||||
print(' Where:')
|
||||
print(' YAML_FILE - Path to the file that will be modified. Ex: /opt/so/conf/service/conf.yaml')
|
||||
print(' KEY - YAML key, does not support \' or " characters at this time. Ex: level1.level2')
|
||||
print(' LISTITEM - Item to add to the list.')
|
||||
print(' VALUE - Value to set for a given key')
|
||||
print(' LISTITEM - Item to append to a given key\'s list value')
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
@@ -37,6 +40,7 @@ def writeYaml(filename, content):
|
||||
file = open(filename, "w")
|
||||
return yaml.dump(content, file)
|
||||
|
||||
|
||||
def appendItem(content, key, listItem):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
@@ -51,6 +55,30 @@ def appendItem(content, key, listItem):
|
||||
print("The key provided does not exist. No action was taken on the file.")
|
||||
return 1
|
||||
|
||||
|
||||
def convertType(value):
|
||||
if len(value) > 0 and (not value.startswith("0") or len(value) == 1):
|
||||
if "." in value:
|
||||
try:
|
||||
value = float(value)
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
value = int(value)
|
||||
return value
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
lowered_value = value.lower()
|
||||
if lowered_value == "false":
|
||||
return False
|
||||
elif lowered_value == "true":
|
||||
return True
|
||||
return value
|
||||
|
||||
|
||||
def append(args):
|
||||
if len(args) != 3:
|
||||
print('Missing filename, key arg, or list item to append', file=sys.stderr)
|
||||
@@ -62,11 +90,41 @@ def append(args):
|
||||
listItem = args[2]
|
||||
|
||||
content = loadYaml(filename)
|
||||
appendItem(content, key, listItem)
|
||||
appendItem(content, key, convertType(listItem))
|
||||
writeYaml(filename, content)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def addKey(content, key, value):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
if not pieces[0] in content:
|
||||
content[pieces[0]] = {}
|
||||
addKey(content[pieces[0]], pieces[1], value)
|
||||
elif key in content:
|
||||
raise KeyError("key already exists")
|
||||
else:
|
||||
content[key] = value
|
||||
|
||||
|
||||
def add(args):
|
||||
if len(args) != 3:
|
||||
print('Missing filename, key arg, and/or value', file=sys.stderr)
|
||||
showUsage(None)
|
||||
return
|
||||
|
||||
filename = args[0]
|
||||
key = args[1]
|
||||
value = args[2]
|
||||
|
||||
content = loadYaml(filename)
|
||||
addKey(content, key, convertType(value))
|
||||
writeYaml(filename, content)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def removeKey(content, key):
|
||||
pieces = key.split(".", 1)
|
||||
if len(pieces) > 1:
|
||||
@@ -91,6 +149,24 @@ def remove(args):
|
||||
return 0
|
||||
|
||||
|
||||
def replace(args):
|
||||
if len(args) != 3:
|
||||
print('Missing filename, key arg, and/or value', file=sys.stderr)
|
||||
showUsage(None)
|
||||
return
|
||||
|
||||
filename = args[0]
|
||||
key = args[1]
|
||||
value = args[2]
|
||||
|
||||
content = loadYaml(filename)
|
||||
removeKey(content, key)
|
||||
addKey(content, key, convertType(value))
|
||||
writeYaml(filename, content)
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def main():
|
||||
args = sys.argv[1:]
|
||||
|
||||
@@ -100,8 +176,10 @@ def main():
|
||||
|
||||
commands = {
|
||||
"help": showUsage,
|
||||
"add": add,
|
||||
"append": append,
|
||||
"remove": remove,
|
||||
"replace": replace,
|
||||
}
|
||||
|
||||
code = 1
|
||||
|
||||
@@ -42,6 +42,14 @@ class TestRemove(unittest.TestCase):
|
||||
sysmock.assert_called()
|
||||
self.assertIn(mock_stdout.getvalue(), "Usage:")
|
||||
|
||||
def test_remove_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stdout:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.remove(["file"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn(mock_stdout.getvalue(), "Missing filename or key arg\n")
|
||||
|
||||
def test_remove(self):
|
||||
filename = "/tmp/so-yaml_test-remove.yaml"
|
||||
file = open(filename, "w")
|
||||
@@ -106,6 +114,14 @@ class TestRemove(unittest.TestCase):
|
||||
sysmock.assert_called_once_with(1)
|
||||
self.assertIn(mock_stdout.getvalue(), "Missing filename or key arg\n")
|
||||
|
||||
def test_append_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stdout:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.append(["file", "key"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn(mock_stdout.getvalue(), "Missing filename, key arg, or list item to append\n")
|
||||
|
||||
def test_append(self):
|
||||
filename = "/tmp/so-yaml_test-remove.yaml"
|
||||
file = open(filename, "w")
|
||||
@@ -201,3 +217,146 @@ class TestRemove(unittest.TestCase):
|
||||
soyaml.main()
|
||||
sysmock.assert_called()
|
||||
self.assertEqual(mock_stdout.getvalue(), "The existing value for the given key is not a list. No action was taken on the file.\n")
|
||||
|
||||
def test_add_key(self):
|
||||
content = {}
|
||||
soyaml.addKey(content, "foo", 123)
|
||||
self.assertEqual(content, {"foo": 123})
|
||||
|
||||
try:
|
||||
soyaml.addKey(content, "foo", "bar")
|
||||
self.assertFail("expected key error since key already exists")
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
try:
|
||||
soyaml.addKey(content, "foo.bar", 123)
|
||||
self.assertFail("expected type error since key parent value is not a map")
|
||||
except TypeError:
|
||||
pass
|
||||
|
||||
content = {}
|
||||
soyaml.addKey(content, "foo", "bar")
|
||||
self.assertEqual(content, {"foo": "bar"})
|
||||
|
||||
soyaml.addKey(content, "badda.badda", "boom")
|
||||
self.assertEqual(content, {"foo": "bar", "badda": {"badda": "boom"}})
|
||||
|
||||
def test_add_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stdout:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.add(["file", "key"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn(mock_stdout.getvalue(), "Missing filename, key arg, and/or value\n")
|
||||
|
||||
def test_add(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: abc }, key2: false, key3: [a,b,c]}")
|
||||
file.close()
|
||||
|
||||
soyaml.add([filename, "key4", "d"])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
expected = "key1:\n child1: 123\n child2: abc\nkey2: false\nkey3:\n- a\n- b\n- c\nkey4: d\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_add_nested(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: [a,b,c] }, key2: false, key3: [e,f,g]}")
|
||||
file.close()
|
||||
|
||||
soyaml.add([filename, "key1.child3", "d"])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2:\n - a\n - b\n - c\n child3: d\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_add_nested_deep(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}")
|
||||
file.close()
|
||||
|
||||
soyaml.add([filename, "key1.child2.deep2", "d"])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2:\n deep1: 45\n deep2: d\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replace_missing_arg(self):
|
||||
with patch('sys.exit', new=MagicMock()) as sysmock:
|
||||
with patch('sys.stderr', new=StringIO()) as mock_stdout:
|
||||
sys.argv = ["cmd", "help"]
|
||||
soyaml.replace(["file", "key"])
|
||||
sysmock.assert_called()
|
||||
self.assertIn(mock_stdout.getvalue(), "Missing filename, key arg, and/or value\n")
|
||||
|
||||
def test_replace(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: abc }, key2: false, key3: [a,b,c]}")
|
||||
file.close()
|
||||
|
||||
soyaml.replace([filename, "key2", True])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
expected = "key1:\n child1: 123\n child2: abc\nkey2: true\nkey3:\n- a\n- b\n- c\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replace_nested(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: [a,b,c] }, key2: false, key3: [e,f,g]}")
|
||||
file.close()
|
||||
|
||||
soyaml.replace([filename, "key1.child2", "d"])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2: d\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_replace_nested_deep(self):
|
||||
filename = "/tmp/so-yaml_test-add.yaml"
|
||||
file = open(filename, "w")
|
||||
file.write("{key1: { child1: 123, child2: { deep1: 45 } }, key2: false, key3: [e,f,g]}")
|
||||
file.close()
|
||||
|
||||
soyaml.replace([filename, "key1.child2.deep1", 46])
|
||||
|
||||
file = open(filename, "r")
|
||||
actual = file.read()
|
||||
file.close()
|
||||
|
||||
expected = "key1:\n child1: 123\n child2:\n deep1: 46\nkey2: false\nkey3:\n- e\n- f\n- g\n"
|
||||
self.assertEqual(actual, expected)
|
||||
|
||||
def test_convert(self):
|
||||
self.assertEqual(soyaml.convertType("foo"), "foo")
|
||||
self.assertEqual(soyaml.convertType("foo.bar"), "foo.bar")
|
||||
self.assertEqual(soyaml.convertType("123"), 123)
|
||||
self.assertEqual(soyaml.convertType("0"), 0)
|
||||
self.assertEqual(soyaml.convertType("00"), "00")
|
||||
self.assertEqual(soyaml.convertType("0123"), "0123")
|
||||
self.assertEqual(soyaml.convertType("123.456"), 123.456)
|
||||
self.assertEqual(soyaml.convertType("0123.456"), "0123.456")
|
||||
self.assertEqual(soyaml.convertType("true"), True)
|
||||
self.assertEqual(soyaml.convertType("TRUE"), True)
|
||||
self.assertEqual(soyaml.convertType("false"), False)
|
||||
self.assertEqual(soyaml.convertType("FALSE"), False)
|
||||
self.assertEqual(soyaml.convertType(""), "")
|
||||
|
||||
@@ -229,7 +229,7 @@ check_local_mods() {
|
||||
# {% endraw %}
|
||||
|
||||
check_pillar_items() {
|
||||
local pillar_output=$(salt-call pillar.items --out=json)
|
||||
local pillar_output=$(salt-call pillar.items -lerror --out=json)
|
||||
|
||||
cond=$(jq '.local | has("_errors")' <<< "$pillar_output")
|
||||
if [[ "$cond" == "true" ]]; then
|
||||
@@ -375,6 +375,7 @@ postupgrade_changes() {
|
||||
[[ "$POSTVERSION" == 2.4.40 ]] && post_to_2.4.50
|
||||
[[ "$POSTVERSION" == 2.4.50 ]] && post_to_2.4.60
|
||||
[[ "$POSTVERSION" == 2.4.60 ]] && post_to_2.4.70
|
||||
[[ "$POSTVERSION" == 2.4.60 ]] && post_to_2.4.70
|
||||
true
|
||||
}
|
||||
|
||||
@@ -582,6 +583,46 @@ up_to_2.4.60() {
|
||||
}
|
||||
|
||||
up_to_2.4.70() {
|
||||
playbook_migration
|
||||
toggle_telemetry
|
||||
INSTALLEDVERSION=2.4.70
|
||||
}
|
||||
|
||||
toggle_telemetry() {
|
||||
if [[ -z $UNATTENDED && $is_airgap -ne 0 ]]; then
|
||||
cat << ASSIST_EOF
|
||||
|
||||
--------------- SOC Telemetry ---------------
|
||||
|
||||
The Security Onion development team could use your help! Enabling SOC
|
||||
Telemetry will help the team understand which UI features are being
|
||||
used and enables informed prioritization of future development.
|
||||
|
||||
Adjust this setting at anytime via the SOC Configuration screen.
|
||||
|
||||
Documentation: https://docs.securityonion.net/en/2.4/telemetry.html
|
||||
|
||||
ASSIST_EOF
|
||||
|
||||
echo -n "Continue the upgrade with SOC Telemetry enabled [Y/n]? "
|
||||
|
||||
read -r input
|
||||
input=$(echo "${input,,}" | xargs echo -n)
|
||||
echo ""
|
||||
if [[ ${#input} -eq 0 || "$input" == "yes" || "$input" == "y" || "$input" == "yy" ]]; then
|
||||
echo "Thank you for helping improve Security Onion!"
|
||||
else
|
||||
if so-yaml.py replace /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.telemetryEnabled false; then
|
||||
echo "Disabled SOC Telemetry."
|
||||
else
|
||||
fail "Failed to disable SOC Telemetry; aborting."
|
||||
fi
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
|
||||
playbook_migration() {
|
||||
# Start SOC Detections migration
|
||||
mkdir -p /nsm/backup/detections-migration/{suricata,sigma/rules,elastalert}
|
||||
|
||||
@@ -649,8 +690,6 @@ up_to_2.4.70() {
|
||||
|
||||
echo
|
||||
echo "Playbook Migration is complete...."
|
||||
|
||||
INSTALLEDVERSION=2.4.70
|
||||
}
|
||||
|
||||
determine_elastic_agent_upgrade() {
|
||||
@@ -835,7 +874,7 @@ verify_latest_update_script() {
|
||||
else
|
||||
echo "You are not running the latest soup version. Updating soup and its components. This might take multiple runs to complete."
|
||||
|
||||
salt-call state.apply common.soup_scripts queue=True -linfo --file-root=$UPDATE_DIR/salt --local
|
||||
salt-call state.apply common.soup_scripts queue=True -lerror --file-root=$UPDATE_DIR/salt --local --out-file=/dev/null
|
||||
|
||||
# Verify that soup scripts updated as expected
|
||||
get_soup_script_hashes
|
||||
|
||||
Reference in New Issue
Block a user