From c64f59929e0767b202fa95f0a0a24357de1a2046 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Sun, 7 Jun 2026 10:32:42 -0500 Subject: [PATCH] resolvers: NXDOMAIN blocklist via RPZ; fix Ansible deprecations Add an RPZ blocklist on the Unbound resolvers that returns NXDOMAIN for a set of domains (and subdomains) and logs only those matches under rpz-log tag "blocklist". Domains are templated from resolver_blocked_domains (single source of truth) into /etc/unbound/blocklist.rpz; respip module enabled for RPZ support. Fix deprecation warnings across the Ansible tree: - apt_repository -> deb822_repository (monitor, aprsc, uisp, grafana), removing stale .list files and adding update_cache where deb822 drops it - community.mysql.* -> ansible.mysql.* (monitor) and requirements.yml - top-level facts -> ansible_facts[...] (ansible_os_family, distribution_release, fqdn, architecture, default_ipv4) repo-wide --- ansible/group_vars/all/all.yml | 4 +- ansible/group_vars/resolvers/main.yml | 9 +++ ansible/regenerate-ssh-keys.yml | 8 +-- ansible/requirements.yml | 4 +- ansible/roles/aprsc/defaults/main.yml | 3 - ansible/roles/aprsc/tasks/main.yml | 14 ++++- ansible/roles/base/tasks/system.yml | 6 +- ansible/roles/base/templates/ntp.conf.j2 | 2 +- ansible/roles/caddy/tasks/main.yml | 22 ++++---- ansible/roles/dokku/tasks/main.yml | 4 +- ansible/roles/firewall/tasks/main.yml | 36 ++++++------ ansible/roles/general/tasks/main.yml | 14 ++--- .../general/templates/etc/apt/sources.list.j2 | 12 ++-- ansible/roles/general/templates/etc/hosts.j2 | 2 +- ansible/roles/grafana/tasks/main.yml | 17 ++++-- ansible/roles/loki/tasks/main.yml | 2 +- ansible/roles/monitor/defaults/main.yml | 2 - ansible/roles/monitor/tasks/main.yml | 56 ++++++++++++------- ansible/roles/ns/handlers/main.yml | 2 +- ansible/roles/ns/tasks/bind9.yml | 4 +- ansible/roles/resolvers/tasks/main.yml | 10 +++- .../resolvers/templates/blocklist.rpz.j2 | 15 +++++ .../roles/resolvers/templates/unbound.conf.j2 | 16 ++++++ ansible/roles/uisp/tasks/main.yml | 16 +++++- 24 files changed, 183 insertions(+), 97 deletions(-) create mode 100644 ansible/roles/resolvers/templates/blocklist.rpz.j2 diff --git a/ansible/group_vars/all/all.yml b/ansible/group_vars/all/all.yml index 14e0d0f..94151a7 100644 --- a/ansible/group_vars/all/all.yml +++ b/ansible/group_vars/all/all.yml @@ -49,10 +49,10 @@ base: server: monitor.vntx.net # SSH service name (varies by distribution) -ssh_service: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" +ssh_service: "{{ 'ssh' if ansible_facts['os_family'] == 'Debian' else 'sshd' }}" # NTP service name (varies by distribution) -ntp_service: "{{ 'ntp' if ansible_os_family == 'Debian' else 'ntpd' }}" +ntp_service: "{{ 'ntp' if ansible_facts['os_family'] == 'Debian' else 'ntpd' }}" # Network configuration - skip for all hosts network: diff --git a/ansible/group_vars/resolvers/main.yml b/ansible/group_vars/resolvers/main.yml index 6b06b3e..1ca6985 100644 --- a/ansible/group_vars/resolvers/main.yml +++ b/ansible/group_vars/resolvers/main.yml @@ -11,6 +11,15 @@ resolver_allowed_netblocks: - ::1 - 2606:1c80::/32 +# Domains returned as NXDOMAIN (blocklist). Covers the name and all subdomains. +# Consumed by unbound.conf.j2 via local-zone ... always_nxdomain. +resolver_blocked_domains: + - proxyjs.brdtnet.com + - proxyjs.luminatinet.com + - proxyjs.bright-sdk.com + - clientsdk.bright-sdk.com + - clientsdk.brdtnet.com + firewall_allow_rules: - port: 53 proto: udp diff --git a/ansible/regenerate-ssh-keys.yml b/ansible/regenerate-ssh-keys.yml index 9985050..2337962 100644 --- a/ansible/regenerate-ssh-keys.yml +++ b/ansible/regenerate-ssh-keys.yml @@ -28,21 +28,21 @@ - name: Regenerate SSH host keys (Debian/Ubuntu) command: dpkg-reconfigure openssh-server - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Regenerate SSH host keys (RHEL/CentOS) shell: | ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" - name: Regenerate SSH host keys (Alpine) shell: | ssh-keygen -t rsa -b 4096 -f /etc/ssh/ssh_host_rsa_key -N '' ssh-keygen -t ecdsa -b 521 -f /etc/ssh/ssh_host_ecdsa_key -N '' ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' - when: ansible_os_family == "Alpine" + when: ansible_facts['os_family'] == "Alpine" - name: Set correct permissions on private keys file: @@ -66,7 +66,7 @@ - name: Restart SSH service service: - name: "{{ 'ssh' if ansible_os_family == 'Debian' else 'sshd' }}" + name: "{{ 'ssh' if ansible_facts['os_family'] == 'Debian' else 'sshd' }}" state: restarted - name: Create marker file to indicate keys were regenerated diff --git a/ansible/requirements.yml b/ansible/requirements.yml index 2e24cd9..7eed1f6 100644 --- a/ansible/requirements.yml +++ b/ansible/requirements.yml @@ -11,8 +11,8 @@ collections: version: ">=3.0.0" # Required for PostgreSQL management - name: community.proxmox version: ">=1.0.0" # Required for Proxmox VM management - - name: community.mysql - version: ">=3.0.0" # Required for Icinga2 MySQL management + - name: ansible.mysql + version: ">=5.0.0" # Required for Icinga2 MySQL management (renamed from community.mysql) - name: netbox.netbox version: ">=3.0.0" # Required for NetBox automation diff --git a/ansible/roles/aprsc/defaults/main.yml b/ansible/roles/aprsc/defaults/main.yml index e894f42..8ae2979 100644 --- a/ansible/roles/aprsc/defaults/main.yml +++ b/ansible/roles/aprsc/defaults/main.yml @@ -30,6 +30,3 @@ aprsc_log_rotate_count: 5 # Resource limits aprsc_file_limit: 10000 - -# APT repository -aprsc_apt_repo: "deb http://aprsc-dist.he.fi/aprsc/apt {{ ansible_distribution_release }} main" diff --git a/ansible/roles/aprsc/tasks/main.yml b/ansible/roles/aprsc/tasks/main.yml index 50eee59..67d99bc 100644 --- a/ansible/roles/aprsc/tasks/main.yml +++ b/ansible/roles/aprsc/tasks/main.yml @@ -1,9 +1,17 @@ --- - name: Add aprsc APT repository - ansible.builtin.apt_repository: - repo: "{{ aprsc_apt_repo }}" + ansible.builtin.deb822_repository: + name: aprsc + types: [deb] + uris: http://aprsc-dist.he.fi/aprsc/apt + suites: "{{ ansible_facts['distribution_release'] }}" + components: [main] state: present - filename: aprsc + +- name: Remove legacy aprsc .list repo (superseded by deb822 .sources) + ansible.builtin.file: + path: /etc/apt/sources.list.d/aprsc.list + state: absent - name: Install aprsc ansible.builtin.apt: diff --git a/ansible/roles/base/tasks/system.yml b/ansible/roles/base/tasks/system.yml index ad72a55..4cfbcf1 100644 --- a/ansible/roles/base/tasks/system.yml +++ b/ansible/roles/base/tasks/system.yml @@ -29,7 +29,7 @@ ansible.builtin.command: args: creates: /etc/ssh/ssh_host_ed25519_key - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" notify: restart ssh - name: Regenerate SSH host keys (RHEL) @@ -39,7 +39,7 @@ ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' args: creates: /etc/ssh/ssh_host_ed25519_key - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" notify: restart ssh - name: Regenerate SSH host keys (Alpine) @@ -49,7 +49,7 @@ ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N '' args: creates: /etc/ssh/ssh_host_ed25519_key - when: ansible_os_family == "Alpine" + when: ansible_facts['os_family'] == "Alpine" notify: restart ssh - name: Create marker file to prevent re-running diff --git a/ansible/roles/base/templates/ntp.conf.j2 b/ansible/roles/base/templates/ntp.conf.j2 index 4c1b483..ba01770 100755 --- a/ansible/roles/base/templates/ntp.conf.j2 +++ b/ansible/roles/base/templates/ntp.conf.j2 @@ -1,4 +1,4 @@ -{% if ansible_fqdn in groups['ntp'] %} +{% if ansible_facts['fqdn'] in groups['ntp'] %} driftfile /var/lib/ntp/ntp.drift statistics loopstats peerstats clockstats diff --git a/ansible/roles/caddy/tasks/main.yml b/ansible/roles/caddy/tasks/main.yml index f3aba62..e9e2eec 100644 --- a/ansible/roles/caddy/tasks/main.yml +++ b/ansible/roles/caddy/tasks/main.yml @@ -5,7 +5,7 @@ register: caddy_installed changed_when: false failed_when: false - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Install required packages (Debian/Ubuntu) ansible.builtin.apt: @@ -17,13 +17,13 @@ - gnupg2 state: present update_cache: true - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Check for conflicting Caddy repositories ansible.builtin.stat: path: /usr/share/keyrings/caddy-stable-archive-keyring.gpg register: old_keyring - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Remove old Caddy repository files if they exist ansible.builtin.file: @@ -34,7 +34,7 @@ - /etc/apt/sources.list.d/caddy.list - /usr/share/keyrings/caddy-stable-archive-keyring.gpg when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - old_keyring.stat.exists | default(false) notify: update apt cache @@ -42,14 +42,14 @@ ansible.builtin.stat: path: /etc/apt/trusted.gpg.d/caddy-stable.asc register: caddy_gpg_key - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Add Caddy GPG key (Debian/Ubuntu) ansible.builtin.get_url: url: "https://dl.cloudsmith.io/public/caddy/stable/gpg.key" dest: /usr/share/keyrings/caddy-stable-archive-keyring.asc mode: '0644' - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Add Caddy repository (Debian/Ubuntu) ansible.builtin.deb822_repository: @@ -60,7 +60,7 @@ components: main signed_by: /usr/share/keyrings/caddy-stable-archive-keyring.asc state: present - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Install Caddy (Debian/Ubuntu) ansible.builtin.apt: @@ -68,7 +68,7 @@ state: present update_cache: true when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - caddy_installed.rc != 0 # --- Install: RedHat/AlmaLinux --- @@ -76,19 +76,19 @@ ansible.builtin.dnf: name: dnf-plugins-core state: present - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" - name: Enable Caddy COPR repository (RedHat) ansible.builtin.command: cmd: dnf -y copr enable @caddy/caddy creates: /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:group_caddy:caddy.repo - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" - name: Install Caddy (RedHat) ansible.builtin.dnf: name: caddy state: present - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" # --- Common configuration --- - name: Ensure Caddy log directory exists diff --git a/ansible/roles/dokku/tasks/main.yml b/ansible/roles/dokku/tasks/main.yml index 5e16af5..85f39fe 100644 --- a/ansible/roles/dokku/tasks/main.yml +++ b/ansible/roles/dokku/tasks/main.yml @@ -21,9 +21,9 @@ name: docker types: deb uris: https://download.docker.com/linux/debian - suites: "{{ ansible_distribution_release }}" + suites: "{{ ansible_facts['distribution_release'] }}" components: stable - architectures: "{{ ansible_architecture | replace('x86_64', 'amd64') }}" + architectures: "{{ ansible_facts['architecture'] | replace('x86_64', 'amd64') }}" signed_by: /usr/share/keyrings/docker-archive-keyring.asc state: present diff --git a/ansible/roles/firewall/tasks/main.yml b/ansible/roles/firewall/tasks/main.yml index 173a8c1..ae8a37c 100644 --- a/ansible/roles/firewall/tasks/main.yml +++ b/ansible/roles/firewall/tasks/main.yml @@ -9,20 +9,20 @@ name: ufw state: present update_cache: true - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Install firewalld ansible.builtin.dnf: name: firewalld state: present - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" - name: Ensure firewalld is started and enabled ansible.builtin.systemd: name: firewalld state: started enabled: true - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" # --- Firewalld (RedHat/AlmaLinux) --- @@ -34,7 +34,7 @@ immediate: true state: enabled loop: "{{ firewall_trusted_subnets }}" - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" - name: Allow SSH from specific IPs in firewalld ansible.posix.firewalld: @@ -45,7 +45,7 @@ state: enabled loop: "{{ firewall_ssh_allow_from }}" when: - - ansible_os_family == "RedHat" + - ansible_facts['os_family'] == "RedHat" - firewall_ssh_allow_from | length > 0 - name: Allow per-host public services in firewalld @@ -57,7 +57,7 @@ state: enabled loop: "{{ firewall_allow_rules }}" when: - - ansible_os_family == "RedHat" + - ansible_facts['os_family'] == "RedHat" - firewall_allow_rules | length > 0 # --- UFW (Debian/Ubuntu) - Check current state --- @@ -68,7 +68,7 @@ changed_when: false failed_when: false check_mode: false - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" # --- UFW (Debian/Ubuntu) - Disable when firewall not managed --- @@ -76,7 +76,7 @@ community.general.ufw: state: disabled when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - not (firewall_enabled | default(true)) - _fw_ufw_active.stdout is defined - "'Status: active' in _fw_ufw_active.stdout" @@ -88,7 +88,7 @@ direction: incoming policy: "{{ firewall_default_incoming }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - name: Set default outgoing policy to allow @@ -96,7 +96,7 @@ direction: outgoing policy: "{{ firewall_default_outgoing }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - name: Set default routed policy @@ -104,7 +104,7 @@ direction: routed policy: "{{ firewall_default_routed }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - name: "Capture existing ufw rules" @@ -114,7 +114,7 @@ failed_when: false check_mode: false when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - _fw_ufw_active.stdout is defined - "'Status: active' in _fw_ufw_active.stdout" @@ -126,7 +126,7 @@ comment: "{{ item.comment }}" loop: "{{ firewall_trusted_subnets }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - _fw_ufw_rules.skipped | default(true) or item.subnet not in _fw_ufw_rules.stdout @@ -139,7 +139,7 @@ comment: "SSH from {{ item.comment }}" loop: "{{ firewall_ssh_allow_from }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - firewall_ssh_allow_from | length > 0 - _fw_ufw_rules.skipped | default(true) or item.ip not in _fw_ufw_rules.stdout @@ -153,7 +153,7 @@ comment: "{{ item.comment }}" loop: "{{ firewall_allow_rules }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - firewall_allow_rules | length > 0 - _fw_ufw_rules.skipped | default(true) or (item.port | string + '/' + item.proto) not in _fw_ufw_rules.stdout @@ -166,7 +166,7 @@ state: present reload: true when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - firewall_ip_forward @@ -182,7 +182,7 @@ COMMIT loop: "{{ firewall_masquerade_rules }}" when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - firewall_masquerade_rules | length > 0 notify: Reload ufw @@ -191,7 +191,7 @@ community.general.ufw: state: enabled when: - - ansible_os_family == "Debian" + - ansible_facts['os_family'] == "Debian" - firewall_enabled | default(true) - _fw_ufw_active.stdout is defined - "'Status: active' not in _fw_ufw_active.stdout" diff --git a/ansible/roles/general/tasks/main.yml b/ansible/roles/general/tasks/main.yml index be32610..93aa2e5 100644 --- a/ansible/roles/general/tasks/main.yml +++ b/ansible/roles/general/tasks/main.yml @@ -1,44 +1,44 @@ --- - name: Install misc Debian packages ansible.builtin.import_tasks: debian/misc.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - misc - name: Configure MOTD ansible.builtin.import_tasks: debian/motd.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - motd - name: Configure networking ansible.builtin.import_tasks: debian/network.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - network - name: Apply UDP GRO fix for Tailscale ansible.builtin.import_tasks: udp-gro-fix.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - network - tailscale - name: Install K3s packages ansible.builtin.import_tasks: debian/k3s.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - k3s - name: Uninstall Icinga2 on non-monitor hosts ansible.builtin.import_tasks: debian/icinga2.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - icinga2 - monitoring - name: Configure NFS mounts ansible.builtin.import_tasks: debian/nfs.yml - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" tags: - nfs \ No newline at end of file diff --git a/ansible/roles/general/templates/etc/apt/sources.list.j2 b/ansible/roles/general/templates/etc/apt/sources.list.j2 index 9b8b1c6..7976263 100644 --- a/ansible/roles/general/templates/etc/apt/sources.list.j2 +++ b/ansible/roles/general/templates/etc/apt/sources.list.j2 @@ -1,11 +1,11 @@ # Main -deb http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_distribution_release }} main -deb-src http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_distribution_release }} main +deb http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_facts['distribution_release'] }} main +deb-src http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_facts['distribution_release'] }} main # Security -deb http://security.debian.org/debian-security {{ ansible_distribution_release }}-security main -deb-src http://security.debian.org/debian-security {{ ansible_distribution_release }}-security main +deb http://security.debian.org/debian-security {{ ansible_facts['distribution_release'] }}-security main +deb-src http://security.debian.org/debian-security {{ ansible_facts['distribution_release'] }}-security main # Updates -deb http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_distribution_release }}-updates main -deb-src http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_distribution_release }}-updates main +deb http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_facts['distribution_release'] }}-updates main +deb-src http://{{ deb_mirror | default('deb.debian.org') }}/debian/ {{ ansible_facts['distribution_release'] }}-updates main diff --git a/ansible/roles/general/templates/etc/hosts.j2 b/ansible/roles/general/templates/etc/hosts.j2 index 15ecce5..d47426b 100644 --- a/ansible/roles/general/templates/etc/hosts.j2 +++ b/ansible/roles/general/templates/etc/hosts.j2 @@ -2,7 +2,7 @@ {% if network.loopback_in_hosts | default(True) %} 127.0.1.1 {{ inventory_hostname }} {{ inventory_hostname | split(".") | first }} {% else %} -{{ "%-15s" | format(ansible_default_ipv4.address) }} {{ inventory_hostname }} {{ inventory_hostname | split(".") | first }} +{{ "%-15s" | format(ansible_facts['default_ipv4'].address) }} {{ inventory_hostname }} {{ inventory_hostname | split(".") | first }} {% endif %} # The following lines are desirable for IPv6 capable hosts diff --git a/ansible/roles/grafana/tasks/main.yml b/ansible/roles/grafana/tasks/main.yml index 0134a62..bc2e3df 100644 --- a/ansible/roles/grafana/tasks/main.yml +++ b/ansible/roles/grafana/tasks/main.yml @@ -23,16 +23,25 @@ force: false - name: Add Grafana apt repository - ansible.builtin.apt_repository: - repo: "deb [signed-by={{ grafana_apt_keyring }}] https://apt.grafana.com stable main" - filename: grafana + ansible.builtin.deb822_repository: + name: grafana + types: [deb] + uris: https://apt.grafana.com + suites: [stable] + components: [main] + signed_by: "{{ grafana_apt_keyring }}" state: present - update_cache: true + +- name: Remove legacy Grafana .list repo (superseded by deb822 .sources) + ansible.builtin.file: + path: /etc/apt/sources.list.d/grafana.list + state: absent - name: Install Grafana OSS ansible.builtin.apt: name: grafana state: present + update_cache: true - name: Configure grafana.ini ansible.builtin.template: diff --git a/ansible/roles/loki/tasks/main.yml b/ansible/roles/loki/tasks/main.yml index 38df20f..9f65922 100644 --- a/ansible/roles/loki/tasks/main.yml +++ b/ansible/roles/loki/tasks/main.yml @@ -7,7 +7,7 @@ name: unzip state: present update_cache: true - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" - name: Create loki group ansible.builtin.group: diff --git a/ansible/roles/monitor/defaults/main.yml b/ansible/roles/monitor/defaults/main.yml index 09466bc..35f9c04 100644 --- a/ansible/roles/monitor/defaults/main.yml +++ b/ansible/roles/monitor/defaults/main.yml @@ -7,12 +7,10 @@ # Icinga repo + packages icinga2_apt_key_url: "https://packages.icinga.com/icinga.key" icinga2_apt_keyring: "/etc/apt/keyrings/icinga-archive-keyring.gpg" -icinga2_apt_repo: "deb [signed-by={{ icinga2_apt_keyring }}] https://packages.icinga.com/ubuntu icinga-{{ ansible_distribution_release }} main" # PagerDuty agent repo + packages pdagent_apt_key_url: "https://packages.pagerduty.com/GPG-KEY-pagerduty" pdagent_apt_keyring: "/etc/apt/keyrings/pagerduty-archive-keyring.gpg" -pdagent_apt_repo: "deb [signed-by={{ pdagent_apt_keyring }}] https://packages.pagerduty.com/pdagent deb/" pdagent_packages: - pdagent - pdagent-integrations diff --git a/ansible/roles/monitor/tasks/main.yml b/ansible/roles/monitor/tasks/main.yml index d2cdef0..206d293 100644 --- a/ansible/roles/monitor/tasks/main.yml +++ b/ansible/roles/monitor/tasks/main.yml @@ -50,11 +50,19 @@ - /etc/apt/sources.list.d/jammy-icinga.list.distUpgrade - name: Add Icinga apt repository - ansible.builtin.apt_repository: - repo: "{{ icinga2_apt_repo }}" - filename: icinga + ansible.builtin.deb822_repository: + name: icinga + types: [deb] + uris: https://packages.icinga.com/ubuntu + suites: "icinga-{{ ansible_facts['distribution_release'] }}" + components: [main] + signed_by: "{{ icinga2_apt_keyring }}" state: present - update_cache: true + +- name: Remove legacy Icinga .list repo (superseded by deb822 .sources) + ansible.builtin.file: + path: /etc/apt/sources.list.d/icinga.list + state: absent - name: Install database stack ansible.builtin.apt: @@ -93,16 +101,24 @@ mode: "0644" - name: Add PagerDuty apt repository - ansible.builtin.apt_repository: - repo: "{{ pdagent_apt_repo }}" - filename: pdagent + ansible.builtin.deb822_repository: + name: pdagent + types: [deb] + uris: https://packages.pagerduty.com/pdagent + suites: "deb/" + signed_by: "{{ pdagent_apt_keyring }}" state: present - update_cache: true + +- name: Remove legacy PagerDuty .list repo (superseded by deb822 .sources) + ansible.builtin.file: + path: /etc/apt/sources.list.d/pdagent.list + state: absent - name: Install PagerDuty agent ansible.builtin.apt: name: "{{ pdagent_packages }}" state: present + update_cache: true - name: Ensure PagerDuty agent is started + enabled ansible.builtin.systemd: @@ -125,9 +141,9 @@ name: "{{ apache_php_version.stdout }}-mysql" state: present when: apache_php_version.stdout | length > 0 - when: ansible_os_family == "Debian" + when: ansible_facts['os_family'] == "Debian" -- name: Ensure PyMySQL is installed (required by community.mysql) +- name: Ensure PyMySQL is installed (required by ansible.mysql) ansible.builtin.shell: cmd: | set -e @@ -149,13 +165,13 @@ enabled: true - name: Create IDO database - community.mysql.mysql_db: + ansible.mysql.mysql_db: name: "{{ icinga2_ido_db_name }}" state: present login_unix_socket: /run/mysqld/mysqld.sock - name: Create IDO daemon DB user (icinga2) - community.mysql.mysql_user: + ansible.mysql.mysql_user: name: "{{ icinga2_ido_db_user }}" host: localhost password: "{{ icinga2_ido_db_password }}" @@ -164,7 +180,7 @@ login_unix_socket: /run/mysqld/mysqld.sock - name: Create read-only IDO user for icingaweb2 (icinga) - community.mysql.mysql_user: + ansible.mysql.mysql_user: name: "{{ icingaweb2_ido_db_user }}" host: localhost password: "{{ icingaweb2_ido_db_password }}" @@ -173,13 +189,13 @@ login_unix_socket: /run/mysqld/mysqld.sock - name: Create icingaweb2 database - community.mysql.mysql_db: + ansible.mysql.mysql_db: name: "{{ icingaweb2_db_name }}" state: present login_unix_socket: /run/mysqld/mysqld.sock - name: Create icingaweb2 DB user - community.mysql.mysql_user: + ansible.mysql.mysql_user: name: "{{ icingaweb2_db_user }}" host: localhost password: "{{ icingaweb2_db_password }}" @@ -188,7 +204,7 @@ login_unix_socket: /run/mysqld/mysqld.sock - name: Check whether IDO schema has been imported - community.mysql.mysql_query: + ansible.mysql.mysql_query: login_db: "{{ icinga2_ido_db_name }}" query: "SHOW TABLES LIKE 'icinga_dbversion'" login_unix_socket: /run/mysqld/mysqld.sock @@ -196,7 +212,7 @@ changed_when: false - name: Import IDO schema (first install only) - community.mysql.mysql_db: + ansible.mysql.mysql_db: name: "{{ icinga2_ido_db_name }}" state: import target: "{{ icinga2_ido_schema_path }}" @@ -205,7 +221,7 @@ notify: Restart icinga2 - name: Check whether icingaweb2 schema has been imported - community.mysql.mysql_query: + ansible.mysql.mysql_query: login_db: "{{ icingaweb2_db_name }}" query: "SHOW TABLES LIKE 'icingaweb_user'" login_unix_socket: /run/mysqld/mysqld.sock @@ -213,7 +229,7 @@ changed_when: false - name: Import icingaweb2 schema (first install only) - community.mysql.mysql_db: + ansible.mysql.mysql_db: name: "{{ icingaweb2_db_name }}" state: import target: /usr/share/icingaweb2/schema/mysql.schema.sql @@ -221,7 +237,7 @@ when: iweb2_schema_check.rowcount[0] == 0 - name: Bootstrap icingaweb2 admin account (first install only) - community.mysql.mysql_query: + ansible.mysql.mysql_query: login_db: "{{ icingaweb2_db_name }}" query: >- INSERT INTO icingaweb_user (name, active, password_hash) VALUES diff --git a/ansible/roles/ns/handlers/main.yml b/ansible/roles/ns/handlers/main.yml index 71aa5d4..7552592 100644 --- a/ansible/roles/ns/handlers/main.yml +++ b/ansible/roles/ns/handlers/main.yml @@ -4,7 +4,7 @@ - name: Restart bind ansible.builtin.service: - name: "{{ 'bind9' if ansible_os_family == 'Debian' else 'named' }}" + name: "{{ 'bind9' if ansible_facts['os_family'] == 'Debian' else 'named' }}" state: restarted become: true diff --git a/ansible/roles/ns/tasks/bind9.yml b/ansible/roles/ns/tasks/bind9.yml index 878e216..a31712b 100644 --- a/ansible/roles/ns/tasks/bind9.yml +++ b/ansible/roles/ns/tasks/bind9.yml @@ -60,7 +60,7 @@ - name: Enable and start BIND9 service ansible.builtin.service: - name: "{{ 'bind9' if ansible_os_family == 'Debian' else 'named' }}" + name: "{{ 'bind9' if ansible_facts['os_family'] == 'Debian' else 'named' }}" state: started enabled: true @@ -71,4 +71,4 @@ permanent: true state: enabled notify: Restart firewalld - when: ansible_os_family == 'RedHat' + when: ansible_facts['os_family'] == 'RedHat' diff --git a/ansible/roles/resolvers/tasks/main.yml b/ansible/roles/resolvers/tasks/main.yml index 214b5f4..0af13b9 100755 --- a/ansible/roles/resolvers/tasks/main.yml +++ b/ansible/roles/resolvers/tasks/main.yml @@ -29,6 +29,14 @@ daemon_reload: true when: unbound_override.changed +- name: Deploy blocklist RPZ zonefile + ansible.builtin.template: + src: blocklist.rpz.j2 + dest: /etc/unbound/blocklist.rpz + mode: "644" + notify: + - Restart unbound + - name: Create Unbound config ansible.builtin.template: src: unbound.conf.j2 @@ -50,7 +58,7 @@ permanent: true immediate: true state: enabled - when: ansible_os_family == "RedHat" + when: ansible_facts['os_family'] == "RedHat" notify: - Restart firewalld diff --git a/ansible/roles/resolvers/templates/blocklist.rpz.j2 b/ansible/roles/resolvers/templates/blocklist.rpz.j2 new file mode 100644 index 0000000..41c55ba --- /dev/null +++ b/ansible/roles/resolvers/templates/blocklist.rpz.j2 @@ -0,0 +1,15 @@ +; Managed by Ansible (roles/resolvers) — do not edit by hand. +; Source of truth: resolver_blocked_domains in group_vars/resolvers/main.yml +; +; Response Policy Zone. Each listed name and its subdomains resolve to +; NXDOMAIN (forced by rpz-action-override in unbound.conf), and matches are +; logged to syslog under rpz-log-name "blocklist". Names are relative to the +; $ORIGIN below, per RPZ convention (the zone suffix is the policy trigger). +$TTL 3600 +$ORIGIN blocklist.rpz. +@ IN SOA localhost. root.localhost. 1 3600 600 86400 3600 +@ IN NS localhost. +{% for domain in resolver_blocked_domains | default([]) %} +{{ domain }} CNAME . +*.{{ domain }} CNAME . +{% endfor %} diff --git a/ansible/roles/resolvers/templates/unbound.conf.j2 b/ansible/roles/resolvers/templates/unbound.conf.j2 index 85d27a2..578f9e6 100644 --- a/ansible/roles/resolvers/templates/unbound.conf.j2 +++ b/ansible/roles/resolvers/templates/unbound.conf.j2 @@ -338,6 +338,10 @@ server: access-control: {{ netblock }} allow {% endfor %} + # Blocklist (NXDOMAIN + logging) is implemented as an RPZ at the end of + # this file so that only blocklist hits are logged. See the rpz: clause + # and /etc/unbound/blocklist.rpz (templated from resolver_blocked_domains). + # tag access-control with list of tags (in "" with spaces between) # Clients using this access control element use localzones that # are tagged with one of these tags. @@ -636,6 +640,8 @@ server: # except cachedb(just before iterator), and python (at the beginning, # or, just before the iterator). # module-config: "validator iterator" + # respip is required for the RPZ blocklist (rpz: clause at end of file). + module-config: "respip validator iterator" # File with trusted keys, kept uptodate using RFC5011 probes, # initial file like trust-anchor-file, then it stores metadata. @@ -1336,3 +1342,13 @@ remote-control: # rpz-signal-nxdomain-ra: no # for-downstream: no # tags: "example" + +# Blocklist RPZ: returns NXDOMAIN for resolver_blocked_domains (and subdomains) +# and logs only these matches to syslog (tag "blocklist"). Zonefile is templated +# from group_vars/resolvers/main.yml. Requires respip in module-config (above). +rpz: + name: "blocklist.rpz" + zonefile: "/etc/unbound/blocklist.rpz" + rpz-action-override: nxdomain + rpz-log: yes + rpz-log-name: "blocklist" diff --git a/ansible/roles/uisp/tasks/main.yml b/ansible/roles/uisp/tasks/main.yml index 167f6fc..efe3b3a 100644 --- a/ansible/roles/uisp/tasks/main.yml +++ b/ansible/roles/uisp/tasks/main.yml @@ -16,11 +16,21 @@ mode: '0644' - name: Add Docker APT repository - ansible.builtin.apt_repository: - repo: "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian {{ ansible_distribution_release }} stable" - filename: docker + ansible.builtin.deb822_repository: + name: docker + types: [deb] + uris: https://download.docker.com/linux/debian + suites: "{{ ansible_facts['distribution_release'] }}" + components: [stable] + architectures: [amd64] + signed_by: /etc/apt/keyrings/docker.asc state: present +- name: Remove legacy Docker .list repo (superseded by deb822 .sources) + ansible.builtin.file: + path: /etc/apt/sources.list.d/docker.list + state: absent + - name: Install Docker CE ansible.builtin.apt: name: