diff options
-rw-r--r-- | debian-ansible-2.yml | 2 | ||||
-rw-r--r-- | patch.yaml | 55 | ||||
-rw-r--r-- | patch.yml | 309 | ||||
-rw-r--r-- | roles/patch_debian/tasks/main.yaml | 99 | ||||
-rw-r--r-- | roles/patch_redhat/tasks/main.yaml | 91 | ||||
-rw-r--r-- | roles/patch_suse/tasks/main.yaml | 95 |
6 files changed, 341 insertions, 310 deletions
diff --git a/debian-ansible-2.yml b/debian-ansible-2.yml index 0780674..a571c66 100644 --- a/debian-ansible-2.yml +++ b/debian-ansible-2.yml @@ -7,7 +7,7 @@ vars: ans: 11: - release: "focal" + release: "impish" debname: "bullseye" 10: release: "bionic" diff --git a/patch.yaml b/patch.yaml new file mode 100644 index 0000000..e9159f7 --- /dev/null +++ b/patch.yaml @@ -0,0 +1,55 @@ +--- +# You may want to change the default to your favourite host (group) you run this on the most. +- name: Arrange Inventory + hosts: "{{ rthosts | default('CHANGE_ME') }}" + order: inventory + gather_facts: false + # default: all in first step, but that shit requires (int) + serial: 666 + tasks: + - name: Gather necessary facts + ansible.builtin.setup: + filter: "ansible_distribution*" + - name: Group hosts by distribution file variety + ansible.builtin.group_by: + # We choose to lowercase anything here as there should be no collisions but + # SUSE could be "SuSE" or "SUSE" (assumed and unverified, but you never know...) + key: "adfv_{{ ansible_distribution_file_variety | lower | default('none') }}" + tags: + - always +- name: Trigger Debian patching role on Debian hosts + hosts: adfv_debian + order: inventory + gather_facts: false + # default: all in first step, but that shit requires (int) + serial: 666 + tasks: + - name: Debian Patches + ansible.builtin.import_role: + name: "patch_debian" + tags: + - debian +- name: Trigger Red Hat patching role on Red Hat hosts + hosts: adfv_redhat + order: inventory + gather_facts: false + # default: all in first step, but that shit requires (int) + serial: 666 + tasks: + - name: Red Hat Patches + ansible.builtin.import_role: + name: "patch_redhat" + tags: + - redhat +- name: Trigger SUSE patching role on SUSE hosts + hosts: adfv_suse + order: inventory + gather_facts: false + # default: all in first step, but that shit requires (int) + serial: 666 + tasks: + - name: SUSE Patches + ansible.builtin.import_role: + name: "patch_suse" + tags: + - suse diff --git a/patch.yml b/patch.yml deleted file mode 100644 index 7fde63e..0000000 --- a/patch.yml +++ /dev/null @@ -1,309 +0,0 @@ ---- -# You may want to change the default to your favourite host (group) you run this on the most. -- hosts: "{{ runtime_hosts | default('CHANGE_ME') }}" - order: inventory - gather_facts: false - # default: all in first step, but that shit requires (int) - serial: 666 - tasks: - - name: Gather necessary facts - setup: - filter: "ansible_distribution*" - - name: Set up Red Hat and derivatives - debug: - msg: "System is {{ansible_distribution}} {{ansible_distribution_version}}, checking in." - when: ansible_distribution_file_variety == "RedHat" - changed_when: true - notify: "redhat upd" - - name: Set up Debian and derivatives - debug: - msg: "System is {{ansible_distribution}} {{ansible_distribution_version}}, checking in." - when: ansible_distribution_file_variety == "Debian" - changed_when: true - notify: "debian upd" - - name: Set up SUSE and derivatives - debug: - msg: "System is {{ansible_distribution}} {{ansible_distribution_version}}, checking in." - # SuSE was "renamed" to SUSE somewhen around SLES 11 (now SLE :-} ), so we'll check for both. Even though generation 11 - # repositories should be pretty ...deaddish by now. - when: ansible_distribution_file_variety == "SUSE" or ansible_distribution_file_variety == "SuSE" - changed_when: true - notify: "suse upd" - - name: Set up Arch and derivatives - debug: - msg: "System is {{ansible_distribution}} ({{ansible_distribution_file_variety}}), checking in." - when: ansible_distribution_file_variety == "Archlinux" - changed_when: true - notify: "arch upd" - handlers: - - name: Update yum/dnf cache (RHEL) - # We want to see a dedicated failure if the repos cannot be fetched already. - # Cheating here: yum wants a "state" statement to be placed before it takes action, and then - other than stated in the docs - - # we can trigger an action containing update_cache without "name" being mandatory. So we will have no package present with - # updated cache :-) - yum: - state: present - update_cache: "yes" - validate_certs: "yes" - become: true - listen: "redhat upd" - - name: Update repository cache (Debian) - apt: - update_cache: "yes" - become: true - listen: "debian upd" - - name: Update repository cache (Arch) - pacman: - update_cache: "yes" - become: true - listen: "arch upd" - - name: Check for upgrades (RHEL) - # yum check-upgrade would normally throw an RC 100 if updates are available. - # But through ansible: RC0! Weeeee - shell: /usr/bin/yum -q -C check-upgrade 2>/dev/null | wc -l - args: - warn: false - register: yue - changed_when: yue.stdout|int > 1 - become: true - listen: "redhat upd" - notify: - - "redhat updates available" - - "rkhunter" - - name: Check for upgrades (Debian) - shell: - cmd: apt list --upgradable 2>/dev/null | grep -v ^Listing | wc -l - # ZWEI GEKREUZTE HÄMMER UND EIN GROSSES W - register: aue - # apt will throw an error because it doesn't like piping yet. - # for our purposes, however, everything has already been sufficiently implemented. - failed_when: false - changed_when: aue.stdout|int > 0 - notify: - - "debian updates available" - - "rkhunter" - listen: "debian upd" - - name: Check for upgrades (Arch) - # TODO: pikaur - shell: /usr/bin/pacman -Qu - become: true - register: pue - failed_when: pue.rc|int > 1 - changed_when: pue.rc|int == 0 - notify: - - "arch updates available" - - "rkhunter" - listen: "arch upd" - - name: Check for existence of rkhunter - stat: - path: /usr/bin/rkhunter - register: rkhex - ignore_errors: true - no_log: true - # yum always tosses this arbitrary extra line at you, a simple tr -s does not eradicate it, so - well, - # 0 and 1 are fine. As explained above, the RC is worthless when run through ansible. - listen: "rkhunter" - changed_when: - - rkhex.stat is defined - - rkhex.stat.executable is defined - - rkhex.stat.executable == true - notify: "rkhunter execution" - - name: rkhunter pre-check - shell: rkhunter -c --sk --rwo --ns - become: true - no_log: true - listen: "rkhunter execution" - - name: Upgrade all installed packages (RHEL) - yum: - name: '*' - state: latest - validate_certs: "yes" - skip_broken: "yes" - become: true - listen: "redhat updates available" - # Auto-removal is broken and will nuke packages we previously selected through e.g. ansible. - # See ansible issue #60349. Leaving commented out. -- pff - # - name: Auto-removal of orphaned dependencies (RHEL) - # yum: - # autoremove: "yes" - # when: (ansible_distribution_file_variety == "RedHat") or (ansible_distribution == "Red Hat Enterprise Linux") or (ansible_distribution == "CentOS") - - name: Register requirement for reboot (RHEL) - command: needs-restarting -r - ignore_errors: "yes" - register: nr - changed_when: "nr.rc > 0" - failed_when: false - notify: "Reboot if required" - become: true - # we listen to "redhat upd" here in case a previous reboot was not executed. If undesired, change to "redhat updates available". - listen: "redhat upd" - - name: Clean packages cache (Debian) - command: apt clean - become: true - listen: "debian upd" - - name: Upgrade packages (Debian) - apt: - upgrade: dist - become: true - listen: "debian updates available" - - name: Remove dependencies that are no longer required (Debian) - apt: - autoremove: "yes" - purge: "yes" - become: true - # we listen to "debian upd" here in case a previous cleanup was skipped. Change to "debian updates available" if undesired. - listen: "debian upd" -# - name: Check for existence of needrestart (Debian) -# stat: -# path: /usr/sbin/needrestart -# register: nrex -# ignore_errors: "yes" -# no_log: true -# failed_when: false -# changed_when: -# - nrex.stat.exists == true -# - nrex.stat.executable == true -# # we listen to "debian upd" here in case a previous reboot was not executed. If undesired, change to "debian updates available". -# notify: "debian needrestart" -# listen: "debian upd" -# - name: Check for outdated kernel (Debian) -# shell: /usr/sbin/needrestart -pk -# register: kernout -# when: -# - nrex.stat.exists == true -# - nrex.stat.executable == true -# become: true -# changed_when: "kernout.rc|int == 1" -# listen: "debian needrestart" -# notify: "Reboot if required" -# # failed_when necessary to have a change for RC 1 instead of a failure -# failed_when: kernout.rc > 1 - - name: Upgrade packages (Arch) - pacman: - # DO NOT RUN payman -Sy instead of pacman -Syu, i.e. avoid partial upgrades: - update_cache: "yes" - upgrade: "yes" - become: true - listen: "arch updates available" - - name: Check for existence of needrestart (Debian, Arch) - stat: - path: /usr/sbin/needrestart - register: nrex - ignore_errors: "yes" - no_log: true - failed_when: false - changed_when: - - nrex.stat.exists == true - - nrex.stat.executable == true - # we listen to "debian upd" here in case a previous reboot was not executed. If undesired, change to "debian updates available". - notify: - - "debian arch needrestart" - listen: - - "debian upd" - - "arch upd" - - name: Check for outdated kernel (Debian, Arch) - shell: /usr/sbin/needrestart -pk - register: kernout - when: - - nrex.stat.exists == true - - nrex.stat.executable == true - become: true - changed_when: "kernout.rc|int == 1" - listen: "debian arch needrestart" - notify: "Reboot if required" - # failed_when necessary to have a change for RC 1 instead of a failure - failed_when: kernout.rc > 2 - - name: Check for outdated services (Debian, Arch) - shell: /usr/sbin/needrestart -pl - register: svcout - when: - - nrex.stat.exists == true - - nrex.stat.executable == true - become: true - changed_when: "svcout.rc|int == 1" - listen: "debian arch needrestart" - # we'll play it safe here: outdated services? --> reboot. - notify: "Reboot if required" - # failed_when necessary to have a change for RC 1 instead of a failure - failed_when: svcout.rc > 2 - - name: Update zypper cache (SUSE) - # we cannot cheat like we did with yum: we need to update any package to refresh the cache with the zypper module. Hence falling back - # to shell. - shell: | - zypper refs && zypper ref - become: true - listen: "suse upd" - - name: Verify Zypper repository availability - # Now, here's the thing with zypper. If you have a dead repository, you need to face the following facts: - # 1. All output goes to stdout. For zypper lu at least on SLE12/openSUSE42 and earlier, this is: - # - The packages available for update - # - Debug output lik "loading repository data..." and "reading installed packages..." - # (could be silenced with -q, but without RC feedback we need the debug strings again, kek.) - # - WARNING(!!) messages - # ... there is no STDERR. - # 2. There is no return code other than 0 for warnings. - # Great. Interaction with automatisms as if that stuff came directly from Redmond. - # So we need to parse the fucking output string in ansible. Let's start with the "repository not available" warnings. - debug: - msg: "Dead repositories existing and no update present, we consider this a failure." - when: - - zypperlu is search("Repository.*appears to be outdated") - - zypperlu is search("No updates found") - listen: "zypperlu" - failed_when: true - - name: Update all packages (SUSE) - # we could narrow this down via type:patch, but that's about all. So fire away. - zypper: - name: '*' - state: latest - become: true - # TODO: suse not productive yet, so we choose an arbitrary listener here. Change to something meaningful when going to production. - listen: "suse upd" - - name: Register requirement for reboot (SUSE) - # change in paradigm: we will now use "needs-rebooting", suse implemented that somewhere between 12 and 15, instead of "ps -sss" - # shell: zypper ps -sss - # todo: what to do if services require a refork? - # shell: zypper ps -sss - shell: zypper needs-rebooting - args: - warn: false - register: zyppout - changed_when: zyppout.rc == 102 - failed_when: zyppout.rc != 102 and zyppout.rc != 0 - notify: "Reboot if required" - # we listen to "suse upd" here in case a previous reboot was skipped. Change to "suse updates available" if undesired. - listen: "suse upd" - - name: Clean packages cache (RHEL) - # ansible's yum module does not have a dedicated action for this. So shell it is. - # CAUTION: This will only work as long as modern RHEL derivatives (RHEL/CentOS >=8, Fedora >=30) will have yum available as pseudo-alias to dnf. - # Also, despite yum not offering this feature, ansible will warn that there is a yum module and we should consider using it. Turning warnings off. - args: - warn: false - shell: yum clean packages - become: true - # we listen to "redhat upd" here in case a previous cleanup was skipped. Change to "redhat updates available" if undesired. - listen: "redhat upd" - - name: Clean apt cache (Debian) - # ansible's apt module does not have a dedicated action for this yet. So shell it is: - shell: apt clean - become: true - # here, we already listen to "debian updates available" already since we already did a more generic cleanup above (unless narrowed down as well) - listen: "debian updates available" - - name: Clean packages cache (SUSE) - # ansible's zypper module does not have a dedicated action for this yet. So shell it is: - shell: zypper clean - become: true - # we listen to "suse upd" here in case a previous cleanup was skipped. Change to "suse updates available" if undesired. - listen: "suse upd" - - name: rkhunter properties update - command: rkhunter --propupd --rwo --ns - become: true - listen: "rkhunter execution" - - name: Reboot if required - # ignore_errors: yes - reboot: - reboot_timeout: 300 - pre_reboot_delay: 5 - test_command: uptime - reboot_command: "/bin/systemctl reboot" - become: true diff --git a/roles/patch_debian/tasks/main.yaml b/roles/patch_debian/tasks/main.yaml new file mode 100644 index 0000000..9d96a4e --- /dev/null +++ b/roles/patch_debian/tasks/main.yaml @@ -0,0 +1,99 @@ +--- +- name: "Check whether OS is a Debian derivative" + ansible.builtin.assert: + that: + - ansible_distribution_file_variety == 'Debian' + no_log: true +- name: Update repository cache + ansible.builtin.apt: + update_cache: "yes" + become: true +- name: Check for upgrades + ansible.builtin.shell: + cmd: apt list --upgradable 2>/dev/null | grep -v ^Listing | wc -l + # ZWEI GEKREUZTE HÄMMER UND EIN GROSSES W + register: aue + # apt will throw an error because it doesn't like piping yet. + # for our purposes, however, everything has already been sufficiently implemented. + failed_when: false + #changed_when: aue.stdout|int > 0 + changed_when: false +- block: + - name: Check for existence of rkhunter + ansible.builtin.stat: + path: /usr/bin/rkhunter + register: rkhex + ignore_errors: true + no_log: true + changed_when: false + - name: RKhunter pre-check + ansible.builtin.command: rkhunter -c --sk --rwo --ns + become: true + no_log: true + changed_when: false + when: + - rkhex.stat is defined + - rkhex.stat.executable is defined + - rkhex.stat.executable|bool == True + - name: Clean packages cache + ansible.builtin.command: apt clean + changed_when: true + become: true + - name: Upgrade packages (Debian) + ansible.builtin.apt: + upgrade: dist + become: true + - name: Remove dependencies that are no longer required + ansible.builtin.apt: + autoremove: "yes" + purge: "yes" + become: true + name: Update and RKhunter checks + when: aue.stdout|int > 0 +- block: + - name: Check for existence of needrestart + ansible.builtin.stat: + path: /usr/sbin/needrestart + register: nrex + - name: Check for outdated kernel + ansible.builtin.command: /usr/sbin/needrestart -pk + register: kernout + changed_when: false + # failed_when necessary to not fail on RC 1 instead of a true failure + failed_when: kernout.rc > 2 + - name: Check for outdated services + ansible.builtin.command: /usr/sbin/needrestart -pl + register: svcout + changed_when: false + # failed_when necessary to not fail on RC 1 instead of a true failure + failed_when: svcout.rc > 2 + become: true + name: Check reboot requirement + when: + - nrex.stat is defined + - nrex.stat.exists == true + - nrex.stat.executable|bool == True +- name: Clean apt cache + # ansible's apt module does not have a dedicated action for this yet. So shell it is: + ansible.builtin.command: apt clean + changed_when: false + become: true + # here, we already listen to "debian updates available" already since we already did a more generic cleanup above (unless narrowed down as well) +- name: RKhunter properties update + ansible.builtin.command: rkhunter --propupd --rwo --ns + become: true + changed_when: true + when: + - rkhex.stat is defined + - rkhex.stat.executable is defined + - rkhex.stat.executable|bool == True +- name: Reboot if required + # ignore_errors: yes + ansible.builtin.reboot: + reboot_timeout: 300 + pre_reboot_delay: 5 + test_command: uptime + reboot_command: "/bin/systemctl reboot" + become: true + when: ( kernout.rc is defined and kernout.rc|int == 1 ) or ( svcout.rc is defined and svcout.r|int == 1 ) or + ( kernout.rc is not defined and svcout.rc is not defined ) diff --git a/roles/patch_redhat/tasks/main.yaml b/roles/patch_redhat/tasks/main.yaml new file mode 100644 index 0000000..7f200e7 --- /dev/null +++ b/roles/patch_redhat/tasks/main.yaml @@ -0,0 +1,91 @@ +--- +- name: "Check whether OS is a Red Hat derivative" + ansible.builtin.assert: + that: + - ansible_distribution_file_variety == 'RedHat' + no_log: true +- name: Update yum/dnf cache + # We want to see a dedicated failure if the repos cannot be fetched already. + # Cheating here: yum wants a "state" statement to be placed before it takes action, and then - other than stated in the docs - + # we can trigger an action containing update_cache without "name" being mandatory. So we will have no package present with + # updated cache :-) + ansible.builtin.yum: + state: present + update_cache: "yes" + validate_certs: "yes" + become: true +- name: Check for upgrades (RHEL) + # yum check-upgrade would normally throw an RC 100 if updates are available. + # But through ansible: RC0! Weeeee + ansible.builtin.shell: /usr/bin/yum -q -C check-upgrade 2>/dev/null | wc -l + # args: + # warn: false + register: yue + changed_when: false + become: true +- block: + - name: Check for existence of rkhunter + ansible.builtin.stat: + path: /usr/bin/rkhunter + register: rkhex + - name: RKhunter pre-check + ansible.builtin.command: rkhunter -c --sk --rwo --ns + become: true + no_log: true + changed_when: false + when: + - rkhex.stat is defined + - rkhex.stat.executable is defined + - rkhex.stat.executable + - name: Upgrade all installed packages (RHEL) + ansible.builtin.yum: + name: '*' + state: latest + validate_certs: "yes" + skip_broken: "yes" + become: true + # Auto-removal is broken and will nuke packages we previously selected through e.g. ansible. + # See ansible issue #60349. Leaving commented out. -- pff + # - name: Auto-removal of orphaned dependencies (RHEL) + # ansible.builtin.yum: + # autoremove: "yes" + name: Updates and RKhunter checks + # yum always tosses an arbitrary extra line at you, a simple tr -s does not eradicate it, so - well, + # 0 and 1 are fine. As explained above, the RC is worthless when run through ansible. + when: yue.stdout|int > 1 +- block: + - name: Register requirement for reboot (RHEL) + # "yum needs-restarting still works on RHEL 8, and "needs-restarting" is obsolete + # On major releases >= 9 you may want to create an alternative for symlinking yum to dnf + ansible.builtin.command: yum needs-restarting -r + register: nr + changed_when: false + failed_when: false + become: true + name: Check reboot requirement +- name: Clean packages cache (RHEL) + # ansible's yum module does not have a dedicated action for this. So shell it is. + # CAUTION: This will only work as long as modern RHEL derivatives (RHEL/CentOS >=8, Fedora >=30) will have yum available as pseudo-alias to dnf. + # Also, despite ansible's yum not offering this feature, ansible will warn that there is a yum module and we should consider using it. Turning warnings off. + #args: + # warn: false + ansible.builtin.command: yum clean packages + changed_when: true + become: true +- name: RKhunter properties update + ansible.builtin.command: rkhunter --propupd --rwo --ns + become: true + changed_when: true + when: + - rkhex.stat is defined + - rkhex.stat.executable is defined + - rkhex.stat.executable +- name: Reboot if required + # ignore_errors: yes + ansible.builtin.reboot: + reboot_timeout: 300 + pre_reboot_delay: 5 + test_command: uptime + reboot_command: "/bin/systemctl reboot" + become: true + when: ( nr.rc is defined and nr.rc|int > 0 ) or ( nr.rc is not defined ) diff --git a/roles/patch_suse/tasks/main.yaml b/roles/patch_suse/tasks/main.yaml new file mode 100644 index 0000000..db15d75 --- /dev/null +++ b/roles/patch_suse/tasks/main.yaml @@ -0,0 +1,95 @@ +--- +- name: "Check whether OS is a SUSE derivative" + ansible.builtin.assert: + that: + - ansible_distribution_file_variety == 'SUSE' or ansible_distribution_file_variety == 'SuSE' + no_log: true +- name: Check for existence of rkhunter + ansible.builtin.stat: + path: /usr/bin/rkhunter + register: rkhex +- name: Update zypper cache (SUSE) + # we cannot cheat like we did with yum: we need to update any package to refresh the cache with the zypper module. Hence falling back + # to shell. + ansible.builtin.shell: + cmd: 'zypper refs && zypper ref' + changed_when: false + register: zypperref + become: true +- name: Verify Zypper repository availability + # Now, here's the thing with zypper. If you have a dead repository, you need to face the following facts: + # 1. All output goes to stdout. For zypper lu at least on SLE12/openSUSE42 and earlier, this is: + # - The packages available for update + # - Debug output lik "loading repository data..." and "reading installed packages..." + # (could be silenced with -q, but without RC feedback we need the debug strings again, kek.) + # - WARNING(!!) messages + # ... there is no STDERR. + # 2. There is no return code other than 0 for warnings. + # Great. Interaction with automatisms as if that stuff came directly from Redmond. + # So we need to parse the fucking output string in ansible. Let's start with the "repository not available" warnings. + ansible.builtin.debug: + msg: "Dead repositories existing and no update present, we consider this a failure." + when: + - zypperref is search("Repository.*appears to be outdated") + - zypperref is search("No updates found") + failed_when: true +- name: Check for zypper updates + ansible.builtin.command: zypper lu + register: zypperlu + changed_when: false + become: true +- block: + - name: Update all packages (SUSE) + # we could narrow this down via type:patch, but that's about all. So fire away. + community.general.zypper: + name: '*' + state: latest + extra_args: '--no-refresh' + # this is only document as "zypper rm -u", so apparently nothing is existing like + # rpm's cleanup or apt's "autoremove" :( + # clean_deps: true + become: true + name: Update and RKhunter checks + when: + - zypperlu is not search("No updates found.") +- block: + - name: Register requirement for reboot (SUSE) + # change in paradigm: we will now use "needs-rebooting", suse implemented that somewhere between 12 and 15, instead of "ps -sss" + # todo: what to do if services require a refork? + # shell: zypper ps -sss + ansible.builtin.command: zypper needs-rebooting + register: nrout + changed_when: nrout.rc|int == 102 + failed_when: nrout.rc|int != 102 and nrout.rc|int != 0 + notify: "Reboot if required" + # we listen to "suse upd" here in case a previous reboot was skipped. Change to "suse updates available" if undesired. + name: Check reboot requirement +- block: + - name: Clean packages cache + # ansible's zypper module does not have a dedicated action for this yet. So shell it is: + ansible.builtin.command: zypper clean + changed_when: false + - name: Purge old kernels + # ansible's zypper module does not have a dedicated action for this yet. So shell it is: + ansible.builtin.command: zypper purge-kernels + # TODO: Check output for actual kernel-purging and make this a proper statement: + changed_when: false + name: Cleanup + become: true +- name: RKhunter properties update + ansible.builtin.command: rkhunter --propupd --rwo --ns + become: true + changed_when: true + when: + - rkhex.stat is defined + - rkhex.stat.executable is defined + - rkhex.stat.executable|bool == true +- name: Reboot if required + # ignore_errors: yes + ansible.builtin.reboot: + reboot_timeout: 300 + pre_reboot_delay: 5 + test_command: uptime + reboot_command: "/bin/systemctl reboot" + become: true + when: nrout is defined and nrout.rc is defined and nrout.rc|int == 102 |