From d78a5867b8bda404be0ea545819629f9857e7bea Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Mon, 9 Mar 2026 17:10:18 -0400 Subject: [PATCH 1/5] Refactor upgrade functions and version checks Removed redundant upgrade functions and streamlined version checks. --- salt/manager/tools/sbin/soup | 507 +---------------------------------- 1 file changed, 5 insertions(+), 502 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 693c48505..de1f7a48c 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -440,33 +440,7 @@ preupgrade_changes() { # This function is to add any new pillar items if needed. echo "Checking to see if changes are needed." - [[ "$INSTALLEDVERSION" == 2.4.2 ]] && up_to_2.4.3 - [[ "$INSTALLEDVERSION" == 2.4.3 ]] && up_to_2.4.4 - [[ "$INSTALLEDVERSION" == 2.4.4 ]] && up_to_2.4.5 - [[ "$INSTALLEDVERSION" == 2.4.5 ]] && up_to_2.4.10 - [[ "$INSTALLEDVERSION" == 2.4.10 ]] && up_to_2.4.20 - [[ "$INSTALLEDVERSION" == 2.4.20 ]] && up_to_2.4.30 - [[ "$INSTALLEDVERSION" == 2.4.30 ]] && up_to_2.4.40 - [[ "$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 - [[ "$INSTALLEDVERSION" == 2.4.80 ]] && up_to_2.4.90 - [[ "$INSTALLEDVERSION" == 2.4.90 ]] && up_to_2.4.100 - [[ "$INSTALLEDVERSION" == 2.4.100 ]] && up_to_2.4.110 - [[ "$INSTALLEDVERSION" == 2.4.110 ]] && up_to_2.4.111 - [[ "$INSTALLEDVERSION" == 2.4.111 ]] && up_to_2.4.120 - [[ "$INSTALLEDVERSION" == 2.4.120 ]] && up_to_2.4.130 - [[ "$INSTALLEDVERSION" == 2.4.130 ]] && up_to_2.4.140 - [[ "$INSTALLEDVERSION" == 2.4.140 ]] && up_to_2.4.141 - [[ "$INSTALLEDVERSION" == 2.4.141 ]] && up_to_2.4.150 - [[ "$INSTALLEDVERSION" == 2.4.150 ]] && up_to_2.4.160 - [[ "$INSTALLEDVERSION" == 2.4.160 ]] && up_to_2.4.170 - [[ "$INSTALLEDVERSION" == 2.4.170 ]] && up_to_2.4.180 - [[ "$INSTALLEDVERSION" == 2.4.180 ]] && up_to_2.4.190 - [[ "$INSTALLEDVERSION" == 2.4.190 ]] && up_to_2.4.200 - [[ "$INSTALLEDVERSION" == 2.4.200 ]] && up_to_2.4.201 - [[ "$INSTALLEDVERSION" == 2.4.201 ]] && up_to_2.4.210 + [[ "$INSTALLEDVERSION" == 2.4.2 ]] && up_to_2.4.3 true } @@ -475,32 +449,6 @@ postupgrade_changes() { echo "Running post upgrade processes." [[ "$POSTVERSION" == 2.4.2 ]] && post_to_2.4.3 - [[ "$POSTVERSION" == 2.4.3 ]] && post_to_2.4.4 - [[ "$POSTVERSION" == 2.4.4 ]] && post_to_2.4.5 - [[ "$POSTVERSION" == 2.4.5 ]] && post_to_2.4.10 - [[ "$POSTVERSION" == 2.4.10 ]] && post_to_2.4.20 - [[ "$POSTVERSION" == 2.4.20 ]] && post_to_2.4.30 - [[ "$POSTVERSION" == 2.4.30 ]] && post_to_2.4.40 - [[ "$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 - [[ "$POSTVERSION" == 2.4.80 ]] && post_to_2.4.90 - [[ "$POSTVERSION" == 2.4.90 ]] && post_to_2.4.100 - [[ "$POSTVERSION" == 2.4.100 ]] && post_to_2.4.110 - [[ "$POSTVERSION" == 2.4.110 ]] && post_to_2.4.111 - [[ "$POSTVERSION" == 2.4.111 ]] && post_to_2.4.120 - [[ "$POSTVERSION" == 2.4.120 ]] && post_to_2.4.130 - [[ "$POSTVERSION" == 2.4.130 ]] && post_to_2.4.140 - [[ "$POSTVERSION" == 2.4.140 ]] && post_to_2.4.141 - [[ "$POSTVERSION" == 2.4.141 ]] && post_to_2.4.150 - [[ "$POSTVERSION" == 2.4.150 ]] && post_to_2.4.160 - [[ "$POSTVERSION" == 2.4.160 ]] && post_to_2.4.170 - [[ "$POSTVERSION" == 2.4.170 ]] && post_to_2.4.180 - [[ "$POSTVERSION" == 2.4.180 ]] && post_to_2.4.190 - [[ "$POSTVERSION" == 2.4.190 ]] && post_to_2.4.200 - [[ "$POSTVERSION" == 2.4.200 ]] && post_to_2.4.201 - [[ "$POSTVERSION" == 2.4.201 ]] && post_to_2.4.210 true } @@ -509,216 +457,11 @@ post_to_2.4.3() { POSTVERSION=2.4.3 } -post_to_2.4.4() { - echo "Nothing to apply" - POSTVERSION=2.4.4 +up_to_2.4.3() { + echo "Nothing to do for 2.4.3" + + INSTALLEDVERSION=2.4.3 } - -post_to_2.4.5() { - echo "Nothing to apply" - POSTVERSION=2.4.5 -} - -post_to_2.4.10() { - echo "Updating Elastic Fleet ES URLs...." - /sbin/so-elastic-fleet-es-url-update --force - POSTVERSION=2.4.10 -} - -post_to_2.4.20() { - echo "Pruning unused docker volumes on all nodes - This process will run in the background." - salt --async \* cmd.run "docker volume prune -f" - POSTVERSION=2.4.20 -} - -post_to_2.4.30() { - # there is an occasional error with this state: pki_public_ca_crt: TypeError: list indices must be integers or slices, not str - set +e - salt-call state.apply ca queue=True - set -e - stop_salt_minion - mv /etc/pki/managerssl.crt /etc/pki/managerssl.crt.old - mv /etc/pki/managerssl.key /etc/pki/managerssl.key.old - systemctl_func "start" "salt-minion" - salt-call state.apply nginx queue=True - enable_highstate - POSTVERSION=2.4.30 -} - -post_to_2.4.40() { - echo "Nothing to apply" - POSTVERSION=2.4.40 -} - -post_to_2.4.50() { - echo "Nothing to apply" - POSTVERSION=2.4.50 -} - -post_to_2.4.60() { - echo "Nothing to apply" - POSTVERSION=2.4.60 -} - -post_to_2.4.70() { - printf "\nRemoving idh.services from any existing IDH node pillar files\n" - for file in /opt/so/saltstack/local/pillar/minions/*.sls; do - if [[ $file =~ "_idh.sls" && ! $file =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then - echo "Removing idh.services from: $file" - so-yaml.py remove "$file" idh.services - fi - done - POSTVERSION=2.4.70 -} - -post_to_2.4.80() { - echo -e "\nChecking if update to Elastic Fleet output policy is required\n" - so-kafka-fleet-output-policy - POSTVERSION=2.4.80 -} - -post_to_2.4.90() { - disable_logstash_heavynodes - POSTVERSION=2.4.90 -} - -post_to_2.4.100() { - echo "Nothing to apply" - POSTVERSION=2.4.100 -} - -post_to_2.4.110() { - echo "Nothing to apply" - POSTVERSION=2.4.110 -} - -post_to_2.4.111() { - echo "Nothing to apply" - POSTVERSION=2.4.111 -} - -post_to_2.4.120() { - update_elasticsearch_index_settings - - # Manually rollover suricata alerts index to ensure data_stream.dataset expected mapping is set to 'suricata' - rollover_index "logs-suricata.alerts-so" - - POSTVERSION=2.4.120 -} - -post_to_2.4.130() { - # Optional integrations are loaded AFTER initial successful load of core ES templates (/opt/so/state/estemplates.txt) - # Dynamic templates are created in elasticsearch.enabled for every optional integration based on output of so-elastic-fleet-optional-integrations-load script - echo "Ensuring Elasticsearch templates are up to date after updating package registry" - salt-call state.apply elasticsearch queue=True - - # Update kibana default space - salt-call state.apply kibana.config queue=True - echo "Updating Kibana default space" - /usr/sbin/so-kibana-space-defaults - - POSTVERSION=2.4.130 -} - -post_to_2.4.140() { - echo "Nothing to apply" - POSTVERSION=2.4.140 -} - -post_to_2.4.141() { - echo "Nothing to apply" - POSTVERSION=2.4.141 -} - -post_to_2.4.150() { - echo "Nothing to apply" - POSTVERSION=2.4.150 -} - -post_to_2.4.160() { - echo "Nothing to apply" - POSTVERSION=2.4.160 -} - -post_to_2.4.170() { - # Update kibana default space - salt-call state.apply kibana.config queue=True - echo "Updating Kibana default space" - /usr/sbin/so-kibana-space-defaults - - POSTVERSION=2.4.170 -} - -post_to_2.4.180() { - # Force update to Kafka output policy - /usr/sbin/so-kafka-fleet-output-policy --force - - POSTVERSION=2.4.180 -} - -post_to_2.4.190() { - # Only need to update import / eval nodes - if [[ "$MINION_ROLE" == "import" ]] || [[ "$MINION_ROLE" == "eval" ]]; then - update_import_fleet_output - fi - - # Check if expected default policy is logstash (global.pipeline is REDIS or "") - pipeline=$(lookup_pillar "pipeline" "global") - if [[ -z "$pipeline" ]] || [[ "$pipeline" == "REDIS" ]]; then - # Check if this grid is currently affected by corrupt fleet output policy - if elastic-agent status | grep "config: key file not configured" > /dev/null 2>&1; then - echo "Elastic Agent shows an ssl error connecting to logstash output. Updating output policy..." - update_default_logstash_output - fi - fi - # Apply new elasticsearch.server index template - rollover_index "logs-elasticsearch.server-default" - - POSTVERSION=2.4.190 -} - -post_to_2.4.200() { - echo "Initiating Suricata idstools migration..." - suricata_idstools_removal_post - - POSTVERSION=2.4.200 -} - -post_to_2.4.201() { - echo "Nothing to apply" - POSTVERSION=2.4.201 -} - -post_to_2.4.210() { - echo "Rolling over Kratos index to apply new index template" - - rollover_index "logs-kratos-so" - - disable_redis_heavynodes - - initialize_elasticsearch_indices "so-case so-casehistory so-assistant-session so-assistant-chat" - - echo "Regenerating Elastic Agent Installers" - /sbin/so-elastic-agent-gen-installers - - # migrate elasticsearch:managed_integrations pillar to manager:managed_integrations - if managed_integrations=$(/usr/sbin/so-yaml.py get /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.managed_integrations 2>/dev/null); then - local managed_integrations_old_pillar="/tmp/elasticsearch-managed_integrations.yaml" - - echo "Migrating managed_integrations pillar" - echo -e "$managed_integrations" > "$managed_integrations_old_pillar" - - /usr/sbin/so-yaml.py add /opt/so/saltstack/local/pillar/manager/soc_manager.sls manager.managed_integrations file:$managed_integrations_old_pillar > /dev/null 2>&1 - - /usr/sbin/so-yaml.py remove /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.managed_integrations - fi - - # Remove so-rule-update script left behind by the idstools removal in 2.4.200 - rm -f /usr/sbin/so-rule-update - - POSTVERSION=2.4.210 -} - repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -769,246 +512,6 @@ stop_salt_minion() { set -e } - -up_to_2.4.3() { - echo "Nothing to do for 2.4.3" - - INSTALLEDVERSION=2.4.3 -} - -up_to_2.4.4() { - echo "Nothing to do for 2.4.4" - - INSTALLEDVERSION=2.4.4 -} - -up_to_2.4.5() { - echo "Nothing to do for 2.4.5" - - INSTALLEDVERSION=2.4.5 -} - -up_to_2.4.10() { - echo "Nothing to do for 2.4.10" - - INSTALLEDVERSION=2.4.10 -} - -up_to_2.4.20() { - echo "Nothing to do for 2.4.20" - - INSTALLEDVERSION=2.4.20 -} - -up_to_2.4.30() { - echo "Nothing to do for 2.4.30" - - INSTALLEDVERSION=2.4.30 -} - -up_to_2.4.40() { - echo "Removing old ATT&CK Navigator Layers..." - rm -f /opt/so/conf/navigator/layers/enterprise-attack.json - rm -f /opt/so/conf/navigator/layers/nav_layer_playbook.json - - INSTALLEDVERSION=2.4.40 -} - -up_to_2.4.50() { - echo "Creating additional pillars.." - mkdir -p /opt/so/saltstack/local/pillar/stig/ - mkdir -p /opt/so/saltstack/local/salt/stig/ - chown socore:socore /opt/so/saltstack/local/salt/stig/ - touch /opt/so/saltstack/local/pillar/stig/adv_stig.sls - touch /opt/so/saltstack/local/pillar/stig/soc_stig.sls - - # the file_roots need to be update due to salt 3006.6 upgrade not allowing symlinks outside the file_roots - # put new so-yaml in place - echo "Updating so-yaml" - \cp -v "$UPDATE_DIR/salt/manager/tools/sbin/so-yaml.py" "$DEFAULT_SALT_DIR/salt/manager/tools/sbin/" - \cp -v "$UPDATE_DIR/salt/manager/tools/sbin/so-yaml.py" /usr/sbin/ - echo "Creating a backup of the salt-master config." - # INSTALLEDVERSION is 2.4.40 at this point, but we want the backup to have the version - # so was at prior to starting upgrade. use POSTVERSION here since it doesnt change until - # post upgrade changes. POSTVERSION set to INSTALLEDVERSION at start of soup - cp -v /etc/salt/master "/etc/salt/master.so-$POSTVERSION.bak" - echo "Adding /opt/so/rules to file_roots in /etc/salt/master using so-yaml" - so-yaml.py append /etc/salt/master file_roots.base /opt/so/rules/nids - echo "Moving Suricata rules" - mkdir /opt/so/rules/nids/suri - chown socore:socore /opt/so/rules/nids/suri - mv -v /opt/so/rules/nids/*.rules /opt/so/rules/nids/suri/. - - echo "Adding /nsm/elastic-fleet/artifacts to file_roots in /etc/salt/master using so-yaml" - so-yaml.py append /etc/salt/master file_roots.base /nsm/elastic-fleet/artifacts - - INSTALLEDVERSION=2.4.50 -} - -up_to_2.4.60() { - echo "Creating directory to store Suricata classification.config" - mkdir -vp /opt/so/saltstack/local/salt/suricata/classification - chown socore:socore /opt/so/saltstack/local/salt/suricata/classification - - INSTALLEDVERSION=2.4.60 -} - -up_to_2.4.70() { - playbook_migration - suricata_idstools_migration - toggle_telemetry - add_detection_test_pillars - - INSTALLEDVERSION=2.4.70 -} - -up_to_2.4.80() { - phases_pillar_2_4_80 - # Kafka configuration changes - - # Global pipeline changes to REDIS or KAFKA - echo "Removing global.pipeline pillar configuration" - sed -i '/pipeline:/d' /opt/so/saltstack/local/pillar/global/soc_global.sls - # Kafka pillars - mkdir -p /opt/so/saltstack/local/pillar/kafka - touch /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - touch /opt/so/saltstack/local/pillar/kafka/adv_kafka.sls - echo 'kafka: ' > /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - kafka_cluster_id=$(get_random_value 22) - echo ' cluster_id: '$kafka_cluster_id >> /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - kafkapass=$(get_random_value) - echo ' password: '$kafkapass >> /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls - - INSTALLEDVERSION=2.4.80 -} - -up_to_2.4.90() { - kafkatrust=$(get_random_value) - # rearranging the kafka pillar to reduce clutter in SOC UI - kafkasavedpass=$(so-yaml.py get /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.password) - kafkatrimpass=$(echo "$kafkasavedpass" | sed -n '1 p' ) - echo "Making changes to the Kafka pillar layout" - so-yaml.py remove /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.password - so-yaml.py add /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.config.password "$kafkatrimpass" - so-yaml.py add /opt/so/saltstack/local/pillar/kafka/soc_kafka.sls kafka.config.trustpass "$kafkatrust" - - INSTALLEDVERSION=2.4.90 -} - -up_to_2.4.100() { - echo "Nothing to do for 2.4.100" - - INSTALLEDVERSION=2.4.100 -} - -up_to_2.4.110() { - echo "Nothing to do for 2.4.110" - - INSTALLEDVERSION=2.4.110 -} - -up_to_2.4.111() { - echo "Nothing to do for 2.4.111" - - INSTALLEDVERSION=2.4.111 -} - -up_to_2.4.120() { - add_hydra_pillars - - # this is needed for the new versionlock state - mkdir -p /opt/so/saltstack/local/pillar/versionlock - touch /opt/so/saltstack/local/pillar/versionlock/adv_versionlock.sls /opt/so/saltstack/local/pillar/versionlock/soc_versionlock.sls - - - INSTALLEDVERSION=2.4.120 -} - -up_to_2.4.130() { - # Remove any old Elastic Defend config files - rm -f /opt/so/conf/elastic-fleet/integrations/endpoints-initial/elastic-defend-endpoints.json - - # Ensure override exists to allow nmcli access to other devices - touch /etc/NetworkManager/conf.d/10-globally-managed-devices.conf - - INSTALLEDVERSION=2.4.130 -} - -up_to_2.4.140() { - echo "Nothing to do for 2.4.140" - - INSTALLEDVERSION=2.4.140 -} - -up_to_2.4.141() { - echo "Nothing to do for 2.4.141" - - INSTALLEDVERSION=2.4.141 -} - -up_to_2.4.150() { - echo "If the Detection indices exists, update the refresh_interval" - so-elasticsearch-query so-detection*/_settings -X PUT -d '{"index":{"refresh_interval":"1s"}}' - - INSTALLEDVERSION=2.4.150 -} - -up_to_2.4.160() { - echo "Nothing to do for 2.4.160" - - INSTALLEDVERSION=2.4.160 -} - -up_to_2.4.170() { - echo "Creating pillar files for virtualization feature" - - states=("hypervisor" "vm" "libvirt") - - # Create pillar files for each state - for state in "${states[@]}"; do - mkdir -p /opt/so/saltstack/local/pillar/$state - touch /opt/so/saltstack/local/pillar/$state/adv_$state.sls /opt/so/saltstack/local/pillar/$state/soc_$state.sls - done - - - INSTALLEDVERSION=2.4.170 -} - -up_to_2.4.180() { - echo "Nothing to do for 2.4.180" - INSTALLEDVERSION=2.4.180 -} - -up_to_2.4.190() { - echo "Nothing to do for 2.4.190" - INSTALLEDVERSION=2.4.190 -} - -up_to_2.4.200() { - echo "Backing up idstools config..." - suricata_idstools_removal_pre - - touch /opt/so/state/esfleet_logstash_config_pillar - - INSTALLEDVERSION=2.4.200 -} - -up_to_2.4.201() { - echo "Nothing to do for 2.4.201" - - INSTALLEDVERSION=2.4.201 -} - -up_to_2.4.210() { - # Elastic Update for this release, so download Elastic Agent files - determine_elastic_agent_upgrade - create_ca_pillar - # This state is used to deal with the breaking change introduced in 3006.17 - https://docs.saltproject.io/en/3006/topics/releases/3006.17.html - # This is the only way the state is called so we can use concurrent=True - salt-call state.apply salt.master.add_minimum_auth_version --file-root=$UPDATE_DIR/salt --local concurrent=True - INSTALLEDVERSION=2.4.210 -} - add_hydra_pillars() { mkdir -p /opt/so/saltstack/local/pillar/hydra touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls From 685e22bd68f364aca635f680c37ef731b6202973 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Mar 2026 11:58:06 -0400 Subject: [PATCH 2/5] soup cleanup --- salt/manager/tools/sbin/soup | 536 ----------------------------------- 1 file changed, 536 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index de1f7a48c..eee7e1c18 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -329,50 +329,6 @@ clone_to_tmp() { fi } -# there is a function like this in so-minion, but we cannot source it since args required for so-minion -create_ca_pillar() { - local ca_pillar_dir="/opt/so/saltstack/local/pillar/ca" - local ca_pillar_file="${ca_pillar_dir}/init.sls" - - echo "Updating CA pillar configuration" - mkdir -p "$ca_pillar_dir" - echo "ca: {}" > "$ca_pillar_file" - - so-yaml.py add "$ca_pillar_file" ca.server "$MINIONID" - chown -R socore:socore "$ca_pillar_dir" -} - -disable_logstash_heavynodes() { - c=0 - printf "\nChecking for heavynodes and disabling Logstash if they exist\n" - for file in /opt/so/saltstack/local/pillar/minions/*.sls; do - if [[ "$file" =~ "_heavynode.sls" && ! "$file" =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then - if [ "$c" -eq 0 ]; then - c=$((c + 1)) - FINAL_MESSAGE_QUEUE+=("Logstash has been disabled on all heavynodes. It can be re-enabled via Grid Configuration in SOC.") - fi - echo "Disabling Logstash for: $file" - so-yaml.py replace "$file" logstash.enabled False - fi - done -} - -disable_redis_heavynodes() { - local c=0 - printf "\nChecking for heavynodes and disabling Redis if they exist\n" - for file in /opt/so/saltstack/local/pillar/minions/*.sls; do - if [[ "$file" =~ "_heavynode.sls" && ! "$file" =~ "/opt/so/saltstack/local/pillar/minions/adv_" ]]; then - c=1 - echo "Disabling Redis for: $file" - so-yaml.py replace "$file" redis.enabled False - fi - done - - if [[ "$c" != 0 ]]; then - FINAL_MESSAGE_QUEUE+=("Redis has been disabled on all heavynodes.") - fi -} - enable_highstate() { echo "Enabling highstate." salt-call state.enable highstate -l info --local @@ -413,28 +369,6 @@ masterunlock() { fi } -phases_pillar_2_4_80() { - echo "Checking if pillar value: elasticsearch.index_settings.global_overrides.index_template.phases exists" - set +e - PHASES=$(so-yaml.py get /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.index_settings.global_overrides.index_template.phases) - case $? in - 0) - so-yaml.py remove /opt/so/saltstack/local/pillar/elasticsearch/soc_elasticsearch.sls elasticsearch.index_settings.global_overrides.index_template.phases - read -r -d '' msg <<- EOF -Found elasticsearch.index_settings.global_overrides.index_template.phases was set to: -${PHASES} - -Removed unused pillar value: elasticsearch.index_settings.global_overrides.index_template.phases -To set policies, navigate to the SOC Grid Configuration UI at elasticsearch.index_settings.global_overrides.policy.phases -A backup of all pillar files was saved to /nsm/backup/ -EOF - FINAL_MESSAGE_QUEUE+=("$msg") - ;; - 2) echo "Pillar elasticsearch.index_settings.global_overrides.index_template.phases does not exist. No action taken." ;; - *) echo "so-yaml.py returned something other than 0 or 2 exit code" ;; # we shouldn't see this - esac - set -e -} preupgrade_changes() { # This function is to add any new pillar items if needed. @@ -512,72 +446,6 @@ stop_salt_minion() { set -e } -add_hydra_pillars() { - mkdir -p /opt/so/saltstack/local/pillar/hydra - touch /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls - chmod 660 /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls - touch /opt/so/saltstack/local/pillar/hydra/adv_hydra.sls - HYDRAKEY=$(get_random_value) - HYDRASALT=$(get_random_value) - printf '%s\n'\ - "hydra:"\ - " config:"\ - " secrets:"\ - " system:"\ - " - '$HYDRAKEY'"\ - " oidc:"\ - " subject_identifiers:"\ - " pairwise:"\ - " salt: '$HYDRASALT'"\ - "" > /opt/so/saltstack/local/pillar/hydra/soc_hydra.sls -} - -add_detection_test_pillars() { - if [[ -n "$SOUP_INTERNAL_TESTING" ]]; then - echo "Adding detection pillar values for automated testing" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.elastalertengine.allowRegex SecurityOnion - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.elastalertengine.failAfterConsecutiveErrorCount 1 - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.strelkaengine.allowRegex "EquationGroup_Toolset_Apr17__ELV_.*" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.strelkaengine.failAfterConsecutiveErrorCount 1 - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.suricataengine.allowRegex "(200033\\d|2100538|2102466)" - so-yaml.py add /opt/so/saltstack/local/pillar/soc/soc_soc.sls soc.config.server.modules.suricataengine.failAfterConsecutiveErrorCount 1 - fi -} - -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://securityonion.net/docs/telemetry - -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 -} - rollover_index() { idx=$1 exists=$(so-elasticsearch-query $idx -o /dev/null -w "%{http_code}") @@ -594,320 +462,6 @@ rollover_index() { fi } -suricata_idstools_migration() { - # For 2.4.70 - - #Backup the pillars for idstools - mkdir -p /nsm/backup/detections-migration/idstools - rsync -av /opt/so/saltstack/local/pillar/idstools/* /nsm/backup/detections-migration/idstools - if [[ $? -eq 0 ]]; then - echo "IDStools configuration has been backed up." - else - fail "Error: rsync failed to copy the files. IDStools configuration has not been backed up." - fi - - #Backup Thresholds - mkdir -p /nsm/backup/detections-migration/suricata - rsync -av /opt/so/saltstack/local/salt/suricata/thresholding /nsm/backup/detections-migration/suricata - if [[ $? -eq 0 ]]; then - echo "Suricata thresholds have been backed up." - else - 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 - 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 - echo "0" > /opt/so/conf/soc/migrations/suricata-migration-2.4.70 - chown -R socore:socore /opt/so/conf/soc/migrations -} - -playbook_migration() { - # Start SOC Detections migration - mkdir -p /nsm/backup/detections-migration/{suricata,sigma/rules,elastalert} - - # Remove cronjobs - crontab -l | grep -v 'so-playbook-sync_cron' | crontab - - crontab -l | grep -v 'so-playbook-ruleupdate_cron' | crontab - - - 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" -o -name "*.yml" \) | wc -l) - - if [[ "$active_rules_count" -gt 0 ]]; then - # 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 "Press ENTER to proceed." - echo - # Read user input - read -r - - echo "Backing up the Elastalert rules..." - 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 - # Delete the Elastlaert rules - rm -f /opt/so/rules/elastalert/playbook/*.yaml - echo "Active Elastalert rules have been backed up." - else - fail "Error: rsync failed to copy the files. Active Elastalert rules have not been backed up." - fi - fi - - echo - echo "Exporting Sigma rules from Playbook..." - MYSQLPW=$(awk '/mysql:/ {print $2}' /opt/so/saltstack/local/pillar/secrets.sls) - - docker exec so-mysql sh -c "exec mysql -uroot -p${MYSQLPW} -D playbook -sN -e \"SELECT id, value FROM custom_values WHERE value LIKE '%View Sigma%'\"" | while read -r id value; do - echo -e "$value" > "/nsm/backup/detections-migration/sigma/rules/$id.yaml" - done || fail "Failed to export Sigma rules..." - - echo - echo "Exporting Sigma Filters from Playbook..." - docker exec so-mysql sh -c "exec mysql -uroot -p${MYSQLPW} -D playbook -sN -e \"SELECT issues.subject as title, custom_values.value as filter FROM issues JOIN custom_values ON issues.id = custom_values.customized_id WHERE custom_values.value LIKE '%sofilter%'\"" > /nsm/backup/detections-migration/sigma/custom-filters.txt || fail "Failed to export Custom Sigma Filters." - - echo - echo "Backing up Playbook database..." - docker exec so-mysql sh -c "mysqldump -uroot -p${MYSQLPW} --databases playbook > /tmp/playbook-dump" || fail "Failed to dump Playbook database." - docker cp so-mysql:/tmp/playbook-dump /nsm/backup/detections-migration/sigma/playbook-dump.sql || fail "Failed to backup Playbook database." - fi - - echo - echo "Stopping Playbook services & cleaning up..." - for container in so-playbook so-mysql so-soctopus; do - if [ -n "$(docker ps -q -f name=^${container}$)" ]; then - docker stop $container - fi - done - sed -i '/so-playbook\|so-soctopus\|so-mysql/d' /opt/so/conf/so-status/so-status.conf - rm -f /usr/sbin/so-playbook-* /usr/sbin/so-soctopus-* /usr/sbin/so-mysql-* - - echo - echo "Playbook Migration is complete...." -} - -suricata_idstools_removal_pre() { -# For SOUPs beginning with 2.4.200 - pre SOUP checks - -# Create syncBlock file -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 -cat > /opt/so/conf/soc/fingerprints/suricataengine.syncBlock << EOF -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://securityonion.net/docs/nids -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 -mkdir -p /nsm/backup/detections-migration/2-4-200 -cp /usr/sbin/so-rule-update /nsm/backup/detections-migration/2-4-200 -cp /opt/so/conf/idstools/etc/rulecat.conf /nsm/backup/detections-migration/2-4-200 - -# Backup so-detection index via reindex -echo "Creating sos-backup index template..." -template_result=$(/sbin/so-elasticsearch-query '_index_template/sos-backup' -X PUT \ - --retry 5 --retry-delay 15 --retry-all-errors \ - -d '{"index_patterns":["sos-backup-*"],"priority":501,"template":{"settings":{"index":{"number_of_replicas":0,"number_of_shards":1}}}}') - -if [[ -z "$template_result" ]] || ! echo "$template_result" | jq -e '.acknowledged == true' > /dev/null 2>&1; then - echo "Error: Failed to create sos-backup index template" - echo "$template_result" - exit 1 -fi - -BACKUP_INDEX="sos-backup-detection-$(date +%Y%m%d-%H%M%S)" -echo "Backing up so-detection index to $BACKUP_INDEX..." -reindex_result=$(/sbin/so-elasticsearch-query '_reindex?wait_for_completion=true' \ - --retry 5 --retry-delay 15 --retry-all-errors \ - -X POST -d "{\"source\": {\"index\": \"so-detection\"}, \"dest\": {\"index\": \"$BACKUP_INDEX\"}}") - -if [[ -z "$reindex_result" ]]; then - echo "Error: Backup of detections failed - no response from Elasticsearch" - exit 1 -elif echo "$reindex_result" | jq -e '.created >= 0' > /dev/null 2>&1; then - echo "Backup complete: $(echo "$reindex_result" | jq -r '.created') documents copied" -elif echo "$reindex_result" | grep -q "index_not_found_exception"; then - echo "so-detection index does not exist, skipping backup" -else - echo "Error: Backup of detections failed" - echo "$reindex_result" - exit 1 -fi - -} - -suricata_idstools_removal_post() { -# For SOUPs beginning with 2.4.200 - post SOUP checks - -echo "Checking idstools configuration for custom modifications..." - -# Normalize and hash file content for consistent comparison -# Args: $1 - file path -# Outputs: SHA256 hash to stdout -# Returns: 0 on success, 1 on failure -hash_normalized_file() { - local file="$1" - - if [[ ! -r "$file" ]]; then - return 1 - fi - - # Ensure trailing newline for consistent hashing regardless of source file - { sed -E \ - -e 's/^[[:space:]]+//; s/[[:space:]]+$//' \ - -e '/^$/d' \ - -e 's|--url=http://[^:]+:7788|--url=http://MANAGER:7788|' \ - "$file"; echo; } | sed '/^$/d' | sha256sum | awk '{print $1}' -} - -# Known-default hashes for so-rule-update (ETOPEN ruleset) -KNOWN_SO_RULE_UPDATE_HASHES=( - # 2.4.100+ (suricata 7.0.3, non-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=( - # 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 -# Args: $1 - file path, $2 - array name of known hashes -check_config_file() { - local file="$1" - local known_hashes_array="$2" - local file_display_name=$(basename "$file") - - if [[ ! -f "$file" ]]; then - echo "Warning: $file not found" - echo "$file_display_name not found - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - return 1 - fi - - echo "Hashing $file..." - local file_hash - if ! file_hash=$(hash_normalized_file "$file"); then - echo "Warning: Could not read $file" - echo "$file_display_name not readable - manual verification required" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - return 1 - fi - - echo " Hash: $file_hash" - - # Check if hash matches any known default - local -n known_hashes=$known_hashes_array - for known_hash in "${known_hashes[@]}"; do - if [[ "$file_hash" == "$known_hash" ]]; then - echo " Matches known default configuration" - return 0 - fi - done - - # No match - custom configuration detected - echo "Does not match known default - custom configuration detected" - echo "Custom $file_display_name detected (hash: $file_hash)" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - - # If this is so-rule-update, check for ETPRO license code and write out to the syncBlock file - # If ETPRO is enabled, the license code already exists in the so-rule-update script, this is just making it easier to migrate - if [[ "$file_display_name" == "so-rule-update" ]]; then - local etpro_code - etpro_code=$(grep -oP '\-\-etpro=\K[0-9a-fA-F]+' "$file" 2>/dev/null) || true - if [[ -n "$etpro_code" ]]; then - echo "ETPRO code found: $etpro_code" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - fi - fi - - return 1 -} - -# Check so-rule-update and rulecat.conf -SO_RULE_UPDATE="/usr/sbin/so-rule-update" -RULECAT_CONF="/opt/so/conf/idstools/etc/rulecat.conf" - -custom_found=0 - -check_config_file "$SO_RULE_UPDATE" "KNOWN_SO_RULE_UPDATE_HASHES" || custom_found=1 -check_config_file "$RULECAT_CONF" "KNOWN_RULECAT_CONF_HASHES" || custom_found=1 - -# Check for ETPRO rules on airgap systems -if [[ $is_airgap -eq 0 ]] && grep -q 'ETPRO ' /nsm/rules/suricata/emerging-all.rules 2>/dev/null; then - echo "ETPRO rules detected on airgap system - custom configuration" - echo "ETPRO rules detected on Airgap in /nsm/rules/suricata/emerging-all.rules" >> /opt/so/conf/soc/fingerprints/suricataengine.syncBlock - custom_found=1 -fi - -# If no custom configs found, remove syncBlock -if [[ $custom_found -eq 0 ]]; then - echo "idstools migration completed successfully - removing Suricata engine syncBlock" - rm -f /opt/so/conf/soc/fingerprints/suricataengine.syncBlock -else - echo "Custom idstools configuration detected - syncBlock remains in place" - echo "Review /opt/so/conf/soc/fingerprints/suricataengine.syncBlock for details" -fi - -echo "Cleaning up idstools" -echo "Stopping and removing the idstools container..." -if [ -n "$(docker ps -q -f name=^so-idstools$)" ]; then - image_name=$(docker ps -a --filter name=^so-idstools$ --format '{{.Image}}' 2>/dev/null || true) - docker stop so-idstools || echo "Warning: failed to stop so-idstools container" - docker rm so-idstools || echo "Warning: failed to remove so-idstools container" - - if [[ -n "$image_name" ]]; then - echo "Removing idstools image: $image_name" - docker rmi "$image_name" || echo "Warning: failed to remove image $image_name" - fi -fi - -echo "Removing idstools symlink and scripts..." -rm -rf /usr/sbin/so-idstools* -sed -i '/^#\?so-idstools$/d' /opt/so/conf/so-status/so-status.conf -crontab -l | grep -v 'so-rule-update' | crontab - - -# 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 - -} - determine_elastic_agent_upgrade() { if [[ $is_airgap -eq 0 ]]; then update_elastic_agent_airgap @@ -974,68 +528,6 @@ update_airgap_repo() { createrepo /nsm/repo } -update_elasticsearch_index_settings() { - # Update managed indices to reflect latest index template - for idx in "so-detection" "so-detectionhistory" "so-case" "so-casehistory"; do - ilm_name=$idx - if [ "$idx" = "so-detectionhistory" ]; then - ilm_name="so-detection" - elif [ "$idx" = "so-casehistory" ]; then - ilm_name="so-case" - fi - JSON_STRING=$( jq -n --arg ILM_NAME "$ilm_name" '{"settings": {"index.auto_expand_replicas":"0-2","index.lifecycle.name":($ILM_NAME + "-logs")}}') - - echo "Checking if index \"$idx\" exists" - exists=$(curl -K /opt/so/conf/elasticsearch/curl.config -s -o /dev/null -w "%{http_code}" -k -L -H "Content-Type: application/json" "https://localhost:9200/$idx") - if [ $exists -eq 200 ]; then - echo "$idx index found..." - echo "Updating $idx index settings" - curl -K /opt/so/conf/elasticsearch/curl.config -s -k -L -H "Content-Type: application/json" "https://localhost:9200/$idx/_settings" -d "$JSON_STRING" -XPUT - echo -e "\n" - else - echo -e "Skipping $idx... index does not exist\n" - fi - done -} - -update_import_fleet_output() { - if output=$(curl -sK /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" --retry 3 --fail 2>/dev/null); then - # Update the current config of so-manager_elasticsearch output policy in place (leaving any customizations like having changed the preset value from 'balanced' to 'performance') - CAFINGERPRINT=$(openssl x509 -in /etc/pki/tls/certs/intca.crt -outform DER | sha256sum | cut -d' ' -f1 | tr '[:lower:]' '[:upper:]') - updated_policy=$(jq --arg CAFINGERPRINT "$CAFINGERPRINT" '.item | (del(.id) | .ca_trusted_fingerprint = $CAFINGERPRINT)' <<< "$output") - if curl -sK /opt/so/conf/elasticsearch/curl.config -L "localhost:5601/api/fleet/outputs/so-manager_elasticsearch" -XPUT -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$updated_policy" --retry 3 --fail 2>/dev/null; then - echo "Successfully updated so-manager_elasticsearch fleet output policy" - else - fail "Failed to update so-manager_elasticsearch fleet output policy" - fi - fi -} - -update_default_logstash_output() { - echo "Updating fleet logstash output policy grid-logstash" - if logstash_policy=$(curl -K /opt/so/conf/elasticsearch/curl.config -L "http://localhost:5601/api/fleet/outputs/so-manager_logstash" --retry 3 --retry-delay 10 --fail 2>/dev/null); then - # Keep already configured hosts for this update, subsequent host updates come from so-elastic-fleet-outputs-update - HOSTS=$(echo "$logstash_policy" | jq -r '.item.hosts') - DEFAULT_ENABLED=$(echo "$logstash_policy" | jq -r '.item.is_default') - DEFAULT_MONITORING_ENABLED=$(echo "$logstash_policy" | jq -r '.item.is_default_monitoring') - LOGSTASHKEY=$(openssl rsa -in /etc/pki/elasticfleet-logstash.key) - LOGSTASHCRT=$(openssl x509 -in /etc/pki/elasticfleet-logstash.crt) - LOGSTASHCA=$(openssl x509 -in /etc/pki/tls/certs/intca.crt) - JSON_STRING=$(jq -n \ - --argjson HOSTS "$HOSTS" \ - --arg DEFAULT_ENABLED "$DEFAULT_ENABLED" \ - --arg DEFAULT_MONITORING_ENABLED "$DEFAULT_MONITORING_ENABLED" \ - --arg LOGSTASHKEY "$LOGSTASHKEY" \ - --arg LOGSTASHCRT "$LOGSTASHCRT" \ - --arg LOGSTASHCA "$LOGSTASHCA" \ - '{"name":"grid-logstash","type":"logstash","hosts": $HOSTS,"is_default": $DEFAULT_ENABLED,"is_default_monitoring": $DEFAULT_MONITORING_ENABLED,"config_yaml":"","ssl":{"certificate": $LOGSTASHCRT,"certificate_authorities":[ $LOGSTASHCA ]},"secrets":{"ssl":{"key": $LOGSTASHKEY }}}') - fi - - if curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/outputs/so-manager_logstash" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" --retry 3 --retry-delay 10 --fail; then - echo "Successfully updated grid-logstash fleet output policy" - fi -} - update_salt_mine() { echo "Populating the mine with mine_functions for each host." set +e @@ -1573,35 +1065,7 @@ EOF # Keeping this block in case we need to do a hotfix that requires salt update apply_hotfix() { - if [[ "$INSTALLEDVERSION" == "2.4.20" ]] ; then - salt-call state.apply elasticfleet -l info queue=True - . /usr/sbin/so-elastic-fleet-common - elastic_fleet_integration_remove endpoints-initial elastic-defend-endpoints - /usr/sbin/so-elastic-fleet-integration-policy-elastic-defend - elif [[ "$INSTALLEDVERSION" == "2.4.30" ]] ; then - if [[ $is_airgap -eq 0 ]]; then - update_airgap_rules - fi - if [[ -f /etc/pki/managerssl.key.old ]]; then - echo "Skipping Certificate Generation" - else - rm -f /opt/so/conf/elastic-fleet/integrations/endpoints-initial/elastic-defend-endpoints.json - so-kibana-restart --force - so-kibana-api-check - . /usr/sbin/so-elastic-fleet-common - - elastic_fleet_integration_remove endpoints-initial elastic-defend-endpoints - rm -f /opt/so/state/eaintegrations.txt - salt-call state.apply ca queue=True - stop_salt_minion - mv /etc/pki/managerssl.crt /etc/pki/managerssl.crt.old - mv /etc/pki/managerssl.key /etc/pki/managerssl.key.old - systemctl_func "start" "salt-minion" - wait_for_salt_minion_with_restart "$MINIONID" "60" "3" "$SOUP_LOG" || fail "Salt minion was not running or ready." - fi - else echo "No actions required. ($INSTALLEDVERSION/$HOTFIXVERSION)" - fi } failed_soup_restore_items() { From bc9841ea8ceb1c02774185c6e5817abb642f45a6 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Mar 2026 14:45:40 -0400 Subject: [PATCH 3/5] Refactor upgrade functions and remove unused code Removed deprecated functions and updated version checks for upgrades. --- salt/manager/tools/sbin/soup | 51 ++++++++---------------------------- 1 file changed, 11 insertions(+), 40 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index eee7e1c18..75ec184e1 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -111,14 +111,6 @@ check_err() { } -add_common() { - cp $UPDATE_DIR/salt/common/tools/sbin/so-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/ - cp $UPDATE_DIR/salt/common/tools/sbin/so-image-common $DEFAULT_SALT_DIR/salt/common/tools/sbin/ - salt-call state.apply common queue=True - echo "Run soup one more time" - exit 0 -} - airgap_mounted() { # Let's see if the ISO is already mounted. if [[ -f /tmp/soagupdate/SecurityOnion/VERSION ]]; then @@ -214,8 +206,6 @@ check_airgap() { fi } -# {% raw %} - check_local_mods() { local salt_local=/opt/so/saltstack/local @@ -243,8 +233,6 @@ check_local_mods() { fi } -# {% endraw %} - check_pillar_items() { local pillar_output=$(salt-call pillar.items -lerror --out=json) @@ -374,7 +362,7 @@ preupgrade_changes() { # This function is to add any new pillar items if needed. echo "Checking to see if changes are needed." - [[ "$INSTALLEDVERSION" == 2.4.2 ]] && up_to_2.4.3 + [[ "$INSTALLEDVERSION" == 2.4.210 ]] && up_to_3.0.0 true } @@ -382,20 +370,23 @@ postupgrade_changes() { # This function is to add any new pillar items if needed. echo "Running post upgrade processes." - [[ "$POSTVERSION" == 2.4.2 ]] && post_to_2.4.3 + [[ "$POSTVERSION" == 2.4.210 ]] && post_to_3.0.0 true } -post_to_2.4.3() { - echo "Nothing to apply" - POSTVERSION=2.4.3 -} - -up_to_2.4.3() { +### 3.0.0 Scripts ### +up_to_3.0.0() { echo "Nothing to do for 2.4.3" INSTALLEDVERSION=2.4.3 } + +post_to_3.0.0() { + echo "Nothing to apply" + POSTVERSION=2.4.3 +} +### 3.0.0 End ### + repo_sync() { echo "Sync the local repo." su socore -c '/usr/sbin/so-repo-sync' || fail "Unable to complete so-repo-sync." @@ -446,22 +437,6 @@ stop_salt_minion() { set -e } -rollover_index() { - idx=$1 - exists=$(so-elasticsearch-query $idx -o /dev/null -w "%{http_code}") - if [[ $exists -eq 200 ]]; then - rollover=$(so-elasticsearch-query $idx/_rollover -o /dev/null -w "%{http_code}" -XPOST) - - if [[ $rollover -eq 200 ]]; then - echo "Successfully triggered rollover for $idx..." - else - echo "Could not trigger rollover for $idx..." - fi - else - echo "Could not find index $idx..." - fi -} - determine_elastic_agent_upgrade() { if [[ $is_airgap -eq 0 ]]; then update_elastic_agent_airgap @@ -703,10 +678,6 @@ verify_es_version_compatibility() { local is_active_intermediate_upgrade=1 # 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" ) From 91759587f5f774d1c882e6926f9330ba70489a46 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Mar 2026 14:58:43 -0400 Subject: [PATCH 4/5] Update version numbers for upgrade scripts --- salt/manager/tools/sbin/soup | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 75ec184e1..2f487c4af 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -375,16 +375,18 @@ postupgrade_changes() { } ### 3.0.0 Scripts ### -up_to_3.0.0() { - echo "Nothing to do for 2.4.3" - INSTALLEDVERSION=2.4.3 +up_to_3.0.0() { + determine_elastic_agent_upgrade() + + INSTALLEDVERSION=3.0.0 } post_to_3.0.0() { echo "Nothing to apply" - POSTVERSION=2.4.3 + POSTVERSION=3.0.0 } + ### 3.0.0 End ### repo_sync() { From 4539024280d1601a210f71f90155d28f28d68155 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Tue, 10 Mar 2026 15:05:52 -0400 Subject: [PATCH 5/5] Add minimum version check and fix function call syntax in soup Require at least Security Onion 2.4.210 before allowing upgrade. Fix determine_elastic_agent_upgrade() call syntax (remove parens). --- salt/manager/tools/sbin/soup | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index 2f487c4af..6d209a750 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -374,10 +374,17 @@ postupgrade_changes() { true } +check_minimum_version() { + if [[ "$INSTALLEDVERSION" != "2.4.210" ]] && [[ ! "$INSTALLEDVERSION" =~ ^3\. ]]; then + echo "You must be on at least Security Onion 2.4.210 to upgrade. Currently installed version: $INSTALLEDVERSION" + exit 1 + fi +} + ### 3.0.0 Scripts ### up_to_3.0.0() { - determine_elastic_agent_upgrade() + determine_elastic_agent_upgrade INSTALLEDVERSION=3.0.0 } @@ -1086,6 +1093,8 @@ main() { MINION_ROLE=$(lookup_role) echo "Found that Security Onion $INSTALLEDVERSION is currently installed." echo "" + check_minimum_version + if [[ $is_airgap -eq 0 ]]; then # Let's mount the ISO since this is airgap airgap_mounted