From 9914e55ec3248b7f367085bab97f2fe99c6d7947 Mon Sep 17 00:00:00 2001 From: m0duspwnens Date: Thu, 7 Nov 2019 09:49:36 -0500 Subject: [PATCH] rework of os patch scheduling, added the abilty to enable/disable and adjust splay - https://github.com/Security-Onion-Solutions/securityonion-saltstack/issues/84 --- pillar/top.sls | 3 - salt/patch/{os.sls => os/init.sls} | 0 salt/patch/os/schedule.sls | 76 ++++++++++ salt/patch/os/schedules/example_schedule.yml | 10 ++ salt/patch/schedule/os.sls | 32 ----- salt/top.sls | 2 +- so-setup-network.sh | 139 ++++++++++++++----- 7 files changed, 188 insertions(+), 74 deletions(-) rename salt/patch/{os.sls => os/init.sls} (100%) create mode 100644 salt/patch/os/schedule.sls create mode 100644 salt/patch/os/schedules/example_schedule.yml delete mode 100644 salt/patch/schedule/os.sls diff --git a/pillar/top.sls b/pillar/top.sls index 13ea5e5a8..031352a11 100644 --- a/pillar/top.sls +++ b/pillar/top.sls @@ -1,7 +1,4 @@ base: - '*': - - patch.os.{{ grains.id }} - 'G@role:so-sensor': - sensors.{{ grains.id }} - static diff --git a/salt/patch/os.sls b/salt/patch/os/init.sls similarity index 100% rename from salt/patch/os.sls rename to salt/patch/os/init.sls diff --git a/salt/patch/os/schedule.sls b/salt/patch/os/schedule.sls new file mode 100644 index 000000000..9ea98ede7 --- /dev/null +++ b/salt/patch/os/schedule.sls @@ -0,0 +1,76 @@ +{% if salt['pillar.get']('patch:os:schedule_name') %} + {% set patch_os_pillar = salt['pillar.get']('patch:os') %} + {% set schedule_name = patch_os_pillar.schedule_name %} + {% set splay = patch_os_pillar.get('splay', 300) %} + + {% if schedule_name != 'manual' and schedule_name != 'auto' %} + {% import_yaml "patch/os/schedules/"~schedule_name~".yml" as os_schedule %} + + {% if patch_os_pillar.enabled %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - when: + {% for days in os_schedule.patch.os.schedule %} + {% for day, times in days.iteritems() %} + {% for time in times %} + - {{day}} {{time}} + {% endfor %} + {% endfor %} + {% endfor %} + - splay: {{splay}} + - return_job: True + + {% else %} + +disable_patch_os_schedule: + schedule.disabled: + - name: patch_os_schedule + + {% endif %} + + + {% elif schedule_name == 'auto' %} + + {% if patch_os_pillar.enabled %} + +patch_os_schedule: + schedule.present: + - function: state.sls + - job_args: + - patch.os + - minutes: 1 + - splay: {{splay}} + - return_job: True + + {% else %} + +disable_patch_os_schedule: + schedule.disabled: + - name: patch_os_schedule + + {% endif %} + + {% elif schedule_name == 'manual' %} + +remove_patch_os_schedule: + schedule.absent: + - name: patch_os_schedule + + {% endif %} + +{% else %} + +no_os_patch_schedule_name_set: + test.fail_without_changes: + - name: "Set a pillar value for patch:os:schedule_name in this minion's .sls file. If an OS patch schedule is not listed as enabled in show_schedule output below, then OS patches will need to be applied manually until this is corrected." + +show_schedule: + module.run: + - name: schedule.is_enabled + - m_name: patch_os_schedule + +{% endif %} diff --git a/salt/patch/os/schedules/example_schedule.yml b/salt/patch/os/schedules/example_schedule.yml new file mode 100644 index 000000000..b2748ab09 --- /dev/null +++ b/salt/patch/os/schedules/example_schedule.yml @@ -0,0 +1,10 @@ +patch: + os: + schedule: + - Tuesday: + - '15:00' + - Thursday: + - '03:00' + - Saturday: + - '01:00' + - '15:00' diff --git a/salt/patch/schedule/os.sls b/salt/patch/schedule/os.sls deleted file mode 100644 index a041afeea..000000000 --- a/salt/patch/schedule/os.sls +++ /dev/null @@ -1,32 +0,0 @@ -{% if salt['pillar.get']('patch:os:schedule') != 'manual' and salt['pillar.get']('patch:os:schedule') != 'auto' %} - -patch_os_schedule: - schedule.present: - - function: state.sls - - job_args: - - patch.os - - when: - {% for days in pillar['patch']['os']['schedule'] %} - {% for day, times in days.iteritems() %} - {% for time in times %} - - {{day}} {{time}} - {% endfor %} - {% endfor %} - {% endfor %} - - splay: - start: 30 - end: 120 - -{% elif salt['pillar.get']('patch:os:schedule') == 'auto' %} - -patch_os_schedule: - schedule.present: - - function: state.sls - - job_args: - - patch.os - - minutes: 20 - - splay: - start: 150 - end: 300 - -{% endif %} diff --git a/salt/top.sls b/salt/top.sls index 08d82285c..f742a66cf 100644 --- a/salt/top.sls +++ b/salt/top.sls @@ -6,7 +6,7 @@ {%- set PLAYBOOK = salt['pillar.get']('master:playbook', '0') -%} base: '*': - - patch.schedule.os + - patch.os.schedule 'G@role:so-sensor': - ca diff --git a/so-setup-network.sh b/so-setup-network.sh index 57280473a..32217a865 100644 --- a/so-setup-network.sh +++ b/so-setup-network.sh @@ -268,14 +268,14 @@ copy_master_config() { } -copy_minion_pillars() { +copy_minion_tmp_files() { if [ $INSTALLTYPE == 'MASTERONLY' ] || [ $INSTALLTYPE == 'EVALMODE' ]; then - echo "rsyncing TMP pillar files to pillar base" >> $SETUPLOG 2>&1 - rsync -a -v $TMP/pillar/ /opt/so/saltstack/pillar/ >> $SETUPLOG 2>&1 + echo "rsyncing all files in $TMP to /opt/so/saltstack" >> $SETUPLOG 2>&1 + rsync -a -v $TMP/ /opt/so/saltstack/ >> $SETUPLOG 2>&1 else - echo "scp TMP pillar files to pillar base on master" >> $SETUPLOG 2>&1 - scp -prv -i /root/.ssh/so.key $TMP/pillar socore@$MSRV:/opt/so/saltstack/pillar >> $SETUPLOG 2>&1 + echo "scp all files in $TMP to master /opt/so/saltstack" >> $SETUPLOG 2>&1 + scp -prv -i /root/.ssh/so.key $TMP socore@$MSRV:/opt/so/saltstack >> $SETUPLOG 2>&1 fi } @@ -626,38 +626,51 @@ node_pillar() { } patch_pillar() { - OSPATCHPILLARDIR="$TMP/pillar/patch/os" - OSPATCHPILLAR="$OSPATCHPILLARDIR/$MINION_ID.sls" - if [ ! -d $OSPATCHPILLARDIR ] ; then - mkdir -p $OSPATCHPILLARDIR + case $INSTALLTYPE in + MASTERONLY | EVALMODE) + PATCHPILLARPATH=/opt/so/saltstack/pillar/masters + ;; + SENSORONLY) + PATCHPILLARPATH=$SENSORPILLARPATH + ;; + STORAGENODE | PARSINGNODE | HOTNODE | WARMNODE) + PATCHPILLARPATH=$NODEPILLARPATH + ;; + esac + + + echo "" >> $PATCHPILLARPATH/$MINION_ID.sls + echo "patch:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " os:" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " schedule_name: $PATCHSCHEDULENAME" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " enabled: True" >> $PATCHPILLARPATH/$MINION_ID.sls + echo " splay: 300" >> $PATCHPILLARPATH/$MINION_ID.sls + + +} + +patch_schedule_os_new() { + OSPATCHSCHEDULEDIR="$TMP/salt/patch/os/schedules" + OSPATCHSCHEDULE="$OSPATCHSCHEDULEDIR/$PATCHSCHEDULENAME.yml" + + if [ ! -d $OSPATCHSCHEDULEDIR ] ; then + mkdir -p $OSPATCHSCHEDULEDIR fi - touch $OSPATCHPILLAR - echo "patch:" > $OSPATCHPILLAR - case $PATCHSCHEDULE in - Scheduled) - echo " os:" >> $OSPATCHPILLAR - echo " schedule:" >> $OSPATCHPILLAR + + echo "patch:" > $OSPATCHSCHEDULE + echo " os:" >> $OSPATCHSCHEDULE + echo " schedule:" >> $OSPATCHSCHEDULE for psd in "${PATCHSCHEDULEDAYS[@]}" do psd=$(echo $psd | sed 's/"//g') - echo " - $psd:" >> $OSPATCHPILLAR + echo " - $psd:" >> $OSPATCHSCHEDULE for psh in "${PATCHSCHEDULEHOURS[@]}" do psh=$(echo $psh | sed 's/"//g') - echo " - '$psh'" >> $OSPATCHPILLAR + echo " - '$psh'" >> $OSPATCHSCHEDULE done done - ;; - Automatic) - echo " os:" >> $OSPATCHPILLAR - echo " schedule: auto" >> $OSPATCHPILLAR - ;; - Manual) - echo " os:" >> $OSPATCHPILLAR - echo " schedule: manual" >> $OSPATCHPILLAR - ;; - esac } @@ -1516,20 +1529,50 @@ whiptail_passwords_dont_match() { } +whiptail_patch_name_new_schedule() { + + unset PATCHSCHEDULENAME + while [[ -z "$PATCHSCHEDULENAME" ]]; do + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "What name do you want to give this OS patch schedule? This schedule needs to be named uniquely. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 75 3>&1 1>&2 2>&3) + done + + +} + whiptail_patch_schedule() { # What kind of patch schedule are we doing? PATCHSCHEDULE=$(whiptail --title "Security Onion Setup" --radiolist \ - "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 75 5 \ + "Choose OS patch schedule. This will NOT update Security Onion related tools such as Zeek, Elasticsearch, Kibana, SaltStack, etc." 25 115 5 \ "Automatic" "Package updates will be installed automatically" ON \ "Manual" "Package updates will need to be installed manually" OFF \ - "Scheduled" "Select a schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) + "Import Schedule" "Enter the name of an existing schedule on the following screen and inherit it" OFF \ + "New Schedule" "Configure and name a new schedule on the following screen" OFF 3>&1 1>&2 2>&3 ) local exitstatus=$? whiptail_check_exitstatus $exitstatus } +whiptail_patch_schedule_import() { + + unset PATCHSCHEDULENAME + # Ask to inherit from master + whiptail --title "Security Onion Setup" --yesno "Do you want to inherit the OS patch schedule from the master?" 8 78 + + local exitstatus=$? + if [ $exitstatus == 0 ]; then + PATCHSCHEDULENAME=default + else + while [[ -z "$PATCHSCHEDULENAME" ]]; do + PATCHSCHEDULENAME=$(whiptail --title "Security Onion Setup" --inputbox \ + "Enter the name of the OS patch schedule you want to inherit. If you leave this as default, it will use the same schedule as the master. Available schedules can be found on the master under /opt/so/salt/patch/os/schedules/.yml" 10 60 default 3>&1 1>&2 2>&3) + done + fi + +} + whiptail_patch_schedule_select_days() { # Select the days to patch PATCHSCHEDULEDAYS=($(whiptail --title "Security Onion Setup" --checklist \ @@ -1721,11 +1764,23 @@ if (whiptail_you_sure); then # How do we want to handle OS patching? manual, auto or scheduled days and hours whiptail_patch_schedule - if [[ $PATCHSCHEDULE == "Scheduled" ]] ; then - whiptail_patch_schedule_select_days - whiptail_patch_schedule_select_hours - fi - patch_pillar + case $PATCHSCHEDULE in + 'New Schedule') + whiptail_patch_schedule_select_days + whiptail_patch_schedule_select_hours + whiptail_patch_name_new_schedule + patch_schedule_os_new + ;; + 'Import Schedule') + whiptail_patch_schedule_import + ;; + Automatic) + PATCHSCHEDULENAME=auto + ;; + Manual) + PATCHSCHEDULENAME=manual + ;; + esac #################### ## Master ## @@ -1821,9 +1876,11 @@ if (whiptail_you_sure); then master_static >> $SETUPLOG 2>&1 echo "** Generating the master pillar **" >> $SETUPLOG master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n30\nAccepting Salt Keys... \nXXX" echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 # Do a checkin to push the key up echo "** Pushing the key up to Master **" >> $SETUPLOG salt_firstcheckin >> $SETUPLOG 2>&1 @@ -1938,6 +1995,8 @@ if (whiptail_you_sure); then network_setup >> $SETUPLOG 2>&1 echo -e "XXX\n4\nGenerating Sensor Pillar... \nXXX" sensor_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n5\nInstalling Salt Components... \nXXX" saltify >> $SETUPLOG 2>&1 echo -e "XXX\n20\nInstalling Docker... \nXXX" @@ -1945,7 +2004,7 @@ if (whiptail_you_sure); then echo -e "XXX\n22\nConfiguring Salt Minion... \nXXX" configure_minion sensor >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n25\nSending Salt Key to Master... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n26\nTelling the Master to Accept Key... \nXXX" @@ -2049,6 +2108,8 @@ if (whiptail_you_sure); then master_static >> $SETUPLOG 2>&1 echo -e "XXX\n7\nCreating the master pillar... \nXXX" master_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n7\nConfiguring minion... \nXXX" configure_minion eval >> $SETUPLOG 2>&1 echo -e "XXX\n7\nSetting the node type to eval... \nXXX" @@ -2058,7 +2119,7 @@ if (whiptail_you_sure); then echo -e "XXX\n8\nCreating firewall policies... \nXXX" set_initial_firewall_policy >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n10\nRegistering agent... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 echo -e "XXX\n11\nAccepting Agent... \nXXX" @@ -2200,8 +2261,10 @@ if (whiptail_you_sure); then configure_minion node >> $SETUPLOG 2>&1 set_node_type >> $SETUPLOG 2>&1 node_pillar >> $SETUPLOG 2>&1 + echo "** Generating the patch pillar **" >> $SETUPLOG + patch_pillar >> $SETUPLOG 2>&1 echo -e "XXX\n24\nCopying Minion Pillars to Master... \nXXX" - copy_minion_pillars >> $SETUPLOG 2>&1 + copy_minion_tmp_files >> $SETUPLOG 2>&1 echo -e "XXX\n35\nSending and Accepting Salt Key... \nXXX" salt_firstcheckin >> $SETUPLOG 2>&1 # Accept the Salt Key