diff --git a/.github/workflows/molecule-install-xnat.yml b/.github/workflows/molecule-install-xnat.yml index 3d041591..5fce8201 100644 --- a/.github/workflows/molecule-install-xnat.yml +++ b/.github/workflows/molecule-install-xnat.yml @@ -6,6 +6,7 @@ on: - "roles/xnat_container_service/**" - "playbooks/install_xnat.yml" - "playbooks/install_container_service.yml" + - "playbooks/molecule/**/xnat/**" - ".github/workflows/molecule-install-xnat.yml" release: types: [published] diff --git a/.github/workflows/molecule-nginx.yml b/.github/workflows/molecule-nginx.yml new file mode 100644 index 00000000..46c82f79 --- /dev/null +++ b/.github/workflows/molecule-nginx.yml @@ -0,0 +1,13 @@ +name: Test nginx +on: + pull_request: + paths: + - "roles/nginx/**" + - ".github/workflows/molecule.yml" + - ".github/workflows/molecule-nginx.yml" + +jobs: + molecule-nginx: + uses: ./.github/workflows/molecule.yml + with: + tests-path: ansible_collections/mirsg/infrastructure/roles/nginx diff --git a/molecule_configs/centos7_base_config.yml b/molecule_configs/centos7_base_config.yml index 7b457d27..cb0564a5 100644 --- a/molecule_configs/centos7_base_config.yml +++ b/molecule_configs/centos7_base_config.yml @@ -48,7 +48,7 @@ provisioner: playbooks: prepare: ../resources/prepare.yml converge: ../resources/converge.yml - verify: ../resources/converge.yml + verify: ../resources/verify.yml env: ANSIBLE_VERBOSITY: "1" diff --git a/molecule_configs/rocky9_base_config.yml b/molecule_configs/rocky9_base_config.yml index b283de69..5407a76a 100644 --- a/molecule_configs/rocky9_base_config.yml +++ b/molecule_configs/rocky9_base_config.yml @@ -49,7 +49,7 @@ provisioner: playbooks: prepare: ../resources/prepare.yml converge: ../resources/converge.yml - verify: ../resources/converge.yml + verify: ../resources/verify.yml env: ANSIBLE_VERBOSITY: "1" diff --git a/playbooks/group_vars/web.yml b/playbooks/group_vars/web.yml index 61d14b9b..bb828235 100644 --- a/playbooks/group_vars/web.yml +++ b/playbooks/group_vars/web.yml @@ -76,3 +76,13 @@ firewalld_public_zone_open_services: firewalld_work_zone_open_services: - http - https + +# mirsg.infrastructure.nginx +nginx_use_ssl: "{{ ssl.use_ssl }}" +nginx_server_name: "{{ xnat_web_server.host }}" +nginx_upstream_port: 8104 +nginx_upstream_listen_port: 8104 +nginx_proxy_port: 8080 # tomcat +nginx_root: /usr/share/tomcat/webapps/ROOT +nginx_app_access_log: "{{ nginx_log_folder }}/xnat.access.log" +nginx_app_error_log: "{{ nginx_log_folder }}/xnat.error.log" diff --git a/playbooks/molecule/centos7_xnat/molecule.yml b/playbooks/molecule/centos7_xnat/molecule.yml index 73ecee6c..d2200f9b 100644 --- a/playbooks/molecule/centos7_xnat/molecule.yml +++ b/playbooks/molecule/centos7_xnat/molecule.yml @@ -64,9 +64,10 @@ platforms: exposed_ports: - 80 - 443 + - 8080 - 8104 published_ports: - - 127.0.0.1:8104:8104 + - 127.0.0.1:8000:80 etc_hosts: xnat.db.local: 192.168.56.2 xnat.cserv.local: 192.168.56.4 @@ -111,11 +112,7 @@ provisioner: playbooks: prepare: ../resources/xnat/prepare.yml converge: ../resources/xnat/converge.yml - env: - ANSIBLE_VERBOSITY: 1 - -verifier: - name: ansible + verify: ../resources/xnat/verify.yml env: ANSIBLE_VERBOSITY: 1 diff --git a/playbooks/molecule/resources/xnat/inventory/group_vars/all/all.yml b/playbooks/molecule/resources/xnat/inventory/group_vars/all/all.yml index 3e0b2b93..f43da6a7 100644 --- a/playbooks/molecule/resources/xnat/inventory/group_vars/all/all.yml +++ b/playbooks/molecule/resources/xnat/inventory/group_vars/all/all.yml @@ -1,14 +1,4 @@ --- -# Bit size for OpenSSL Diffie-Hellman Parameters. Higher bit sizes are more -# secure, but require exponentially larger times for the one-off parameter -# generation. Use 4096 for production. These may take 10mins+ to generate but -# are only generated once per server. -# For local testing (non-production), use 2096 to speed up deployment. -diffie_helman_size_bits: 2048 - -# Support for ipv6 -ipv6_enabled: false - # XNAT configuration shared between all servers xnat_common_config: admin_email: "xnatadmin@{{ hostvars['xnat_web']['hostname'] }}" diff --git a/playbooks/molecule/resources/xnat/inventory/group_vars/all/server.yml b/playbooks/molecule/resources/xnat/inventory/group_vars/all/server.yml index 4dfab2d4..355ad383 100644 --- a/playbooks/molecule/resources/xnat/inventory/group_vars/all/server.yml +++ b/playbooks/molecule/resources/xnat/inventory/group_vars/all/server.yml @@ -26,10 +26,6 @@ ssl: use_ssl: false validate_certs: false -# nginx config -dicom_port: 8104 -xnat_dicom_port: 8105 - # XNAT configuration xnat_config: site_name: "MIRSG XNAT" diff --git a/playbooks/molecule/resources/xnat/inventory/group_vars/web.yml b/playbooks/molecule/resources/xnat/inventory/group_vars/web.yml index acd14263..d36bc6e2 100644 --- a/playbooks/molecule/resources/xnat/inventory/group_vars/web.yml +++ b/playbooks/molecule/resources/xnat/inventory/group_vars/web.yml @@ -6,19 +6,20 @@ firewalld_public_zone_sources: - "0.0.0.0/0" firewalld_internal_zone_ports: - - "{{ dicom_port }}" - - "{{ tomcat_port }}" + - "{{ nginx_upstream_listen_port }}" firewalld_work_zone_ports: - - "{{ dicom_port }}" - - "{{ tomcat_port }}" + - "{{ nginx_upstream_listen_port }}" firewalld_public_zone_ports: - - "{{ dicom_port }}" - - "{{ tomcat_port }}" + - "{{ nginx_upstream_listen_port }}" # mirsg.xnat.xnat # Some times the default admin account hasn't finished creating even after tomcat has started # Add a delay here to give the admin account a chance to be created # Note, this issue only seems to happen in CI xnat_wait_for_tomcat: 15 + +# nginx config +nginx_diffie_helman_size_bits: 2048 +nginx_add_default_server: false # set Tomcat as default server to allow access to XNAT web UI through localhost:8000 diff --git a/playbooks/molecule/resources/xnat/verify.yml b/playbooks/molecule/resources/xnat/verify.yml new file mode 100644 index 00000000..a9864fc2 --- /dev/null +++ b/playbooks/molecule/resources/xnat/verify.yml @@ -0,0 +1,18 @@ +--- +- name: Verify XNAT instance is running + hosts: localhost + tasks: + - name: Get server status + ansible.builtin.uri: + url: http://localhost:8000 + method: GET + validate_certs: false + return_content: true + register: response + + - name: Check server status and response + ansible.builtin.assert: + that: + - response.status == 200 + - response.server == "nginx" + - "response.content is search('MIRSG XNAT')" diff --git a/playbooks/molecule/rocky9_xnat/molecule.yml b/playbooks/molecule/rocky9_xnat/molecule.yml index afbb4b0c..fb760790 100644 --- a/playbooks/molecule/rocky9_xnat/molecule.yml +++ b/playbooks/molecule/rocky9_xnat/molecule.yml @@ -66,9 +66,10 @@ platforms: exposed_ports: - 80 - 443 + - 8080 - 8104 published_ports: - - 127.0.0.1:8104:8104 + - 127.0.0.1:8000:80 etc_hosts: xnat.db.local: 192.168.56.2 xnat.cserv.local: 192.168.56.4 @@ -95,7 +96,7 @@ platforms: - name: xnat ipv4_address: 192.168.56.4 exposed_ports: - - "2376" + - 2376 extra_hosts: xnat.db.local: 192.168.56.2 xnat.web.local: 192.168.56.3 @@ -114,6 +115,7 @@ provisioner: playbooks: prepare: ../resources/xnat/prepare.yml converge: ../resources/xnat/converge.yml + verify: ../resources/xnat/verify.yml env: ANSIBLE_VERBOSITY: "1" diff --git a/roles/firewalld/molecule/resources/inventory/group_vars/all.yml b/roles/firewalld/molecule/resources/inventory/group_vars/all.yml index dd7bf1eb..b2420dce 100644 --- a/roles/firewalld/molecule/resources/inventory/group_vars/all.yml +++ b/roles/firewalld/molecule/resources/inventory/group_vars/all.yml @@ -12,6 +12,6 @@ firewalld_work_zone_open_services: - http - https firewalld_public_zone_ports: - - "8080" + - "80" firewalld_internal_zone_ports: - "5432" diff --git a/roles/nginx/README.md b/roles/nginx/README.md new file mode 100644 index 00000000..50ef7c05 --- /dev/null +++ b/roles/nginx/README.md @@ -0,0 +1,57 @@ +# mirsg.infrastructure.nginx + +This role is for configuring [nginx](https://www.nginx.com/) as a +[reverse proxy](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) +on CentOS 7 or RockyLinux 9. + +## Role Variables + +| Name | Description | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `nginx_owner` | The OS user that will have ownership of the nginx service file and directory. Defaults to `root` | +| `nginx_group` | The OS group that will have ownership of the nginx service file and directory. Defaults to `root` | +| `nginx_log_folder` | The path to the nginx logs. Defaults to `/var/log/nginx` | +| `nginx_access_log` | File in which to write access logs for the default server. Defaults to `/var/log/access.log` | +| `nginx_error_log` | File in which to write error logs for the default server. Defaults to `/var/log/error.log` | +| `nginx_app_access_log` | File in which to write access logs for the application server. Defaults to `/var/log/app.access.log` | +| `nginx_app_error_log` | File in which to write error logs for the application server. Defaults to `/var/log/app.error.log` | +| `nginx_http_port` | The port to listen on for HTTP connections. Defaults to `80` | +| `nginx_https_port` | The port to listen on for HTTPS connections. Defaults to `443` | +| `nginx_proxy_port` | The port to forward requests to. Required variable; no default | +| `nginx_root` | The path to search for static files. Optional variable; no default | +| `nginx_conf_template` | The template to use for generating the NGINX config. See currently available [templates](templates/). Defaults to `nginx_reverse_proxy.j2`, which is used to configure NGINX as a reverse proxy | +| `nginx_conf_file` | The path to write the NGINX config to. Defaults to `/etc/nginx/nginx.conf` | +| `nginx_add_default_server` | Whether to add an additional server block for a default server that returns an empty response. Defaults to `true` | +| `nginx_ipv6_enabled` | Whether to enable support for IPv6. Defaults to `false` | + +If you would like to use SSL with NGINX, you will need to have the +certificate and key on your Ansible Controller, and may also need to set +the following variables: + +| Name | Description | +| ------------------------------- | ----------------------------------------------------------------------------------------- | +| `nginx_use_ssl` | Whether to use SSL. Defaults to `true` | +| `nginx_certs_dir` | Where to store the certificates. Defaults to `/etc/nginx/ssl` | +| `nginx_server_cert_cache` | Path to SSL certificate on the Ansible Controller. Required if using SSL; no default | +| `nginx_server_key_cache` | Path to SSL certificate on the Ansible Controller. Required if using SSL; no default | +| `nginx_ssl_cert_file` | Path to copy the SSL certificate to. Defaults to `/etc/nginx/ssl/server.cert` | +| `nginx_ssl_key_file` | Path to copy the SSL key to. Defaults to `/etc/nginx/ssl/server.key` | +| `nginx_diffie_helman_size_bits` | Bit size for OpenSSL Diffie-Hellman Parameters. Defaults to `4096` | +| `nginx_dh_params_file` | Path to write the Diffie-Hellman Parameters to. Defaults to `"/etc/nginx/ssl/dhparam.pem` | + +## Dependencies + +You will need to install the following collections before using `mirsg.infrastructure.nginx`: + +- `ansible.posix` +- `community.crypto` +- `community.general` + +## Example Playbook + +```yaml +- name: Configure nginx + hosts: all + roles: + - mirsg.infrastructure.nginx +``` diff --git a/roles/nginx/defaults/main.yml b/roles/nginx/defaults/main.yml index 0e2ff8a4..b54e653b 100644 --- a/roles/nginx/defaults/main.yml +++ b/roles/nginx/defaults/main.yml @@ -1,15 +1,26 @@ --- -nginx: # noqa: var-naming[no-role-prefix] - owner: root - group: root - log_folder: "/var/log/nginx" - http_port: 80 - https_port: 443 - certs_dir: "/etc/nginx/ssl" - dh_params_file: "/etc/nginx/ssl/dhparam.pem" - conf_file: "/etc/nginx/nginx.conf" - ssl_cert_file: "/etc/nginx/ssl/server.cert" - ssl_key_file: "/etc/nginx/ssl/server.key" +nginx_owner: root +nginx_group: root + +nginx_log_folder: /var/log/nginx +nginx_access_log: "{{ nginx_log_folder }}/access.log" +nginx_error_log: "{{ nginx_log_folder }}/error.log" +nginx_app_access_log: "{{ nginx_log_folder }}/app.access.log" +nginx_app_error_log: "{{ nginx_log_folder }}/app.error.log" + +nginx_http_port: 80 +nginx_https_port: 443 + +nginx_conf_template: nginx_reverse_proxy.j2 # check the template file for the variables it requires +nginx_conf_file: /etc/nginx/nginx.conf +nginx_add_default_server: true + +nginx_ipv6_enabled: false + +nginx_use_ssl: true +nginx_certs_dir: /etc/nginx/ssl +nginx_ssl_cert_file: /etc/nginx/ssl/server.cert +nginx_ssl_key_file: /etc/nginx/ssl/server.key # Bit size for OpenSSL Diffie-Hellman Parameters. Higher bit sizes are more # secure, but require exponentially larger times for the one-off parameter @@ -17,3 +28,4 @@ nginx: # noqa: var-naming[no-role-prefix] # are only generated once per server. # For local testing (non-production), use 2048 to speed up deployment. nginx_diffie_helman_size_bits: 4096 +nginx_dh_params_file: /etc/nginx/ssl/dhparam.pem diff --git a/roles/nginx/molecule/centos7/molecule.yml b/roles/nginx/molecule/centos7/molecule.yml new file mode 100644 index 00000000..0279dcbd --- /dev/null +++ b/roles/nginx/molecule/centos7/molecule.yml @@ -0,0 +1,35 @@ +--- +# test this scenario from the roles/provision directory with the command +# molecule --base-config ../../molecule_configs/centos7_base_config.yml test --scenario centos7 +platforms: + - name: instance + hostname: molecule.instance.local + image: ${MOLECULE_DOCKER_IMAGE:-geerlingguy/docker-centos7-ansible:latest} + required: true + command: "" + cgroupns_mode: host + privileged: true + pre_build_image: ${MOLECULE_PRE_BUILD_IMAGE:-true} + volumes: + - ./molecule-data:/storage/molecule + keep_volumes: false + groups: + - all + - molecule + - centos7 + docker_networks: + - name: molecule + ipam_config: + - subnet: 192.168.56.0/24 + gateway: 192.168.56.1 + networks: + - name: molecule + ipv4_address: 192.168.56.2 + exposed_ports: + - 80 + - 443 + - 8000 + published_ports: + - 127.0.0.1:8080:80 + etc_hosts: + molecule.instance.local: 192.168.56.2 diff --git a/roles/nginx/molecule/resources/converge.yml b/roles/nginx/molecule/resources/converge.yml new file mode 100644 index 00000000..a8449d65 --- /dev/null +++ b/roles/nginx/molecule/resources/converge.yml @@ -0,0 +1,7 @@ +--- +- name: Configure nginx as a reverse proxy + hosts: all + become: true + gather_facts: true + roles: + - role: mirsg.infrastructure.nginx diff --git a/roles/nginx/molecule/resources/files/app.py b/roles/nginx/molecule/resources/files/app.py new file mode 100644 index 00000000..5186476f --- /dev/null +++ b/roles/nginx/molecule/resources/files/app.py @@ -0,0 +1,7 @@ +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def index(): + return "