From d19c1a514bee994b03a3f3f54df531bbcabcbd7c Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Wed, 22 May 2024 15:12:23 -0400 Subject: [PATCH 01/23] Detections backup script --- salt/soc/config.sls | 20 ++++ salt/soc/files/soc/so-detections-backup.py | 111 +++++++++++++++++++++ 2 files changed, 131 insertions(+) create mode 100644 salt/soc/files/soc/so-detections-backup.py diff --git a/salt/soc/config.sls b/salt/soc/config.sls index a85032295..65d6bd2fa 100644 --- a/salt/soc/config.sls +++ b/salt/soc/config.sls @@ -80,6 +80,15 @@ socmotd: - mode: 600 - template: jinja +filedetectionsbackup: + file.managed: + - name: /opt/so/conf/soc/so-detections-backup.py + - source: salt://soc/files/soc/so-detections-backup.py + - user: 939 + - group: 939 + - mode: 600 + - show_changes: False + crondetectionsruntime: cron.present: - name: /usr/sbin/so-detections-runtime-status cron @@ -91,6 +100,17 @@ crondetectionsruntime: - month: '*' - dayweek: '*' +crondetectionsbackup: + cron.present: + - name: python3 /opt/so/conf/soc/so-detections-backup.py + - identifier: detections-backup + - user: root + - minute: '0' + - hour: '0' + - daymonth: '*' + - month: '*' + - dayweek: '*' + socsigmafinalpipeline: file.managed: - name: /opt/so/conf/soc/sigma_final_pipeline.yaml diff --git a/salt/soc/files/soc/so-detections-backup.py b/salt/soc/files/soc/so-detections-backup.py new file mode 100644 index 000000000..b7e6e2491 --- /dev/null +++ b/salt/soc/files/soc/so-detections-backup.py @@ -0,0 +1,111 @@ +# Copyright 2020-2023 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. + +# This script queries Elasticsearch for Custom Detections and all Overrides, +# and git commits them to disk at $OUTPUT_DIR + +import os +import subprocess +import json +import requests +from requests.auth import HTTPBasicAuth +import urllib3 +from datetime import datetime + +# Suppress SSL warnings +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +# Constants +ES_URL = "https://localhost:9200/so-detection/_search" +QUERY_DETECTIONS = '{"query": {"bool": {"must": [{"match_all": {}}, {"term": {"so_detection.ruleset": "__custom__"}}]}},"size": 10000}' +QUERY_OVERRIDES = '{"query": {"bool": {"must": [{"exists": {"field": "so_detection.overrides"}}]}},"size": 10000}' +OUTPUT_DIR = "/nsm/backup/detections/repo" +AUTH_FILE = "/opt/so/conf/elasticsearch/curl.config" + +def get_auth_credentials(auth_file): + with open(auth_file, 'r') as file: + for line in file: + if line.startswith('user ='): + return line.split('=', 1)[1].strip().replace('"', '') + +def query_elasticsearch(query, auth): + headers = {"Content-Type": "application/json"} + response = requests.get(ES_URL, headers=headers, data=query, auth=auth, verify=False) + response.raise_for_status() + return response.json() + +def save_content(hit, base_folder, subfolder="", extension="txt"): + so_detection = hit["_source"]["so_detection"] + public_id = so_detection["publicId"] + content = so_detection["content"] + file_dir = os.path.join(base_folder, subfolder) + os.makedirs(file_dir, exist_ok=True) + file_path = os.path.join(file_dir, f"{public_id}.{extension}") + with open(file_path, "w") as f: + f.write(content) + return file_path + +def save_overrides(hit): + so_detection = hit["_source"]["so_detection"] + public_id = so_detection["publicId"] + overrides = so_detection["overrides"] + language = so_detection["language"] + folder = os.path.join(OUTPUT_DIR, language, "overrides") + os.makedirs(folder, exist_ok=True) + extension = "yaml" if language == "sigma" else "txt" + file_path = os.path.join(folder, f"{public_id}.{extension}") + with open(file_path, "w") as f: + f.write('\n'.join(json.dumps(override) for override in overrides) if isinstance(overrides, list) else overrides) + return file_path + +def ensure_git_repo(): + if not os.path.isdir(os.path.join(OUTPUT_DIR, '.git')): + subprocess.run(["git", "config", "--global", "init.defaultBranch", "main"], check=True) + subprocess.run(["git", "-C", OUTPUT_DIR, "init"], check=True) + subprocess.run(["git", "-C", OUTPUT_DIR, "remote", "add", "origin", "default"], check=True) + +def commit_changes(): + ensure_git_repo() + subprocess.run(["git", "-C", OUTPUT_DIR, "config", "user.email", "securityonion@local.invalid"], check=True) + subprocess.run(["git", "-C", OUTPUT_DIR, "config", "user.name", "securityonion"], check=True) + subprocess.run(["git", "-C", OUTPUT_DIR, "add", "."], check=True) + status_result = subprocess.run(["git", "-C", OUTPUT_DIR, "status"], capture_output=True, text=True) + print(status_result.stdout) + commit_result = subprocess.run(["git", "-C", OUTPUT_DIR, "commit", "-m", "Update detections and overrides"], check=False, capture_output=True) + if commit_result.returncode == 1: + print("No changes to commit.") + elif commit_result.returncode == 0: + print("Changes committed successfully.") + else: + commit_result.check_returncode() + +def main(): + try: + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + print(f"Backing up Custom Detections and all Overrides to {OUTPUT_DIR} - {timestamp}\n") + + auth_credentials = get_auth_credentials(AUTH_FILE) + username, password = auth_credentials.split(':', 1) + auth = HTTPBasicAuth(username, password) + + # Query and save custom detections + detections = query_elasticsearch(QUERY_DETECTIONS, auth)["hits"]["hits"] + for hit in detections: + save_content(hit, OUTPUT_DIR, hit["_source"]["so_detection"]["language"], "yaml" if hit["_source"]["so_detection"]["language"] == "sigma" else "txt") + + # Query and save overrides + overrides = query_elasticsearch(QUERY_OVERRIDES, auth)["hits"]["hits"] + for hit in overrides: + save_overrides(hit) + + commit_changes() + + timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") + print(f"Backup Completed - {timestamp}") + except Exception as e: + print(f"An error occurred: {e}") + +if __name__ == "__main__": + main() \ No newline at end of file From 0b9ebefdb670e9ad85bd4bb415291e82ef71c505 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 23 May 2024 10:08:23 -0400 Subject: [PATCH 02/23] only show telem status in final whiptail if new deployment --- setup/so-whiptail | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-whiptail b/setup/so-whiptail index 1dab63237..4fab6dbe4 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -451,7 +451,7 @@ whiptail_end_settings() { done fi - if [[ ! $is_airgap ]]; then + if [[ ! $is_airgap ]] && [[ $dist_option == "NEWDEPLOYMENT" ]]; then if [[ $telemetry -eq 0 ]]; then __append_end_msg "SOC Telemetry: enabled" else From ea7715f7297c426956b7074193ca331f0aaa0b18 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 23 May 2024 10:41:10 -0400 Subject: [PATCH 03/23] use waitforstate var instead. --- setup/so-whiptail | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup/so-whiptail b/setup/so-whiptail index 4fab6dbe4..d950f2921 100755 --- a/setup/so-whiptail +++ b/setup/so-whiptail @@ -451,7 +451,7 @@ whiptail_end_settings() { done fi - if [[ ! $is_airgap ]] && [[ $dist_option == "NEWDEPLOYMENT" ]]; then + if [[ ! $is_airgap ]] && [[ $waitforstate ]]; then if [[ $telemetry -eq 0 ]]; then __append_end_msg "SOC Telemetry: enabled" else From 15155613c3d60a2e48a7e0c922ae09eb5d225acb Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 24 May 2024 08:23:45 -0400 Subject: [PATCH 04/23] provide default columns when viewing SOC logs --- salt/soc/defaults.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 86170b4ce..39960d946 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1271,6 +1271,14 @@ soc: - netflow.type - netflow.exporter.version - observer.ip + ':soc:': + - soc_timestamp + - source.ip + - soc.fields.requestMethod + - soc.fields.requestPath + - soc.fields.statusCode + - event.action + - soc.fields.error server: bindAddress: 0.0.0.0:9822 baseUrl: / From bd11d59c15fb711332ab0c67423e217f2b4b1b70 Mon Sep 17 00:00:00 2001 From: Jason Ertel Date: Fri, 24 May 2024 08:38:12 -0400 Subject: [PATCH 05/23] add event.dataset since there are other datasets in soc logs --- salt/soc/defaults.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/soc/defaults.yaml b/salt/soc/defaults.yaml index 39960d946..9f5faf50b 100644 --- a/salt/soc/defaults.yaml +++ b/salt/soc/defaults.yaml @@ -1273,6 +1273,7 @@ soc: - observer.ip ':soc:': - soc_timestamp + - event.dataset - source.ip - soc.fields.requestMethod - soc.fields.requestPath From 66725b11b304d1742caad49854bd968f71196c97 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Fri, 24 May 2024 09:55:10 -0400 Subject: [PATCH 06/23] Added unit tests --- salt/soc/config.sls | 3 +- salt/soc/files/soc/so-detections-backup.py | 2 + .../files/soc/so-detections-backup_test.py | 159 ++++++++++++++++++ 3 files changed, 162 insertions(+), 2 deletions(-) create mode 100644 salt/soc/files/soc/so-detections-backup_test.py diff --git a/salt/soc/config.sls b/salt/soc/config.sls index 65d6bd2fa..8d1f0f694 100644 --- a/salt/soc/config.sls +++ b/salt/soc/config.sls @@ -87,7 +87,6 @@ filedetectionsbackup: - user: 939 - group: 939 - mode: 600 - - show_changes: False crondetectionsruntime: cron.present: @@ -102,7 +101,7 @@ crondetectionsruntime: crondetectionsbackup: cron.present: - - name: python3 /opt/so/conf/soc/so-detections-backup.py + - name: python3 /opt/so/conf/soc/so-detections-backup.py &>> /opt/so/log/soc/detections-backup.log - identifier: detections-backup - user: root - minute: '0' diff --git a/salt/soc/files/soc/so-detections-backup.py b/salt/soc/files/soc/so-detections-backup.py index b7e6e2491..085b1e4c7 100644 --- a/salt/soc/files/soc/so-detections-backup.py +++ b/salt/soc/files/soc/so-detections-backup.py @@ -86,6 +86,8 @@ def main(): timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"Backing up Custom Detections and all Overrides to {OUTPUT_DIR} - {timestamp}\n") + os.makedirs(OUTPUT_DIR, exist_ok=True) + auth_credentials = get_auth_credentials(AUTH_FILE) username, password = auth_credentials.split(':', 1) auth = HTTPBasicAuth(username, password) diff --git a/salt/soc/files/soc/so-detections-backup_test.py b/salt/soc/files/soc/so-detections-backup_test.py new file mode 100644 index 000000000..3afa11886 --- /dev/null +++ b/salt/soc/files/soc/so-detections-backup_test.py @@ -0,0 +1,159 @@ +# Copyright 2020-2023 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. + +import unittest +from unittest.mock import patch, MagicMock, mock_open, call +import requests +import os +import subprocess +import json +from datetime import datetime +import importlib + +ds = importlib.import_module('so-detections-backup') + +class TestBackupScript(unittest.TestCase): + + def setUp(self): + self.output_dir = '/nsm/backup/detections/repo' + self.auth_file_path = '/nsm/backup/detections/repo' + self.mock_auth_data = 'user = "so_elastic:@Tu_dv_[7SvK7[-JZN39BBlSa;WAyf8rCY+3w~Sntp=7oR9*~34?Csi)a@v?)K*vK4vQAywS"' + self.auth_credentials = 'so_elastic:@Tu_dv_[7SvK7[-JZN39BBlSa;WAyf8rCY+3w~Sntp=7oR9*~34?Csi)a@v?)K*vK4vQAywS' + self.auth = requests.auth.HTTPBasicAuth('so_elastic', '@Tu_dv_[7SvK7[-JZN39BBlSa;WAyf8rCY+3w~Sntp=7oR9*~34?Csi)a@v?)K*vK4vQAywS') + self.mock_detection_hit = { + "_source": { + "so_detection": { + "publicId": "test_id", + "content": "test_content", + "language": "suricata" + } + } + } + self.mock_override_hit = { + "_source": { + "so_detection": { + "publicId": "test_id", + "overrides": [{"key": "value"}], + "language": "sigma" + } + } + } + + def assert_file_written(self, mock_file, expected_path, expected_content): + mock_file.assert_called_once_with(expected_path, 'w') + mock_file().write.assert_called_once_with(expected_content) + + @patch('builtins.open', new_callable=mock_open, read_data='user = "so_elastic:@Tu_dv_[7SvK7[-JZN39BBlSa;WAyf8rCY+3w~Sntp=7oR9*~34?Csi)a@v?)K*vK4vQAywS"') + def test_get_auth_credentials(self, mock_file): + credentials = ds.get_auth_credentials(self.auth_file_path) + self.assertEqual(credentials, self.auth_credentials) + mock_file.assert_called_once_with(self.auth_file_path, 'r') + + @patch('requests.get') + def test_query_elasticsearch(self, mock_get): + mock_response = MagicMock() + mock_response.json.return_value = {'hits': {'hits': []}} + mock_response.raise_for_status = MagicMock() + mock_get.return_value = mock_response + + response = ds.query_elasticsearch(ds.QUERY_DETECTIONS, self.auth) + + self.assertEqual(response, {'hits': {'hits': []}}) + mock_get.assert_called_once_with( + ds.ES_URL, + headers={"Content-Type": "application/json"}, + data=ds.QUERY_DETECTIONS, + auth=self.auth, + verify=False + ) + + @patch('os.makedirs') + @patch('builtins.open', new_callable=mock_open) + def test_save_content(self, mock_file, mock_makedirs): + file_path = ds.save_content(self.mock_detection_hit, self.output_dir, 'subfolder', 'txt') + expected_path = f'{self.output_dir}/subfolder/test_id.txt' + self.assertEqual(file_path, expected_path) + mock_makedirs.assert_called_once_with(f'{self.output_dir}/subfolder', exist_ok=True) + self.assert_file_written(mock_file, expected_path, 'test_content') + + @patch('os.makedirs') + @patch('builtins.open', new_callable=mock_open) + def test_save_overrides(self, mock_file, mock_makedirs): + file_path = ds.save_overrides(self.mock_override_hit) + expected_path = f'{self.output_dir}/sigma/overrides/test_id.yaml' + self.assertEqual(file_path, expected_path) + mock_makedirs.assert_called_once_with(f'{self.output_dir}/sigma/overrides', exist_ok=True) + self.assert_file_written(mock_file, expected_path, json.dumps({"key": "value"})) + + @patch('subprocess.run') + def test_ensure_git_repo(self, mock_run): + mock_run.return_value = MagicMock(returncode=0) + + ds.ensure_git_repo() + + mock_run.assert_has_calls([ + call(["git", "config", "--global", "init.defaultBranch", "main"], check=True), + call(["git", "-C", self.output_dir, "init"], check=True), + call(["git", "-C", self.output_dir, "remote", "add", "origin", "default"], check=True) + ]) + + @patch('subprocess.run') + def test_commit_changes(self, mock_run): + mock_status_result = MagicMock() + mock_status_result.stdout = "On branch main\nnothing to commit, working tree clean" + mock_commit_result = MagicMock(returncode=1) + # Ensure sufficient number of MagicMock instances for each subprocess.run call + mock_run.side_effect = [mock_status_result, mock_commit_result, MagicMock(returncode=0), MagicMock(returncode=0), MagicMock(returncode=0), MagicMock(returncode=0), MagicMock(returncode=0), MagicMock(returncode=0)] + + print("Running test_commit_changes...") + ds.commit_changes() + print("Finished test_commit_changes.") + + mock_run.assert_has_calls([ + call(["git", "-C", self.output_dir, "config", "user.email", "securityonion@local.invalid"], check=True), + call(["git", "-C", self.output_dir, "config", "user.name", "securityonion"], check=True), + call(["git", "-C", self.output_dir, "add", "."], check=True), + call(["git", "-C", self.output_dir, "status"], capture_output=True, text=True), + call(["git", "-C", self.output_dir, "commit", "-m", "Update detections and overrides"], check=False, capture_output=True) + ]) + + @patch('builtins.print') + @patch('so-detections-backup.commit_changes') + @patch('so-detections-backup.save_overrides') + @patch('so-detections-backup.save_content') + @patch('so-detections-backup.query_elasticsearch') + @patch('so-detections-backup.get_auth_credentials') + @patch('os.makedirs') + def test_main(self, mock_makedirs, mock_get_auth, mock_query, mock_save_content, mock_save_overrides, mock_commit, mock_print): + mock_get_auth.return_value = self.auth_credentials + mock_query.side_effect = [ + {'hits': {'hits': [{"_source": {"so_detection": {"publicId": "1", "content": "content1", "language": "sigma"}}}]}}, + {'hits': {'hits': [{"_source": {"so_detection": {"publicId": "2", "overrides": [{"key": "value"}], "language": "suricata"}}}]}} + ] + + with patch('datetime.datetime') as mock_datetime: + mock_datetime.now.return_value.strftime.return_value = "2024-05-23 20:49:44" + ds.main() + + mock_makedirs.assert_called_once_with(self.output_dir, exist_ok=True) + mock_get_auth.assert_called_once_with(ds.AUTH_FILE) + mock_query.assert_has_calls([ + call(ds.QUERY_DETECTIONS, self.auth), + call(ds.QUERY_OVERRIDES, self.auth) + ]) + mock_save_content.assert_called_once_with( + {"_source": {"so_detection": {"publicId": "1", "content": "content1", "language": "sigma"}}}, + self.output_dir, + "sigma", + "yaml" + ) + mock_save_overrides.assert_called_once_with( + {"_source": {"so_detection": {"publicId": "2", "overrides": [{"key": "value"}], "language": "suricata"}}} + ) + mock_commit.assert_called_once() + mock_print.assert_called() + +if __name__ == '__main__': + unittest.main(verbosity=2) From 4344988abeafe731e26f0305cdd62af1034c4e59 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Fri, 24 May 2024 12:54:36 -0400 Subject: [PATCH 07/23] Add instructions for sigma and yara repos --- salt/soc/soc_soc.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 60de637b4..415829460 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -119,14 +119,14 @@ soc: advanced: True rulesRepos: default: &eerulesRepos - description: "Custom Git repos to pull Sigma rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled." + description: "Custom Git repositories to pull Sigma rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Elastalert --> Full Update." global: True advanced: True forcedType: "[]{}" helpLink: sigma.html airgap: *eerulesRepos sigmaRulePackages: - description: 'Defines the Sigma Community Ruleset you want to run. One of these (core | core+ | core++ | all ) as well as an optional Add-on (emerging_threats_addon). Once you have changed the ruleset here, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Elastalert --> Full Update. WARNING! Changing the ruleset will remove all existing non-overlapping Sigma rules of the previous ruleset and their associated overrides. This removal cannot be undone.' + description: 'Defines the Sigma Community Ruleset you want to run. One of these (core | core+ | core++ | all ) as well as an optional Add-on (emerging_threats_addon). Once you have changed the ruleset here, the new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Elastalert --> Full Update. WARNING! Changing the ruleset will remove all existing non-overlapping Sigma rules of the previous ruleset and their associated overrides. This removal cannot be undone.' global: True advanced: False helpLink: sigma.html @@ -221,7 +221,7 @@ soc: advanced: True rulesRepos: default: &serulesRepos - description: "Custom Git repos to pull YARA rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled." + description: "Custom Git repositories to pull YARA rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Strelka --> Full Update."" global: True advanced: True forcedType: "[]{}" From f90d40b4714073c640bccfa05e36755f6a31c6af Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Fri, 24 May 2024 12:56:17 -0400 Subject: [PATCH 08/23] Fix typo --- salt/soc/soc_soc.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/soc/soc_soc.yaml b/salt/soc/soc_soc.yaml index 415829460..1f64eb0bc 100644 --- a/salt/soc/soc_soc.yaml +++ b/salt/soc/soc_soc.yaml @@ -221,7 +221,7 @@ soc: advanced: True rulesRepos: default: &serulesRepos - description: "Custom Git repositories to pull YARA rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Strelka --> Full Update."" + description: "Custom Git repositories to pull YARA rules from. 'license' field is required, 'folder' is optional. 'community' disables some management options for the imported rules - they can't be deleted or edited, just tuned, duplicated and Enabled | Disabled. The new settings will be applied within 15 minutes. At that point, you will need to wait for the scheduled rule update to take place (by default, every 24 hours), or you can force the update by nagivating to Detections --> Options dropdown menu --> Strelka --> Full Update." global: True advanced: True forcedType: "[]{}" From 550b3ee92d02d4d6ce6bb11610532b68fb02089c Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Fri, 24 May 2024 14:46:24 -0400 Subject: [PATCH 09/23] Add IDH mappings --- salt/soc/files/soc/sigma_so_pipeline.yaml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/salt/soc/files/soc/sigma_so_pipeline.yaml b/salt/soc/files/soc/sigma_so_pipeline.yaml index 312d07965..8314361f5 100644 --- a/salt/soc/files/soc/sigma_so_pipeline.yaml +++ b/salt/soc/files/soc/sigma_so_pipeline.yaml @@ -17,6 +17,16 @@ transformations: dst_ip: destination.ip.keyword dst_port: destination.port winlog.event_data.User: user.name + logtype: event.code # OpenCanary + # Maps "opencanary" product to SO IDH logs + - id: opencanary_idh_add-fields + type: add_condition + conditions: + event.module: 'opencanary' + event.dataset: 'opencanary.idh' + rule_conditions: + - type: logsource + product: opencanary # Maps "antivirus" category to Windows Defender logs shipped by Elastic Agent Winlog Integration # winlog.event_data.threat_name has to be renamed prior to ingestion, it is originally winlog.event_data.Threat Name - id: antivirus_field-mappings_windows-defender @@ -88,3 +98,11 @@ transformations: - type: logsource product: linux service: auth + # event.code should always be a string + - id: convert_event_code_to_string + type: convert_type + target_type: 'str' + field_name_conditions: + - type: include_fields + fields: + - event.code From 58b565558df8acf341d2419fb27fb92e8725056e Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Fri, 24 May 2024 16:21:59 -0400 Subject: [PATCH 10/23] Dont bail - just wait for enter --- salt/manager/tools/sbin/soup | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 525fce3f6..b6bf61d2a 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -680,16 +680,15 @@ playbook_migration() { active_rules_count=$(find /opt/so/rules/elastalert/playbook/ -type f -name "*.yaml" | wc -l) if [[ "$active_rules_count" -gt 0 ]]; then - # Prompt the user to AGREE if active Elastalert rules found + # Prompt the user to press ENTER if active Elastalert rules found echo echo "$active_rules_count Active Elastalert/Playbook rules found." echo "In preparation for the new Detections module, they will be backed up and then disabled." echo - echo "If you would like to proceed, then type AGREE and press ENTER." + echo "Press ENTER to proceed." echo # Read user input - read INPUT - if [ "${INPUT^^}" != 'AGREE' ]; then fail "SOUP canceled."; fi + read -r echo "Backing up the Elastalert rules..." rsync -av --stats /opt/so/rules/elastalert/playbook/*.yaml /nsm/backup/detections-migration/elastalert/ From 81ee60e6586f2fac5e47c96c40fa2ca32245f6c6 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Tue, 28 May 2024 06:42:18 -0400 Subject: [PATCH 11/23] Backup .yml files too --- salt/manager/tools/sbin/soup | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index b6bf61d2a..c37138e19 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -677,7 +677,7 @@ playbook_migration() { if grep -A 1 'playbook:' /opt/so/saltstack/local/pillar/minions/* | grep -q 'enabled: True'; then # Check for active Elastalert rules - active_rules_count=$(find /opt/so/rules/elastalert/playbook/ -type f -name "*.yaml" | wc -l) + active_rules_count=$(find /opt/so/rules/elastalert/playbook/ -type f \( -name "*.yaml" -o -name "*.yml" \) | wc -l) if [[ "$active_rules_count" -gt 0 ]]; then # Prompt the user to press ENTER if active Elastalert rules found @@ -691,7 +691,8 @@ playbook_migration() { read -r echo "Backing up the Elastalert rules..." - rsync -av --stats /opt/so/rules/elastalert/playbook/*.yaml /nsm/backup/detections-migration/elastalert/ + rsync -av --stats /opt/so/rules/elastalert/playbook/*.{yaml,yml} /nsm/backup/detections-migration/elastalert/ + fi # Verify that rsync completed successfully if [[ $? -eq 0 ]]; then From 74dfc25376d845d042cfd1c00b57541ec40cffcc Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Tue, 28 May 2024 09:29:10 -0400 Subject: [PATCH 12/23] backup local rules --- salt/manager/tools/sbin/soup | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index c37138e19..9b61f3c8c 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -660,6 +660,11 @@ suricata_idstools_migration() { fail "Error: rsync failed to copy the files. Thresholds have not been backed up." fi + #Backup local rules + mkdir -p /nsm/backup/detections-migration/suricata/local-rules + rsync -av /opt/so/rules/nids/suri/local.rules /nsm/backup/detections-migration/suricata/local-rules + rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules + #Tell SOC to migrate mkdir -p /opt/so/conf/soc/migrations echo "0" > /opt/so/conf/soc/migrations/suricata-migration-2.4.70 From 2a2b86ebe62b2690b4c2b0e51d0124f60c976b24 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Tue, 28 May 2024 09:43:45 -0400 Subject: [PATCH 13/23] Dont overwrite --- salt/manager/tools/sbin/soup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 9b61f3c8c..7d94fcf55 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -663,7 +663,7 @@ suricata_idstools_migration() { #Backup local rules mkdir -p /nsm/backup/detections-migration/suricata/local-rules rsync -av /opt/so/rules/nids/suri/local.rules /nsm/backup/detections-migration/suricata/local-rules - rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules + rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules/local.rules.bak #Tell SOC to migrate mkdir -p /opt/so/conf/soc/migrations From f68ac23f0eb69334e78fb0c8c45ddd71f6a7f8d4 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Tue, 28 May 2024 10:03:31 -0400 Subject: [PATCH 14/23] Fix fi Signed-off-by: DefensiveDepth --- salt/manager/tools/sbin/soup | 1 - 1 file changed, 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 7d94fcf55..39c684c08 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -697,7 +697,6 @@ playbook_migration() { echo "Backing up the Elastalert rules..." rsync -av --stats /opt/so/rules/elastalert/playbook/*.{yaml,yml} /nsm/backup/detections-migration/elastalert/ - fi # Verify that rsync completed successfully if [[ $? -eq 0 ]]; then From ee4ca0d7a214ee764f841d0d90e9119ced80fe07 Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Tue, 28 May 2024 10:24:09 -0400 Subject: [PATCH 15/23] Check to see if local exists --- salt/manager/tools/sbin/soup | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 39c684c08..b8297ad44 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -663,7 +663,9 @@ suricata_idstools_migration() { #Backup local rules mkdir -p /nsm/backup/detections-migration/suricata/local-rules rsync -av /opt/so/rules/nids/suri/local.rules /nsm/backup/detections-migration/suricata/local-rules - rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules/local.rules.bak + if [[ -f /opt/so/saltstack/local/salt/idstools/rules/local.rules ]]; then + rsync -av /opt/so/saltstack/local/salt/idstools/rules/local.rules /nsm/backup/detections-migration/suricata/local-rules/local.rules.bak + fi #Tell SOC to migrate mkdir -p /opt/so/conf/soc/migrations From 0d034e7adcacc414cce6531f95e94da65ee9f56e Mon Sep 17 00:00:00 2001 From: DefensiveDepth Date: Wed, 29 May 2024 10:55:56 -0400 Subject: [PATCH 16/23] fix rsync --- salt/manager/tools/sbin/soup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index b8297ad44..1e9585987 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -698,7 +698,7 @@ playbook_migration() { read -r echo "Backing up the Elastalert rules..." - rsync -av --stats /opt/so/rules/elastalert/playbook/*.{yaml,yml} /nsm/backup/detections-migration/elastalert/ + rsync -av --ignore-missing-args --stats /opt/so/rules/elastalert/playbook/*.{yaml,yml} /nsm/backup/detections-migration/elastalert/ # Verify that rsync completed successfully if [[ $? -eq 0 ]]; then From e98b8566c942a4557b9ab33ced61524f4d2e725c Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 29 May 2024 14:50:22 -0400 Subject: [PATCH 17/23] 2.4.70 --- DOWNLOAD_AND_VERIFY_ISO.md | 22 ++++++++++----------- sigs/securityonion-2.4.70-20240529.iso.sig | Bin 0 -> 566 bytes 2 files changed, 11 insertions(+), 11 deletions(-) create mode 100644 sigs/securityonion-2.4.70-20240529.iso.sig diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index 4493f210d..fcefce469 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,17 +1,17 @@ -### 2.4.60-20240320 ISO image released on 2024/03/20 +### 2.4.70-20240529 ISO image released on 2024/03/20 ### Download and Verify -2.4.60-20240320 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.60-20240320.iso +2.4.70-20240529 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-2.4.70-20240529.iso -MD5: 178DD42D06B2F32F3870E0C27219821E -SHA1: 73EDCD50817A7F6003FE405CF1808A30D034F89D -SHA256: DD334B8D7088A7B78160C253B680D645E25984BA5CCAB5CC5C327CA72137FC06 +MD5: 8FCCF31C2470D1ABA380AF196B611DEC +SHA1: EE5E8F8C14819E7A1FE423E6920531A97F39600B +SHA256: EF5E781D50D50660F452ADC54FD4911296ECBECED7879FA8E04687337CA89BEC Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.60-20240320.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.70-20240529.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS @@ -25,22 +25,22 @@ wget https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2. Download the signature file for the ISO: ``` -wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.60-20240320.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.70-20240529.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.60-20240320.iso +wget https://download.securityonion.net/file/securityonion/securityonion-2.4.70-20240529.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.60-20240320.iso.sig securityonion-2.4.60-20240320.iso +gpg --verify securityonion-2.4.70-20240529.iso.sig securityonion-2.4.70-20240529.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Tue 19 Mar 2024 03:17:58 PM EDT using RSA key ID FE507013 +gpg: Signature made Wed 29 May 2024 11:40:59 AM EDT using RSA key ID FE507013 gpg: Good signature from "Security Onion Solutions, LLC " gpg: WARNING: This key is not certified with a trusted signature! gpg: There is no indication that the signature belongs to the owner. diff --git a/sigs/securityonion-2.4.70-20240529.iso.sig b/sigs/securityonion-2.4.70-20240529.iso.sig new file mode 100644 index 0000000000000000000000000000000000000000..c3825eb6e72a860f67708c45b3926d7fdc90b650 GIT binary patch literal 566 zcmV-60?GY}0y6{v0SEvc79j-41gSkXz6^6dp_W8^5Ma0dP;e6k0%liCivS7<5PT3| zxBgIY6IO;00GUA4^4cz_ff*If5}A0oP7{X5>Z=GC&kVQad2loDR}h58qGE)=Rx^yp z-+xRh;q#;TL)Clt%_Pqf`(+ZrTTxv(K=m6LP%GfSK4WmEzCYmDGF{x`Aax-QCl14M?B(?m6}F< z8ytoSd0DJjf3dNdprN}#!)CDM%UoA1<6_PF(m7Ed~UxN<0?0bGK zYZmg%ne6j4P621BW!vQmH~#^`e1^aJc(KS3%i>sop?;h9?k z$XnSrS90)^;tYA8-5UvbUO{ZLYxgUGGhIA}2I}y$to?u$rExzvc+R*l{a!nVSe@G} zA9x@C>(y#~9Pmj<<|Xctul~dkY1TD+#W?!T-m;neL){fdtG)HlsOCQTaX0s?y^bC10U|My|kDl##27 Date: Wed, 29 May 2024 14:52:47 -0400 Subject: [PATCH 18/23] 2.4.70 --- DOWNLOAD_AND_VERIFY_ISO.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index fcefce469..a5fd6e157 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,4 +1,4 @@ -### 2.4.70-20240529 ISO image released on 2024/03/20 +### 2.4.70-20240529 ISO image released on 2024/05/29 ### Download and Verify From 62bdb2627aea9378f7c11ae9a72f04cbf2a14e96 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Wed, 29 May 2024 16:53:27 -0400 Subject: [PATCH 19/23] Update VERSION --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index b3c5d8c27..d2587d896 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.4.70 +2.4.80 From 55c5ea5c4cf75f8c73e2762ce6382f0adbe9d120 Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 30 May 2024 16:58:56 +0000 Subject: [PATCH 20/23] Add template for Suricata alerts --- salt/elasticsearch/defaults.yaml | 111 +++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index e54d58c3b..6ecdc96a1 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -11088,6 +11088,117 @@ elasticsearch: set_priority: priority: 50 min_age: 30d + so-suricata_x_alerts: + index_sorting: false + index_template: + composed_of: + - agent-mappings + - dtc-agent-mappings + - base-mappings + - dtc-base-mappings + - client-mappings + - dtc-client-mappings + - cloud-mappings + - container-mappings + - data_stream-mappings + - destination-mappings + - dtc-destination-mappings + - pb-override-destination-mappings + - dll-mappings + - dns-mappings + - dtc-dns-mappings + - ecs-mappings + - dtc-ecs-mappings + - error-mappings + - event-mappings + - dtc-event-mappings + - file-mappings + - dtc-file-mappings + - group-mappings + - host-mappings + - dtc-host-mappings + - http-mappings + - dtc-http-mappings + - log-mappings + - network-mappings + - dtc-network-mappings + - observer-mappings + - dtc-observer-mappings + - orchestrator-mappings + - organization-mappings + - package-mappings + - process-mappings + - dtc-process-mappings + - registry-mappings + - related-mappings + - rule-mappings + - dtc-rule-mappings + - server-mappings + - service-mappings + - dtc-service-mappings + - source-mappings + - dtc-source-mappings + - pb-override-source-mappings + - suricata-mappings + - threat-mappings + - tls-mappings + - tracing-mappings + - url-mappings + - user_agent-mappings + - dtc-user_agent-mappings + - vulnerability-mappings + - common-settings + - common-dynamic-mappings + data_stream: {} + index_patterns: + - logs-suricata.alerts-* + priority: 500 + template: + mappings: + date_detection: false + dynamic_templates: + - strings_as_keyword: + mapping: + ignore_above: 1024 + type: keyword + match_mapping_type: string + settings: + index: + lifecycle: + name: so-suricata.alerts-logs + mapping: + total_fields: + limit: 5000 + number_of_replicas: 0 + number_of_shards: 1 + refresh_interval: 30s + sort: + field: '@timestamp' + order: desc + policy: + phases: + cold: + actions: + set_priority: + priority: 0 + min_age: 60d + delete: + actions: + delete: {} + min_age: 365d + hot: + actions: + rollover: + max_age: 1d + max_primary_shard_size: 50gb + set_priority: + priority: 100 + min_age: 0ms + warm: + actions: + set_priority: + priority: 50 + min_age: 30d so-syslog: index_sorting: false index_template: From e83135440198e8ed2bb0f79e420e6abd7d73e7be Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 30 May 2024 17:00:11 +0000 Subject: [PATCH 21/23] Add Suricata alerts setting for configuration --- salt/elasticsearch/soc_elasticsearch.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/elasticsearch/soc_elasticsearch.yaml b/salt/elasticsearch/soc_elasticsearch.yaml index 000fd60b7..f56ed313e 100644 --- a/salt/elasticsearch/soc_elasticsearch.yaml +++ b/salt/elasticsearch/soc_elasticsearch.yaml @@ -521,6 +521,7 @@ elasticsearch: so-endgame: *indexSettings so-idh: *indexSettings so-suricata: *indexSettings + so-suricata_x_alerts: *indexSettings so-import: *indexSettings so-kratos: *indexSettings so-kismet: *indexSettings From 2c635bce6201859256af9891c4ae76411e8d38de Mon Sep 17 00:00:00 2001 From: Wes Date: Thu, 30 May 2024 17:02:31 +0000 Subject: [PATCH 22/23] Set index for Suricata alerts --- salt/elasticsearch/files/ingest/suricata.alert | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/elasticsearch/files/ingest/suricata.alert b/salt/elasticsearch/files/ingest/suricata.alert index 87d5144ed..68e0a5cb3 100644 --- a/salt/elasticsearch/files/ingest/suricata.alert +++ b/salt/elasticsearch/files/ingest/suricata.alert @@ -1,6 +1,7 @@ { "description" : "suricata.alert", "processors" : [ + { "set": { "field": "_index", "value": "logs-suricata.alerts-so" } }, { "set": { "field": "tags","value": "alert" }}, { "rename":{ "field": "message2.alert", "target_field": "rule", "ignore_failure": true } }, { "rename":{ "field": "rule.signature", "target_field": "rule.name", "ignore_failure": true } }, From 7702f05756cf83830013e41217a756aa87c5876d Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 30 May 2024 15:00:32 -0400 Subject: [PATCH 23/23] upgrade salt 3006.8. soup for 2.4.80 --- salt/manager/tools/sbin/soup | 12 ++++++++++++ salt/salt/master.defaults.yaml | 2 +- salt/salt/minion.defaults.yaml | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 525fce3f6..30f40ee5a 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -358,6 +358,7 @@ preupgrade_changes() { [[ "$INSTALLEDVERSION" == 2.4.40 ]] && up_to_2.4.50 [[ "$INSTALLEDVERSION" == 2.4.50 ]] && up_to_2.4.60 [[ "$INSTALLEDVERSION" == 2.4.60 ]] && up_to_2.4.70 + [[ "$INSTALLEDVERSION" == 2.4.70 ]] && up_to_2.4.80 true } @@ -375,6 +376,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.70 ]] && post_to_2.4.80 true } @@ -448,6 +450,11 @@ post_to_2.4.70() { POSTVERSION=2.4.70 } +post_to_2.4.80() { + echo "Nothing to apply" + POSTVERSION=2.4.80 +} + repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -595,6 +602,11 @@ up_to_2.4.70() { INSTALLEDVERSION=2.4.70 } +up_to_2.4.80() { + echo "Nothing to do for 2.4.80" + INSTALLEDVERSION=2.4.80 +} + add_detection_test_pillars() { if [[ -n "$SOUP_INTERNAL_TESTING" ]]; then echo "Adding detection pillar values for automated testing" diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index 19677f70b..24ba29d98 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -1,4 +1,4 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: master: - version: 3006.6 + version: 3006.8 diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index 2e4ebc93e..dddd6683b 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -1,6 +1,6 @@ # version cannot be used elsewhere in this pillar as soup is grepping for it to determine if Salt needs to be patched salt: minion: - version: 3006.6 + version: 3006.8 check_threshold: 3600 # in seconds, threshold used for so-salt-minion-check. any value less than 600 seconds may cause a lot of salt-minion restarts since the job to touch the file occurs every 5-8 minutes by default service_start_delay: 30 # in seconds.