diff --git a/CHANGELOG.md b/CHANGELOG.md index f83a442..c186eeb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## 0.9.1 (Unreleased) +FEATURES: + +- Add support for installing NGINX App Protect WAF on Alpine Linux 3.16/3.17, RHEL 9, and Ubuntu jammy. +- Remove support for installing NGINX App Protect WAF on Ubuntu bionic. + ENHANCEMENTS: - Bump the Ansible `ansible.posix` collection to `1.5.4`, `community.general` collection to `6.4.0`, `community.crypto` collection to `2.14.1` and `community.docker` collection to `3.4.7`. diff --git a/meta/main.yml b/meta/main.yml index af17950..cc69838 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -12,14 +12,16 @@ galaxy_info: platforms: - name: Alpine versions: [all] - - name: Amazon Linux 2 - versions: [all] - - name: EL - versions: ["7", "8"] + - name: Amazon Linux + versions: ['2'] - name: Debian versions: [bullseye] + - name: EL + versions: ['7', '8', '9'] + - name: OracleLinux + versions: ['8'] - name: Ubuntu - versions: [bionic, focal] + versions: [focal, jammy] galaxy_tags: - waf diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index d9070c4..fc436ce 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -2,6 +2,24 @@ driver: name: docker platforms: + - name: alpine-3.16 + image: alpine:3.16 + platform: amd64 + dockerfile: ../common/Dockerfile.j2 + privileged: true + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + command: /sbin/init + - name: alpine-3.17 + image: alpine:3.17 + platform: amd64 + dockerfile: ../common/Dockerfile.j2 + privileged: true + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + command: /sbin/init - name: amazonlinux-2 image: amazonlinux:2 platform: amd64 @@ -56,15 +74,17 @@ platforms: volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw command: /usr/sbin/init - - name: ubuntu-bionic - image: ubuntu:bionic + - name: rhel-9 + image: redhat/ubi9:9.1.0 + env: + SMDEV_CONTAINER_OFF: "1" platform: amd64 dockerfile: ../common/Dockerfile.j2 privileged: true cgroupns_mode: host volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw - command: /sbin/init + command: /usr/sbin/init - name: ubuntu-focal image: ubuntu:focal platform: amd64 @@ -74,6 +94,15 @@ platforms: volumes: - /sys/fs/cgroup:/sys/fs/cgroup:rw command: /sbin/init + - name: ubuntu-jammy + image: ubuntu:jammy + platform: amd64 + dockerfile: ../common/Dockerfile.j2 + privileged: true + cgroupns_mode: host + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + command: /sbin/init provisioner: name: ansible playbooks: diff --git a/molecule/uninstall/molecule.yml b/molecule/uninstall/molecule.yml index 68492de..e918dd3 100644 --- a/molecule/uninstall/molecule.yml +++ b/molecule/uninstall/molecule.yml @@ -1,7 +1,7 @@ --- driver: name: docker -platforms: # Ubuntu bionic results in a segmentation fault error as of Ansible core 2.13 +platforms: - name: centos-7 image: centos:7 platform: amd64 diff --git a/tasks/common/install/setup-license.yml b/tasks/common/install/setup-license.yml index 1b6160c..8b31d02 100644 --- a/tasks/common/install/setup-license.yml +++ b/tasks/common/install/setup-license.yml @@ -88,7 +88,7 @@ - name: (Debian/Red Hat OSs) Check that NGINX App Protect WAF/DoS license is valid ansible.builtin.assert: that: - - "{{ not cert['expired'] | bool }}" - - "{{ cert['public_key'] == key['public_key'] }}" + - not cert['expired'] | bool + - cert['public_key'] == key['public_key'] success_msg: Your NGINX App Protect WAF/DoS license is valid! fail_msg: Something went wrong! Make sure your NGINX App Protect WAF/DoS license is valid! diff --git a/tasks/common/keys/setup-keys.yml b/tasks/common/keys/setup-keys.yml index 17b112f..3f46275 100644 --- a/tasks/common/keys/setup-keys.yml +++ b/tasks/common/keys/setup-keys.yml @@ -1,39 +1,51 @@ --- -- name: (Alpine Linux) Set up NGINX App Protect DoS signing key +- name: (Alpine Linux) Set up NGINX App Protect and security updates signing key when: ansible_facts['os_family'] == "Alpine" block: - - name: (Alpine Linux) Set up NGINX App Protect DoS signing key URL + - name: (Alpine Linux) Set up NGINX App Protect WAF/DoS signing key URL ansible.builtin.set_fact: keysite: "{{ nginx_app_protect_signing_key['nginx_plus'] | default(nginx_app_protect_default_signing_key_rsa_pub) }}" - - name: (Alpine Linux) Download NGINX App Protect DoS signing key + - name: (Alpine Linux) Download NGINX App Protect WAF/DoS signing key ansible.builtin.get_url: url: "{{ keysite }}" dest: /etc/apk/keys/nginx_signing.rsa.pub mode: "0400" + - name: (Alpine Linux) Set up NGINX App Protect WAF security updates signing key URL + ansible.builtin.set_fact: + keysite_security_updates: "{{ nginx_app_protect_signing_key['waf_security_updates'] | default(nginx_app_protect_waf_security_updates_default_signing_key_rsa_pub) }}" + when: nginx_app_protect_waf_enable | bool + + - name: (Alpine Linux) Download NGINX App Protect WAF security updates signing key + ansible.builtin.get_url: + url: "{{ keysite_security_updates }}" + dest: /etc/apk/keys/app-protect-security-updates.rsa.pub + mode: "0400" + when: nginx_app_protect_waf_enable | bool + - name: (Debian/Ubuntu) Set up NGINX App Protect and security updates signing key when: ansible_facts['os_family'] == "Debian" block: - - name: (Debian/Ubuntu) Add NGINX Plus signing key + - name: (Debian/Ubuntu) Add NGINX App Protect WAF/DoS signing key ansible.builtin.apt_key: keyring: /usr/share/keyrings/nginx-archive-keyring.gpg url: "{{ nginx_app_protect_signing_key['nginx_plus'] | default(nginx_app_protect_default_signing_key_pgp) }}" - - name: (Debian/Ubuntu) Add NGINX App Protect security updates signing key + - name: (Debian/Ubuntu) Add NGINX App Protect WAF security updates signing key ansible.builtin.apt_key: keyring: /usr/share/keyrings/nginx-archive-keyring.gpg url: "{{ nginx_app_protect_waf_signing_key['waf_security_updates'] | default(nginx_app_protect_waf_security_updates_default_signing_key_pgp) }}" - when: (nginx_app_protect_waf_install_signatures | bool) or (nginx_app_protect_waf_install_threat_campaigns | bool) + when: nginx_app_protect_waf_enable | bool - name: (Amazon Linux/CentOS/RHEL) Set up NGINX App Protect and security updates signing key when: ansible_facts['os_family'] == "RedHat" block: - - name: (CentOS/RHEL) Add NGINX Plus signing key + - name: (CentOS/RHEL) Add NGINX WAF/DoS signing key ansible.builtin.rpm_key: key: "{{ nginx_app_protect_signing_key['nginx_plus'] | default(nginx_app_protect_default_signing_key_pgp) }}" - - name: (Amazon Linux/CentOS/RHEL) Add NGINX App Protect security updates signing key + - name: (Amazon Linux/CentOS/RHEL) Add NGINX App Protect WAF security updates signing key ansible.builtin.rpm_key: key: "{{ nginx_app_protect_waf_signing_key['waf_security_updates'] | default(nginx_app_protect_waf_security_updates_default_signing_key_pgp) }}" - when: (nginx_app_protect_waf_install_signatures | bool) or (nginx_app_protect_waf_install_threat_campaigns | bool) + when: nginx_app_protect_waf_enable | bool diff --git a/tasks/common/prerequisites/install-dependencies.yml b/tasks/common/prerequisites/install-dependencies.yml index 575e878..939ffa6 100644 --- a/tasks/common/prerequisites/install-dependencies.yml +++ b/tasks/common/prerequisites/install-dependencies.yml @@ -78,11 +78,11 @@ - ansible_facts['distribution_major_version'] is version('7', '==') - nginx_app_protect_use_rhel_subscription_repos | bool - - name: (RHEL 8) Set up RHEL dependencies from RHEL official repositories + - name: (RHEL 8/9) Set up RHEL dependencies from RHEL official repositories community.general.rhsm_repository: - name: codeready-builder-for-rhel-8-x86_64-rpms + name: codeready-builder-for-rhel-{{ ansible_facts['distribution_major_version'] }}-x86_64-rpms when: - - ansible_facts['distribution_major_version'] is version('8', '==') + - ansible_facts['distribution_major_version'] is version('8', '>=') - nginx_app_protect_use_rhel_subscription_repos | bool - name: (Oracle Linux) Set up Oracle Linux specific repositories diff --git a/tasks/common/validate/validate.yml b/tasks/common/validate/validate.yml index 0be2f5b..49ce48c 100644 --- a/tasks/common/validate/validate.yml +++ b/tasks/common/validate/validate.yml @@ -2,10 +2,9 @@ - name: (WAF) Check whether you are using a supported NGINX App Protect WAF distribution ansible.builtin.assert: that: - - "{{ ansible_facts['distribution'] | lower in nginx_app_protect_waf_distributions.keys() | list }}" - - "{{ (ansible_facts['distribution_version'] | regex_search('\\d+\\.?\\d*') in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['versions'] | string) - if ansible_facts['distribution'] | lower in ['ubuntu'] else ansible_facts['distribution_major_version'] in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['versions'] | string }}" - - "{{ ansible_facts['architecture'] in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['architectures'] }}" + - ansible_facts['distribution'] | lower in nginx_app_protect_waf_distributions.keys() | list + - (ansible_facts['distribution_version'] | regex_search('\\d+\\.?\\d*') in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['versions'] | string if ansible_facts['distribution'] | lower in ['ubuntu'] else ansible_facts['distribution_major_version'] in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['versions'] | string) + - ansible_facts['architecture'] in nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['architectures'] success_msg: Your distribution, {{ nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['name'] }} {{ ansible_facts['distribution_version'] }} ({{ ansible_facts['architecture'] }}), is supported by NGINX App Protect WAF. fail_msg: Your distribution, {{ nginx_app_protect_waf_distributions[ansible_facts['distribution'] | lower]['name'] }} {{ ansible_facts['distribution_version'] }} ({{ ansible_facts['architecture'] }}), is not supported by NGINX App Protect WAF. when: @@ -16,10 +15,9 @@ - name: (DoS) Check whether you are using a supported NGINX App Protect DoS distribution ansible.builtin.assert: that: - - "{{ ansible_facts['distribution'] | lower in nginx_app_protect_dos_distributions.keys() | list }}" - - "{{ (ansible_facts['distribution_version'] | regex_search('\\d+\\.?\\d*') in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['versions'] | string) - if ansible_facts['distribution'] | lower in ['alpine', 'ubuntu'] else ansible_facts['distribution_major_version'] in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['versions'] | string }}" - - "{{ ansible_facts['architecture'] in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['architectures'] }}" + - ansible_facts['distribution'] | lower in nginx_app_protect_dos_distributions.keys() | list + - (ansible_facts['distribution_version'] | regex_search('\\d+\\.?\\d*') in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['versions'] | string if ansible_facts['distribution'] | lower in ['alpine', 'ubuntu'] else ansible_facts['distribution_major_version'] in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['versions'] | string) + - ansible_facts['architecture'] in nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['architectures'] success_msg: Your distribution, {{ nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['name'] }} {{ ansible_facts['distribution_version'] }} ({{ ansible_facts['architecture'] }}), is supported by NGINX App Protect DoS. fail_msg: Your distribution, {{ nginx_app_protect_dos_distributions[ansible_facts['distribution'] | lower]['name'] }} {{ ansible_facts['distribution_version'] }} ({{ ansible_facts['architecture'] }}), is not supported by NGINX App Protect DoS. when: @@ -53,8 +51,8 @@ - name: Check that the variables for 'nginx_app_protect_security_policy_file_enable' are defined ansible.builtin.assert: that: - - "{{ item }} is defined" - - "{{ item }} | length > 0" + - item is defined + - item | length > 0 fail_msg: If you want to publish a security policy file, don't forget to define at least one 'src' and 'dest' variables loop: - nginx_app_protect_security_policy_file.0.src @@ -65,8 +63,8 @@ - name: Check that the variables for 'nginx_app_protect_log_policy_file_enable' are defined ansible.builtin.assert: that: - - "{{ item }} is defined" - - "{{ item }} | length > 0" + - item is defined + - item | length > 0 fail_msg: If you want to publish a log policy file, don't forget to define at least one 'src' and 'dest' variables loop: - nginx_app_protect_log_policy_file.0.src diff --git a/tasks/dos/install-alpine.yml b/tasks/dos/install-alpine.yml index 02a3d40..d370c1f 100644 --- a/tasks/dos/install-alpine.yml +++ b/tasks/dos/install-alpine.yml @@ -27,7 +27,6 @@ - name: (Alpine Linux) {{ nginx_app_protect_dos_setup | capitalize }} NGINX App Protect DoS community.general.apk: name: app-protect-dos{{ (nginx_app_protect_dos_state == 'absent') | ternary(',nginx-plus-module-appprotectdos', '') }} - repository: "{{ nginx_app_protect_dos_repository | default(nginx_app_protect_dos_default_repository_alpine) }}" state: "{{ nginx_app_protect_dos_state }}" ignore_errors: "{{ ansible_check_mode }}" when: nginx_app_protect_license_status is not defined diff --git a/tasks/waf/install-alpine.yml b/tasks/waf/install-alpine.yml new file mode 100644 index 0000000..b3a19f3 --- /dev/null +++ b/tasks/waf/install-alpine.yml @@ -0,0 +1,57 @@ +--- +- name: (Alpine Linux) {{ nginx_app_protect_license_status is defined | ternary('Remove', 'Configure') }} NGINX Plus repository + ansible.builtin.lineinfile: + path: /etc/apk/repositories + insertafter: EOF + line: "{{ nginx_plus_repository | default(nginx_plus_default_repository_alpine) }}" + state: "{{ nginx_app_protect_license_status | default((nginx_app_protect_waf_setup == 'uninstall') | ternary('absent', 'present')) }}" + when: nginx_app_protect_waf_manage_repo | bool + +- name: (Alpine Linux) {{ nginx_app_protect_license_status is defined | ternary('Remove', 'Configure') }} NGINX App Protect WAF repository + ansible.builtin.lineinfile: + path: /etc/apk/repositories + insertafter: EOF + line: "{{ nginx_app_protect_waf_repository | default(nginx_app_protect_waf_default_repository_alpine) }}" + state: "{{ nginx_app_protect_license_status | default((nginx_app_protect_waf_setup == 'uninstall') | ternary('absent', 'present')) }}" + when: nginx_app_protect_waf_manage_repo | bool + +- name: (Alpine Linux) {{ nginx_app_protect_license_status is defined | ternary('Remove', 'Configure') }} NGINX App Protect WAF security updates repository + ansible.builtin.lineinfile: + path: /etc/apk/repositories + insertafter: EOF + line: "{{ nginx_app_protect_waf_security_updates_repository | default(nginx_app_protect_waf_security_updates_default_repository_alpine) }}" + state: "{{ nginx_app_protect_license_status | default((nginx_app_protect_waf_setup == 'uninstall') | ternary('absent', 'present')) }}" + when: nginx_app_protect_waf_manage_repo | bool + +- name: (Alpine Linux) {{ nginx_app_protect_waf_setup | capitalize }} NGINX Plus + community.general.apk: + name: nginx-plus + repository: "{{ nginx_plus_repository | default(nginx_plus_default_repository_alpine) }}" + state: "{{ nginx_app_protect_waf_state }}" + ignore_errors: "{{ ansible_check_mode }}" + when: nginx_app_protect_license_status is not defined + notify: (Handler - NGINX App Protect) Run NGINX + +- name: (Alpine Linux) {{ nginx_app_protect_waf_setup | capitalize }} NGINX App Protect WAF + community.general.apk: + name: app-protect + state: "{{ nginx_app_protect_waf_state }}" + ignore_errors: "{{ ansible_check_mode }}" + when: nginx_app_protect_license_status is not defined + notify: (Handler - NGINX App Protect) Run NGINX + +- name: (Alpine Linux) {{ nginx_app_protect_waf_setup | capitalize }} NGINX App Protect WAF signatures {{ nginx_app_protect_waf_signatures_version is defined | ternary(nginx_app_protect_signatures_version, '') }} + community.general.apk: + name: app-protect-attack-signatures{{ nginx_app_protect_waf_signatures_version | default('') }} + state: "{{ nginx_app_protect_waf_state }}" + ignore_errors: "{{ ansible_check_mode }}" + when: nginx_app_protect_license_status is not defined + notify: (Handler - NGINX App Protect) Run NGINX + +- name: (Alpine Linux) {{ nginx_app_protect_waf_setup | capitalize }} NGINX App Protect WAF threat campaigns {{ nginx_app_protect_waf_signatures_version is defined | ternary(nginx_app_protect_signatures_version, '') }} + community.general.apk: + name: app-protect-threat-campaigns{{ nginx_app_protect_waf_threat_campaigns_version | default('') }} + state: "{{ nginx_app_protect_waf_state }}" + ignore_errors: "{{ ansible_check_mode }}" + when: nginx_app_protect_license_status is not defined + notify: (Handler - NGINX App Protect) Run NGINX diff --git a/vars/main.yml b/vars/main.yml index 8687ff7..18c3a28 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -16,6 +16,10 @@ nginx_app_protect_dos_state: "{{ nginx_app_protect_state_vals[nginx_app_protect_ # Supported NGINX App Protect WAF distributions nginx_app_protect_waf_distributions: + alpine: + name: Alpine Linux + versions: [3.16, 3.17] + architectures: [x86_64] amazon: name: Amazon Linux versions: [2] @@ -34,11 +38,11 @@ nginx_app_protect_waf_distributions: architectures: [x86_64] redhat: name: Red Hat Enterprise Linux - versions: [7, 8] + versions: [7, 8, 9] architectures: [x86_64] ubuntu: name: Ubuntu - versions: [18.04, 20.04] + versions: [20.04, 22.04] architectures: [x86_64] # Supported NGINX App Protect DoS distributions @@ -90,11 +94,13 @@ nginx_plus_default_repository_debian: deb [arch=amd64 signed-by=/usr/share/keyri nginx_plus_default_repository_redhat: https://pkgs.nginx.com/plus/centos/{{ ansible_facts['distribution_major_version'] }}/$basearch/ # Default NGINX App Protect WAF repositories +nginx_app_protect_waf_default_repository_alpine: https://pkgs.nginx.com/app-protect/alpine/v{{ ansible_facts['distribution_version'] | regex_search('^[0-9]+\.[0-9]+') }}/main nginx_app_protect_waf_default_repository_amazon: https://pkgs.nginx.com/app-protect/centos/7/$basearch/ nginx_app_protect_waf_default_repository_debian: deb [arch=amd64 signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/app-protect/{{ ansible_facts['distribution'] | lower }} {{ ansible_distribution_release }} nginx-plus nginx_app_protect_waf_default_repository_redhat: https://pkgs.nginx.com/app-protect/centos/{{ ansible_facts['distribution_major_version'] }}/$basearch/ # Default NGINX App Protect WAF Security Updates repositories +nginx_app_protect_waf_security_updates_default_repository_alpine: https://pkgs.nginx.com/app-protect-security-updates/alpine/v{{ ansible_facts['distribution_version'] | regex_search('^[0-9]+\.[0-9]+') }}/main nginx_app_protect_waf_security_updates_default_repository_amazon: https://pkgs.nginx.com/app-protect-security-updates/centos/7/$basearch/ nginx_app_protect_waf_security_updates_default_repository_debian: deb [arch=amd64 signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] https://pkgs.nginx.com/app-protect-security-updates/{{ ansible_facts['distribution'] | lower }} {{ ansible_distribution_release }} nginx-plus nginx_app_protect_waf_security_updates_default_repository_redhat: https://pkgs.nginx.com/app-protect-security-updates/centos/{{ ansible_facts['distribution_major_version'] }}/$basearch/