diff --git a/DOWNLOAD_AND_VERIFY_ISO.md b/DOWNLOAD_AND_VERIFY_ISO.md index dabfd285c..539dd9e8e 100644 --- a/DOWNLOAD_AND_VERIFY_ISO.md +++ b/DOWNLOAD_AND_VERIFY_ISO.md @@ -1,18 +1,18 @@ -### 2.4.20-20231006 ISO image released on 2023/10/06 +### 2.4.20-20231012 ISO image released on 2023/10/12 ### Download and Verify -2.4.20-20231006 ISO image: -https://download.securityonion.net/file/securityonion/securityonion-2.4.20-20231006.iso +2.4.20-20231012 ISO image: +https://download.securityonion.net/file/securityonion/securityonion-2.4.20-20231012.iso -MD5: 269F00308C53976BF0EAE788D1DB29DB -SHA1: 3F7C2324AE1271112F3B752BA4724AF36688FC27 -SHA256: 542B8B3F4F75AD24DC78007F8FE0857E00DC4CC9F4870154DCB8D5D0C4144B65 +MD5: 7D6ACA843068BA9432B3FF63BFD1EF0F +SHA1: BEF2B906066A1B04921DF0B80E7FDD4BC8ECED5C +SHA256: 5D511D50F11666C69AE12435A47B9A2D30CB3CC88F8D38DC58A5BC0ECADF1BF5 Signature for ISO image: -https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.20-20231006.iso.sig +https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.20-20231012.iso.sig Signing key: https://raw.githubusercontent.com/Security-Onion-Solutions/securityonion/2.4/main/KEYS @@ -26,22 +26,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.20-20231006.iso.sig +wget https://github.com/Security-Onion-Solutions/securityonion/raw/2.4/main/sigs/securityonion-2.4.20-20231012.iso.sig ``` Download the ISO image: ``` -wget https://download.securityonion.net/file/securityonion/securityonion-2.4.20-20231006.iso +wget https://download.securityonion.net/file/securityonion/securityonion-2.4.20-20231012.iso ``` Verify the downloaded ISO image using the signature file: ``` -gpg --verify securityonion-2.4.20-20231006.iso.sig securityonion-2.4.20-20231006.iso +gpg --verify securityonion-2.4.20-20231012.iso.sig securityonion-2.4.20-20231012.iso ``` The output should show "Good signature" and the Primary key fingerprint should match what's shown below: ``` -gpg: Signature made Tue 03 Oct 2023 11:40:51 AM EDT using RSA key ID FE507013 +gpg: Signature made Thu 12 Oct 2023 01:28:32 PM 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/pillar/logstash/nodes.sls b/pillar/logstash/nodes.sls index 8d3bdab65..a77978821 100644 --- a/pillar/logstash/nodes.sls +++ b/pillar/logstash/nodes.sls @@ -7,19 +7,23 @@ tgt_type='compound') | dictsort() %} -{% set hostname = cached_grains[minionid]['host'] %} -{% set node_type = minionid.split('_')[1] %} -{% if node_type not in node_types.keys() %} -{% do node_types.update({node_type: {hostname: ip[0]}}) %} -{% else %} -{% if hostname not in node_types[node_type] %} -{% do node_types[node_type].update({hostname: ip[0]}) %} +# only add a node to the pillar if it returned an ip from the mine +{% if ip | length > 0%} +{% set hostname = cached_grains[minionid]['host'] %} +{% set node_type = minionid.split('_')[1] %} +{% if node_type not in node_types.keys() %} +{% do node_types.update({node_type: {hostname: ip[0]}}) %} {% else %} -{% do node_types[node_type][hostname].update(ip[0]) %} +{% if hostname not in node_types[node_type] %} +{% do node_types[node_type].update({hostname: ip[0]}) %} +{% else %} +{% do node_types[node_type][hostname].update(ip[0]) %} +{% endif %} {% endif %} {% endif %} {% endfor %} + logstash: nodes: {% for node_type, values in node_types.items() %} diff --git a/pillar/node_data/ips.sls b/pillar/node_data/ips.sls index 59c598879..5801d36f1 100644 --- a/pillar/node_data/ips.sls +++ b/pillar/node_data/ips.sls @@ -4,18 +4,22 @@ {% set hostname = minionid.split('_')[0] %} {% set node_type = minionid.split('_')[1] %} {% set is_alive = False %} -{% if minionid in manage_alived.keys() %} -{% if ip[0] == manage_alived[minionid] %} -{% set is_alive = True %} + +# only add a node to the pillar if it returned an ip from the mine +{% if ip | length > 0%} +{% if minionid in manage_alived.keys() %} +{% if ip[0] == manage_alived[minionid] %} +{% set is_alive = True %} +{% endif %} {% endif %} -{% endif %} -{% if node_type not in node_types.keys() %} -{% do node_types.update({node_type: {hostname: {'ip':ip[0], 'alive':is_alive }}}) %} -{% else %} -{% if hostname not in node_types[node_type] %} -{% do node_types[node_type].update({hostname: {'ip':ip[0], 'alive':is_alive}}) %} +{% if node_type not in node_types.keys() %} +{% do node_types.update({node_type: {hostname: {'ip':ip[0], 'alive':is_alive }}}) %} {% else %} -{% do node_types[node_type][hostname].update({'ip':ip[0], 'alive':is_alive}) %} +{% if hostname not in node_types[node_type] %} +{% do node_types[node_type].update({hostname: {'ip':ip[0], 'alive':is_alive}}) %} +{% else %} +{% do node_types[node_type][hostname].update({'ip':ip[0], 'alive':is_alive}) %} +{% endif %} {% endif %} {% endif %} {% endfor %} diff --git a/salt/ca/init.sls b/salt/ca/init.sls index 0eaf86b3c..895e8235a 100644 --- a/salt/ca/init.sls +++ b/salt/ca/init.sls @@ -50,6 +50,12 @@ pki_public_ca_crt: attempts: 5 interval: 30 +mine_update_ca_crt: + module.run: + - mine.update: [] + - onchanges: + - x509: pki_public_ca_crt + cakeyperms: file.managed: - replace: False diff --git a/salt/common/tools/sbin/so-common b/salt/common/tools/sbin/so-common index f754b34ef..87f40c9d4 100755 --- a/salt/common/tools/sbin/so-common +++ b/salt/common/tools/sbin/so-common @@ -8,7 +8,7 @@ # Elastic agent is not managed by salt. Because of this we must store this base information in a # script that accompanies the soup system. Since so-common is one of those special soup files, # and since this same logic is required during installation, it's included in this file. -ELASTIC_AGENT_TARBALL_VERSION="8.8.2" +ELASTIC_AGENT_TARBALL_VERSION="8.10.4" ELASTIC_AGENT_URL="https://repo.securityonion.net/file/so-repo/prod/2.4/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz" ELASTIC_AGENT_MD5_URL="https://repo.securityonion.net/file/so-repo/prod/2.4/elasticagent/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.md5" ELASTIC_AGENT_FILE="/nsm/elastic-fleet/artifacts/elastic-agent_SO-$ELASTIC_AGENT_TARBALL_VERSION.tar.gz" @@ -133,22 +133,37 @@ check_elastic_license() { } check_salt_master_status() { - local timeout=$1 - echo "Checking if we can talk to the salt master" - salt-call state.show_top concurrent=true - - return + local count=0 + local attempts="${1:- 10}" + current_time="$(date '+%b %d %H:%M:%S')" + echo "Checking if we can access the salt master and that it is ready at: ${current_time}" + while ! salt-call state.show_top -l error concurrent=true 1> /dev/null; do + current_time="$(date '+%b %d %H:%M:%S')" + echo "Can't access salt master or it is not ready at: ${current_time}" + ((count+=1)) + if [[ $count -eq $attempts ]]; then + # 10 attempts takes about 5.5 minutes + echo "Gave up trying to access salt-master" + return 1 + fi + done + current_time="$(date '+%b %d %H:%M:%S')" + echo "Successfully accessed and salt master ready at: ${current_time}" + return 0 } +# this is only intended to be used to check the status of the minion check_salt_minion_status() { - local timeout=$1 - echo "Checking if the salt minion will respond to jobs" >> "$setup_log" 2>&1 - salt "$MINION_ID" test.ping -t $timeout > /dev/null 2>&1 + local minion="$1" + local timeout="${2:-5}" + local logfile="${3:-'/dev/stdout'}" + echo "Checking if the salt minion will respond to jobs" >> "$logfile" 2>&1 + salt "$minion" test.ping -t $timeout > /dev/null 2>&1 local status=$? if [ $status -gt 0 ]; then - echo " Minion did not respond" >> "$setup_log" 2>&1 + echo " Minion did not respond" >> "$logfile" 2>&1 else - echo " Received job response from salt minion" >> "$setup_log" 2>&1 + echo " Received job response from salt minion" >> "$logfile" 2>&1 fi return $status @@ -428,6 +443,24 @@ run_check_net_err() { fi } +wait_for_salt_minion() { + local minion="$1" + local timeout="${2:-5}" + local logfile="${3:-'/dev/stdout'}" + retry 60 5 "journalctl -u salt-minion.service | grep 'Minion is ready to receive requests'" >> "$logfile" 2>&1 || fail + local attempt=0 + # each attempts would take about 15 seconds + local maxAttempts=20 + until check_salt_minion_status "$minion" "$timeout" "$logfile"; do + attempt=$((attempt+1)) + if [[ $attempt -eq $maxAttempts ]]; then + return 1 + fi + sleep 10 + done + return 0 +} + salt_minion_count() { local MINIONDIR="/opt/so/saltstack/local/pillar/minions" MINIONCOUNT=$(ls -la $MINIONDIR/*.sls | grep -v adv_ | wc -l) @@ -440,19 +473,51 @@ set_os() { OS=rocky OSVER=9 is_rocky=true + is_rpm=true elif grep -q "CentOS Stream release 9" /etc/redhat-release; then OS=centos OSVER=9 is_centos=true - elif grep -q "Oracle Linux Server release 9" /etc/system-release; then - OS=oel + is_rpm=true + elif grep -q "AlmaLinux release 9" /etc/redhat-release; then + OS=alma OSVER=9 - is_oracle=true + is_alma=true + is_rpm=true + elif grep -q "Red Hat Enterprise Linux release 9" /etc/redhat-release; then + if [ -f /etc/oracle-release ]; then + OS=oracle + OSVER=9 + is_oracle=true + is_rpm=true + else + OS=rhel + OSVER=9 + is_rhel=true + is_rpm=true + fi fi cron_service_name="crond" - else - OS=ubuntu - is_ubuntu=true + elif [ -f /etc/os-release ]; then + if grep -q "UBUNTU_CODENAME=focal" /etc/os-release; then + OSVER=focal + UBVER=20.04 + OS=ubuntu + is_ubuntu=true + is_deb=true + elif grep -q "UBUNTU_CODENAME=jammy" /etc/os-release; then + OSVER=jammy + UBVER=22.04 + OS=ubuntu + is_ubuntu=true + is_deb=true + elif grep -q "VERSION_CODENAME=bookworm" /etc/os-release; then + OSVER=bookworm + DEBVER=12 + is_debian=true + OS=debian + is_deb=true + fi cron_service_name="cron" fi } diff --git a/salt/common/tools/sbin/so-image-common b/salt/common/tools/sbin/so-image-common index 11d2d6366..7e510e3ad 100755 --- a/salt/common/tools/sbin/so-image-common +++ b/salt/common/tools/sbin/so-image-common @@ -137,7 +137,7 @@ update_docker_containers() { for i in "${TRUSTED_CONTAINERS[@]}" do if [ -z "$PROGRESS_CALLBACK" ]; then - echo "Downloading $i" >> "$LOG_FILE" 2>&1 + echo "Downloading $i" >> "$LOG_FILE" 2>&1 else $PROGRESS_CALLBACK $i fi diff --git a/salt/common/tools/sbin/so-log-check b/salt/common/tools/sbin/so-log-check index c2d16fd86..395f60c7d 100755 --- a/salt/common/tools/sbin/so-log-check +++ b/salt/common/tools/sbin/so-log-check @@ -136,6 +136,7 @@ if [[ $EXCLUDE_FALSE_POSITIVE_ERRORS == 'Y' ]]; then EXCLUDED_ERRORS="$EXCLUDED_ERRORS|invalid query input" # false positive (Invalid user input in hunt query) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|example" # false positive (example test data) EXCLUDED_ERRORS="$EXCLUDED_ERRORS|status 200" # false positive (request successful, contained error string in content) + EXCLUDED_ERRORS="$EXCLUDED_ERRORS|app_layer.error" # false positive (suricata 7) in stats.log e.g. app_layer.error.imap.parser | Total | 0 fi if [[ $EXCLUDE_KNOWN_ERRORS == 'Y' ]]; then @@ -230,4 +231,4 @@ else echo -e "\nResult: One or more errors found" fi -exit $RESULT \ No newline at end of file +exit $RESULT diff --git a/salt/docker/init.sls b/salt/docker/init.sls index 45ba4a1ac..769c58af8 100644 --- a/salt/docker/init.sls +++ b/salt/docker/init.sls @@ -6,6 +6,9 @@ {% from 'docker/docker.map.jinja' import DOCKER %} {% from 'vars/globals.map.jinja' import GLOBALS %} +# include ssl since docker service requires the intca +include: + - ssl dockergroup: group.present: @@ -86,6 +89,11 @@ docker_running: - enable: True - watch: - file: docker_daemon + - x509: trusttheca + - require: + - file: docker_daemon + - x509: trusttheca + # Reserve OS ports for Docker proxy in case boot settings are not already applied/present # 57314 = Strelka, 47760-47860 = Zeek diff --git a/salt/elasticfleet/defaults.yaml b/salt/elasticfleet/defaults.yaml index a4862623d..a17957e7c 100644 --- a/salt/elasticfleet/defaults.yaml +++ b/salt/elasticfleet/defaults.yaml @@ -30,18 +30,24 @@ elasticfleet: packages: - apache - auditd + - auth0 - aws - azure - barracuda + - carbonblack_edr - cisco_asa + - cisco_duo + - cisco_meraki + - cisco_umbrella - cloudflare - crowdstrike - darktrace - elasticsearch - endpoint - f5_bigip - - fleet_server - fim + - fireeye + - fleet_server - fortinet - fortinet_fortigate - gcp @@ -57,18 +63,24 @@ elasticfleet: - m365_defender - microsoft_defender_endpoint - microsoft_dhcp + - mimecast - netflow - o365 - okta - osquery_manager - panw - pfsense + - pulse_connect_secure - redis - sentinel_one + - snyk - sonicwall_firewall + - sophos + - sophos_central - symantec_endpoint - system - tcp + - tenable_sc - ti_abusech - ti_misp - ti_otx diff --git a/salt/elasticfleet/files/integrations/endpoints-initial/elastic-defend-endpoints.json b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json similarity index 95% rename from salt/elasticfleet/files/integrations/endpoints-initial/elastic-defend-endpoints.json rename to salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json index 8ab4f748e..de35f803b 100644 --- a/salt/elasticfleet/files/integrations/endpoints-initial/elastic-defend-endpoints.json +++ b/salt/elasticfleet/files/integrations/elastic-defend/elastic-defend-endpoints.json @@ -5,7 +5,7 @@ "package": { "name": "endpoint", "title": "Elastic Defend", - "version": "8.8.0" + "version": "8.10.2" }, "enabled": true, "policy_id": "endpoints-initial", diff --git a/salt/elasticfleet/tools/sbin/so-elastic-fleet-common b/salt/elasticfleet/tools/sbin/so-elastic-fleet-common old mode 100755 new mode 100644 index 6ada43003..c0b4db53a --- a/salt/elasticfleet/tools/sbin/so-elastic-fleet-common +++ b/salt/elasticfleet/tools/sbin/so-elastic-fleet-common @@ -42,6 +42,23 @@ elastic_fleet_integration_create() { curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/package_policies" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" } + +elastic_fleet_integration_remove() { + + AGENT_POLICY=$1 + + NAME=$2 + + INTEGRATION_ID=$(/usr/sbin/so-elastic-fleet-agent-policy-view "$AGENT_POLICY" | jq -r '.item.package_policies[] | select(.name=="'"$NAME"'") | .id') + + JSON_STRING=$( jq -n \ + --arg INTEGRATIONID "$INTEGRATION_ID" \ + '{"packagePolicyIds":[$INTEGRATIONID]}' + ) + + curl -K /opt/so/conf/elasticsearch/curl.config -L -X POST "localhost:5601/api/fleet/package_policies/delete" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" +} + elastic_fleet_integration_update() { UPDATE_ID=$1 @@ -98,3 +115,4 @@ elastic_fleet_policy_update() { curl -K /opt/so/conf/elasticsearch/curl.config -L -X PUT "localhost:5601/api/fleet/agent_policies/$POLICYID" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d "$JSON_STRING" } + diff --git a/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-elastic-defend b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-elastic-defend new file mode 100755 index 000000000..c4a7d39fd --- /dev/null +++ b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-elastic-defend @@ -0,0 +1,27 @@ +#!/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. + +# Usage: Run with --force to update the Elastic Defend integration policy + +. /usr/sbin/so-elastic-fleet-common + +# Manage Elastic Defend Integration for Initial Endpoints Policy +for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/elastic-defend/*.json +do + printf "\n\nInitial Endpoints Policy - Loading $INTEGRATION\n" + elastic_fleet_integration_check "endpoints-initial" "$INTEGRATION" + if [ -n "$INTEGRATION_ID" ]; then + if [ "$1" = "--force" ]; then + printf "\n\nIntegration $NAME exists - Updating integration\n" + elastic_fleet_integration_update "$INTEGRATION_ID" "@$INTEGRATION" + else + printf "\n\nIntegration $NAME exists - Not updating - rerun with --force to force the update.\n" + fi + else + printf "\n\nIntegration does not exist - Creating integration\n" + elastic_fleet_integration_create "@$INTEGRATION" + fi +done diff --git a/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load old mode 100755 new mode 100644 index ae0fbb6ba..44e7ccf2b --- a/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load +++ b/salt/elasticfleet/tools/sbin/so-elastic-fleet-integration-policy-load @@ -12,6 +12,9 @@ if [ ! -f /opt/so/state/eaintegrations.txt ]; then # First, check for any package upgrades /usr/sbin/so-elastic-fleet-package-upgrade + # Second, configure Elastic Defend Integration seperately + /usr/sbin/so-elastic-fleet-integration-policy-elastic-defend + # Initial Endpoints for INTEGRATION in /opt/so/conf/elastic-fleet/integrations/endpoints-initial/*.json do @@ -65,3 +68,4 @@ else exit $RETURN_CODE fi + diff --git a/salt/elasticsearch/defaults.yaml b/salt/elasticsearch/defaults.yaml index 91e5191f6..1296ef549 100644 --- a/salt/elasticsearch/defaults.yaml +++ b/salt/elasticsearch/defaults.yaml @@ -4398,3 +4398,525 @@ elasticsearch: min_age: 365d actions: delete: {} + so-logs-auth0_x_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-auth0.logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-auth0.logs@package" + - "logs-auth0.logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-carbonblack_edr_x_log: + index_sorting: False + index_template: + index_patterns: + - "logs-carbonblack_edr.log-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-carbonblack_edr.log@package" + - "logs-carbonblack_edr.log@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_duo_x_admin: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_duo.admin-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_duo.admin@package" + - "logs-cisco_duo.admin@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_duo_x_auth: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_duo.auth-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_duo.auth@package" + - "logs-cisco_duo.auth@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_duo_x_offline_enrollment: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_duo.offline_enrollment-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_duo.offline_enrollment@package" + - "logs-cisco_duo.offline_enrollment@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_duo_x_summary: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_duo.summary-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_duo.summary@package" + - "logs-cisco_duo.summary@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_duo_x_telephony: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_duo.telephony-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_duo.telephony@package" + - "logs-cisco_duo.telephony@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_meraki_x_events: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_meraki.events-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_meraki.events@package" + - "logs-cisco_meraki.events@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_meraki_x_log: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_meraki.log-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_meraki.log@package" + - "logs-cisco_meraki.log@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-cisco_umbrella_x_log: + index_sorting: False + index_template: + index_patterns: + - "logs-cisco_umbrella.log-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-cisco_umbrella.log@package" + - "logs-cisco_umbrella.log@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-fireeye_x_nx: + index_sorting: False + index_template: + index_patterns: + - "logs-fireeye.nx-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-fireeye.nx@package" + - "logs-fireeye.nx@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_audit_events: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.audit_events-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.audit_events@package" + - "logs-mimecast.audit_events@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_dlp_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.dlp_logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.dlp_logs@package" + - "logs-mimecast.dlp_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_siem_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.siem_logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.siem_logs@package" + - "logs-mimecast.siem_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_threat_intel_malware_customer: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.threat_intel_malware_customer-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.threat_intel_malware_customer@package" + - "logs-mimecast.threat_intel_malware_customer@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_threat_intel_malware_grid: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.threat_intel_malware_grid-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.threat_intel_malware_grid@package" + - "logs-mimecast.threat_intel_malware_grid@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_ttp_ap_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.ttp_ap_logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.ttp_ap_logs@package" + - "logs-mimecast.ttp_ap_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_ttp_ip_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.ttp_ip_logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.ttp_ip_logs@package" + - "logs-mimecast.ttp_ip_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-mimecast_x_ttp_url_logs: + index_sorting: False + index_template: + index_patterns: + - "logs-mimecast.ttp_url_logs-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-mimecast.ttp_url_logs@package" + - "logs-mimecast.ttp_url_logs@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-pulse_connect_secure_x_log: + index_sorting: False + index_template: + index_patterns: + - "logs-pulse_connect_secure.log-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-pulse_connect_secure.log@package" + - "logs-pulse_connect_secure.log@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-snyk_x_audit: + index_sorting: False + index_template: + index_patterns: + - "logs-snyk.audit-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-snyk.audit@package" + - "logs-snyk.audit@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-snyk_x_vulnerabilities: + index_sorting: False + index_template: + index_patterns: + - "logs-snyk.vulnerabilities-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-snyk.vulnerabilities@package" + - "logs-snyk.vulnerabilities@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-sophos_x_utm: + index_sorting: False + index_template: + index_patterns: + - "logs-sophos.utm-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-sophos.utm@package" + - "logs-sophos.utm@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-sophos_x_xg: + index_sorting: False + index_template: + index_patterns: + - "logs-sophos.xg-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-sophos.xg@package" + - "logs-sophos.xg@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-sophos_central_x_alert: + index_sorting: False + index_template: + index_patterns: + - "logs-sophos_central.alert-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-sophos_central.alert@package" + - "logs-sophos_central.alert@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-sophos_central_x_event: + index_sorting: False + index_template: + index_patterns: + - "logs-sophos_central.event-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-sophos_central.event@package" + - "logs-sophos_central.event@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-tenable_sc_x_asset: + index_sorting: False + index_template: + index_patterns: + - "logs-tenable_sc.asset-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-tenable_sc.asset@package" + - "logs-tenable_sc.asset@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-tenable_sc_x_plugin: + index_sorting: False + index_template: + index_patterns: + - "logs-tenable_sc.plugin-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-tenable_sc.plugin@package" + - "logs-tenable_sc.plugin@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false + so-logs-tenable_sc_x_vulnerability: + index_sorting: False + index_template: + index_patterns: + - "logs-tenable_sc.vulnerability-*" + template: + settings: + index: + number_of_replicas: 0 + composed_of: + - "logs-tenable_sc.vulnerability@package" + - "logs-tenable_sc.vulnerability@custom" + - "so-fleet_globals-1" + - "so-fleet_agent_id_verification-1" + priority: 501 + data_stream: + hidden: false + allow_custom_routing: false diff --git a/salt/elasticsearch/files/ingest/suricata.common b/salt/elasticsearch/files/ingest/suricata.common index e12fea0be..6b6a03a60 100644 --- a/salt/elasticsearch/files/ingest/suricata.common +++ b/salt/elasticsearch/files/ingest/suricata.common @@ -2,6 +2,7 @@ "description" : "suricata.common", "processors" : [ { "json": { "field": "message", "target_field": "message2", "ignore_failure": true } }, + { "rename": { "field": "message2.pkt_src", "target_field": "network.packet_source","ignore_failure": true } }, { "rename": { "field": "message2.proto", "target_field": "network.transport", "ignore_failure": true } }, { "rename": { "field": "message2.flow_id", "target_field": "log.id.uid", "ignore_failure": true } }, { "rename": { "field": "message2.src_ip", "target_field": "source.ip", "ignore_failure": true } }, diff --git a/salt/kibana/files/config_saved_objects.ndjson b/salt/kibana/files/config_saved_objects.ndjson index a2dedd324..bc503debb 100644 --- a/salt/kibana/files/config_saved_objects.ndjson +++ b/salt/kibana/files/config_saved_objects.ndjson @@ -1 +1 @@ -{"attributes": {"buildNum": 39457,"defaultIndex": "logs-*","defaultRoute": "/app/dashboards#/view/a8411b30-6d03-11ea-b301-3d6c35840645","discover:sampleSize": 100,"theme:darkMode": true,"timepicker:timeDefaults": "{\n \"from\": \"now-24h\",\n \"to\": \"now\"\n}"},"coreMigrationVersion": "8.8.2","id": "8.8.2","references": [],"type": "config","updated_at": "2021-10-10T10:10:10.105Z","version": "WzI5NzUsMl0="} +{"attributes": {"buildNum": 39457,"defaultIndex": "logs-*","defaultRoute": "/app/dashboards#/view/a8411b30-6d03-11ea-b301-3d6c35840645","discover:sampleSize": 100,"theme:darkMode": true,"timepicker:timeDefaults": "{\n \"from\": \"now-24h\",\n \"to\": \"now\"\n}"},"coreMigrationVersion": "8.10.4","id": "8.10.4","references": [],"type": "config","updated_at": "2021-10-10T10:10:10.105Z","version": "WzI5NzUsMl0="} diff --git a/salt/kibana/tools/sbin_jinja/so-kibana-config-load b/salt/kibana/tools/sbin_jinja/so-kibana-config-load index 159a69e68..b9df9c6d4 100644 --- a/salt/kibana/tools/sbin_jinja/so-kibana-config-load +++ b/salt/kibana/tools/sbin_jinja/so-kibana-config-load @@ -63,7 +63,7 @@ update() { IFS=$'\r\n' GLOBIGNORE='*' command eval 'LINES=($(cat $1))' for i in "${LINES[@]}"; do - RESPONSE=$(curl -K /opt/so/conf/elasticsearch/curl.config -X PUT "localhost:5601/api/saved_objects/config/8.8.2" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d " $i ") + RESPONSE=$(curl -K /opt/so/conf/elasticsearch/curl.config -X PUT "localhost:5601/api/saved_objects/config/8.10.4" -H 'kbn-xsrf: true' -H 'Content-Type: application/json' -d " $i ") echo $RESPONSE; if [[ "$RESPONSE" != *"\"success\":true"* ]] && [[ "$RESPONSE" != *"updated_at"* ]] ; then RETURN_CODE=1;fi done diff --git a/salt/manager/tools/sbin/so-minion b/salt/manager/tools/sbin/so-minion index 64084dbd0..eca96da5c 100755 --- a/salt/manager/tools/sbin/so-minion +++ b/salt/manager/tools/sbin/so-minion @@ -406,12 +406,17 @@ function update_logstash_outputs() { 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" } +function checkMine() { + local func=$1 + # make sure the minion sees itself in the mine since it needs to see itself for states as opposed to using salt-run + retry 20 1 "salt '$MINION_ID' mine.get '\*' '$func'" "$MINION_ID" + +} + function updateMine() { - salt "$MINION_ID" mine.send network.ip_addrs interface="$MNIC" -} -function apply_ES_state() { - salt-call state.apply elasticsearch concurrent=True + retry 20 1 "salt '$MINION_ID' mine.update" True } + function createEVAL() { is_pcaplimit=true add_elasticsearch_to_minion @@ -547,8 +552,6 @@ function createSEARCHNODE() { add_elasticsearch_to_minion add_logstash_to_minion add_telegraf_to_minion - updateMine - apply_ES_state } function createRECEIVER() { @@ -563,6 +566,19 @@ function createDESKTOP() { } function testConnection() { + # the minion should be trying to auth every 10 seconds so 15 seconds should be more than enough time to see this in the log + # this retry was put in because it is possible that a minion is attempted to be pinged before it has authenticated and connected to the Salt master + # causing the first ping to fail and typically wouldn't be successful until the second ping + # this check may pass without the minion being authenticated if it was previously connected and the line exists in the log + retry 15 1 "grep 'Authentication accepted from $MINION_ID' /opt/so/log/salt/master" + local retauth=$? + if [[ $retauth != 0 ]]; then + echo "The Minion did not authenticate with the Salt master in the allotted time" + echo "Deleting the key" + deleteminion + exit 1 + fi + retry 15 3 "salt '$MINION_ID' test.ping" True local ret=$? if [[ $ret != 0 ]]; then @@ -582,9 +598,9 @@ if [[ "$OPERATION" = 'delete' ]]; then deleteminion fi -if [[ "$OPERATION" = 'add' || "$OPERATION" = 'setup' ]]; then +if [[ "$OPERATION" == 'add' || "$OPERATION" == 'setup' ]]; then # Skip this if its setup - if [ $OPERATION != 'setup' ]; then + if [[ $OPERATION == 'add' ]]; then # Accept the salt key acceptminion # Test to see if the minion was accepted @@ -605,8 +621,19 @@ if [[ "$OPERATION" = 'add' || "$OPERATION" = 'setup' ]]; then else add_sensoroni_to_minion fi + create$NODETYPE echo "Minion file created for $MINION_ID" + + if [[ "$OPERATION" == 'add' ]]; then + # tell the minion to populate the mine with data from mine_functions which is populated during setup + # this only needs to happen on non managers since they handle this during setup + # and they need to wait for ca creation to update the mine + updateMine + checkMine "network.ip_addrs" + # run this async so the cli doesn't wait for a return + salt "$MINION_ID" state.highstate --async + fi fi if [[ "$OPERATION" = 'test' ]]; then diff --git a/salt/manager/tools/sbin/soup b/salt/manager/tools/sbin/soup index e4b388e22..dee39ac59 100755 --- a/salt/manager/tools/sbin/soup +++ b/salt/manager/tools/sbin/soup @@ -460,7 +460,6 @@ stop_salt_master() { echo "" echo "Killing any queued Salt jobs on the manager." pkill -9 -ef "/usr/bin/python3 /bin/salt" >> $SOUP_LOG 2>&1 - set -e echo "" echo "Storing salt-master pid." @@ -468,6 +467,7 @@ stop_salt_master() { echo "Found salt-master PID $MASTERPID" systemctl_func "stop" "salt-master" timeout 30 tail --pid=$MASTERPID -f /dev/null || echo "salt-master still running at $(date +"%T.%6N") after waiting 30s. We cannot kill due to systemd restart option." + set -e } stop_salt_minion() { @@ -480,14 +480,12 @@ stop_salt_minion() { echo "" echo "Killing Salt jobs on this node." salt-call saltutil.kill_all_jobs --local - set -e echo "Storing salt-minion pid." MINIONPID=$(pgrep -f '/opt/saltstack/salt/bin/python3.10 /usr/bin/salt-minion' | head -1) echo "Found salt-minion PID $MINIONPID" systemctl_func "stop" "salt-minion" - set +e timeout 30 tail --pid=$MINIONPID -f /dev/null || echo "Killing salt-minion at $(date +"%T.%6N") after waiting 30s" && pkill -9 -ef /usr/bin/salt-minion set -e } @@ -578,7 +576,7 @@ update_centos_repo() { } update_salt_mine() { - echo "Populating the mine with network.ip_addrs pillar.host.mainint for each host." + echo "Populating the mine with mine_functions for each host." set +e salt \* mine.update -b 50 set -e @@ -620,6 +618,7 @@ upgrade_check_salt() { if [ "$INSTALLEDSALTVERSION" == "$NEWSALTVERSION" ]; then echo "You are already running the correct version of Salt for Security Onion." else + echo "Salt needs to be upgraded to $NEWSALTVERSION." UPGRADESALT=1 fi } @@ -628,22 +627,48 @@ upgrade_salt() { SALTUPGRADED=True echo "Performing upgrade of Salt from $INSTALLEDSALTVERSION to $NEWSALTVERSION." echo "" - # If CentOS - if [[ $OS == 'centos' ]]; then + # If rhel family + if [[ $is_rpm ]]; then echo "Removing yum versionlock for Salt." echo "" yum versionlock delete "salt-*" echo "Updating Salt packages." echo "" set +e - run_check_net_err \ - "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M -x python3 stable \"$NEWSALTVERSION\"" \ - "Could not update salt, please check $SOUP_LOG for details." + # if oracle run with -r to ignore repos set by bootstrap + if [[ $OS == 'oracle' ]]; then + run_check_net_err \ + "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -r -F -M -x python3 stable \"$NEWSALTVERSION\"" \ + "Could not update salt, please check $SOUP_LOG for details." + # if another rhel family variant we want to run without -r to allow the bootstrap script to manage repos + else + run_check_net_err \ + "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -F -M -x python3 stable \"$NEWSALTVERSION\"" \ + "Could not update salt, please check $SOUP_LOG for details." + fi set -e echo "Applying yum versionlock for Salt." echo "" yum versionlock add "salt-*" # Else do Ubuntu things + elif [[ $is_deb ]]; then + echo "Removing apt hold for Salt." + echo "" + apt-mark unhold "salt-common" + apt-mark unhold "salt-master" + apt-mark unhold "salt-minion" + echo "Updating Salt packages." + echo "" + set +e + run_check_net_err \ + "sh $UPDATE_DIR/salt/salt/scripts/bootstrap-salt.sh -X -F -M -x python3 stable \"$NEWSALTVERSION\"" \ + "Could not update salt, please check $SOUP_LOG for details." + set -e + echo "Applying apt hold for Salt." + echo "" + apt-mark hold "salt-common" + apt-mark hold "salt-master" + apt-mark hold "salt-minion" fi echo "Checking if Salt was upgraded." @@ -655,7 +680,7 @@ upgrade_salt() { echo "Once the issue is resolved, run soup again." echo "Exiting." echo "" - exit 0 + exit 1 else echo "Salt upgrade success." echo "" @@ -691,13 +716,16 @@ verify_latest_update_script() { # Keeping this block in case we need to do a hotfix that requires salt update apply_hotfix() { -# if [[ "$INSTALLEDVERSION" == "2.3.90" ]] ; then -# fix_wazuh + 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.3.110" ]] ; then # 2_3_10_hotfix_1 -# else + else echo "No actions required. ($INSTALLEDVERSION/$HOTFIXVERSION)" -# fi + fi } @@ -733,14 +761,8 @@ main() { echo "" set_os - if ! check_salt_master_status; then - echo "Could not talk to salt master" - echo "Please run 'systemctl status salt-master' to ensure the salt-master service is running and check the log at /opt/so/log/salt/master." - echo "SOUP will now attempt to start the salt-master service and exit." - exit 1 - fi - echo "This node can communicate with the salt-master." + check_salt_master_status 1 || fail "Could not talk to salt master: Please run 'systemctl status salt-master' to ensure the salt-master service is running and check the log at /opt/so/log/salt/master." echo "Checking to see if this is a manager." echo "" @@ -788,7 +810,7 @@ main() { if [[ $is_airgap -eq 0 ]]; then yum clean all check_os_updates - elif [[ $OS == 'oel' ]]; then + elif [[ $OS == 'oracle' ]]; then # sync remote repo down to local if not airgap repo_sync check_os_updates @@ -805,7 +827,8 @@ main() { echo "Hotfix applied" update_version enable_highstate - salt-call state.highstate -l info queue=True + (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" + highstate else echo "" echo "Performing upgrade from Security Onion $INSTALLEDVERSION to Security Onion $NEWVERSION." @@ -826,7 +849,7 @@ main() { else update_registry set +e - update_docker_containers "soup" "" "" "$SOUP_LOG" + update_docker_containers 'soup' '' '' '/dev/stdout' 2>&1 | tee -a "$SOUP_LOG" set -e fi @@ -841,6 +864,14 @@ main() { echo "Upgrading Salt" # Update the repo files so it can actually upgrade upgrade_salt + + # for Debian based distro, we need to stop salt again after upgrade output below is from bootstrap-salt + # * WARN: Not starting daemons on Debian based distributions + # is not working mostly because starting them is the default behaviour. + if [[ $is_deb ]]; then + stop_salt_minion + stop_salt_master + fi fi preupgrade_changes @@ -878,7 +909,7 @@ main() { # Testing that salt-master is up by checking that is it connected to itself set +e echo "Waiting on the Salt Master service to be ready." - salt-call state.show_top -l error queue=True || fail "salt-master could not be reached. Check $SOUP_LOG for details." + check_salt_master_status || fail "Can't access salt master or it is not ready. Check $SOUP_LOG for details." set -e # update the salt-minion configs here and start the minion @@ -903,7 +934,8 @@ main() { echo "" echo "Running a highstate. This could take several minutes." set +e - salt-call state.highstate -l info queue=True + (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" + highstate set -e stop_salt_master @@ -914,11 +946,12 @@ main() { set +e echo "Waiting on the Salt Master service to be ready." - salt-call state.show_top -l error queue=True || fail "salt-master could not be reached. Check $SOUP_LOG for details." + check_salt_master_status || fail "Can't access salt master or it is not ready. Check $SOUP_LOG for details." set -e echo "Running a highstate to complete the Security Onion upgrade on this manager. This could take several minutes." - salt-call state.highstate -l info queue=True + (wait_for_salt_minion "$MINIONID" "5" '/dev/stdout' || fail "Salt minion was not running or ready.") 2>&1 | tee -a "$SOUP_LOG" + highstate postupgrade_changes [[ $is_airgap -eq 0 ]] && unmount_update diff --git a/salt/pcap/config.sls b/salt/pcap/config.sls index 26236e2ff..9ea5cee65 100644 --- a/salt/pcap/config.sls +++ b/salt/pcap/config.sls @@ -41,7 +41,7 @@ pcap_sbin: - file_mode: 755 {% if PCAPBPF %} - {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %} + {% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + PCAPBPF|join(" "),cwd='/root') %} {% if BPF_CALC['stderr'] == "" %} {% set BPF_COMPILED = ",\\\"--filter=" + BPF_CALC['stdout'] + "\\\"" %} {% else %} diff --git a/salt/salt/engines/master/checkmine.py b/salt/salt/engines/master/checkmine.py new file mode 100644 index 000000000..f33392575 --- /dev/null +++ b/salt/salt/engines/master/checkmine.py @@ -0,0 +1,90 @@ +# -*- coding: utf-8 -*- + +import logging +from time import sleep +import os +import salt.client + +log = logging.getLogger(__name__) +local = salt.client.LocalClient() + +def start(interval=60): + def mine_delete(minion, func): + log.warning('checkmine engine: deleting mine function %s for %s' % (func, minion)) + local.cmd(minion, 'mine.delete', [func]) + + def mine_flush(minion): + log.warning('checkmine engine: flushing mine cache for %s' % minion) + local.cmd(minion, 'mine.flush') + + def mine_update(minion): + log.warning('checkmine engine: updating mine cache for %s' % minion) + local.cmd(minion, 'mine.update') + + log.info("checkmine engine: started") + cachedir = __opts__['cachedir'] + while True: + log.debug('checkmine engine: checking which minions are alive') + manage_alived = __salt__['saltutil.runner']('manage.alived', show_ip=False) + log.debug('checkmine engine: alive minions: %s' % ' , '.join(manage_alived)) + + for minion in manage_alived: + mine_path = os.path.join(cachedir, 'minions', minion, 'mine.p') + # it is possible that a minion is alive, but hasn't created a mine file yet + try: + mine_size = os.path.getsize(mine_path) + log.debug('checkmine engine: minion: %s mine_size: %i' % (minion, mine_size)) + # For some reason the mine file can be corrupt and only be 1 byte in size + if mine_size == 1: + log.error('checkmine engine: found %s to be 1 byte' % mine_path) + mine_flush(minion) + mine_update(minion) + continue + except FileNotFoundError: + log.warning('checkmine engine: minion: %s %s does not exist' % (minion, mine_path)) + mine_flush(minion) + mine_update(minion) + continue + + # if a manager check that the ca in in the mine and it is correct + if minion.split('_')[-1] in ['manager', 'managersearch', 'eval', 'standalone', 'import']: + x509 = __salt__['saltutil.runner']('mine.get', tgt=minion, fun='x509.get_pem_entries') + try: + ca_crt = x509[minion]['/etc/pki/ca.crt'] + log.debug('checkmine engine: found minion %s has ca_crt: %s' % (minion, ca_crt)) + # since the cert is defined, make sure it is valid + import salt.modules.x509_v2 as x509_v2 + if not x509_v2.verify_private_key('/etc/pki/ca.key', '/etc/pki/ca.crt'): + log.error('checkmine engine: found minion %s does\'t have a valid ca_crt in the mine' % (minion)) + log.error('checkmine engine: %s: ca_crt: %s' % (minion, ca_crt)) + mine_delete(minion, 'x509.get_pem_entries') + mine_update(minion) + continue + else: + log.debug('checkmine engine: found minion %s has a valid ca_crt in the mine' % (minion)) + except IndexError: + log.error('checkmine engine: found minion %s does\'t have a ca_crt in the mine' % (minion)) + mine_delete(minion, 'x509.get_pem_entries') + mine_update(minion) + continue + except KeyError: + log.error('checkmine engine: found minion %s is not in the mine' % (minion)) + mine_flush(minion) + mine_update(minion) + continue + + # Update the mine if the ip in the mine doesn't match returned from manage.alived + network_ip_addrs = __salt__['saltutil.runner']('mine.get', tgt=minion, fun='network.ip_addrs') + try: + mine_ip = network_ip_addrs[minion][0] + log.debug('checkmine engine: found minion %s has mine_ip: %s' % (minion, mine_ip)) + except IndexError: + log.error('checkmine engine: found minion %s does\'t have a mine_ip' % (minion)) + mine_delete(minion, 'network.ip_addrs') + mine_update(minion) + except KeyError: + log.error('checkmine engine: found minion %s is not in the mine' % (minion)) + mine_flush(minion) + mine_update(minion) + + sleep(interval) diff --git a/salt/salt/files/engines.conf b/salt/salt/files/engines.conf new file mode 100644 index 000000000..7c43e99e1 --- /dev/null +++ b/salt/salt/files/engines.conf @@ -0,0 +1,6 @@ +engines_dirs: + - /etc/salt/engines + +engines: + - checkmine: + interval: 60 diff --git a/salt/salt/map.jinja b/salt/salt/map.jinja index 1120685fb..131ff46ca 100644 --- a/salt/salt/map.jinja +++ b/salt/salt/map.jinja @@ -23,7 +23,7 @@ {% if grains.os|lower in ['Rocky', 'redhat', 'CentOS Stream'] %} {% set UPGRADECOMMAND = 'yum clean all ; /usr/sbin/bootstrap-salt.sh -s 120 -r -F -x python3 stable ' ~ SALTVERSION %} {% elif grains.os_family|lower == 'debian' %} - {% set UPGRADECOMMAND = '/usr/sbin/bootstrap-salt.sh -s 120 -r -F -x python3 stable ' ~ SALTVERSION %} + {% set UPGRADECOMMAND = '/usr/sbin/bootstrap-salt.sh -s 120 -F -x python3 stable ' ~ SALTVERSION %} {% endif %} {% else %} {% set UPGRADECOMMAND = 'echo Already running Salt Minion version ' ~ SALTVERSION %} diff --git a/salt/salt/master.defaults.yaml b/salt/salt/master.defaults.yaml index 126039802..40b6f5268 100644 --- a/salt/salt/master.defaults.yaml +++ b/salt/salt/master.defaults.yaml @@ -2,4 +2,4 @@ # When updating the salt version, also update the version in securityonion-builds/images/iso-task/Dockerfile and saltify function in so-functions salt: master: - version: 3006.1 + version: 3006.3 diff --git a/salt/salt/master.sls b/salt/salt/master.sls index b10a4df0f..0a65f3e01 100644 --- a/salt/salt/master.sls +++ b/salt/salt/master.sls @@ -12,22 +12,34 @@ hold_salt_master_package: - name: salt-master {% endif %} +# prior to 2.4.30 this engine ran on the manager with salt-minion +# this has changed to running with the salt-master in 2.4.30 +remove_engines_config: + file.absent: + - name: /etc/salt/minion.d/engines.conf + - source: salt://salt/files/engines.conf + - watch_in: + - service: salt_minion_service + +checkmine_engine: + file.managed: + - name: /etc/salt/engines/checkmine.py + - source: salt://salt/engines/master/checkmine.py + - makedirs: True + +engines_config: + file.managed: + - name: /etc/salt/master.d/engines.conf + - source: salt://salt/files/engines.conf + salt_master_service: service.running: - name: salt-master - enable: True - -checkmine_engine: - file.absent: - - name: /etc/salt/engines/checkmine.py - - watch_in: - - service: salt_minion_service - -engines_config: - file.absent: - - name: /etc/salt/minion.d/engines.conf - - watch_in: - - service: salt_minion_service + - watch: + - file: checkmine_engine + - file: engines_config + - order: last {% else %} diff --git a/salt/salt/minion.defaults.yaml b/salt/salt/minion.defaults.yaml index 7e1540d17..71fd18f96 100644 --- a/salt/salt/minion.defaults.yaml +++ b/salt/salt/minion.defaults.yaml @@ -2,6 +2,6 @@ # When updating the salt version, also update the version in securityonion-builds/images/iso-task/Dockerfile and saltify function in so-functions salt: minion: - version: 3006.1 + version: 3006.3 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. diff --git a/salt/salt/minion.sls b/salt/salt/minion.sls index 865bd367f..e0c422e7f 100644 --- a/salt/salt/minion.sls +++ b/salt/salt/minion.sls @@ -67,6 +67,9 @@ set_log_levels: - "log_level: info" - "log_level_logfile: info" +# prior to 2.4.30 this managed file would restart the salt-minion service when updated +# since this file is currently only adding a sleep timer on service start +# it is not required to restart the service salt_minion_service_unit_file: file.managed: - name: {{ SYSTEMD_UNIT_FILE }} @@ -89,6 +92,5 @@ salt_minion_service: - file: mine_functions {% if INSTALLEDSALTVERSION|string == SALTVERSION|string %} - file: set_log_levels - - file: salt_minion_service_unit_file {% endif %} - order: last diff --git a/salt/salt/scripts/bootstrap-salt.sh b/salt/salt/scripts/bootstrap-salt.sh index 47d25949c..a016524e6 100644 --- a/salt/salt/scripts/bootstrap-salt.sh +++ b/salt/salt/scripts/bootstrap-salt.sh @@ -14,7 +14,7 @@ # # BUGS: https://github.com/saltstack/salt-bootstrap/issues # -# COPYRIGHT: (c) 2012-2021 by the SaltStack Team, see AUTHORS.rst for more +# COPYRIGHT: (c) 2012-2022 by the SaltStack Team, see AUTHORS.rst for more # details. # # LICENSE: Apache 2.0 @@ -23,7 +23,7 @@ #====================================================================================================================== set -o nounset # Treat unset variables as an error -__ScriptVersion="2021.09.17" +__ScriptVersion="2023.08.03" __ScriptName="bootstrap-salt.sh" __ScriptFullName="$0" @@ -224,7 +224,6 @@ _KEEP_TEMP_FILES=${BS_KEEP_TEMP_FILES:-$BS_FALSE} _TEMP_CONFIG_DIR="null" _SALTSTACK_REPO_URL="https://github.com/saltstack/salt.git" _SALT_REPO_URL=${_SALTSTACK_REPO_URL} -_DOWNSTREAM_PKG_REPO=$BS_FALSE _TEMP_KEYS_DIR="null" _SLEEP="${__DEFAULT_SLEEP}" _INSTALL_MASTER=$BS_FALSE @@ -268,6 +267,8 @@ _CUSTOM_MASTER_CONFIG="null" _CUSTOM_MINION_CONFIG="null" _QUIET_GIT_INSTALLATION=$BS_FALSE _REPO_URL="repo.saltproject.io" +_ONEDIR_DIR="salt" +_ONEDIR_NIGHTLY_DIR="salt-dev/${_ONEDIR_DIR}" _PY_EXE="python3" _INSTALL_PY="$BS_FALSE" _TORNADO_MAX_PY3_VERSION="5.0" @@ -275,6 +276,9 @@ _POST_NEON_INSTALL=$BS_FALSE _MINIMUM_PIP_VERSION="9.0.1" _MINIMUM_SETUPTOOLS_VERSION="9.1" _POST_NEON_PIP_INSTALL_ARGS="--prefix=/usr" +_PIP_DOWNLOAD_ARGS="" +_QUICK_START="$BS_FALSE" +_AUTO_ACCEPT_MINION_KEYS="$BS_FALSE" # Defaults for install arguments ITYPE="stable" @@ -290,110 +294,130 @@ __usage() { Usage : ${__ScriptName} [options] [install-type-args] Installation types: - - stable Install latest stable release. This is the default - install type - - stable [branch] Install latest version on a branch. Only supported - for packages available at repo.saltproject.io - - stable [version] Install a specific version. Only supported for - packages available at repo.saltproject.io - To pin a 3xxx minor version, specify it as 3xxx.0 - - testing RHEL-family specific: configure EPEL testing repo - - git Install from the head of the master branch - - git [ref] Install from any git ref (such as a branch, tag, or - commit) + - stable Install latest stable release. This is the default + install type + - stable [branch] Install latest version on a branch. Only supported + for packages available at repo.saltproject.io + - stable [version] Install a specific version. Only supported for + packages available at repo.saltproject.io + To pin a 3xxx minor version, specify it as 3xxx.0 + - testing RHEL-family specific: configure EPEL testing repo + - git Install from the head of the master branch + - git [ref] Install from any git ref (such as a branch, tag, or + commit) + - onedir Install latest onedir release. + - onedir [version] Install a specific version. Only supported for + onedir packages available at repo.saltproject.io + + - onedir_rc Install latest onedir RC release. + - onedir_rc [version] Install a specific version. Only supported for + onedir RC packages available at repo.saltproject.io + - old-stable Install latest old stable release. + - old-stable [branch] Install latest version on a branch. Only supported + for packages available at repo.saltproject.io + - old-stable [version] Install a specific version. Only supported for + packages available at repo.saltproject.io + To pin a 3xxx minor version, specify it as 3xxx.0 Examples: - ${__ScriptName} - ${__ScriptName} stable - - ${__ScriptName} stable 2017.7 - - ${__ScriptName} stable 2017.7.2 + - ${__ScriptName} stable 3006 + - ${__ScriptName} stable 3006.1 - ${__ScriptName} testing - ${__ScriptName} git - ${__ScriptName} git 2017.7 - ${__ScriptName} git v2017.7.2 - ${__ScriptName} git 06f249901a2e2f1ed310d58ea3921a129f214358 + - ${__ScriptName} onedir + - ${__ScriptName} onedir 3006 + - ${__ScriptName} onedir_rc + - ${__ScriptName} onedir_rc 3006 + - ${__ScriptName} old-stable + - ${__ScriptName} old-stable 3005 + - ${__ScriptName} old-stable 3005.1 + Options: - -h Display this message - -v Display script version - -n No colours - -D Show debug output + -a Pip install all Python pkg dependencies for Salt. Requires -V to install + all pip pkgs into the virtualenv. + (Only available for Ubuntu based distributions) + -A Pass the salt-master DNS name or IP. This will be stored under + \${BS_SALT_ETC_DIR}/minion.d/99-master-address.conf + -b Assume that dependencies are already installed and software sources are + set up. If git is selected, git tree is still checked out as dependency + step. -c Temporary configuration directory - -g Salt Git repository URL. Default: ${_SALTSTACK_REPO_URL} - -w Install packages from downstream package repository rather than - upstream, saltstack package repository. This is currently only - implemented for SUSE. - -k Temporary directory holding the minion keys which will pre-seed - the master. - -s Sleep time used when waiting for daemons to start, restart and when - checking for the services running. Default: ${__DEFAULT_SLEEP} - -L Also install salt-cloud and required python-libcloud package - -M Also install salt-master - -S Also install salt-syndic - -N Do not install salt-minion - -X Do not start daemons after installation - -d Disables checking if Salt services are enabled to start on system boot. - You can also do this by touching /tmp/disable_salt_checks on the target - host. Default: \${BS_FALSE} - -P Allow pip based installations. On some distributions the required salt - packages or its dependencies are not available as a package for that - distribution. Using this flag allows the script to use pip as a last - resort method. NOTE: This only works for functions which actually - implement pip based installations. - -U If set, fully upgrade the system prior to bootstrapping Salt - -I If set, allow insecure connections while downloading any files. For - example, pass '--no-check-certificate' to 'wget' or '--insecure' to - 'curl'. On Debian and Ubuntu, using this option with -U allows obtaining - GnuPG archive keys insecurely if distro has changed release signatures. - -F Allow copied files to overwrite existing (config, init.d, etc) - -K If set, keep the temporary files in the temporary directories specified - with -c and -k -C Only run the configuration function. Implies -F (forced overwrite). To overwrite Master or Syndic configs, -M or -S, respectively, must also be specified. Salt installation will be ommitted, but some of the dependencies could be installed to write configuration with -j or -J. - -A Pass the salt-master DNS name or IP. This will be stored under - \${BS_SALT_ETC_DIR}/minion.d/99-master-address.conf - -i Pass the salt-minion id. This will be stored under - \${BS_SALT_ETC_DIR}/minion_id - -p Extra-package to install while installing Salt dependencies. One package - per -p flag. You are responsible for providing the proper package name. - -H Use the specified HTTP proxy for all download URLs (including https://). - For example: http://myproxy.example.com:3128 - -b Assume that dependencies are already installed and software sources are - set up. If git is selected, git tree is still checked out as dependency - step. + -d Disables checking if Salt services are enabled to start on system boot. + You can also do this by touching /tmp/disable_salt_checks on the target + host. Default: \${BS_FALSE} + -D Show debug output -f Force shallow cloning for git installations. This may result in an "n/a" in the version number. - -l Disable ssl checks. When passed, switches "https" calls to "http" where - possible. - -V Install Salt into virtualenv - (only available for Ubuntu based distributions) - -a Pip install all Python pkg dependencies for Salt. Requires -V to install - all pip pkgs into the virtualenv. - (Only available for Ubuntu based distributions) - -r Disable all repository configuration performed by this script. This - option assumes all necessary repository configuration is already present - on the system. - -R Specify a custom repository URL. Assumes the custom repository URL - points to a repository that mirrors Salt packages located at - repo.saltproject.io. The option passed with -R replaces the - "repo.saltproject.io". If -R is passed, -r is also set. Currently only - works on CentOS/RHEL and Debian based distributions. - -J Replace the Master config file with data passed in as a JSON string. If - a Master config file is found, a reasonable effort will be made to save - the file with a ".bak" extension. If used in conjunction with -C or -F, - no ".bak" file will be created as either of those options will force - a complete overwrite of the file. + -F Allow copied files to overwrite existing (config, init.d, etc) + -g Salt Git repository URL. Default: ${_SALTSTACK_REPO_URL} + -h Display this message + -H Use the specified HTTP proxy for all download URLs (including https://). + For example: http://myproxy.example.com:3128 + -i Pass the salt-minion id. This will be stored under + \${BS_SALT_ETC_DIR}/minion_id + -I If set, allow insecure connections while downloading any files. For + example, pass '--no-check-certificate' to 'wget' or '--insecure' to + 'curl'. On Debian and Ubuntu, using this option with -U allows obtaining + GnuPG archive keys insecurely if distro has changed release signatures. -j Replace the Minion config file with data passed in as a JSON string. If a Minion config file is found, a reasonable effort will be made to save the file with a ".bak" extension. If used in conjunction with -C or -F, no ".bak" file will be created as either of those options will force a complete overwrite of the file. + -J Replace the Master config file with data passed in as a JSON string. If + a Master config file is found, a reasonable effort will be made to save + the file with a ".bak" extension. If used in conjunction with -C or -F, + no ".bak" file will be created as either of those options will force + a complete overwrite of the file. + -k Temporary directory holding the minion keys which will pre-seed + the master. + -K If set, keep the temporary files in the temporary directories specified + with -c and -k + -l Disable ssl checks. When passed, switches "https" calls to "http" where + possible. + -L Also install salt-cloud and required python-libcloud package + -M Also install salt-master + -n No colours + -N Do not install salt-minion + -p Extra-package to install while installing Salt dependencies. One package + per -p flag. You are responsible for providing the proper package name. + -P Allow pip based installations. On some distributions the required salt + packages or its dependencies are not available as a package for that + distribution. Using this flag allows the script to use pip as a last + resort method. NOTE: This only works for functions which actually + implement pip based installations. -q Quiet salt installation from git (setup.py install -q) + -Q Quickstart, install the Salt master and the Salt minion. + And automatically accept the minion key. + -R Specify a custom repository URL. Assumes the custom repository URL + points to a repository that mirrors Salt packages located at + repo.saltproject.io. The option passed with -R replaces the + "repo.saltproject.io". If -R is passed, -r is also set. Currently only + works on CentOS/RHEL and Debian based distributions and macOS. + -s Sleep time used when waiting for daemons to start, restart and when + checking for the services running. Default: ${__DEFAULT_SLEEP} + -S Also install salt-syndic + -r Disable all repository configuration performed by this script. This + option assumes all necessary repository configuration is already present + on the system. + -U If set, fully upgrade the system prior to bootstrapping Salt + -v Display script version + -V Install Salt into virtualenv + (only available for Ubuntu based distributions) -x Changes the Python version used to install Salt. For CentOS 6 git installations python2.7 is supported. - Fedora git installation, CentOS 7, Debian 9, Ubuntu 16.04 and 18.04 support python3. + Fedora git installation, CentOS 7, Ubuntu 18.04 support python3. + -X Do not start daemons after installation -y Installs a different python version on host. Currently this has only been tested with CentOS 6 and is considered experimental. This will install the ius repo on the box if disable repo is false. This must be used in conjunction @@ -406,7 +430,7 @@ EOT } # ---------- end of function __usage ---------- -while getopts ':hvnDc:g:Gyx:wk:s:MSNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:aq' opt +while getopts ':hvnDc:g:Gyx:k:s:MSNXCPFUKIA:i:Lp:dH:bflV:J:j:rR:aqQ' opt do case "${opt}" in @@ -422,7 +446,6 @@ do echowarn "No need to provide this option anymore, now it is a default behavior." ;; - w ) _DOWNSTREAM_PKG_REPO=$BS_TRUE ;; k ) _TEMP_KEYS_DIR="$OPTARG" ;; s ) _SLEEP=$OPTARG ;; M ) _INSTALL_MASTER=$BS_TRUE ;; @@ -451,6 +474,7 @@ do J ) _CUSTOM_MASTER_CONFIG=$OPTARG ;; j ) _CUSTOM_MINION_CONFIG=$OPTARG ;; q ) _QUIET_GIT_INSTALLATION=$BS_TRUE ;; + Q ) _QUICK_START=$BS_TRUE ;; x ) _PY_EXE="$OPTARG" ;; y ) _INSTALL_PY="$BS_TRUE" ;; @@ -572,7 +596,7 @@ fi echoinfo "Running version: ${__ScriptVersion}" echoinfo "Executed by: ${CALLER}" echoinfo "Command line: '${__ScriptFullName} ${__ScriptArgs}'" -#echowarn "Running the unstable version of ${__ScriptName}" +echowarn "Running the unstable version of ${__ScriptName}" # Define installation type if [ "$#" -gt 0 ];then @@ -582,11 +606,17 @@ if [ "$#" -gt 0 ];then fi # Check installation type -if [ "$(echo "$ITYPE" | grep -E '(stable|testing|git)')" = "" ]; then +if [ "$(echo "$ITYPE" | grep -E '(stable|testing|git|onedir|onedir_rc|old-stable)')" = "" ]; then echoerror "Installation type \"$ITYPE\" is not known..." exit 1 fi +# Due to our modifications to install_centos_onedir it is easiest to just lock down to only allowing stable install +if [ "$(echo "$ITYPE" | grep stable)" = "" ]; then + echoerror "This script has been modified to only support stable installation type. Installation type \"$ITYPE\" is not allowed..." + exit 1 +fi + # If doing a git install, check what branch/tag/sha will be checked out if [ "$ITYPE" = "git" ]; then if [ "$#" -eq 0 ];then @@ -602,23 +632,123 @@ if [ "$ITYPE" = "git" ]; then # If doing stable install, check if version specified elif [ "$ITYPE" = "stable" ]; then if [ "$#" -eq 0 ];then - STABLE_REV="latest" + ONEDIR_REV="latest" + _ONEDIR_REV="latest" + ITYPE="onedir" else - if [ "$(echo "$1" | grep -E '^(latest|1\.6|1\.7|2014\.1|2014\.7|2015\.5|2015\.8|2016\.3|2016\.11|2017\.7|2018\.3|2019\.2|3000|3001|3002|3003|3004)$')" != "" ]; then - STABLE_REV="$1" + if [ "$(echo "$1" | grep -E '^(nightly|latest|3005|3006)$')" != "" ]; then + ONEDIR_REV="$1" + _ONEDIR_REV="$1" + ITYPE="onedir" shift - elif [ "$(echo "$1" | grep -E '^(2[0-9]*\.[0-9]*\.[0-9]*|[3-9][0-9]{3}(\.[0-9]*)?)$')" != "" ]; then + elif [ "$(echo "$1" | grep -E '^([3-9][0-5]{2}[5-9](\.[0-9]*)?)')" != "" ]; then + ONEDIR_REV="minor/$1" + _ONEDIR_REV="$1" + ITYPE="onedir" + shift + else + echo "Unknown stable version: $1 (valid: 3005, 3006, latest)" + exit 1 + fi + fi + +# If doing old-stable install, check if version specified +elif [ "$ITYPE" = "old-stable" ]; then + if [ "$#" -eq 0 ];then + ITYPE="stable" + else + if [ "$(echo "$1" | grep -E '^(3003|3004|3005)$')" != "" ]; then + STABLE_REV="$1" + ITYPE="stable" + shift + elif [ "$(echo "$1" | grep -E '^([3-9][0-5]{3}(\.[0-9]*)?)$')" != "" ]; then # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix + ITYPE="stable" STABLE_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') if [ "$(uname)" != "Darwin" ]; then STABLE_REV="archive/$STABLE_REV" fi shift else - echo "Unknown stable version: $1 (valid: 1.6, 1.7, 2014.1, 2014.7, 2015.5, 2015.8, 2016.3, 2016.11, 2017.7, 2018.3, 2019.2, 3000, 3001, 3002, 3003, 3004, latest, \$MAJOR.\$MINOR.\$PATCH until 2019.2, \$MAJOR or \$MAJOR.\$PATCH starting from 3000)" + echo "Unknown old stable version: $1 (valid: 3003, 3004, 3005)" exit 1 fi fi + +elif [ "$ITYPE" = "onedir" ]; then + if [ "$#" -eq 0 ];then + ONEDIR_REV="latest" + else + if [ "$(echo "$1" | grep -E '^(nightly|latest|3005|3006)$')" != "" ]; then + ONEDIR_REV="$1" + shift + elif [ "$(echo "$1" | grep -E '^(3005(\.[0-9]*)?)')" != "" ]; then + # Handle the 3005.0 version as 3005 archive (pin to minor) and strip the fake ".0" suffix + ONEDIR_REV=$(echo "$1" | sed -E 's/^(3005)\.0$/\1/') + ONEDIR_REV="minor/$ONEDIR_REV" + shift + elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}(\.[0-9]*)?)')" != "" ]; then + ONEDIR_REV="minor/$1" + shift + else + echo "Unknown onedir version: $1 (valid: 3005, 3006, latest, nightly.)" + exit 1 + fi + fi + +elif [ "$ITYPE" = "onedir_rc" ]; then + # Change the _ONEDIR_DIR to be the location for the RC packages + _ONEDIR_DIR="salt_rc/salt" + + # Change ITYPE to onedir so we use the regular onedir functions + ITYPE="onedir" + + if [ "$#" -eq 0 ];then + ONEDIR_REV="latest" + else + if [ "$(echo "$1" | grep -E '^(latest)$')" != "" ]; then + ONEDIR_REV="$1" + shift + elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}?rc[0-9]-[0-9]$)')" != "" ]; then + # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix + #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') + ONEDIR_REV="minor/$1" + shift + elif [ "$(echo "$1" | grep -E '^([3-9][0-9]{3}\.[0-9]?rc[0-9]$)')" != "" ]; then + # Handle the 3xxx.0 version as 3xxx archive (pin to minor) and strip the fake ".0" suffix + #ONEDIR_REV=$(echo "$1" | sed -E 's/^([3-9][0-9]{3})\.0$/\1/') + ONEDIR_REV="minor/$1" + shift + else + echo "Unknown onedir_rc version: $1 (valid: 3005-1, latest.)" + exit 1 + fi + fi +fi + +# Doing a quick start, so install master +# set master address to 127.0.0.1 +if [ "$_QUICK_START" -eq "$BS_TRUE" ]; then + # make install type is stable + ITYPE="stable" + + # make sure the revision is latest + STABLE_REV="latest" + ONEDIR_REV="latest" + + # make sure we're installing the master + _INSTALL_MASTER=$BS_TRUE + + # override incase install minion + # is set to false + _INSTALL_MINION=$BS_TRUE + + # Set master address to loopback IP + _SALT_MASTER_ADDRESS="127.0.0.1" + + # Auto accept the minion key + # when the install is done. + _AUTO_ACCEPT_MINION_KEYS=$BS_TRUE fi # Check for any unparsed arguments. Should be an error. @@ -824,6 +954,18 @@ __fetch_verify() { return 1 } +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: __check_url_exists +# DESCRIPTION: Checks if a URL exists +#---------------------------------------------------------------------------------------------------------------------- +__check_url_exists() { + _URL="$1" + if curl --output /dev/null --silent --fail "${_URL}"; then + return 0 + else + return 1 + fi +} #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __gather_hardware_info # DESCRIPTION: Discover hardware information @@ -945,7 +1087,7 @@ __strip_duplicates() { __sort_release_files() { KNOWN_RELEASE_FILES=$(echo "(arch|alpine|centos|debian|ubuntu|fedora|redhat|suse|\ mandrake|mandriva|gentoo|slackware|turbolinux|unitedlinux|void|lsb|system|\ - oracle|os)(-|_)(release|version)" | sed -E 's:[[:space:]]::g') + oracle|os|almalinux|rocky)(-|_)(release|version)" | sed -E 's:[[:space:]]::g') primary_release_files="" secondary_release_files="" # Sort know VS un-known files first @@ -959,7 +1101,7 @@ __sort_release_files() { done # Now let's sort by know files importance, max important goes last in the max_prio list - max_prio="redhat-release centos-release oracle-release fedora-release" + max_prio="redhat-release centos-release oracle-release fedora-release almalinux-release rocky-release" for entry in $max_prio; do if [ "$(echo "${primary_release_files}" | grep "$entry")" != "" ]; then primary_release_files=$(echo "${primary_release_files}" | sed -e "s:\\(.*\\)\\($entry\\)\\(.*\\):\\2 \\1 \\3:g") @@ -1028,6 +1170,8 @@ __gather_linux_system_info() { elif [ "${DISTRO_NAME}" = "Arch" ]; then DISTRO_NAME="Arch Linux" return + elif [ "${DISTRO_NAME}" = "Rocky" ]; then + DISTRO_NAME="Rocky Linux" fi rv=$(lsb_release -sr) [ "${rv}" != "" ] && DISTRO_VERSION=$(__parse_version_string "$rv") @@ -1086,6 +1230,8 @@ __gather_linux_system_info() { unitedlinux ) n="UnitedLinux" ;; void ) n="VoidLinux" ;; oracle ) n="Oracle Linux" ;; + almalinux ) n="AlmaLinux" ;; + rocky ) n="Rocky Linux" ;; system ) while read -r line; do [ "${n}x" != "systemx" ] && break @@ -1308,7 +1454,7 @@ __gather_system_info() { #---------------------------------------------------------------------------------------------------------------------- # shellcheck disable=SC2034 __ubuntu_derivatives_translation() { - UBUNTU_DERIVATIVES="(trisquel|linuxmint|linaro|elementary_os|neon)" + UBUNTU_DERIVATIVES="(trisquel|linuxmint|linaro|elementary_os|neon|pop)" # Mappings trisquel_6_ubuntu_base="12.04" linuxmint_13_ubuntu_base="12.04" @@ -1321,6 +1467,8 @@ __ubuntu_derivatives_translation() { neon_16_ubuntu_base="16.04" neon_18_ubuntu_base="18.04" neon_20_ubuntu_base="20.04" + neon_22_ubuntu_base="22.04" + pop_22_ubuntu_base="22.04" # Translate Ubuntu derivatives to their base Ubuntu version match=$(echo "$DISTRO_NAME_L" | grep -E ${UBUNTU_DERIVATIVES}) @@ -1380,9 +1528,13 @@ __check_dpkg_architecture() { if [ "$_CUSTOM_REPO_URL" != "null" ]; then warn_msg="Support for arm64 is experimental, make sure the custom repository used has the expected structure and contents." else - # Saltstack official repository does not yet have arm64 metadata, - # use amd64 repositories on arm64, since all pkgs are arch-independent - __REPO_ARCH="amd64" + # Saltstack official repository has arm64 metadata beginning with Debian 11, + # use amd64 repositories on arm64 for anything older, since all pkgs are arch-independent + if [ "$DISTRO_NAME_L" = "debian" ] && [ "$DISTRO_MAJOR_VERSION" -lt 11 ]; then + __REPO_ARCH="amd64" + else + __REPO_ARCH="arm64" + fi __REPO_ARCH_DEB="deb [signed-by=/usr/share/keyrings/salt-archive-keyring.gpg arch=$__REPO_ARCH]" warn_msg="Support for arm64 packages is experimental and might rely on architecture-independent packages from the amd64 repository." fi @@ -1462,6 +1614,9 @@ __ubuntu_codename_translation() { "21") DISTRO_CODENAME="hirsute" ;; + "22") + DISTRO_CODENAME="jammy" + ;; *) DISTRO_CODENAME="trusty" ;; @@ -1488,10 +1643,12 @@ __debian_derivatives_translation() { devuan_1_debian_base="8.0" devuan_2_debian_base="9.0" kali_1_debian_base="7.0" + kali_2021_debian_base="10.0" linuxmint_1_debian_base="8.0" raspbian_8_debian_base="8.0" raspbian_9_debian_base="9.0" raspbian_10_debian_base="10.0" + raspbian_11_debian_base="11.0" bunsenlabs_9_debian_base="9.0" turnkey_9_debian_base="9.0" @@ -1559,6 +1716,14 @@ __debian_codename_translation() { "11") DISTRO_CODENAME="bullseye" ;; + "12") + DISTRO_CODENAME="bookworm" + # FIXME - TEMPORARY + # use bullseye packages until bookworm packages are available + DISTRO_CODENAME="bullseye" + DISTRO_MAJOR_VERSION=11 + rv=11 + ;; *) DISTRO_CODENAME="stretch" ;; @@ -1590,11 +1755,13 @@ __check_end_of_life_versions() { # = 17.04, 17.10 # = 18.10 # = 19.04, 19.10 + # = 20.10 if [ "$DISTRO_MAJOR_VERSION" -lt 16 ] || \ [ "$DISTRO_MAJOR_VERSION" -eq 17 ] || \ [ "$DISTRO_MAJOR_VERSION" -eq 19 ] || \ { [ "$DISTRO_MAJOR_VERSION" -eq 16 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - { [ "$DISTRO_MAJOR_VERSION" -eq 18 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; }; then + { [ "$DISTRO_MAJOR_VERSION" -eq 18 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; }; then echoerror "End of life distributions are not supported." echoerror "Please consider upgrading to the next stable. See:" echoerror " https://wiki.ubuntu.com/Releases" @@ -1812,14 +1979,14 @@ elif [ "${DISTRO_NAME_L}" = "debian" ]; then __debian_codename_translation fi -if [ "$(echo "${DISTRO_NAME_L}" | grep -E '(debian|ubuntu|centos|gentoo|red_hat|oracle|scientific|amazon|fedora|macosx)')" = "" ] && [ "$ITYPE" = "stable" ] && [ "$STABLE_REV" != "latest" ]; then +if [ "$(echo "${DISTRO_NAME_L}" | grep -E '(debian|ubuntu|centos|gentoo|red_hat|oracle|scientific|amazon|fedora|macosx|almalinux|rocky)')" = "" ] && [ "$ITYPE" = "stable" ] && [ "$STABLE_REV" != "latest" ]; then echoerror "${DISTRO_NAME} does not have major version pegged packages support" exit 1 fi # Only RedHat based distros have testing support if [ "${ITYPE}" = "testing" ]; then - if [ "$(echo "${DISTRO_NAME_L}" | grep -E '(centos|red_hat|amazon|oracle)')" = "" ]; then + if [ "$(echo "${DISTRO_NAME_L}" | grep -E '(centos|red_hat|amazon|oracle|almalinux|rocky)')" = "" ]; then echoerror "${DISTRO_NAME} does not have testing packages support" exit 1 fi @@ -1850,10 +2017,6 @@ if [ "$ITYPE" = "git" ]; then if [ "$__NEW_VS_TAG_REGEX_MATCH" = "MATCH" ]; then _POST_NEON_INSTALL=$BS_TRUE __TAG_REGEX_MATCH="${__NEW_VS_TAG_REGEX_MATCH}" - if [ "$(echo "${GIT_REV}" | cut -c -1)" != "v" ]; then - # We do this to properly clone tags - GIT_REV="v${GIT_REV}" - fi echodebug "Post Neon Tag Regex Match On: ${GIT_REV}" else __TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed -E 's/^(v?[0-9]{1,4}\.[0-9]{1,2})(\.[0-9]{1,2})?.*$/MATCH/') @@ -1865,10 +2028,6 @@ if [ "$ITYPE" = "git" ]; then if [ "$__NEW_VS_TAG_REGEX_MATCH" = "MATCH" ]; then _POST_NEON_INSTALL=$BS_TRUE __TAG_REGEX_MATCH="${__NEW_VS_TAG_REGEX_MATCH}" - if [ "$(echo "${GIT_REV}" | cut -c -1)" != "v" ]; then - # We do this to properly clone tags - GIT_REV="v${GIT_REV}" - fi echodebug "Post Neon Tag Regex Match On: ${GIT_REV}" else __TAG_REGEX_MATCH=$(echo "${GIT_REV}" | sed 's/^.*\(v\?[[:digit:]]\{1,4\}\.[[:digit:]]\{1,2\}\)\(\.[[:digit:]]\{1,2\}\)\?.*$/MATCH/') @@ -2031,20 +2190,13 @@ __rpm_import_gpg() { #---------------------------------------------------------------------------------------------------------------------- __yum_install_noinput() { - ENABLE_EPEL_CMD="" - # Skip Amazon Linux for the first round, since EPEL is no longer required. - # See issue #724 - if [ $_DISABLE_REPOS -eq $BS_FALSE ] && [ "$DISTRO_NAME_L" != "amazon_linux_ami" ]; then - ENABLE_EPEL_CMD="--enablerepo=${_EPEL_REPO}" - fi - if [ "$DISTRO_NAME_L" = "oracle_linux" ]; then # We need to install one package at a time because --enablerepo=X disables ALL OTHER REPOS!!!! for package in "${@}"; do - yum -y install "${package}" || yum -y install "${package}" ${ENABLE_EPEL_CMD} || return $? + yum -y install "${package}" || yum -y install "${package}" || return $? done else - yum -y install "${@}" ${ENABLE_EPEL_CMD} || return $? + yum -y install "${@}" || return $? fi } # ---------- end of function __yum_install_noinput ---------- @@ -2057,6 +2209,15 @@ __dnf_install_noinput() { dnf -y install "${@}" || return $? } # ---------- end of function __dnf_install_noinput ---------- +#--- FUNCTION ------------------------------------------------------------------------------------------------------- +# NAME: __tdnf_install_noinput +# DESCRIPTION: (DRY) tdnf install with noinput options +#---------------------------------------------------------------------------------------------------------------------- +__tdnf_install_noinput() { + + tdnf -y install "${@}" || return $? +} # ---------- end of function __tdnf_install_noinput ---------- + #--- FUNCTION ------------------------------------------------------------------------------------------------------- # NAME: __git_clone_and_checkout # DESCRIPTION: (DRY) Helper function to clone and checkout salt to a @@ -2582,7 +2743,7 @@ __activate_virtualenv() { # NAME: __install_pip_pkgs # DESCRIPTION: Return 0 or 1 if successfully able to install pip packages. Can provide a different python version to # install pip packages with. If $py_ver is not specified it will use the default python version. -# PARAMETERS: pkgs, py_ver +# PARAMETERS: pkgs, py_ver, upgrade #---------------------------------------------------------------------------------------------------------------------- __install_pip_pkgs() { @@ -2751,15 +2912,15 @@ EOM fi echodebug "Running '${_pip_cmd} install wheel ${_setuptools_dep}'" - ${_pip_cmd} install ${_POST_NEON_PIP_INSTALL_ARGS} wheel "${_setuptools_dep}" + ${_pip_cmd} install --upgrade ${_POST_NEON_PIP_INSTALL_ARGS} wheel "${_setuptools_dep}" echoinfo "Installing salt using ${_py_exe}" cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 mkdir /tmp/git/deps echoinfo "Downloading Salt Dependencies from PyPi" - echodebug "Running '${_pip_cmd} download -d /tmp/git/deps .'" - ${_pip_cmd} download -d /tmp/git/deps . || (echo "Failed to download salt dependencies" && return 1) + echodebug "Running '${_pip_cmd} download -d /tmp/git/deps ${_PIP_DOWNLOAD_ARGS} .'" + ${_pip_cmd} download -d /tmp/git/deps ${_PIP_DOWNLOAD_ARGS} . || (echo "Failed to download salt dependencies" && return 1) echoinfo "Installing Downloaded Salt Dependencies" echodebug "Running '${_pip_cmd} install --ignore-installed ${_POST_NEON_PIP_INSTALL_ARGS} /tmp/git/deps/*'" @@ -2918,7 +3079,8 @@ __enable_universe_repository() { __install_saltstack_ubuntu_repository() { # Workaround for latest non-LTS Ubuntu if { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ - { [ "$DISTRO_MAJOR_VERSION" -eq 21 ] && [ "$DISTRO_MINOR_VERSION" -eq 04 ]; }; then + # remove 22 version when salt packages for 22.04 are available + [ "$DISTRO_MAJOR_VERSION" -eq 21 ] || [ "$DISTRO_MAJOR_VERSION" -eq 22 ]; then echowarn "Non-LTS Ubuntu detected, but stable packages requested. Trying packages for previous LTS release. You may experience problems." UBUNTU_VERSION=20.04 UBUNTU_CODENAME="focal" @@ -2957,6 +3119,58 @@ __install_saltstack_ubuntu_repository() { __wait_for_apt apt-get update || return 1 } +__install_saltstack_ubuntu_onedir_repository() { + # Workaround for latest non-LTS Ubuntu + if { [ "$DISTRO_MAJOR_VERSION" -eq 20 ] && [ "$DISTRO_MINOR_VERSION" -eq 10 ]; } || \ + [ "$DISTRO_MAJOR_VERSION" -eq 21 ]; then + echowarn "Non-LTS Ubuntu detected, but stable packages requested. Trying packages for previous LTS release. You may experience problems." + UBUNTU_VERSION=20.04 + UBUNTU_CODENAME="focal" + else + UBUNTU_VERSION=${DISTRO_VERSION} + UBUNTU_CODENAME=${DISTRO_CODENAME} + fi + + # Install downloader backend for GPG keys fetching + __PACKAGES='wget' + + # Required as it is not installed by default on Ubuntu 18+ + if [ "$DISTRO_MAJOR_VERSION" -ge 18 ]; then + __PACKAGES="${__PACKAGES} gnupg" + fi + + # Make sure https transport is available + if [ "$HTTP_VAL" = "https" ] ; then + __PACKAGES="${__PACKAGES} apt-transport-https ca-certificates" + fi + + # shellcheck disable=SC2086,SC2090 + __apt_get_install_noinput ${__PACKAGES} || return 1 + + __PY_VERSION_REPO="apt" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + # SaltStack's stable Ubuntu repository: + SALTSTACK_UBUNTU_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/ubuntu/${UBUNTU_VERSION}/${__REPO_ARCH}/${ONEDIR_REV}/" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + SALTSTACK_UBUNTU_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/ubuntu/${UBUNTU_VERSION}/${__REPO_ARCH}/" + fi + echo "$__REPO_ARCH_DEB $SALTSTACK_UBUNTU_URL $UBUNTU_CODENAME main" > /etc/apt/sources.list.d/salt.list + + if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ]; then + __apt_key_fetch "${SALTSTACK_UBUNTU_URL}salt-archive-keyring.gpg" || return 1 + elif [ "$(echo "${ONEDIR_REV}" | grep -E '(latest|nightly)')" != "" ]; then + __apt_key_fetch "${SALTSTACK_UBUNTU_URL}salt-archive-keyring.gpg" || \ + __apt_key_fetch "${SALTSTACK_UBUNTU_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 + else + __apt_key_fetch "${SALTSTACK_UBUNTU_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 + fi + + __wait_for_apt apt-get update || return 1 +} + install_ubuntu_deps() { if [ $_DISABLE_REPOS -eq $BS_FALSE ]; then # Install add-apt-repository @@ -3032,7 +3246,7 @@ install_ubuntu_stable_deps() { if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then - if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] || [ "$DISTRO_MAJOR_VERSION" -ge 21 ]; then + if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] || [ "$DISTRO_MAJOR_VERSION" -ge 21 ] || [ "$DISTRO_MAJOR_VERSION" -ge 22 ]; then __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 else __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && @@ -3113,6 +3327,9 @@ install_ubuntu_git_deps() { fi else __PACKAGES="python${PY_PKG_VER}-dev python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" + if [ "$DISTRO_MAJOR_VERSION" -ge 22 ]; then + __PACKAGES="${__PACKAGES} g++" + fi # shellcheck disable=SC2086 __apt_get_install_noinput ${__PACKAGES} || return 1 fi @@ -3126,6 +3343,44 @@ install_ubuntu_git_deps() { return 0 } +install_ubuntu_onedir_deps() { + if [ "${_SLEEP}" -eq "${__DEFAULT_SLEEP}" ] && [ "$DISTRO_MAJOR_VERSION" -lt 16 ]; then + # The user did not pass a custom sleep value as an argument, let's increase the default value + echodebug "On Ubuntu systems we increase the default sleep value to 10." + echodebug "See https://github.com/saltstack/salt/issues/12248 for more info." + _SLEEP=10 + fi + + if [ $_START_DAEMONS -eq $BS_FALSE ]; then + echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." + fi + + # No user interaction, libc6 restart services for example + export DEBIAN_FRONTEND=noninteractive + + __wait_for_apt apt-get update || return 1 + + if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then + if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then + if [ "$DISTRO_MAJOR_VERSION" -ge 20 ] || [ "$DISTRO_MAJOR_VERSION" -ge 21 ]; then + __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 + else + __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && + apt-key update && apt-get update || return 1 + fi + fi + + __apt_get_upgrade_noinput || return 1 + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then + __check_dpkg_architecture || return 1 + __install_saltstack_ubuntu_onedir_repository || return 1 + fi + + install_ubuntu_deps || return 1 +} + install_ubuntu_stable() { __PACKAGES="" @@ -3170,7 +3425,15 @@ install_ubuntu_git() { _POST_NEON_PIP_INSTALL_ARGS="" __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 - sed -i 's:/usr/bin:/usr/local/bin:g' pkg/*.service + + # Account for new path for services files in later releases + if [ -d "pkg/common" ]; then + _SERVICE_DIR="pkg/common" + else + _SERVICE_DIR="pkg" + fi + + sed -i 's:/usr/bin:/usr/local/bin:g' ${_SERVICE_DIR}/*.service return 0 fi @@ -3185,6 +3448,28 @@ install_ubuntu_git() { return 0 } +install_ubuntu_onedir() { + __PACKAGES="" + + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-cloud" + fi + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-master" + fi + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-minion" + fi + if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-syndic" + fi + + # shellcheck disable=SC2086 + __apt_get_install_noinput ${__PACKAGES} || return 1 + + return 0 +} + install_ubuntu_stable_post() { for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -3220,8 +3505,15 @@ install_ubuntu_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg" + fi + if [ -f /bin/systemctl ] && [ "$DISTRO_MAJOR_VERSION" -ge 16 ]; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -3236,8 +3528,8 @@ install_ubuntu_git_post() { if [ ! -f $_upstart_conf ]; then # upstart does not know about our service, let's copy the proper file echowarn "Upstart does not appear to know about salt-$fname" - echodebug "Copying ${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-$fname.upstart to $_upstart_conf" - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.upstart" "$_upstart_conf" + echodebug "Copying ${_SERVICE_DIR}/salt-$fname.upstart to $_upstart_conf" + __copyfile "${_SERVICE_DIR}/salt-${fname}.upstart" "$_upstart_conf" # Set service to know about virtualenv if [ "${_VIRTUALENV_DIR}" != "null" ]; then echo "SALT_USE_VIRTUALENV=${_VIRTUALENV_DIR}" > /etc/default/salt-${fname} @@ -3349,17 +3641,8 @@ install_ubuntu_check_services() { # Debian Install Functions # __install_saltstack_debian_repository() { - if [ "$DISTRO_MAJOR_VERSION" -eq 11 ]; then - # Packages for Debian 11 at repo.saltproject.io are not yet available - # Set up repository for Debian 10 for Debian 11 for now until support - # is available at repo.saltproject.io for Debian 11. - echowarn "Debian 11 distribution detected, but stable packages requested. Trying packages from Debian 10. You may experience problems." - DEBIAN_RELEASE="10" - DEBIAN_CODENAME="buster" - else - DEBIAN_RELEASE="$DISTRO_MAJOR_VERSION" - DEBIAN_CODENAME="$DISTRO_CODENAME" - fi + DEBIAN_RELEASE="$DISTRO_MAJOR_VERSION" + DEBIAN_CODENAME="$DISTRO_CODENAME" __PY_VERSION_REPO="apt" if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then @@ -3391,6 +3674,50 @@ __install_saltstack_debian_repository() { __wait_for_apt apt-get update || return 1 } +__install_saltstack_debian_onedir_repository() { + DEBIAN_RELEASE="$DISTRO_MAJOR_VERSION" + DEBIAN_CODENAME="$DISTRO_CODENAME" + + __PY_VERSION_REPO="apt" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + # Install downloader backend for GPG keys fetching + __PACKAGES='wget' + + # Required as it is not installed by default on Debian 9+ + if [ "$DISTRO_MAJOR_VERSION" -ge 9 ]; then + __PACKAGES="${__PACKAGES} gnupg2" + fi + + # Make sure https transport is available + if [ "$HTTP_VAL" = "https" ] ; then + __PACKAGES="${__PACKAGES} apt-transport-https ca-certificates" + fi + + # shellcheck disable=SC2086,SC2090 + __apt_get_install_noinput ${__PACKAGES} || return 1 + + # amd64 is just a part of repository URI, 32-bit pkgs are hosted under the same location + SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/${ONEDIR_REV}/" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + SALTSTACK_DEBIAN_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/debian/${DEBIAN_RELEASE}/${__REPO_ARCH}/" + fi + echo "$__REPO_ARCH_DEB $SALTSTACK_DEBIAN_URL $DEBIAN_CODENAME main" > "/etc/apt/sources.list.d/salt.list" + + if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ]; then + __apt_key_fetch "${SALTSTACK_DEBIAN_URL}salt-archive-keyring.gpg" || return 1 + elif [ "$(echo "${ONEDIR_REV}" | grep -E '(latest|nightly)')" != "" ]; then + __apt_key_fetch "${SALTSTACK_DEBIAN_URL}salt-archive-keyring.gpg" || \ + __apt_key_fetch "${SALTSTACK_DEBIAN_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 + else + __apt_key_fetch "${SALTSTACK_DEBIAN_URL}SALT-PROJECT-GPG-PUBKEY-2023.gpg" || return 1 + fi + + __wait_for_apt apt-get update || return 1 +} + install_debian_deps() { if [ $_START_DAEMONS -eq $BS_FALSE ]; then echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." @@ -3444,6 +3771,59 @@ install_debian_deps() { return 0 } +install_debian_onedir_deps() { + if [ $_START_DAEMONS -eq $BS_FALSE ]; then + echowarn "Not starting daemons on Debian based distributions is not working mostly because starting them is the default behaviour." + fi + + # No user interaction, libc6 restart services for example + export DEBIAN_FRONTEND=noninteractive + + __wait_for_apt apt-get update || return 1 + + if [ "${_UPGRADE_SYS}" -eq $BS_TRUE ]; then + # Try to update GPG keys first if allowed + if [ "${_INSECURE_DL}" -eq $BS_TRUE ]; then + if [ "$DISTRO_MAJOR_VERSION" -ge 10 ]; then + __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && apt-get update || return 1 + else + __apt_get_install_noinput --allow-unauthenticated debian-archive-keyring && + apt-key update && apt-get update || return 1 + fi + fi + + __apt_get_upgrade_noinput || return 1 + fi + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + PY_PKG_VER=3 + else + PY_PKG_VER="" + fi + + # Additionally install procps and pciutils which allows for Docker bootstraps. See 366#issuecomment-39666813 + __PACKAGES='procps pciutils' + + # YAML module is used for generating custom master/minion configs + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-yaml" + + # shellcheck disable=SC2086 + __apt_get_install_noinput ${__PACKAGES} || return 1 + + if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then + __check_dpkg_architecture || return 1 + __install_saltstack_debian_onedir_repository || return 1 + fi + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __apt_get_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi + + return 0 +} + install_debian_git_pre() { if ! __check_command_exists git; then __apt_get_install_noinput git || return 1 @@ -3692,7 +4072,15 @@ install_debian_git() { _POST_NEON_PIP_INSTALL_ARGS="" __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 cd "${_SALT_GIT_CHECKOUT_DIR}" || return 1 - sed -i 's:/usr/bin:/usr/local/bin:g' pkg/*.service + + # Account for new path for services files in later releases + if [ -d "pkg/common" ]; then + _SERVICE_DIR="pkg/common" + else + _SERVICE_DIR="pkg" + fi + + sed -i 's:/usr/bin:/usr/local/bin:g' ${_SERVICE_DIR}/*.service return 0 fi @@ -3720,6 +4108,28 @@ install_debian_9_git() { return 0 } +install_debian_onedir() { + __PACKAGES="" + + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-cloud" + fi + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-master" + fi + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-minion" + fi + if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-syndic" + fi + + # shellcheck disable=SC2086 + __apt_get_install_noinput ${__PACKAGES} || return 1 + + return 0 +} + install_debian_git_post() { for fname in api master minion syndic; do # Skip if not meant to be installed @@ -3729,16 +4139,23 @@ install_debian_git_post() { [ "$fname" = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ "$fname" = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg" + fi + # Configure SystemD for Debian 8 "Jessie" and later if [ -f /bin/systemctl ]; then if [ ! -f /lib/systemd/system/salt-${fname}.service ] || \ { [ -f /lib/systemd/system/salt-${fname}.service ] && [ $_FORCE_OVERWRITE -eq $BS_TRUE ]; }; then - if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" ]; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" /lib/systemd/system - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.environment" "/etc/default/salt-${fname}" + if [ -f "${_SERVICE_DIR}/salt-${fname}.service" ]; then + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" /lib/systemd/system + __copyfile "${_SERVICE_DIR}/salt-${fname}.environment" "/etc/default/salt-${fname}" else # workaround before adding Debian-specific unit files to the Salt main repo - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" /lib/systemd/system + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" /lib/systemd/system sed -i -e '/^Type/ s/notify/simple/' /lib/systemd/system/salt-${fname}.service fi fi @@ -3770,6 +4187,13 @@ install_debian_git_post() { done } +install_debian_2021_post() { + # Kali 2021 (debian derivative) disables all network services by default + # Using archlinux post function to enable salt systemd services + install_arch_linux_post || return 1 + return 0 +} + install_debian_restart_daemons() { [ "$_START_DAEMONS" -eq $BS_FALSE ] && return 0 @@ -3826,6 +4250,41 @@ install_debian_check_services() { # Fedora Install Functions # +__install_saltstack_fedora_onedir_repository() { + if [ "$ITYPE" = "stable" ]; then + REPO_REV="$ONEDIR_REV" + else + REPO_REV="latest" + fi + + __PY_VERSION_REPO="yum" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + GPG_KEY="SALT-PROJECT-GPG-PUBKEY-2023.pub" + + REPO_FILE="/etc/yum.repos.d/salt.repo" + + if [ ! -s "$REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/fedora/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/fedora/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + fi + + __fetch_url "${REPO_FILE}" "${FETCH_URL}.repo" + + __rpm_import_gpg "${FETCH_URL}/${GPG_KEY}" || return 1 + + yum clean metadata || return 1 + elif [ "$REPO_REV" != "latest" ]; then + echowarn "salt.repo already exists, ignoring salt version argument." + echowarn "Use -F (forced overwrite) to install $REPO_REV." + fi + + return 0 +} + install_fedora_deps() { if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then dnf -y update || return 1 @@ -3985,6 +4444,9 @@ install_fedora_git_deps() { done else __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc" + if [ "${DISTRO_VERSION}" -ge 35 ]; then + __PACKAGES="${__PACKAGES} gcc-c++" + fi # shellcheck disable=SC2086 __dnf_install_noinput ${__PACKAGES} || return 1 fi @@ -4028,7 +4490,18 @@ install_fedora_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm" + fi + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + + # Salt executables are located under `/usr/local/bin/` on Fedora 36+ + #if [ "${DISTRO_VERSION}" -ge 36 ]; then + # sed -i -e 's:/usr/bin/:/usr/local/bin/:g' /lib/systemd/system/salt-*.service + #fi # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -4076,6 +4549,83 @@ install_fedora_check_services() { return 0 } + +install_fedora_onedir_deps() { + + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + yum -y update || return 1 + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_TRUE" ] && [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + echowarn "Detected -r or -R option while installing Salt packages for Python 3." + echowarn "Python 3 packages for older Salt releases requires the EPEL repository to be installed." + echowarn "Installing the EPEL repository automatically is disabled when using the -r or -R options." + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then + __install_saltstack_fedora_onedir_repository || return 1 + fi + + # If -R was passed, we need to configure custom repo url with rsync-ed packages + # Which is still handled in __install_saltstack_rhel_repository. This call has + # its own check in case -r was passed without -R. + if [ "$_CUSTOM_REPO_URL" != "null" ]; then + __install_saltstack_fedora_onedir_repository || return 1 + fi + + if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then + __PACKAGES="dnf-utils chkconfig" + else + __PACKAGES="yum-utils chkconfig" + fi + + __PACKAGES="${__PACKAGES} procps" + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi + + return 0 + +} + + +install_fedora_onedir() { + STABLE_REV=$ONEDIR_REV + #install_fedora_stable || return 1 + + __PACKAGES="" + + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-cloud" + fi + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-master" + fi + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-minion" + fi + if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-syndic" + fi + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + + return 0 +} + +install_fedora_onedir_post() { + STABLE_REV=$ONEDIR_REV + install_fedora_stable_post || return 1 + + return 0 +} # # Ended Fedora Install Functions # @@ -4085,27 +4635,13 @@ install_fedora_check_services() { # # CentOS Install Functions # -__install_epel_repository() { - if [ ${_EPEL_REPOS_INSTALLED} -eq $BS_TRUE ]; then - return 0 - fi - - # Check if epel repo is already enabled and flag it accordingly - if yum repolist | grep -q "^[!]\\?${_EPEL_REPO}/"; then - _EPEL_REPOS_INSTALLED=$BS_TRUE - return 0 - fi - - # Download latest 'epel-release' package for the distro version directly - epel_repo_url="${HTTP_VAL}://dl.fedoraproject.org/pub/epel/epel-release-latest-${DISTRO_MAJOR_VERSION}.noarch.rpm" - rpm -Uvh --force "$epel_repo_url" || return 1 - - _EPEL_REPOS_INSTALLED=$BS_TRUE - - return 0 -} - __install_saltstack_rhel_repository() { + if [ "${DISTRO_MAJOR_VERSION}" -ge 9 ]; then + echoerror "Old stable repository unavailable on RH variants greater than or equal to 9" + echoerror "Use the stable install type." + exit 1 + fi + if [ "$ITYPE" = "stable" ]; then repo_rev="$STABLE_REV" else @@ -4120,7 +4656,19 @@ __install_saltstack_rhel_repository() { # Avoid using '$releasever' variable for yum. # Instead, this should work correctly on all RHEL variants. base_url="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/${repo_rev}/" - gpg_key="SALTSTACK-GPG-KEY.pub" + if [ "${DISTRO_MAJOR_VERSION}" -eq 7 ]; then + gpg_key="SALTSTACK-GPG-KEY.pub base/RPM-GPG-KEY-CentOS-7" + elif [ "${DISTRO_MAJOR_VERSION}" -ge 9 ]; then + gpg_key="SALTSTACK-GPG-KEY2.pub" + else + gpg_key="SALTSTACK-GPG-KEY.pub" + fi + + gpg_key_urls="" + for key in $gpg_key; do + gpg_key_urls=$(printf "${base_url}${key},%s" "$gpg_key_urls") + done + repo_file="/etc/yum.repos.d/salt.repo" if [ ! -s "$repo_file" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then @@ -4130,13 +4678,80 @@ name=SaltStack ${repo_rev} Release Channel for RHEL/CentOS \$releasever baseurl=${base_url} skip_if_unavailable=True gpgcheck=1 -gpgkey=${base_url}${gpg_key} +gpgkey=${gpg_key_urls} enabled=1 enabled_metadata=1 _eof fetch_url="${HTTP_VAL}://${_REPO_URL}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${repo_rev}/" - __rpm_import_gpg "${fetch_url}${gpg_key}" || return 1 + for key in $gpg_key; do + __rpm_import_gpg "${fetch_url}${key}" || return 1 + done + + yum clean metadata || return 1 + elif [ "$repo_rev" != "latest" ]; then + echowarn "salt.repo already exists, ignoring salt version argument." + echowarn "Use -F (forced overwrite) to install $repo_rev." + fi + + return 0 +} + +__install_saltstack_rhel_onedir_repository() { + if [ "$ITYPE" = "stable" ]; then + repo_rev="$ONEDIR_REV" + else + repo_rev="latest" + fi + + __PY_VERSION_REPO="yum" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + # Avoid using '$releasever' variable for yum. + # Instead, this should work correctly on all RHEL variants. + base_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/${ONEDIR_REV}/" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + base_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/\$basearch/" + fi + if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ] || [ "${ONEDIR_REV}" = "nightly" ]; then + if [ "${DISTRO_MAJOR_VERSION}" -eq 9 ]; then + gpg_key="SALTSTACK-GPG-KEY2.pub" + else + gpg_key="SALTSTACK-GPG-KEY.pub" + fi + else + gpg_key="SALT-PROJECT-GPG-PUBKEY-2023.pub" + fi + + gpg_key_urls="" + for key in $gpg_key; do + gpg_key_urls=$(printf "${base_url}${key},%s" "$gpg_key_urls") + done + + repo_file="/etc/yum.repos.d/salt.repo" + + if [ ! -s "$repo_file" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + cat <<_eof > "$repo_file" +[saltstack] +name=SaltStack ${repo_rev} Release Channel for RHEL/CentOS \$releasever +baseurl=${base_url} +skip_if_unavailable=True +gpgcheck=1 +gpgkey=${gpg_key_urls} +enabled=1 +enabled_metadata=1 +_eof + + fetch_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}/" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + fetch_url="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/redhat/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + fi + for key in $gpg_key; do + __rpm_import_gpg "${fetch_url}${key}" || return 1 + done + yum clean metadata || return 1 elif [ "$repo_rev" != "latest" ]; then echowarn "salt.repo already exists, ignoring salt version argument." @@ -4158,7 +4773,6 @@ install_centos_stable_deps() { fi if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then - __install_epel_repository || return 1 __install_saltstack_rhel_repository || return 1 fi @@ -4179,27 +4793,29 @@ install_centos_stable_deps() { if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then # YAML module is used for generating custom master/minion configs if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python3-pyyaml" + __PACKAGES="${__PACKAGES} python3-pyyaml python3-setuptools" else __PACKAGES="${__PACKAGES} python2-pyyaml" fi elif [ "$DISTRO_MAJOR_VERSION" -eq 7 ]; then # YAML module is used for generating custom master/minion configs if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python36-PyYAML" + __PACKAGES="${__PACKAGES} python36-PyYAML python36-setuptools" else __PACKAGES="${__PACKAGES} PyYAML" fi else # YAML module is used for generating custom master/minion configs if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then - __PACKAGES="${__PACKAGES} python34-PyYAML" + __PACKAGES="${__PACKAGES} python34-PyYAML python34-setuptools" else __PACKAGES="${__PACKAGES} PyYAML" fi fi fi + __PACKAGES="${__PACKAGES} procps" + # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 @@ -4216,40 +4832,29 @@ install_centos_stable_deps() { install_centos_stable() { __PACKAGES="" - local cloud='salt-cloud' - local master='salt-master' - local minion='salt-minion' - local syndic='salt-syndic' - - if echo "$STABLE_REV" | grep -q "archive";then # point release being applied - local ver=$(echo "$STABLE_REV"|awk -F/ '{print $2}') # strip archive/ - elif echo "$STABLE_REV" | egrep -vq "archive|latest";then # latest or major version(3003, 3004, etc) being applie - local ver=$STABLE_REV - fi - - if [ ! -z $ver ]; then - cloud+="-$ver" - master+="-$ver" - minion+="-$ver" - syndic+="-$ver" - fi - if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $cloud" + __PACKAGES="${__PACKAGES} salt-cloud" fi if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $master" + __PACKAGES="${__PACKAGES} salt-master" fi if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then - __PACKAGES="${__PACKAGES} $minion" + __PACKAGES="${__PACKAGES} salt-minion" fi if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then - __PACKAGES="${__PACKAGES} $syndic" + __PACKAGES="${__PACKAGES} salt-syndic" fi # shellcheck disable=SC2086 __yum_install_noinput ${__PACKAGES} || return 1 + # Workaround for 3.11 broken on CentOS Stream 8.x + # Re-install Python 3.6 + _py_version=$(${_PY_EXE} -c "import sys; print('{0}.{1}'.format(*sys.version_info))") + if [ "$DISTRO_MAJOR_VERSION" -eq 8 ] && [ "${_py_version}" = "3.11" ]; then + __yum_install_noinput python3 + fi + return 0 } @@ -4285,7 +4890,14 @@ install_centos_stable_post() { } install_centos_git_deps() { - install_centos_stable_deps || return 1 + # First try stable deps then fall back to onedir deps if that one fails + # if we're installing on a Red Hat based host that doesn't have the classic + # package repos available. + # Set ONEDIR_REV to STABLE_REV in case we + # end up calling install_centos_onedir_deps + ONEDIR_REV=${STABLE_REV} + install_centos_onedir_deps || \ + return 1 if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then __yum_install_noinput ca-certificates || return 1 @@ -4445,10 +5057,16 @@ install_centos_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_FILE="${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" + else + _SERVICE_FILE="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm/salt-${fname}.service" + fi if [ -f /bin/systemctl ]; then if [ ! -f "/usr/lib/systemd/system/salt-${fname}.service" ] || \ { [ -f "/usr/lib/systemd/system/salt-${fname}.service" ] && [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; }; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm/salt-${fname}.service" /usr/lib/systemd/system + __copyfile "${_SERVICE_FILE}" /usr/lib/systemd/system fi SYSTEMD_RELOAD=$BS_TRUE @@ -4468,6 +5086,117 @@ install_centos_git_post() { return 0 } +install_centos_onedir_deps() { + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + yum -y update || return 1 + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_TRUE" ] && [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + echowarn "Detected -r or -R option while installing Salt packages for Python 3." + echowarn "Python 3 packages for older Salt releases requires the EPEL repository to be installed." + echowarn "Installing the EPEL repository automatically is disabled when using the -r or -R options." + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then + __install_saltstack_rhel_onedir_repository || return 1 + fi + + # If -R was passed, we need to configure custom repo url with rsync-ed packages + # Which is still handled in __install_saltstack_rhel_repository. This call has + # its own check in case -r was passed without -R. + if [ "$_CUSTOM_REPO_URL" != "null" ]; then + __install_saltstack_rhel_onedir_repository || return 1 + fi + + if [ "$DISTRO_MAJOR_VERSION" -ge 8 ]; then + __PACKAGES="dnf-utils chkconfig" + else + __PACKAGES="yum-utils chkconfig" + fi + + __PACKAGES="${__PACKAGES} procps" + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi + + + return 0 +} + +# This function has been modified to allow for specific versions to be installed +# when not using the salt repo +install_centos_onedir() { + __PACKAGES="" + + local cloud='salt-cloud' + local master='salt-master' + local minion='salt-minion' + local syndic='salt-syndic' + local ver="$_ONEDIR_REV" + + if [ ! -z $ver ]; then + cloud+="-$ver" + master+="-$ver" + minion+="-$ver" + syndic+="-$ver" + fi + + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} $cloud" + fi + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} $master" + fi + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} $minion" + fi + if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} $syndic" + fi + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + + return 0 +} + +install_centos_onedir_post() { + SYSTEMD_RELOAD=$BS_FALSE + + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + if [ -f /bin/systemctl ]; then + /bin/systemctl is-enabled salt-${fname}.service > /dev/null 2>&1 || ( + /bin/systemctl preset salt-${fname}.service > /dev/null 2>&1 && + /bin/systemctl enable salt-${fname}.service > /dev/null 2>&1 + ) + + SYSTEMD_RELOAD=$BS_TRUE + elif [ -f "/etc/init.d/salt-${fname}" ]; then + /sbin/chkconfig salt-${fname} on + fi + done + + if [ "$SYSTEMD_RELOAD" -eq $BS_TRUE ]; then + /bin/systemctl daemon-reload + fi + + return 0 +} + install_centos_restart_daemons() { [ $_START_DAEMONS -eq $BS_FALSE ] && return @@ -4567,6 +5296,11 @@ install_red_hat_linux_git_deps() { return 0 } +install_red_hat_linux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + install_red_hat_enterprise_stable_deps() { install_red_hat_linux_stable_deps || return 1 return 0 @@ -4577,6 +5311,11 @@ install_red_hat_enterprise_git_deps() { return 0 } +install_red_hat_enterprise_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 + return 0 +} + install_red_hat_enterprise_linux_stable_deps() { install_red_hat_linux_stable_deps || return 1 return 0 @@ -4587,6 +5326,11 @@ install_red_hat_enterprise_linux_git_deps() { return 0 } +install_red_hat_enterprise_linux_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 + return 0 +} + install_red_hat_enterprise_server_stable_deps() { install_red_hat_linux_stable_deps || return 1 return 0 @@ -4597,6 +5341,11 @@ install_red_hat_enterprise_server_git_deps() { return 0 } +install_red_hat_enterprise_server_onedir_deps() { + install_red_hat_linux_onedir_deps || return 1 + return 0 +} + install_red_hat_enterprise_workstation_stable_deps() { install_red_hat_linux_stable_deps || return 1 return 0 @@ -4607,6 +5356,11 @@ install_red_hat_enterprise_workstation_git_deps() { return 0 } +install_red_hat_enterprise_workstation_onedir_deps() { + install_red_hat_linux_timat_deps || return 1 + return 0 +} + install_red_hat_linux_stable() { install_centos_stable || return 1 return 0 @@ -4617,6 +5371,11 @@ install_red_hat_linux_git() { return 0 } +install_red_hat_linux_onedir() { + install_centos_onedir || return 1 + return 0 +} + install_red_hat_enterprise_stable() { install_red_hat_linux_stable || return 1 return 0 @@ -4627,6 +5386,11 @@ install_red_hat_enterprise_git() { return 0 } +install_red_hat_enterprise_onedir() { + install_red_hat_linux_onedir || return 1 + return 0 +} + install_red_hat_enterprise_linux_stable() { install_red_hat_linux_stable || return 1 return 0 @@ -4637,6 +5401,11 @@ install_red_hat_enterprise_linux_git() { return 0 } +install_red_hat_enterprise_linux_onedir() { + install_red_hat_linux_onedir || return 1 + return 0 +} + install_red_hat_enterprise_server_stable() { install_red_hat_linux_stable || return 1 return 0 @@ -4647,6 +5416,11 @@ install_red_hat_enterprise_server_git() { return 0 } +install_red_hat_enterprise_server_onedir() { + install_red_hat_linux_onedir || return 1 + return 0 +} + install_red_hat_enterprise_workstation_stable() { install_red_hat_linux_stable || return 1 return 0 @@ -4657,6 +5431,11 @@ install_red_hat_enterprise_workstation_git() { return 0 } +install_red_hat_enterprise_workstation_onedir() { + install_red_hat_linux_onedir || return 1 + return 0 +} + install_red_hat_linux_stable_post() { install_centos_stable_post || return 1 return 0 @@ -4801,6 +5580,15 @@ install_red_hat_enterprise_workstation_testing_post() { # Oracle Linux Install Functions # install_oracle_linux_stable_deps() { + # Install Oracle's EPEL. + if [ ${_EPEL_REPOS_INSTALLED} -eq $BS_FALSE ]; then + _EPEL_REPO=oracle-epel-release-el${DISTRO_MAJOR_VERSION} + if ! rpm -q "${_EPEL_REPO}" > /dev/null; then + __yum_install_noinput "${_EPEL_REPO}" + fi + _EPEL_REPOS_INSTALLED=$BS_TRUE + fi + install_centos_stable_deps || return 1 return 0 } @@ -4810,6 +5598,11 @@ install_oracle_linux_git_deps() { return 0 } +install_oracle_linux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + install_oracle_linux_testing_deps() { install_centos_testing_deps || return 1 return 0 @@ -4825,6 +5618,11 @@ install_oracle_linux_git() { return 0 } +install_oracle_linux_onedir() { + install_centos_onedir || return 1 + return 0 +} + install_oracle_linux_testing() { install_centos_testing || return 1 return 0 @@ -4840,6 +5638,11 @@ install_oracle_linux_git_post() { return 0 } +install_oracle_linux_onedir_post() { + install_centos_onedir_post || return 1 + return 0 +} + install_oracle_linux_testing_post() { install_centos_testing_post || return 1 return 0 @@ -4859,6 +5662,162 @@ install_oracle_linux_check_services() { # ####################################################################################################################### +####################################################################################################################### +# +# AlmaLinux Install Functions +# +install_almalinux_stable_deps() { + install_centos_stable_deps || return 1 + return 0 +} + +install_almalinux_git_deps() { + install_centos_git_deps || return 1 + return 0 +} + +install_almalinux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + +install_almalinux_testing_deps() { + install_centos_testing_deps || return 1 + return 0 +} + +install_almalinux_stable() { + install_centos_stable || return 1 + return 0 +} + +install_almalinux_git() { + install_centos_git || return 1 + return 0 +} + +install_almalinux_onedir() { + install_centos_onedir || return 1 + return 0 +} + +install_almalinux_testing() { + install_centos_testing || return 1 + return 0 +} + +install_almalinux_stable_post() { + install_centos_stable_post || return 1 + return 0 +} + +install_almalinux_git_post() { + install_centos_git_post || return 1 + return 0 +} + +install_almalinux_onedir_post() { + install_centos_onedir_post || return 1 + return 0 +} + +install_almalinux_testing_post() { + install_centos_testing_post || return 1 + return 0 +} + +install_almalinux_restart_daemons() { + install_centos_restart_daemons || return 1 + return 0 +} + +install_almalinux_check_services() { + install_centos_check_services || return 1 + return 0 +} +# +# Ended AlmaLinux Install Functions +# +####################################################################################################################### + +####################################################################################################################### +# +# Rocky Linux Install Functions +# +install_rocky_linux_stable_deps() { + install_centos_stable_deps || return 1 + return 0 +} + +install_rocky_linux_git_deps() { + install_centos_git_deps || return 1 + return 0 +} + +install_rocky_linux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + +install_rocky_linux_testing_deps() { + install_centos_testing_deps || return 1 + return 0 +} + +install_rocky_linux_stable() { + install_centos_stable || return 1 + return 0 +} + +install_rocky_linux_onedir() { + install_centos_onedir || return 1 + return 0 +} + +install_rocky_linux_git() { + install_centos_git || return 1 + return 0 +} + +install_rocky_linux_testing() { + install_centos_testing || return 1 + return 0 +} + +install_rocky_linux_stable_post() { + install_centos_stable_post || return 1 + return 0 +} + +install_rocky_linux_git_post() { + install_centos_git_post || return 1 + return 0 +} + +install_rocky_linux_onedir_post() { + install_centos_onedir_post || return 1 + return 0 +} + +install_rocky_linux_testing_post() { + install_centos_testing_post || return 1 + return 0 +} + +install_rocky_linux_restart_daemons() { + install_centos_restart_daemons || return 1 + return 0 +} + +install_rocky_linux_check_services() { + install_centos_check_services || return 1 + return 0 +} +# +# Ended Rocky Linux Install Functions +# +####################################################################################################################### + ####################################################################################################################### # # Scientific Linux Install Functions @@ -4873,6 +5832,11 @@ install_scientific_linux_git_deps() { return 0 } +install_scientific_linux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + install_scientific_linux_testing_deps() { install_centos_testing_deps || return 1 return 0 @@ -4888,6 +5852,11 @@ install_scientific_linux_git() { return 0 } +install_scientific_linux_onedir() { + install_centos_onedir || return 1 + return 0 +} + install_scientific_linux_testing() { install_centos_testing || return 1 return 0 @@ -4903,6 +5872,11 @@ install_scientific_linux_git_post() { return 0 } +install_scientific_linux_onedir_post() { + install_centos_onedir_post || return 1 + return 0 +} + install_scientific_linux_testing_post() { install_centos_testing_post || return 1 return 0 @@ -4936,6 +5910,11 @@ install_cloud_linux_git_deps() { return 0 } +install_cloud_linux_onedir_deps() { + install_centos_onedir_deps || return 1 + return 0 +} + install_cloud_linux_testing_deps() { install_centos_testing_deps || return 1 return 0 @@ -5029,8 +6008,8 @@ install_alpine_linux_git_deps() { fi fi else - apk -U add python2 py2-pip py2-setuptools || return 1 - _PY_EXE=python2 + apk -U add python3 python3-dev py3-pip py3-setuptools g++ linux-headers zeromq-dev openrc || return 1 + _PY_EXE=python3 return 0 fi @@ -5500,6 +6479,100 @@ _eof fi } +install_amazon_linux_ami_2_onedir_deps() { + # Shim to figure out if we're using old (rhel) or new (aws) rpms. + _USEAWS=$BS_FALSE + pkg_append="python" + + if [ "$ITYPE" = "onedir" ]; then + repo_rev="$ONEDIR_REV" + else + repo_rev="latest" + fi + + if echo $repo_rev | grep -E -q '^archive'; then + year=$(echo "$repo_rev" | cut -d '/' -f 2 | cut -c1-4) + else + year=$(echo "$repo_rev" | cut -c1-4) + fi + + # We need to install yum-utils before doing anything else when installing on + # Amazon Linux ECS-optimized images. See issue #974. + __yum_install_noinput yum-utils + + # Do upgrade early + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + yum -y update || return 1 + fi + + if [ $_DISABLE_REPOS -eq $BS_FALSE ] || [ "$_CUSTOM_REPO_URL" != "null" ]; then + __REPO_FILENAME="salt.repo" + __PY_VERSION_REPO="yum" + PY_PKG_VER="" + repo_label="saltstack-repo" + repo_name="SaltStack repo for Amazon Linux 2" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __REPO_FILENAME="salt.repo" + __PY_VERSION_REPO="py3" + PY_PKG_VER=3 + repo_label="saltstack-py3-repo" + repo_name="SaltStack Python 3 repo for Amazon Linux 2" + fi + + base_url="$HTTP_VAL://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/amazon/2/\$basearch/$repo_rev/" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + base_url="$HTTP_VAL://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/amazon/2/\$basearch/" + fi + + if [ "$(echo "${ONEDIR_REV}" | grep -E '(3004|3005)')" != "" ] || [ "${ONEDIR_REV}" = "nightly" ]; then + gpg_key="${base_url}SALTSTACK-GPG-KEY.pub,${base_url}base/RPM-GPG-KEY-CentOS-7" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + gpg_key="${base_url}SALTSTACK-GPG-KEY.pub" + fi + else + gpg_key="${base_url}SALT-PROJECT-GPG-PUBKEY-2023.pub" + fi + + # This should prob be refactored to use __install_saltstack_rhel_repository() + # With args passed in to do the right thing. Reformatted to be more like the + # amazon linux yum file. + if [ ! -s "/etc/yum.repos.d/${__REPO_FILENAME}" ]; then + cat <<_eof > "/etc/yum.repos.d/${__REPO_FILENAME}" +[$repo_label] +name=$repo_name +failovermethod=priority +priority=10 +gpgcheck=1 +gpgkey=$gpg_key +baseurl=$base_url +_eof + fi + + fi + + if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then + # Package python-ordereddict-1.1-2.el6.noarch is obsoleted by python26-2.6.9-2.88.amzn1.x86_64 + # which is already installed + if [ -n "${PY_PKG_VER}" ] && [ "${PY_PKG_VER}" -eq 3 ]; then + __PACKAGES="${pkg_append}${PY_PKG_VER}-m2crypto ${pkg_append}${PY_PKG_VER}-pyyaml" + else + __PACKAGES="m2crypto PyYAML ${pkg_append}-futures" + fi + + __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-crypto ${pkg_append}${PY_PKG_VER}-jinja2 procps-ng" + __PACKAGES="${__PACKAGES} ${pkg_append}${PY_PKG_VER}-msgpack ${pkg_append}${PY_PKG_VER}-requests ${pkg_append}${PY_PKG_VER}-zmq" + + # shellcheck disable=SC2086 + __yum_install_noinput ${__PACKAGES} || return 1 + fi + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __yum_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi +} + install_amazon_linux_ami_stable() { install_centos_stable || return 1 return 0 @@ -5575,6 +6648,16 @@ install_amazon_linux_ami_2_check_services() { return 0 } +install_amazon_linux_ami_2_onedir() { + install_centos_stable || return 1 + return 0 +} + +install_amazon_linux_ami_2_onedir_post() { + install_centos_stable_post || return 1 + return 0 +} + # # Ended Amazon Linux AMI Install Functions # @@ -5666,6 +6749,10 @@ install_arch_linux_git_deps() { return 0 } +install_arch_linux_onedir_deps() { + install_arch_linux_stable_deps || return 1 +} + install_arch_linux_stable() { # Pacman does not resolve dependencies on outdated versions # They always need to be updated @@ -5684,6 +6771,8 @@ install_arch_linux_stable() { install_arch_linux_git() { + _POST_NEON_PIP_INSTALL_ARGS="${_POST_NEON_PIP_INSTALL_ARGS} --use-pep517" + _PIP_DOWNLOAD_ARGS="${_PIP_DOWNLOAD_ARGS} --use-pep517" if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then __install_salt_from_repo_post_neon "${_PY_EXE}" || return 1 return 0 @@ -5741,8 +6830,15 @@ install_arch_linux_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm" + fi + if [ -f /usr/bin/systemctl ]; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -5809,11 +6905,344 @@ install_arch_check_services() { return 0 } + +install_arch_linux_onedir() { + install_arch_linux_stable || return 1 + + return 0 +} + +install_arch_linux_onedir_post() { + install_arch_linux_post || return 1 + + return 0 +} # # Ended Arch Install Functions # ####################################################################################################################### +####################################################################################################################### +# +# Photon OS Install Functions +# + +__install_saltstack_photon_onedir_repository() { + if [ "$ITYPE" = "stable" ]; then + REPO_REV="$ONEDIR_REV" + else + REPO_REV="latest" + fi + + __PY_VERSION_REPO="yum" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + REPO_FILE="/etc/yum.repos.d/salt.repo" + + if [ ! -s "$REPO_FILE" ] || [ "$_FORCE_OVERWRITE" -eq $BS_TRUE ]; then + FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/photon/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/${ONEDIR_REV}" + if [ "${ONEDIR_REV}" = "nightly" ] ; then + FETCH_URL="${HTTP_VAL}://${_REPO_URL}/${_ONEDIR_NIGHTLY_DIR}/${__PY_VERSION_REPO}/photon/${DISTRO_MAJOR_VERSION}/${CPU_ARCH_L}/" + fi + + __fetch_url "${REPO_FILE}" "${FETCH_URL}.repo" + + GPG_KEY="SALT-PROJECT-GPG-PUBKEY-2023.pub" + + __rpm_import_gpg "${FETCH_URL}/${GPG_KEY}" || return 1 + + tdnf makecache || return 1 + elif [ "$REPO_REV" != "latest" ]; then + echowarn "salt.repo already exists, ignoring salt version argument." + echowarn "Use -F (forced overwrite) to install $REPO_REV." + fi + + return 0 +} + +install_photon_deps() { + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + tdnf -y update || return 1 + fi + + __PACKAGES="${__PACKAGES:=}" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -lt 3 ]; then + echoerror "There are no Python 2 stable packages for Fedora, only Py3 packages" + return 1 + fi + + PY_PKG_VER=3 + + __PACKAGES="${__PACKAGES} libyaml procps-ng python${PY_PKG_VER}-crypto python${PY_PKG_VER}-jinja2" + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-msgpack python${PY_PKG_VER}-requests python${PY_PKG_VER}-zmq" + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-pip python${PY_PKG_VER}-m2crypto python${PY_PKG_VER}-pyyaml" + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-systemd" + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + fi + + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} ${_EXTRA_PACKAGES} || return 1 + + return 0 +} + +install_photon_stable_post() { + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) + sleep 1 + systemctl daemon-reload + done +} + +install_photon_git_deps() { + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + # Packages are named python3- + PY_PKG_VER=3 + else + PY_PKG_VER=2 + fi + + __PACKAGES="" + if ! __check_command_exists ps; then + __PACKAGES="${__PACKAGES} procps-ng" + fi + if ! __check_command_exists git; then + __PACKAGES="${__PACKAGES} git" + fi + + if [ -n "${__PACKAGES}" ]; then + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} || return 1 + __PACKAGES="" + fi + + __git_clone_and_checkout || return 1 + + if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then + + if [ "$_INSECURE_DL" -eq $BS_FALSE ] && [ "${_SALT_REPO_URL%%://*}" = "https" ]; then + __PACKAGES="${__PACKAGES} ca-certificates" + fi + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} python${PY_PKG_VER}-libcloud python${PY_PKG_VER}-netaddr" + fi + + install_photon_deps || return 1 + + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + if __check_command_exists python3; then + __python="python3" + fi + elif [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 2 ]; then + if __check_command_exists python2; then + __python="python2" + fi + else + if ! __check_command_exists python; then + echoerror "Unable to find a python binary?!" + return 1 + fi + # Let's hope it's the right one + __python="python" + fi + + grep tornado "${_SALT_GIT_CHECKOUT_DIR}/requirements/base.txt" | while IFS=' + ' read -r dep; do + echodebug "Running '${__python}' -m pip install '${dep}'" + "${__python}" -m pip install "${dep}" || return 1 + done + else + __PACKAGES="python${PY_PKG_VER}-devel python${PY_PKG_VER}-pip python${PY_PKG_VER}-setuptools gcc glibc-devel linux-devel.x86_64" + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} || return 1 + fi + + if [ "${DISTRO_MAJOR_VERSION}" -gt 3 ]; then + # Need newer version of setuptools on Photon + _setuptools_dep="setuptools>=${_MINIMUM_SETUPTOOLS_VERSION}" + echodebug "Running '${_PY_EXE} -m pip --upgrade install ${_setuptools_dep}'" + ${_PY_EXE} -m pip install --upgrade "${_setuptools_dep}" + fi + + # Let's trigger config_salt() + if [ "$_TEMP_CONFIG_DIR" = "null" ]; then + _TEMP_CONFIG_DIR="${_SALT_GIT_CHECKOUT_DIR}/conf/" + CONFIG_SALT_FUNC="config_salt" + fi + + return 0 +} + +install_photon_git() { + if [ "${_PY_EXE}" != "" ]; then + _PYEXE=${_PY_EXE} + echoinfo "Using the following python version: ${_PY_EXE} to install salt" + else + _PYEXE='python2' + fi + + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/salt/syspaths.py" ]; then + ${_PYEXE} setup.py --salt-config-dir="$_SALT_ETC_DIR" --salt-cache-dir="${_SALT_CACHE_DIR}" ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 + else + ${_PYEXE} setup.py ${SETUP_PY_INSTALL_ARGS} install --prefix=/usr || return 1 + fi + return 0 +} + +install_photon_git_post() { + for fname in api master minion syndic; do + # Skip if not meant to be installed + [ $fname = "api" ] && \ + ([ "$_INSTALL_MASTER" -eq $BS_FALSE ] || ! __check_command_exists "salt-${fname}") && continue + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/rpm" + fi + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + + # Salt executables are located under `/usr/local/bin/` on Fedora 36+ + #if [ "${DISTRO_VERSION}" -ge 36 ]; then + # sed -i -e 's:/usr/bin/:/usr/local/bin/:g' /lib/systemd/system/salt-*.service + #fi + + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + systemctl is-enabled salt-$fname.service || (systemctl preset salt-$fname.service && systemctl enable salt-$fname.service) + sleep 1 + systemctl daemon-reload + done +} + +install_photon_restart_daemons() { + [ $_START_DAEMONS -eq $BS_FALSE ] && return + + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + systemctl stop salt-$fname > /dev/null 2>&1 + systemctl start salt-$fname.service && continue + echodebug "Failed to start salt-$fname using systemd" + if [ "$_ECHO_DEBUG" -eq $BS_TRUE ]; then + systemctl status salt-$fname.service + journalctl -xe + fi + done +} + +install_photon_check_services() { + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + __check_services_systemd salt-$fname || return 1 + done + + return 0 +} + +install_photon_onedir_deps() { + + if [ "$_UPGRADE_SYS" -eq $BS_TRUE ]; then + tdnf -y update || return 1 + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_TRUE" ] && [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + echowarn "Detected -r or -R option while installing Salt packages for Python 3." + echowarn "Python 3 packages for older Salt releases requires the EPEL repository to be installed." + echowarn "Installing the EPEL repository automatically is disabled when using the -r or -R options." + fi + + if [ "$_DISABLE_REPOS" -eq "$BS_FALSE" ]; then + __install_saltstack_photon_onedir_repository || return 1 + fi + + # If -R was passed, we need to configure custom repo url with rsync-ed packages + # Which is still handled in __install_saltstack_rhel_repository. This call has + # its own check in case -r was passed without -R. + if [ "$_CUSTOM_REPO_URL" != "null" ]; then + __install_saltstack_photon_onedir_repository || return 1 + fi + + __PACKAGES="procps-ng" + + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} || return 1 + + if [ "${_EXTRA_PACKAGES}" != "" ]; then + echoinfo "Installing the following extra packages as requested: ${_EXTRA_PACKAGES}" + # shellcheck disable=SC2086 + __tdnf_install_noinput ${_EXTRA_PACKAGES} || return 1 + fi + + return 0 + +} + + +install_photon_onedir() { + STABLE_REV=$ONEDIR_REV + + __PACKAGES="" + + if [ "$_INSTALL_CLOUD" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-cloud" + fi + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-master" + fi + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + __PACKAGES="${__PACKAGES} salt-minion" + fi + if [ "$_INSTALL_SYNDIC" -eq $BS_TRUE ];then + __PACKAGES="${__PACKAGES} salt-syndic" + fi + + # shellcheck disable=SC2086 + __tdnf_install_noinput ${__PACKAGES} || return 1 + + return 0 +} + +install_photon_onedir_post() { + STABLE_REV=$ONEDIR_REV + install_photon_stable_post || return 1 + + return 0 +} +# +# Ended Fedora Install Functions +# +####################################################################################################################### + ####################################################################################################################### # # FreeBSD Install Functions @@ -5841,15 +7270,15 @@ install_freebsd_git_deps() { if [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - SALT_DEPENDENCIES=$(/usr/local/sbin/pkg rquery %dn py38-salt) + SALT_DEPENDENCIES=$(/usr/local/sbin/pkg rquery %dn py39-salt) # shellcheck disable=SC2086 /usr/local/sbin/pkg install -y ${SALT_DEPENDENCIES} python || return 1 - /usr/local/sbin/pkg install -y py38-requests || return 1 - /usr/local/sbin/pkg install -y py38-tornado4 || return 1 + /usr/local/sbin/pkg install -y py39-requests || return 1 + /usr/local/sbin/pkg install -y py39-tornado4 || return 1 else - /usr/local/sbin/pkg install -y python py38-pip py38-setuptools libzmq4 libunwind || return 1 + /usr/local/sbin/pkg install -y python py39-pip py39-setuptools libzmq4 libunwind || return 1 fi echodebug "Adapting paths to FreeBSD" @@ -5895,7 +7324,7 @@ install_freebsd_stable() { # installing latest version of salt from FreeBSD CURRENT ports repo # # shellcheck disable=SC2086 - /usr/local/sbin/pkg install -y py38-salt || return 1 + /usr/local/sbin/pkg install -y py39-salt || return 1 return 0 } @@ -5987,6 +7416,15 @@ install_freebsd_restart_daemons() { service salt_$fname start done } + +install_freebsd_onedir() { +# +# call install_freebsd_stable +# + install_freebsd_stable || return 1 + + return 0 +} # # Ended FreeBSD Install Functions # @@ -6021,7 +7459,7 @@ install_openbsd_git_deps() { __git_clone_and_checkout || return 1 if [ "${_POST_NEON_INSTALL}" -eq $BS_TRUE ]; then - pkg_add -I -v py-pip py-setuptools + pkg_add -I -v py3-pip py3-setuptools fi # @@ -6105,6 +7543,14 @@ install_openbsd_restart_daemons() { return 0 } +install_openbsd_onedir() { +# +# Call install_openbsd_stable +# + install_openbsd_stable || return 1 + + return 0 +} # # Ended OpenBSD Install Functions # @@ -6305,6 +7751,14 @@ install_smartos_restart_daemons() { return 0 } +install_smartos_onedir() { +# +# call install_smartos_stable +# + install_smartos_stable || return 1 + + return 0 +} # # Ended SmartOS Install Functions # @@ -6321,19 +7775,16 @@ __set_suse_pkg_repo() { # Set distro repo variable if [ "${DISTRO_MAJOR_VERSION}" -gt 2015 ]; then DISTRO_REPO="openSUSE_Tumbleweed" + elif [ "${DISTRO_MAJOR_VERSION}" -eq 15 ] && [ "${DISTRO_MINOR_VERSION}" -ge 4 ]; then + DISTRO_REPO="${DISTRO_MAJOR_VERSION}.${DISTRO_MINOR_VERSION}" elif [ "${DISTRO_MAJOR_VERSION}" -ge 42 ] || [ "${DISTRO_MAJOR_VERSION}" -eq 15 ]; then DISTRO_REPO="openSUSE_Leap_${DISTRO_MAJOR_VERSION}.${DISTRO_MINOR_VERSION}" else DISTRO_REPO="SLE_${DISTRO_MAJOR_VERSION}_SP${SUSE_PATCHLEVEL}" fi - if [ "$_DOWNSTREAM_PKG_REPO" -eq $BS_TRUE ]; then - suse_pkg_url_base="https://download.opensuse.org/repositories/systemsmanagement:/saltstack" - suse_pkg_url_path="${DISTRO_REPO}/systemsmanagement:saltstack.repo" - else - suse_pkg_url_base="${HTTP_VAL}://repo.saltproject.io/opensuse" - suse_pkg_url_path="${DISTRO_REPO}/systemsmanagement:saltstack:products.repo" - fi + suse_pkg_url_base="https://download.opensuse.org/repositories/systemsmanagement:/saltstack" + suse_pkg_url_path="${DISTRO_REPO}/systemsmanagement:saltstack.repo" SUSE_PKG_URL="$suse_pkg_url_base/$suse_pkg_url_path" } @@ -6353,7 +7804,7 @@ __version_lte() { zypper --non-interactive install --auto-agree-with-licenses python || return 1 fi - if [ "$(python -c 'import sys; V1=tuple([int(i) for i in sys.argv[1].split(".")]); V2=tuple([int(i) for i in sys.argv[2].split(".")]); print V1<=V2' "$1" "$2")" = "True" ]; then + if [ "$(${_PY_EXE} -c 'import sys; V1=tuple([int(i) for i in sys.argv[1].split(".")]); V2=tuple([int(i) for i in sys.argv[2].split(".")]); print(V1<=V2)' "$1" "$2")" = "True" ]; then __ZYPPER_REQUIRES_REPLACE_FILES=${BS_TRUE} else __ZYPPER_REQUIRES_REPLACE_FILES=${BS_FALSE} @@ -6470,7 +7921,7 @@ install_opensuse_git_deps() { fi # Check for Tumbleweed elif [ "${DISTRO_MAJOR_VERSION}" -ge 20210101 ]; then - __PACKAGES="python3-pip" + __PACKAGES="python3-pip gcc-c++ python3-pyzmq-devel" else __PACKAGES="python-pip python-setuptools gcc" fi @@ -6487,6 +7938,10 @@ install_opensuse_git_deps() { return 0 } +install_opensuse_onedir_deps() { + install_opensuse_stable_deps || return 1 +} + install_opensuse_stable() { __PACKAGES="" @@ -6519,6 +7974,10 @@ install_opensuse_git() { return 0 } +install_opensuse_onedir() { + install_opensuse_stable || return 1 +} + install_opensuse_stable_post() { for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -6563,10 +8022,17 @@ install_opensuse_git_post() { use_usr_lib=$BS_TRUE fi - if [ "${use_usr_lib}" -eq $BS_TRUE ]; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" "/usr/lib/systemd/system/salt-${fname}.service" + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" else - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/" + fi + + if [ "${use_usr_lib}" -eq $BS_TRUE ]; then + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/usr/lib/systemd/system/salt-${fname}.service" + else + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" fi continue @@ -6581,6 +8047,10 @@ install_opensuse_git_post() { return 0 } +install_opensuse_onedir_post() { + install_opensuse_stable_post || return 1 +} + install_opensuse_restart_daemons() { [ $_START_DAEMONS -eq $BS_FALSE ] && return @@ -6740,6 +8210,11 @@ install_opensuse_15_git() { return 0 } +install_opensuse_15_onedir_deps() { + __opensuse_prep_install || return 1 + return 0 +} + # # End of openSUSE Leap 15 # @@ -6769,6 +8244,13 @@ install_suse_15_git_deps() { return 0 } +install_suse_15_onedir_deps() { + __opensuse_prep_install || return 1 + install_opensuse_15_onedir_deps || return 1 + + return 0 +} + install_suse_15_stable() { install_opensuse_stable || return 1 return 0 @@ -6779,6 +8261,11 @@ install_suse_15_git() { return 0 } +install_suse_15_onedir() { + install_opensuse_stable || return 1 + return 0 +} + install_suse_15_stable_post() { install_opensuse_stable_post || return 1 return 0 @@ -6789,6 +8276,11 @@ install_suse_15_git_post() { return 0 } +install_suse_15_onedir_post() { + install_opensuse_stable_post || return 1 + return 0 +} + install_suse_15_restart_daemons() { install_opensuse_restart_daemons || return 1 return 0 @@ -6871,6 +8363,11 @@ install_suse_12_git_deps() { return 0 } +install_suse_12_onedir_deps() { + install_suse_12_stable_deps || return 1 + return 0 +} + install_suse_12_stable() { install_opensuse_stable || return 1 return 0 @@ -6881,6 +8378,11 @@ install_suse_12_git() { return 0 } +install_suse_12_onedir() { + install_opensuse_stable || return 1 + return 0 +} + install_suse_12_stable_post() { install_opensuse_stable_post || return 1 return 0 @@ -6891,6 +8393,11 @@ install_suse_12_git_post() { return 0 } +install_suse_12_onedir_post() { + install_opensuse_stable_post || return 1 + return 0 +} + install_suse_12_restart_daemons() { install_opensuse_restart_daemons || return 1 return 0 @@ -6967,6 +8474,11 @@ install_suse_11_git_deps() { return 0 } +install_suse_11_onedir_deps() { + install_suse_11_stable_deps || return 1 + return 0 +} + install_suse_11_stable() { install_opensuse_stable || return 1 return 0 @@ -6977,6 +8489,11 @@ install_suse_11_git() { return 0 } +install_suse_11_onedir() { + install_opensuse_stable || return 1 + return 0 +} + install_suse_11_stable_post() { install_opensuse_stable_post || return 1 return 0 @@ -6987,6 +8504,11 @@ install_suse_11_git_post() { return 0 } +install_suse_11_onedir_post() { + install_opensuse_stable_post || return 1 + return 0 +} + install_suse_11_restart_daemons() { install_opensuse_restart_daemons || return 1 return 0 @@ -7086,11 +8608,6 @@ __gentoo_pre_dep() { mkdir /etc/portage fi - # Enable Python 3.6 target for pre Neon Salt release - if echo "${STABLE_REV}" | grep -q "2019" || [ "${ITYPE}" = "git" ] && [ "${_POST_NEON_INSTALL}" -eq $BS_FALSE ]; then - EXTRA_PYTHON_TARGET=python3_6 - fi - # Enable Python 3.7 target for Salt Neon using GIT if [ "${ITYPE}" = "git" ] && [ "${GIT_REV}" = "v3000" ]; then EXTRA_PYTHON_TARGET=python3_7 @@ -7186,6 +8703,9 @@ install_gentoo_git_deps() { __emerge ${GENTOO_GIT_PACKAGES} || return 1 fi + echoinfo "Running emerge -v1 setuptools" + __emerge -v1 setuptools || return 1 + __git_clone_and_checkout || return 1 __gentoo_post_dep || return 1 } @@ -7233,6 +8753,11 @@ install_gentoo_git() { return 0 } +install_gentoo_onedir() { + STABLE_REV=${ONEDIR_REV} + install_gentoo_stable || return 1 +} + install_gentoo_post() { for fname in api master minion syndic; do # Skip salt-api since the service should be opt-in and not necessarily started on boot @@ -7268,8 +8793,15 @@ install_gentoo_git_post() { [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + # Account for new path for services files in later releases + if [ -f "${_SALT_GIT_CHECKOUT_DIR}/pkg/common/salt-${fname}.service" ]; then + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg/common" + else + _SERVICE_DIR="${_SALT_GIT_CHECKOUT_DIR}/pkg" + fi + if __check_command_exists systemctl ; then - __copyfile "${_SALT_GIT_CHECKOUT_DIR}/pkg/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" + __copyfile "${_SERVICE_DIR}/salt-${fname}.service" "/lib/systemd/system/salt-${fname}.service" # Skip salt-api since the service should be opt-in and not necessarily started on boot [ $fname = "api" ] && continue @@ -7315,6 +8847,10 @@ _eof return 0 } +install_gentoo_onedir_post() { + install_gentoo_post || return 1 +} + install_gentoo_restart_daemons() { [ $_START_DAEMONS -eq $BS_FALSE ] && return @@ -7466,7 +9002,46 @@ __macosx_get_packagesite() { fi PKG="salt-${STABLE_REV}-${__PY_VERSION_REPO}-${DARWIN_ARCH}.pkg" - SALTPKGCONFURL="https://repo.saltproject.io/osx/${PKG}" + SALTPKGCONFURL="https://${_REPO_URL}/osx/${PKG}" +} + +__parse_repo_json_python() { + + # Using latest, grab the right + # version from the repo.json + _JSON_VERSION=$(python - <<-EOF +import json, urllib.request +url = "https://repo.saltproject.io/salt/py3/macos/repo.json" +response = urllib.request.urlopen(url) +data = json.loads(response.read()) +version = data["${_ONEDIR_REV}"][list(data["${_ONEDIR_REV}"])[0]]['version'] +print(version) +EOF +) +echo "${_JSON_VERSION}" +} + +__macosx_get_packagesite_onedir() { + DARWIN_ARCH="x86_64" + + __PY_VERSION_REPO="py2" + if [ -n "$_PY_EXE" ] && [ "$_PY_MAJOR_VERSION" -eq 3 ]; then + __PY_VERSION_REPO="py3" + fi + + if [ "$(echo "$_ONEDIR_REV" | grep -E '^(latest)$')" != "" ]; then + _PKG_VERSION=$(__parse_repo_json_python) + elif [ "$(echo "$_ONEDIR_REV" | grep -E '^([3-9][0-9]{3}(\.[0-9]*))')" != "" ]; then + _PKG_VERSION=$_ONEDIR_REV + else + _PKG_VERSION=$(__parse_repo_json_python) + fi + if [ "$(echo "$_ONEDIR_REV" | grep -E '^(3005)')" != "" ]; then + PKG="salt-${_PKG_VERSION}-macos-${DARWIN_ARCH}.pkg" + else + PKG="salt-${_PKG_VERSION}-${__PY_VERSION_REPO}-${DARWIN_ARCH}.pkg" + fi + SALTPKGCONFURL="https://${_REPO_URL}/${_ONEDIR_DIR}/${__PY_VERSION_REPO}/macos/${ONEDIR_REV}/${PKG}" } # Using a separate conf step to head for idempotent install... @@ -7475,11 +9050,21 @@ __configure_macosx_pkg_details() { return 0 } +__configure_macosx_pkg_details_onedir() { + __macosx_get_packagesite_onedir || return 1 + return 0 +} + install_macosx_stable_deps() { __configure_macosx_pkg_details || return 1 return 0 } +install_macosx_onedir_deps() { + __configure_macosx_pkg_details_onedir || return 1 + return 0 +} + install_macosx_git_deps() { install_macosx_stable_deps || return 1 @@ -7526,6 +9111,16 @@ install_macosx_stable() { return 0 } +install_macosx_onedir() { + install_macosx_onedir_deps || return 1 + + __fetch_url "/tmp/${PKG}" "${SALTPKGCONFURL}" || return 1 + + /usr/sbin/installer -pkg "/tmp/${PKG}" -target / || return 1 + + return 0 +} + install_macosx_git() { if [ -n "$_PY_EXE" ]; then @@ -7563,6 +9158,11 @@ install_macosx_stable_post() { return 0 } +install_macosx_onedir_post() { + install_macosx_stable_post || return 1 + return 0 +} + install_macosx_git_post() { install_macosx_stable_post || return 1 return 0 @@ -7571,8 +9171,15 @@ install_macosx_git_post() { install_macosx_restart_daemons() { [ $_START_DAEMONS -eq $BS_FALSE ] && return - /bin/launchctl unload -w /Library/LaunchDaemons/com.saltstack.salt.minion.plist || return 1 - /bin/launchctl load -w /Library/LaunchDaemons/com.saltstack.salt.minion.plist || return 1 + if [ "$_INSTALL_MINION" -eq $BS_TRUE ]; then + /bin/launchctl unload -w /Library/LaunchDaemons/com.saltstack.salt.minion.plist || return 1 + /bin/launchctl load -w /Library/LaunchDaemons/com.saltstack.salt.minion.plist || return 1 + fi + + if [ "$_INSTALL_MASTER" -eq $BS_TRUE ]; then + /bin/launchctl unload -w /Library/LaunchDaemons/com.saltstack.salt.master.plist || return 1 + /bin/launchctl load -w /Library/LaunchDaemons/com.saltstack.salt.master.plist || return 1 + fi return 0 } @@ -7774,6 +9381,43 @@ preseed_master() { # ####################################################################################################################### +####################################################################################################################### +# +# This function checks if all of the installed daemons are running or not. +# +daemons_running_onedir() { + [ "$_START_DAEMONS" -eq $BS_FALSE ] && return 0 + + FAILED_DAEMONS=0 + for fname in api master minion syndic; do + # Skip salt-api since the service should be opt-in and not necessarily started on boot + [ $fname = "api" ] && continue + + # Skip if not meant to be installed + [ $fname = "minion" ] && [ "$_INSTALL_MINION" -eq $BS_FALSE ] && continue + [ $fname = "master" ] && [ "$_INSTALL_MASTER" -eq $BS_FALSE ] && continue + [ $fname = "syndic" ] && [ "$_INSTALL_SYNDIC" -eq $BS_FALSE ] && continue + + if [ -f "/opt/saltstack/salt/run/run" ]; then + salt_path="/opt/saltstack/salt/run/run ${fname}" + else + salt_path="salt-${fname}" + fi + process_running=$(pgrep -f "${salt_path}") + if [ "${process_running}" = "" ]; then + echoerror "${salt_path} was not found running" + FAILED_DAEMONS=$((FAILED_DAEMONS + 1)) + fi + done + + return $FAILED_DAEMONS +} + +# +# Ended daemons running check function +# +####################################################################################################################### + ####################################################################################################################### # # This function checks if all of the installed daemons are running or not. @@ -7874,6 +9518,7 @@ echodebug "PRESEED_MASTER_FUNC=${PRESEED_MASTER_FUNC}" INSTALL_FUNC_NAMES="install_${DISTRO_NAME_L}${PREFIXED_DISTRO_MAJOR_VERSION}_${ITYPE}" INSTALL_FUNC_NAMES="$INSTALL_FUNC_NAMES install_${DISTRO_NAME_L}${PREFIXED_DISTRO_MAJOR_VERSION}${PREFIXED_DISTRO_MINOR_VERSION}_${ITYPE}" INSTALL_FUNC_NAMES="$INSTALL_FUNC_NAMES install_${DISTRO_NAME_L}_${ITYPE}" +echodebug "INSTALL_FUNC_NAMES=${INSTALL_FUNC_NAMES}" INSTALL_FUNC="null" for FUNC_NAME in $(__strip_duplicates "$INSTALL_FUNC_NAMES"); do @@ -7925,6 +9570,7 @@ DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running_${DISTRO DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running_${DISTRO_NAME_L}${PREFIXED_DISTRO_MAJOR_VERSION}${PREFIXED_DISTRO_MINOR_VERSION}" DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running_${DISTRO_NAME_L}_${ITYPE}" DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running_${DISTRO_NAME_L}" +DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running_${ITYPE}" DAEMONS_RUNNING_FUNC_NAMES="$DAEMONS_RUNNING_FUNC_NAMES daemons_running" DAEMONS_RUNNING_FUNC="null" @@ -8114,6 +9760,11 @@ if [ "$DAEMONS_RUNNING_FUNC" != "null" ] && [ ${_START_DAEMONS} -eq $BS_TRUE ]; fi fi +if [ "$_AUTO_ACCEPT_MINION_KEYS" -eq "$BS_TRUE" ]; then + echoinfo "Accepting the Salt Minion Keys" + salt-key -yA +fi + # Done! if [ "$_CONFIG_ONLY" -eq $BS_FALSE ]; then echoinfo "Salt installed!" @@ -8121,6 +9772,13 @@ else echoinfo "Salt configured!" fi +if [ "$_QUICK_START" -eq "$BS_TRUE" ]; then + echoinfo "Congratulations!" + echoinfo "A couple of commands to try:" + echoinfo " salt \* test.ping" + echoinfo " salt \* test.version" +fi + exit 0 # vim: set sts=4 ts=4 et diff --git a/salt/sensoroni/files/analyzers/malwarehashregistry/README.md b/salt/sensoroni/files/analyzers/malwarehashregistry/README.md new file mode 100644 index 000000000..8c50a3124 --- /dev/null +++ b/salt/sensoroni/files/analyzers/malwarehashregistry/README.md @@ -0,0 +1,10 @@ +# Malware Hash Registry + +## Description +Search Team Cymru's Malware Hash Registry for a file hash. + +## Configuration Requirements + +None. + +**NOTE:** If you try to run the Malware Hash Registry analyzer but it results in a "Name or service not known" error, then it may be a DNS issue. Folks using 8.8.4.4 or 8.8.8.8 as their DNS resolver have reported this issue. A potential workaround is to switch to another DNS resolver like 1.1.1.1. diff --git a/salt/setup/highstate_cron.sls b/salt/setup/highstate_cron.sls index 862968d97..f8f76e737 100644 --- a/salt/setup/highstate_cron.sls +++ b/salt/setup/highstate_cron.sls @@ -3,5 +3,5 @@ post_setup_cron: - name: 'PATH=$PATH:/usr/sbin salt-call state.highstate' - identifier: post_setup_cron - user: root - - minute: '*/1' + - minute: '*/5' - identifier: post_setup_cron diff --git a/salt/soc/defaults.map.jinja b/salt/soc/defaults.map.jinja index 2587051c5..83cb5637c 100644 --- a/salt/soc/defaults.map.jinja +++ b/salt/soc/defaults.map.jinja @@ -13,11 +13,13 @@ {% do SOCDEFAULTS.soc.config.server.modules[module].update({'hostUrl': application_url}) %} {% endfor %} -{# add nodes from the logstash:nodes pillar to soc.server.modules.elastic.remoteHostUrls #} +{# add all grid heavy nodes to soc.server.modules.elastic.remoteHostUrls #} {% for node_type, minions in salt['pillar.get']('logstash:nodes', {}).items() %} -{% for m in minions.keys() %} -{% do SOCDEFAULTS.soc.config.server.modules.elastic.remoteHostUrls.append('https://' ~ m ~ ':9200') %} -{% endfor %} +{% if node_type in ['heavynode'] %} +{% for m in minions.keys() %} +{% do SOCDEFAULTS.soc.config.server.modules.elastic.remoteHostUrls.append('https://' ~ m ~ ':9200') %} +{% endfor %} +{% endif %} {% endfor %} {% do SOCDEFAULTS.soc.config.server.modules.elastic.update({'username': GLOBALS.elasticsearch.auth.users.so_elastic_user.user, 'password': GLOBALS.elasticsearch.auth.users.so_elastic_user.pass}) %} diff --git a/salt/soc/files/bin/salt-relay.sh b/salt/soc/files/bin/salt-relay.sh index ac56ec6e3..fea81728d 100755 --- a/salt/soc/files/bin/salt-relay.sh +++ b/salt/soc/files/bin/salt-relay.sh @@ -67,10 +67,10 @@ function manage_minion() { response=$(so-minion "-o=$op" "-m=$minion_id") exit_code=$? if [[ exit_code -eq 0 ]]; then - log "Successful command execution" + log "Successful '$op' command execution on $minion_id" respond "$id" "true" else - log "Unsuccessful command execution: $response ($exit_code)" + log "Unsuccessful '$op' command execution on $minion_id: $response ($exit_code)" respond "$id" "false" fi } diff --git a/salt/soctopus/enabled.sls b/salt/soctopus/enabled.sls index 0474998cb..567562fbb 100644 --- a/salt/soctopus/enabled.sls +++ b/salt/soctopus/enabled.sls @@ -52,6 +52,8 @@ so-soctopus: - {{ XTRAENV }} {% endfor %} {% endif %} + - watch: + - file: /opt/so/conf/soctopus/SOCtopus.conf - require: - file: soctopusconf - file: navigatordefaultlayer diff --git a/salt/suricata/config.sls b/salt/suricata/config.sls index 9da40660e..8d5279349 100644 --- a/salt/suricata/config.sls +++ b/salt/suricata/config.sls @@ -129,7 +129,7 @@ surithresholding: # BPF compilation and configuration {% if SURICATABPF %} - {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %} + {% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + SURICATABPF|join(" "),cwd='/root') %} {% if BPF_CALC['stderr'] == "" %} {% set BPF_STATUS = 1 %} {% else %} diff --git a/salt/suricata/defaults.yaml b/salt/suricata/defaults.yaml index 050efa8f8..e9e39d40a 100644 --- a/salt/suricata/defaults.yaml +++ b/salt/suricata/defaults.yaml @@ -280,7 +280,7 @@ suricata: mqtt: enabled: 'no' http2: - enabled: 'no' + enabled: 'yes' asn1-max-frames: 256 run-as: user: suricata diff --git a/salt/zeek/config.sls b/salt/zeek/config.sls index 703da8d85..7fdbd8560 100644 --- a/salt/zeek/config.sls +++ b/salt/zeek/config.sls @@ -152,7 +152,7 @@ plcronscript: # BPF compilation and configuration {% if ZEEKBPF %} - {% set BPF_CALC = salt['cmd.script']('/usr/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %} + {% set BPF_CALC = salt['cmd.script']('salt://common/tools/sbin/so-bpf-compile', GLOBALS.sensor.interface + ' ' + ZEEKBPF|join(" "),cwd='/root') %} {% if BPF_CALC['stderr'] == "" %} {% set BPF_STATUS = 1 %} {% else %} diff --git a/salt/zeek/defaults.yaml b/salt/zeek/defaults.yaml index 4435670a2..2621c2738 100644 --- a/salt/zeek/defaults.yaml +++ b/salt/zeek/defaults.yaml @@ -49,12 +49,13 @@ zeek: - frameworks/files/hash-all-files - frameworks/files/detect-MHR - policy/frameworks/notice/extend-email/hostnames + - policy/frameworks/notice/community-id + - policy/protocols/conn/community-id-logging - ja3 - hassh - intel - cve-2020-0601 - securityonion/bpfconf - - securityonion/communityid - securityonion/file-extraction - oui-logging - icsnpp-modbus @@ -75,7 +76,7 @@ zeek: - LogAscii::use_json = T; - CaptureLoss::watch_interval = 5 mins; networks: - HOME_NET: + HOME_NET: - 192.168.0.0/16 - 10.0.0.0/8 - 172.16.0.0/12 @@ -120,4 +121,4 @@ zeek: - stats - stderr - stdout - + diff --git a/setup/so-functions b/setup/so-functions index 42a4b4ac6..b64daaa92 100755 --- a/setup/so-functions +++ b/setup/so-functions @@ -1258,7 +1258,7 @@ generate_ssl() { # if the install type is a manager then we need to wait for the minion to be ready before trying # to run the ssl state since we need the minion to sign the certs if [[ "$install_type" =~ ^(EVAL|MANAGER|MANAGERSEARCH|STANDALONE|IMPORT|HELIXSENSOR)$ ]]; then - wait_for_salt_minion + wait_for_salt_minion "$MINION_ID" "5" "$setup_log" || fail_setup fi info "Applying SSL state" logCmd "salt-call state.apply ssl -l info" @@ -1972,6 +1972,7 @@ securityonion_repo() { } repo_sync_local() { + SALTVERSION=$(egrep 'version: [0-9]{4}' ../salt/salt/master.defaults.yaml | sed 's/^.*version: //') info "Repo Sync" if [[ $is_supported ]]; then # Sync the repo from the the SO repo locally. @@ -2021,7 +2022,7 @@ repo_sync_local() { curl -fsSL https://repo.securityonion.net/file/so-repo/prod/2.4/so/so.repo | tee /etc/yum.repos.d/so.repo rpm --import https://repo.saltproject.io/salt/py3/redhat/9/x86_64/SALT-PROJECT-GPG-PUBKEY-2023.pub dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - curl -fsSL https://repo.saltproject.io/salt/py3/redhat/9/x86_64/minor/3006.1.repo | tee /etc/yum.repos.d/salt.repo + curl -fsSL "https://repo.saltproject.io/salt/py3/redhat/9/x86_64/minor/$SALTVERSION.repo" | tee /etc/yum.repos.d/salt.repo dnf repolist curl --retry 5 --retry-delay 60 -A "netinstall/$SOVERSION/$OS/$(uname -r)/1" https://sigs.securityonion.net/checkup --output /tmp/install else @@ -2111,11 +2112,6 @@ saltify() { } -# Run a salt command to generate the minion key -salt_firstcheckin() { - salt-call state.show_top >> /dev/null 2>&1 # send output to /dev/null because we don't actually care about the ouput -} - salt_install_module_deps() { logCmd "salt-pip install docker --no-index --only-binary=:all: --find-links files/salt_module_deps/docker/" logCmd "salt-pip install pymysql --no-index --only-binary=:all: --find-links files/salt_module_deps/pymysql/" @@ -2500,6 +2496,16 @@ wait_for_file() { wait_for_salt_minion() { retry 60 5 "journalctl -u salt-minion.service | grep 'Minion is ready to receive requests'" >> "$setup_log" 2>&1 || fail_setup + local attempt=0 + # each attempts would take about 15 seconds + local maxAttempts=20 + until check_salt_minion_status; do + attempt=$((attempt+1)) + if [[ $attempt -eq $maxAttempts ]]; then + fail_setup + fi + sleep 10 + done } verify_setup() { diff --git a/setup/so-setup b/setup/so-setup index e35dde579..543ac0156 100755 --- a/setup/so-setup +++ b/setup/so-setup @@ -91,7 +91,7 @@ fi # if packages are updated and the box isn't rebooted if [[ $is_debian ]]; then update_packages - if [[ -f "/var/run/reboot-required" ]]; then + if [[ -f "/var/run/reboot-required" ]] && [ -z "$test_profile" ]; then whiptail_debian_reboot_required reboot fi @@ -714,6 +714,17 @@ if ! [[ -f $install_opt_file ]]; then logCmd "salt-call state.apply common.packages" logCmd "salt-call state.apply common" + # this will apply the salt.minion state first since salt.master includes salt.minion + logCmd "salt-call state.apply salt.master" + # wait here until we get a response from the salt-master since it may have just restarted + # exit setup after 5-6 minutes of trying + check_salt_master_status || fail "Can't access salt master or it is not ready" + # apply the ca state to create the ca and put it in the mine early in the install + # the minion ip will already be in the mine from configure_minion function in so-functions + generate_ca + # this will also call the ssl state since docker requires the intca + # the salt-minion service will need to be up on the manager to sign requests + generate_ssl logCmd "salt-call state.apply docker" firewall_generate_templates set_initial_firewall_policy @@ -721,8 +732,6 @@ if ! [[ -f $install_opt_file ]]; then title "Downloading Elastic Agent Artifacts" download_elastic_agent_artifacts - generate_ca - generate_ssl logCmd "salt-call state.apply -l info firewall" # create these so the registry state can add so-registry to /opt/so/conf/so-status/so-status.conf @@ -768,8 +777,6 @@ if ! [[ -f $install_opt_file ]]; then checkin_at_boot set_initial_firewall_access logCmd "salt-call schedule.enable -linfo --local" - systemctl restart salt-master - systemctl restart salt-minion verify_setup else touch /root/accept_changes diff --git a/sigs/securityonion-2.4.20-20231012.iso.sig b/sigs/securityonion-2.4.20-20231012.iso.sig new file mode 100644 index 000000000..0704f7d1c Binary files /dev/null and b/sigs/securityonion-2.4.20-20231012.iso.sig differ