diff --git a/tasks/apt.yml b/tasks/apt.yml index f9f130c0f6f9cf62e8b251e5f3027bd1ba54afec..78a7acdb7e3bf746649c3bef10a8bf17534d196c 100644 --- a/tasks/apt.yml +++ b/tasks/apt.yml @@ -9,139 +9,278 @@ # You should have received a copy of the GNU General Public License along with the Webarchitects Icinga Ansible role. If not, see <https://www.gnu.org/licenses/>. --- # https://icinga.com/docs/icinga2/latest/doc/02-installation/#debianubunturaspbian-repositories -- name: Icinga Debian apt repo enabled +- name: Icinga Debian / Ubuntu apt repo configuration block: - - name: Legacy Icinga apt configuration absent - ansible.builtin.file: - path: "{{ icinga_legacy_apt_path }}" - state: absent - loop: - - /etc/apt/sources.list.d/icinga.list - - /usr/share/keyrings/icinga.gpg - - /usr/local/share/keyrings/icinga-archive-keyring.gpg - loop_control: - loop_var: icinga_legacy_apt_path - - - name: Apt Keyrings directory present - ansible.builtin.file: - path: /etc/apt/keyrings - state: directory - mode: "0755" - owner: root - group: root - - - name: Icinga gpg ascii armored key present - ansible.builtin.get_url: - url: "{{ icinga_gpg_url }}" - checksum: "{{ icinga_gpg_checksum }}" - dest: /root/icinga.asc - mode: "0644" - owner: root - group: root - register: icinga_tmp_asc_file - - - name: Stat Icinga2 gpg ascii armored file - ansible.builtin.stat: - path: /root/icinga.asc - register: icinga_asc_file + - name: Python3 Debian present for deb822 module + ansible.builtin.apt: + pkg: python3-debian + state: present - - name: Check gpg key when it exists + - name: Apt GPG configuration for supported Debian and Ubuntu distros block: - - name: Stat Icinga gpg dearmored file - ansible.builtin.stat: - path: /etc/apt/keyrings/icinga.gpg - register: icinga_gpg_file - - - name: Icinga gpg key dearmored - ansible.builtin.shell: |- - set -e -o pipefail - gpg --dearmor < /root/icinga.asc > /etc/apt/keyrings/icinga.gpg - chmod 644 /etc/apt/keyrings/icinga.gpg - args: - executable: "{{ ansible_local.bash.path }}" - when: ( icinga_tmp_asc_file.changed | bool ) or ( not icinga_gpg_file.stat.exists | bool ) - - - name: Stat Icinga gpg dearmored file + - name: "Icinga GPG package present {{ icinga_archive_keyring_deb_url | ansible.builtin.urlsplit('path') | ansible.builtin.regex_replace('^[/]') }}" + ansible.builtin.apt: + deb: "{{ icinga_archive_keyring_deb_url }}" + state: present + + - name: Stat /usr/share/keyrings/icinga-archive-keyring.gpg ansible.builtin.stat: - path: /etc/apt/keyrings/icinga.gpg - register: icinga_gpg_file - - - name: Debug disto - ansible.builtin.debug: - var: ansible_distribution - verbosity: 2 - - - name: Debug disto version - ansible.builtin.debug: - var: ansible_distribution_version - verbosity: 2 - - - name: Icinga gpg key check command - ansible.builtin.command: > - gpg --with-colons - {% if ansible_local.gpg.version is version('2.2.12', '<') %} - --with-fingerprint --with-subkey-fingerprint - {% else %} - --show-keys - {% endif %} - /etc/apt/keyrings/icinga.gpg - when: ( icinga_gpg_file.stat.exists | bool ) - check_mode: false - changed_when: false - register: icinga_gpg - - - name: Icinga gpg key check first fingerprint on Debian 10 and older - ansible.builtin.assert: - that: - - icinga_fpr in icinga_gpg.stdout - quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" - when: - - ansible_loop.first | bool - - ansible_distribution == "Debian" - - ansible_distribution_version is version('10', '<') - loop: "{{ icinga_gpg_fingerprints }}" - loop_control: - extended: true - loop_var: icinga_fpr + path: /usr/share/keyrings/icinga-archive-keyring.gpg + register: icinga_archive_keyring_pub_key - - name: Icinga gpg key check first fingerprint on Ubuntu 18.04 and older + - name: "The GPG key provided by the Icinga GPG package is required {{ icinga_archive_keyring_deb_url | ansible.builtin.urlsplit('path') | ansible.builtin.regex_replace('^[/]') }}" ansible.builtin.assert: that: - - icinga_fpr in icinga_gpg.stdout - quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" - when: - - ansible_loop.first | bool - - ansible_distribution == "Ubuntu" - - ansible_distribution_version is version('18.04', '<=') - loop: "{{ icinga_gpg_fingerprints }}" + - icinga_archive_keyring_pub_key.stat.exists | bool + quiet: "{% if ansible_check_mode or ansible_verbosity >= 1 %}false{% else %}true{% endif %}" + fail_msg: >- + The GPG key provided by {{ icinga_archive_keyring_deb_url }} is required to configure the Icinga apt repo. + + - name: Configure the Icinga apt repo when the GPG public key is present + block: + + - name: Stat Icinga repository sources file + ansible.builtin.stat: + path: /etc/apt/sources.list.d/icinga.sources + register: icinga_sources_path + + - name: Read and backup Icinga repository sources file + block: + + - name: Slurp /etc/apt/sources.list.d/icinga.sources + ansible.builtin.slurp: + src: /etc/apt/sources.list.d/icinga.sources + register: icinga_sources_contents_b64encoded + + - name: Decode the base64 encoded version of /etc/apt/sources.list.d/icinga.sources + ansible.builtin.set_fact: + icinga_sources_contents: "{{ icinga_sources_contents_b64encoded['content'] | ansible.builtin.b64decode | community.general.jc('ini') }}" + + - name: Print the contents of /etc/apt/sources.list.d/icinga.sources + ansible.builtin.debug: + var: icinga_sources_contents + verbosity: "{% if ansible_check_mode | bool %}0{% else %}1{% endif %}" + + - name: Set a fact for the prior Icinga repository sources file contents + ansible.builtin.set_fact: + icinga_sources_contents_prior: "{{ icinga_sources_contents }}" + when: icinga_sources_contents is defined + + - name: Check Icinga repository sources file present + ansible.builtin.deb822_repository: + allow_downgrade_to_insecure: false + allow_insecure: false + allow_weak: false + architectures: "{{ ansible_facts.ansible_local.dpkg.arch }}" + check_date: true + check_valid_until: true + components: main + enabled: true + name: icinga + pdiffs: true + signed_by: /usr/share/keyrings/icinga-archive-keyring.gpg + suites: "icinga-{{ ansible_facts.distribution_release }}" + types: deb + uris: "https://packages.icinga.com/{{ ansible_distribution | lower }}" + check_mode: true + changed_when: false + register: icinga_sources_check + + - name: Debug proposed icinga_sources_check.repo + ansible.builtin.debug: + var: icinga_sources_check.repo + verbosity: "{% if ansible_check_mode | bool or ansible_diff_mode | bool %}1{% else %}2{% endif %}" + + - name: Backup old Icinga sources file + ansible.builtin.command: + cmd: >- + mv + /etc/apt/sources.list.d/icinga.sources + /etc/apt/sources.list.d/.icinga.sources.{{ icinga_date_timestamp }}.ansible.save + args: + creates: "/etc/apt/sources.list.d/.icinga.sources.{{ icinga_date_timestamp }}.ansible.save" + removes: /etc/apt/sources.list.d/icinga.sources + vars: + icinga_date_timestamp: "{{ ansible_facts.date_time.iso8601_basic_short }}" + when: icinga_sources_contents_prior != icinga_sources_check.repo | string | community.general.jc('ini') + + when: icinga_sources_path.stat.exists | bool + + - name: Icinga repository sources file present + ansible.builtin.deb822_repository: + allow_downgrade_to_insecure: false + allow_insecure: false + allow_weak: false + architectures: "{{ ansible_facts.ansible_local.dpkg.arch }}" + check_date: true + check_valid_until: true + components: main + enabled: true + name: icinga + pdiffs: true + signed_by: /usr/share/keyrings/icinga-archive-keyring.gpg + suites: "icinga-{{ ansible_facts.distribution_release }}" + types: deb + uris: "https://packages.icinga.com/{{ ansible_distribution | lower }}" + register: icinga_sources + + when: icinga_archive_keyring_pub_key.stat.exists | bool + + - name: Legacy Icinga apt configuration absent + ansible.builtin.file: + path: "{{ icinga_legacy_apt_path }}" + state: absent + loop: + - /etc/apt/keyrings/icinga.gpg + - /etc/apt/sources.list.d/icinga.list + - /usr/local/share/keyrings/icinga-archive-keyring.gpg + - /usr/share/keyrings/icinga.gpg loop_control: - extended: true - loop_var: icinga_fpr + loop_var: icinga_legacy_apt_path - - name: Icinga gpg key check all fingerprints - ansible.builtin.assert: - that: - - icinga_fpr in icinga_gpg.stdout - quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" - when: > - ( ( ansible_distribution == "Debian" ) and ( ansible_distribution_version is version('10', '>=') ) ) or - ( ( ansible_distribution == "Ubuntu" ) and ( ansible_distribution_version is version('18.04', '>') ) ) - loop: "{{ icinga_gpg_fingerprints }}" + when: ansible_facts.distribution_release in icinga_distros + + - name: Apt GPG configuration for unsupported Debian and Ubuntu distros + block: + + - name: EOL Distribution Versions + ansible.builtin.fail: + msg: "TODO see Required Actions for Users of EOL Distribution Versions https://icinga.com/blog/2024/08/26/icinga-package-repository-key-rotation-2024/" + + - name: Legacy Icinga apt configuration absent + ansible.builtin.file: + path: "{{ icinga_legacy_apt_path }}" + state: absent + loop: + - /etc/apt/sources.list.d/icinga.list + - /usr/share/keyrings/icinga.gpg + - /usr/local/share/keyrings/icinga-archive-keyring.gpg loop_control: - loop_var: icinga_fpr + loop_var: icinga_legacy_apt_path - when: icinga_asc_file.stat.exists | bool + - name: Apt Keyrings directory present + ansible.builtin.file: + path: /etc/apt/keyrings + state: directory + mode: "0755" + owner: root + group: root - - name: Icinga repo apt sources file present - ansible.builtin.template: - src: icinga.sources.j2 - dest: /etc/apt/sources.list.d/icinga.sources - mode: "0644" - owner: root - group: root - register: icinga_sources + - name: Icinga gpg ascii armored key present + ansible.builtin.get_url: + url: "{{ icinga_gpg_url }}" + checksum: "{{ icinga_gpg_checksum }}" + dest: /root/icinga.asc + mode: "0644" + owner: root + group: root + register: icinga_tmp_asc_file + + - name: Stat Icinga2 gpg ascii armored file + ansible.builtin.stat: + path: /root/icinga.asc + register: icinga_asc_file + + - name: Check gpg key when it exists + block: + + - name: Stat Icinga gpg dearmored file + ansible.builtin.stat: + path: /etc/apt/keyrings/icinga.gpg + register: icinga_gpg_file + + - name: Icinga gpg key dearmored + ansible.builtin.shell: |- + set -e -o pipefail + gpg --dearmor < /root/icinga.asc > /etc/apt/keyrings/icinga.gpg + chmod 644 /etc/apt/keyrings/icinga.gpg + args: + executable: "{{ ansible_local.bash.path }}" + when: ( icinga_tmp_asc_file.changed | bool ) or ( not icinga_gpg_file.stat.exists | bool ) + + - name: Stat Icinga gpg dearmored file + ansible.builtin.stat: + path: /etc/apt/keyrings/icinga.gpg + register: icinga_gpg_file + + - name: Debug disto + ansible.builtin.debug: + var: ansible_distribution + verbosity: 2 + + - name: Debug disto version + ansible.builtin.debug: + var: ansible_distribution_version + verbosity: 2 + + - name: Icinga gpg key check command + ansible.builtin.command: > + gpg --with-colons + {% if ansible_local.gpg.version is version('2.2.12', '<') %} + --with-fingerprint --with-subkey-fingerprint + {% else %} + --show-keys + {% endif %} + /etc/apt/keyrings/icinga.gpg + when: ( icinga_gpg_file.stat.exists | bool ) + check_mode: false + changed_when: false + register: icinga_gpg + + - name: Icinga gpg key check first fingerprint on Debian 10 and older + ansible.builtin.assert: + that: + - icinga_fpr in icinga_gpg.stdout + quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" + when: + - ansible_loop.first | bool + - ansible_distribution == "Debian" + - ansible_distribution_version is version('10', '<') + loop: "{{ icinga_gpg_fingerprints }}" + loop_control: + extended: true + loop_var: icinga_fpr + + - name: Icinga gpg key check first fingerprint on Ubuntu 18.04 and older + ansible.builtin.assert: + that: + - icinga_fpr in icinga_gpg.stdout + quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" + when: + - ansible_loop.first | bool + - ansible_distribution == "Ubuntu" + - ansible_distribution_version is version('18.04', '<=') + loop: "{{ icinga_gpg_fingerprints }}" + loop_control: + extended: true + loop_var: icinga_fpr + + - name: Icinga gpg key check all fingerprints + ansible.builtin.assert: + that: + - icinga_fpr in icinga_gpg.stdout + quiet: "{% if ansible_verbosity == 0 %}true{% else %}false{% endif %}" + when: > + ( ( ansible_distribution == "Debian" ) and ( ansible_distribution_version is version('10', '>=') ) ) or + ( ( ansible_distribution == "Ubuntu" ) and ( ansible_distribution_version is version('18.04', '>') ) ) + loop: "{{ icinga_gpg_fingerprints }}" + loop_control: + loop_var: icinga_fpr + + when: icinga_asc_file.stat.exists | bool + + - name: Icinga repo apt sources file present + ansible.builtin.template: + src: icinga.sources.j2 + dest: /etc/apt/sources.list.d/icinga.sources + mode: "0644" + owner: root + group: root + register: icinga_sources + + when: ansible_facts.distribution_release not in icinga_distros - name: Icinga apt prefs file present ansible.builtin.template: diff --git a/tasks/install.yml b/tasks/install.yml index 287189aa6e33ef69715765e508725d9e6bcb7143..e9534acceab8cc9bd9550fa8e07d811def5e28ed 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -45,7 +45,7 @@ pkg: - monitoring-plugins-systemd state: present - when: ansible_distribution_release is regex('^bookworm|trixie|jessie$') + when: ansible_distribution_release is regex('^bookworm|jessie|noble|trixie$') - name: Check if /usr/lib/nagios/plugins/check_systemd exists ansible.builtin.stat: @@ -78,6 +78,7 @@ - name: Icinga package present from packages.icinga.com ansible.builtin.apt: pkg: + - icinga-archive-keyring - icinga2 - icinga2-bin - icinga2-common diff --git a/vars/main.yml b/vars/main.yml index 73296f67f31ec1e6e7f9c040946ba4bbe72f434b..c8ae682513c54348f028236f90cd2a8b98476a52 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -12,6 +12,18 @@ icingavarnames: "{{ q('varnames', '^icinga_') | sort }}" icingahostvars: "{{ dict(icingavarnames | list | zip(q('vars', *icingavarnames))) }}" +# Icinga distros +# https://icinga.com/subscriptions/support-matrix/ +icinga_distros: + - bookworm + - bullseye + - focal + - jammy + - noble +# https://packages.icinga.com/debian/README.html +# https://packages.icinga.com/ubuntu/README.html +icinga_archive_keyring_deb_url: "https://packages.icinga.com/icinga-archive-keyring_latest+{{ ansible_facts.distribution | lower }}{{ ansible_facts.distribution_major_version }}.deb" + # JMESPath query to check existing IPv4 rule icinga_iptables_ipv4_query: "[?chain == 'INPUT'].rules | [0] | [?source == '{{ icinga_master_node }}'] | [0] | options"