From 31aaf10a5c4c18f87e228469fdb6580a2734e8a0 Mon Sep 17 00:00:00 2001 From: NaeiKinDus Date: Thu, 8 Aug 2024 00:00:00 +0000 Subject: [PATCH] feat(nginx): added new nginx role to install and configure nginx webservers --- .../roles/nginx/defaults/main.yml | 8 ++ .../roles/nginx/handlers/main.yml | 28 ++++++ .../infrastructure/roles/nginx/meta/main.yml | 20 ++++ .../infrastructure/roles/nginx/tasks/main.yml | 97 +++++++++++++++++++ .../roles/nginx/tasks/nginx-config.yml | 58 +++++++++++ .../roles/nginx/tasks/nginx-service-entry.yml | 49 ++++++++++ .../nginx/templates/ingress_http_nginx.nft.j2 | 9 ++ .../roles/nginx/templates/nginx.conf.j2 | 44 +++++++++ .../nginx/templates/nginx_limits.conf.j2 | 1 + .../roles/nginx/tests/inventory | 2 + .../infrastructure/roles/nginx/tests/test.yml | 5 + .../infrastructure/roles/nginx/vars/main.yml | 2 + inventory/host_vars/lithium/vars.yml | 3 + playbooks/external.yml | 10 ++ 14 files changed, 336 insertions(+) create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/defaults/main.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/handlers/main.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/meta/main.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/main.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-config.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-service-entry.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/ingress_http_nginx.nft.j2 create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx.conf.j2 create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx_limits.conf.j2 create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/inventory create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/test.yml create mode 100644 collections/ansible_collections/nullified/infrastructure/roles/nginx/vars/main.yml diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/defaults/main.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/defaults/main.yml new file mode 100644 index 0000000..78c8456 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/defaults/main.yml @@ -0,0 +1,8 @@ +--- +nginx_extra_packages: [] +nginx_custom_config: false +nginx_limits_nofile: 524288 +nginx_service_user: nginx +nginx_service_group: nginx +nginx_sites: [] +nginx_streams: [] diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/handlers/main.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/handlers/main.yml new file mode 100644 index 0000000..46f6587 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/handlers/main.yml @@ -0,0 +1,28 @@ +--- +- name: restart firewall service + become: true + ansible.builtin.systemd_service: + name: nftables.service + enabled: true + state: restarted + +- name: reload nginx service + become: true + ansible.builtin.systemd_service: + name: nginx.service + enabled: true + state: reloaded + +- name: check configuration is valid + become: true + ansible.builtin.command: /usr/sbin/nginx -t -q + changed_when: false + listen: 'nginx : restart nginx service' + +- name: restart service + become: true + ansible.builtin.systemd_service: + name: nginx.service + enabled: true + state: restarted + listen: 'nginx : restart nginx service' diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/meta/main.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/meta/main.yml new file mode 100644 index 0000000..a2fbde3 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/meta/main.yml @@ -0,0 +1,20 @@ +--- +galaxy_info: + author: Florian L. + namespace: nullified + description: Install and configure Nginx webserver + # issue_tracker_url: http://example.com/issue/tracker + license: MIT + min_ansible_version: 2.15 + + # https://galaxy.ansible.com/api/v1/platforms/ + platforms: + - name: Debian + versions: + - bookworm + + galaxy_tags: + - nginx + - webserver + +dependencies: [] diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/main.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/main.yml new file mode 100644 index 0000000..f5a8418 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/main.yml @@ -0,0 +1,97 @@ +--- +- name: install requirements + become: true + ansible.builtin.apt: + update_cache: true + force_apt_get: true + cache_valid_time: 3600 + pkg: + - ca-certificates + - curl + - debian-archive-keyring + - gnupg2 + - lsb-release + +- name: install nginx repository + become: true + ansible.builtin.deb822_repository: + allow_downgrade_to_insecure: false + allow_insecure: false + allow_weak: false + components: + - nginx + enabled: true + name: nginx + signed_by: 'https://nginx.org/keys/nginx_signing.key' + state: present + suites: '{{ ansible_facts.distribution_release }}' + trusted: true + uris: 'http://nginx.org/packages/mainline/debian' + +- name: pin nginx packages + become: true + ansible.builtin.copy: + content: |- + Package: * + Pin: origin nginx.org + Pin: release o=nginx + Pin-Priority: 900 + dest: /etc/apt/preferences.d/55-nginx + mode: '0600' + owner: root + group: root + +- name: update cache and install nginx package + become: true + ansible.builtin.apt: + cache_valid_time: 0 + force_apt_get: true + update_cache: true + pkg: '{{ nginx_extra_packages | default([]) + ["nginx"] }}' + +- ansible.builtin.include_tasks: + file: nginx-config.yml + apply: + tags: [webserver-config] + tags: [webserver-config] + +- name: setup firewall rules + become: true + ansible.builtin.template: + src: ../templates/ingress_http_nginx.nft.j2 + dest: /etc/nftables.d/ingress_http_nginx.nft + owner: root + group: root + mode: '0600' + notify: + - 'nginx : restart firewall service' + +- ansible.builtin.include_tasks: + file: nginx-service-entry.yml + apply: + tags: [webserver-sites] + tags: [webserver-sites] + vars: + nginx_entry_type: site + loop: '{{ nginx_sites }}' + loop_control: + label: '{{ item.name }}' +- ansible.builtin.include_tasks: + file: nginx-service-entry.yml + apply: + tags: [webserver-streams] + tags: [webserver-streams] + vars: + nginx_entry_type: stream + loop: '{{ nginx_streams }}' + loop_control: + label: '{{ item.name }}' + +- name: set permissions + become: true + ansible.builtin.file: + path: /etc/nginx + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_user }}' + mode: 'u=rwX,g=rX,o=' + recurse: true diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-config.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-config.yml new file mode 100644 index 0000000..ebec5a5 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-config.yml @@ -0,0 +1,58 @@ +--- +- name: setup configuration directories + become: true + ansible.builtin.file: + path: '/etc/nginx/{{ item }}' + state: directory + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_group }}' + mode: '0750' + loop: + - ssl + - ssl/certificates + - ssl/keys + - sites-available + - sites-enabled + - streams-available + - streams-enabled + +- name: generate dhparams.pem file + become: true + ansible.builtin.command: + cmd: /usr/bin/openssl dhparam -out /etc/nginx/ssl/dhparams.pem 4096 + creates: /etc/nginx/ssl/dhparams.pem + notify: + - 'nginx : restart nginx service' + +- name: setup nginx.conf + become: true + block: + - name: use default configuration + ansible.builtin.template: + src: ../templates/nginx.conf.j2 + dest: /etc/nginx/nginx.conf + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_group }}' + mode: '0640' + when: nginx_custom_config is falsy + - name: use custom configuration + ansible.builtin.copy: + content: '{{ nginx_custom_config }}' + dest: /etc/nginx/nginx.conf + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_group }}' + mode: '0640' + when: nginx_custom_config is truthy + notify: + - 'nginx : restart nginx service' + +- name: set process limits + become: true + ansible.builtin.template: + src: ../templates/nginx_limits.conf.j2 + dest: /etc/security/limits.d/nginx.conf + owner: root + group: root + mode: '0600' + notify: + - 'nginx : restart nginx service' diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-service-entry.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-service-entry.yml new file mode 100644 index 0000000..d46d627 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tasks/nginx-service-entry.yml @@ -0,0 +1,49 @@ +--- +- name: set facts + ansible.builtin.set_fact: + safe_filename: "{{ item.name | regex_replace('[^\\w]', '') }}" + nginx_entry_type: '{{ nginx_entry_type | default(item.get("entry_type", None)) }}' + +- name: perform sanity checks + ansible.builtin.assert: + that: + - nginx_entry_type in ["stream", "site"] + fail_msg: Invalid value for `nginx_entry_type`; expected "stream" or "site", got "{{ nginx_entry_type }}" + +- name: 'copy entry in {{ nginx_entry_type }}s-available' + become: true + ansible.builtin.copy: + content: '{{ item.content }}' + dest: "/etc/nginx/{{ nginx_entry_type }}s-available/{{ safe_filename }}.conf" + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_user }}' + mode: '0640' + when: item.get('state', 'present') == 'present' + notify: + - 'nginx : reload nginx service' + +- name: 'enable {{ nginx_entry_type }}' + become: true + ansible.builtin.file: + src: "/etc/nginx/{{ nginx_entry_type }}s-available/{{ safe_filename }}.conf" + path: "/etc/nginx/{{ nginx_entry_type }}s-enabled/{{ safe_filename }}.conf" + owner: '{{ nginx_service_user }}' + group: '{{ nginx_service_user }}' + state: 'link' + when: item.get('state', 'present') == 'present' + notify: + - 'nginx : reload nginx service' + +- name: 'disable {{ nginx_entry_type }}' + become: true + ansible.builtin.file: + path: "/etc/nginx/{{ nginx_entry_type }}s-enabled/{{ safe_filename }}.conf" + state: absent + when: item.get('state', 'present') in ['disabled', 'deleted'] + +- name: 'remove {{ nginx_entry_type }}' + become: true + ansible.builtin.file: + path: "/etc/nginx/{{ nginx_entry_type }}s-available/{{ safe_filename }}.conf" + state: absent + when: item.get('state', 'present') == 'deleted' diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/ingress_http_nginx.nft.j2 b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/ingress_http_nginx.nft.j2 new file mode 100644 index 0000000..9d335fe --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/ingress_http_nginx.nft.j2 @@ -0,0 +1,9 @@ +table inet filter { + chain input { + meta nfproto { ipv4, ipv6 } tcp dport { http, https } accept + } + + chain output { + meta nfproto { ipv4, ipv6 } tcp sport { http, https } accept + } +} diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx.conf.j2 b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx.conf.j2 new file mode 100644 index 0000000..28be4b2 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx.conf.j2 @@ -0,0 +1,44 @@ +user {{ nginx_service_user }}; +worker_processes auto; + +error_log /var/log/nginx/error.log notice; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + server_tokens off; + + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305; + ssl_dhparam /etc/nginx/ssl/dhparams.pem; + ssl_prefer_server_ciphers off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ecdh_curve x25519:secp256r1:secp521r1:secp384r1; + + keepalive_timeout 65; + + include /etc/nginx/sites-enabled/*.conf; +} + +stream { + log_format proxy '$remote_addr [$time_local] ' + '$protocol $status $bytes_sent $bytes_received ' + '$session_time "$upstream_addr" "-- $ssl_preread_server_name --"' + '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"'; + + access_log /var/log/nginx/stream-access.log proxy; + + include /etc/nginx/streams-enabled/*.conf; +} diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx_limits.conf.j2 b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx_limits.conf.j2 new file mode 100644 index 0000000..691b000 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/templates/nginx_limits.conf.j2 @@ -0,0 +1 @@ +nginx - nofile {{ nginx_limits_nofile }} diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/inventory b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/inventory new file mode 100644 index 0000000..878877b --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/inventory @@ -0,0 +1,2 @@ +localhost + diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/test.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/test.yml new file mode 100644 index 0000000..261c779 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/tests/test.yml @@ -0,0 +1,5 @@ +--- +- hosts: localhost + remote_user: root + roles: + - nginx diff --git a/collections/ansible_collections/nullified/infrastructure/roles/nginx/vars/main.yml b/collections/ansible_collections/nullified/infrastructure/roles/nginx/vars/main.yml new file mode 100644 index 0000000..1fc4c53 --- /dev/null +++ b/collections/ansible_collections/nullified/infrastructure/roles/nginx/vars/main.yml @@ -0,0 +1,2 @@ +--- +nginx_repository_signing_key_url: 'https://nginx.org/keys/nginx_signing.key' diff --git a/inventory/host_vars/lithium/vars.yml b/inventory/host_vars/lithium/vars.yml index e7c8a02..54b86be 100644 --- a/inventory/host_vars/lithium/vars.yml +++ b/inventory/host_vars/lithium/vars.yml @@ -1,3 +1,6 @@ ansible_become_password: "{{ vault_root_pass }}" ansible_host: "{{ vault_ansible_host }}" ansible_user: "{{ vault_ssh_user }}" +nginx_extra_packages: [nginx-module-geoip, nginx-module-otel] +nginx_sites: "{{ vault_nginx_sites }}" +nginx_streams: "{{ vault_nginx_streams }}" diff --git a/playbooks/external.yml b/playbooks/external.yml index 14bc88b..d29c1ab 100644 --- a/playbooks/external.yml +++ b/playbooks/external.yml @@ -37,3 +37,13 @@ apply: tags: [server] tags: [server] + +- name: setup web servers + hosts: external:&webserver + tasks: + - name: include nginx role + ansible.builtin.include_role: + name: nullified.infrastructure.nginx + apply: + tags: [webserver] + tags: [webserver, webserver-config, webserver-sites, webserver-streams]