diff --git a/playbooks/group_vars/db.yml b/playbooks/group_vars/db.yml index 374377a1..8fa48d6b 100644 --- a/playbooks/group_vars/db.yml +++ b/playbooks/group_vars/db.yml @@ -37,6 +37,7 @@ postgresql_ssl_certificate: csr_common_name: "{{ db_server.host }}" certificate_filename: "{{ postgresql.base_directory }}/certs/server.crt" provider: selfsigned + selfsigned_not_after: +3650d cache_filename: "{{ database_server_certificate_cache_filename }}" # where to store the server certificate in cache firewalld_rich_rules: diff --git a/playbooks/group_vars/omero.yml b/playbooks/group_vars/omero.yml index 8c784c45..6b533d21 100644 --- a/playbooks/group_vars/omero.yml +++ b/playbooks/group_vars/omero.yml @@ -14,6 +14,7 @@ postgresql_client_ssl_certificate: csr_common_name: "{{ web_server.host }}" certificate_filename: /opt/omero/server/.postgresql/postgresql.crt provider: selfsigned + selfsigned_not_after: +3650d cache_filename: "{{ database_client_certificate_cache_filename }}" # where to store the client certificate in cache # firewalld diff --git a/playbooks/group_vars/xnat.yml b/playbooks/group_vars/xnat.yml index eb35a9fe..8ecca5b5 100644 --- a/playbooks/group_vars/xnat.yml +++ b/playbooks/group_vars/xnat.yml @@ -21,7 +21,7 @@ xnat_source: context_file_location: /usr/share/tomcat/webapps/ROOT/META-INF/context.xml # mirsg.infrastructure.tomcat -tomcat_version: 9.0.82 +tomcat_version: 9.0.97 tomcat_owner: tomcat tomcat_group: tomcat @@ -60,6 +60,7 @@ postgresql_client_ssl_certificate: csr_common_name: "{{ web_server.host }}" certificate_filename: /usr/share/tomcat/.postgresql/postgresql.crt provider: selfsigned + selfsigned_not_after: +3650d cache_filename: "{{ database_client_certificate_cache_filename }}" # where to store the client certificate in cache java: diff --git a/playbooks/molecule/resources/monitoring/inventory/host_vars/mserv.yml b/playbooks/molecule/resources/monitoring/inventory/host_vars/mserv.yml index 3b7a6549..986a87f4 100644 --- a/playbooks/molecule/resources/monitoring/inventory/host_vars/mserv.yml +++ b/playbooks/molecule/resources/monitoring/inventory/host_vars/mserv.yml @@ -9,3 +9,4 @@ monitoring_server_ssl_certificate: csr_common_name: "{{ hostvars['mserv']['hostname'] }}" certificate_filename: /etc/ssl/certs/{{ hostvars['mserv']['hostname'] }}.cert provider: selfsigned + selfsigned_not_after: +3650d diff --git a/roles/nginx/README.md b/roles/nginx/README.md index 8f38247c..0f881619 100644 --- a/roles/nginx/README.md +++ b/roles/nginx/README.md @@ -32,8 +32,8 @@ variables: | ------------------------------- | ----------------------------------------------------------------------------------------- | | `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_server_cert_cache` | Path to SSL certificates on the Ansible host. Required if using SSL; no default | +| `nginx_server_key_cache` | Path to SSL certificate on the Ansible host. 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` | diff --git a/roles/nginx/molecule/centos7/molecule.yml b/roles/nginx/molecule/centos7/molecule.yml index 0279dcbd..15b4ec4b 100644 --- a/roles/nginx/molecule/centos7/molecule.yml +++ b/roles/nginx/molecule/centos7/molecule.yml @@ -30,6 +30,6 @@ platforms: - 443 - 8000 published_ports: - - 127.0.0.1:8080:80 + - 127.0.0.1:8080:443 etc_hosts: molecule.instance.local: 192.168.56.2 diff --git a/roles/nginx/molecule/resources/inventory/group_vars/all.yml b/roles/nginx/molecule/resources/inventory/group_vars/all.yml index 018954e3..a2343cf5 100644 --- a/roles/nginx/molecule/resources/inventory/group_vars/all.yml +++ b/roles/nginx/molecule/resources/inventory/group_vars/all.yml @@ -1,6 +1,39 @@ --- +nginx_owner: root +nginx_group: root + nginx_server_name: molecule.instance.local nginx_proxy_port: 8000 nginx_diffie_helman_size_bits: 2048 nginx_root: /home/ -nginx_use_ssl: 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 +nginx_server_cert_cache: /etc/ssl/certs/server.cert +nginx_server_key_cache: /etc//ssl/certs/server.key + +nginx_old_ssl_certificate: + owner: "{{ nginx_owner }}" + group: "{{ nginx_group }}" + certificate_directory: /etc/ssl/certs + privatekey_filename: "{{ nginx_server_key_cache }}" + use_pk8: false + csr_filename: /etc/ssl/certs/server.csr" + csr_common_name: "{{ nginx_server_name }}" + certificate_filename: "{{ nginx_server_cert_cache }}" + provider: selfsigned + selfsigned_not_after: +365d + +nginx_new_ssl_certificate: + owner: "{{ nginx_owner }}" + group: "{{ nginx_group }}" + certificate_directory: "{{ nginx_certs_dir }}" + privatekey_filename: "{{ nginx_ssl_key_file }}" + use_pk8: false + csr_filename: "{{ nginx_certs_dir }}/server.csr" + csr_common_name: "{{ nginx_server_name }}" + certificate_filename: "{{ nginx_ssl_cert_file }}" + provider: selfsigned + selfsigned_not_after: +3650d diff --git a/roles/nginx/molecule/resources/inventory/group_vars/centos7.yml b/roles/nginx/molecule/resources/inventory/group_vars/centos7.yml index 8be670cc..aff12e5b 100644 --- a/roles/nginx/molecule/resources/inventory/group_vars/centos7.yml +++ b/roles/nginx/molecule/resources/inventory/group_vars/centos7.yml @@ -11,6 +11,7 @@ install_python: - libselinux-python - policycoreutils-python pip_packages: + - cryptography - gunicorn - Flask diff --git a/roles/nginx/molecule/resources/inventory/group_vars/rocky9.yml b/roles/nginx/molecule/resources/inventory/group_vars/rocky9.yml index e587b569..044f6ca3 100644 --- a/roles/nginx/molecule/resources/inventory/group_vars/rocky9.yml +++ b/roles/nginx/molecule/resources/inventory/group_vars/rocky9.yml @@ -11,6 +11,7 @@ install_python: - python3-libselinux - policycoreutils-python-utils pip_packages: + - cryptography - gunicorn - flask diff --git a/roles/nginx/molecule/resources/prepare.yml b/roles/nginx/molecule/resources/prepare.yml index 3c014205..b0542b2e 100644 --- a/roles/nginx/molecule/resources/prepare.yml +++ b/roles/nginx/molecule/resources/prepare.yml @@ -44,3 +44,21 @@ ansible.builtin.systemd: name: gunicorn state: restarted + +- name: Create SSL certificates for nginx + hosts: all + gather_facts: true + tasks: + - name: + Create SSL certificate that expires in 1 year and store in server cache + ansible.builtin.include_role: + name: mirsg.infrastructure.ssl_certificates + vars: + ssl_certificate: "{{ nginx_old_ssl_certificate }}" # noqa: var-naming[no-role-prefix] + - name: + Create SSL certificate that expires in 10 years and store in nginx + certificate directory + ansible.builtin.include_role: + name: mirsg.infrastructure.ssl_certificates + vars: + ssl_certificate: "{{ nginx_new_ssl_certificate }}" # noqa: var-naming[no-role-prefix] diff --git a/roles/nginx/molecule/resources/verify.yml b/roles/nginx/molecule/resources/verify.yml index 267189cd..d2c6fcc5 100644 --- a/roles/nginx/molecule/resources/verify.yml +++ b/roles/nginx/molecule/resources/verify.yml @@ -4,7 +4,7 @@ tasks: - name: Get server status ansible.builtin.uri: - url: http://localhost:8080 + url: https://localhost:8080 method: GET headers: Host: molecule.instance.local diff --git a/roles/nginx/molecule/rocky9/molecule.yml b/roles/nginx/molecule/rocky9/molecule.yml index 8142a715..e33a343f 100644 --- a/roles/nginx/molecule/rocky9/molecule.yml +++ b/roles/nginx/molecule/rocky9/molecule.yml @@ -31,4 +31,4 @@ platforms: - 443 - 8000 published_ports: - - 127.0.0.1:8080:80 + - 127.0.0.1:8080:443 diff --git a/roles/nginx/tasks/copy_certificates.yml b/roles/nginx/tasks/copy_certificates.yml new file mode 100644 index 00000000..9f6b8c9b --- /dev/null +++ b/roles/nginx/tasks/copy_certificates.yml @@ -0,0 +1,11 @@ +--- +- name: Copy certificate to new location + ansible.builtin.copy: + remote_src: true + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "{{ nginx_owner }}" + group: "{{ nginx_group }}" + mode: "0600" + backup: true # Preserve overwritten certificates and keys for rollback + with_items: "{{ items }}" diff --git a/roles/nginx/tasks/main.yml b/roles/nginx/tasks/main.yml index 5edb101a..263e2d8f 100644 --- a/roles/nginx/tasks/main.yml +++ b/roles/nginx/tasks/main.yml @@ -36,38 +36,8 @@ - nginx-mod-stream state: installed -- name: Ensure nginx certs directory exists - ansible.builtin.file: - path: "{{ nginx_certs_dir }}" - owner: "{{ nginx_owner }}" - group: "{{ nginx_group }}" - state: directory - mode: "0700" - when: nginx_use_ssl - -- name: Copy server certificates to nginx - ansible.builtin.copy: - remote_src: true - src: "{{ item.src }}" - dest: "{{ item.dest }}" - owner: "{{ nginx_owner }}" - group: "{{ nginx_group }}" - mode: "0600" - with_items: - - src: "{{ nginx_server_cert_cache }}" - dest: "{{ nginx_ssl_cert_file }}" - - src: "{{ nginx_server_key_cache }}" - dest: "{{ nginx_ssl_key_file }}" - notify: Reload nginx - when: nginx_use_ssl - -- name: - Generate Diffie-Hellman (DH) parameters. Number of {{ - nginx_diffie_helman_size_bits }}. - community.crypto.openssl_dhparam: - path: "{{ nginx_dh_params_file }}" - size: "{{ nginx_diffie_helman_size_bits }}" - notify: Reload nginx +- name: Copy certificates when SSL is enabled + ansible.builtin.include_tasks: ssl_enabled.yml when: nginx_use_ssl - name: Copy nginx config file diff --git a/roles/nginx/tasks/ssl_enabled.yml b/roles/nginx/tasks/ssl_enabled.yml new file mode 100644 index 00000000..5cae1270 --- /dev/null +++ b/roles/nginx/tasks/ssl_enabled.yml @@ -0,0 +1,99 @@ +--- +- name: Ensure nginx certs directory exists + ansible.builtin.file: + path: "{{ nginx_certs_dir }}" + owner: "{{ nginx_owner }}" + group: "{{ nginx_group }}" + state: directory + mode: "0700" + +- name: Stat current SSL certificate + ansible.builtin.stat: + path: "{{ nginx_ssl_cert_file }}" + register: current_cert + +- name: Stat cached SSL certificate + ansible.builtin.stat: + path: "{{ nginx_server_cert_cache }}" + register: cached_cert + +- name: Check whether the certs exist + ansible.builtin.debug: + msg: + - "Cached nginx cert exists at {{ nginx_server_cert_cache }}: {{ + cached_cert.stat.exists }}." + - "nginx cert exists at {{ nginx_ssl_cert_file }}: {{ + current_cert.stat.exists }}." + failed_when: (not cached_cert.stat.exists) and (not current_cert.stat.exists) + +- name: Get current SSL certificate info + community.crypto.x509_certificate_info: + path: "{{ nginx_ssl_cert_file }}" + when: current_cert.stat.exists + register: current_cert_info + +- name: Get cached SSL certificate info + community.crypto.x509_certificate_info: + path: "{{ nginx_server_cert_cache }}" + when: cached_cert.stat.exists + register: cached_cert_info + +- name: Copy server certificates from cache if the nginx cert doesn't exist + ansible.builtin.include_tasks: copy_certificates.yml + vars: + items: + - src: "{{ nginx_server_cert_cache }}" + dest: "{{ nginx_ssl_cert_file }}" + - src: "{{ nginx_server_key_cache }}" + dest: "{{ nginx_ssl_key_file }}" + when: + - not current_cert.stat.exists + - cached_cert.stat.exists + +- name: Copy server certificates to cache if the cache cert doesn't exist + ansible.builtin.include_tasks: copy_certificates.yml + vars: + items: + - src: "{{ nginx_ssl_cert_file }}" + dest: "{{ nginx_server_cert_cache }}" + - src: "{{ nginx_ssl_key_file }}" + dest: "{{ nginx_server_key_cache }}" + when: + - current_cert.stat.exists + - not cached_cert.stat.exists + +- name: Copy server certificates from cache if the nginx cert expires sooner + ansible.builtin.include_tasks: copy_certificates.yml + vars: + items: + - src: "{{ nginx_server_cert_cache }}" + dest: "{{ nginx_ssl_cert_file }}" + - src: "{{ nginx_server_key_cache }}" + dest: "{{ nginx_ssl_key_file }}" + when: + - current_cert.stat.exists + - cached_cert.stat.exists + - current_cert_info.not_after | to_datetime('%Y%m%d%H%M%SZ') < + cached_cert_info.not_after | to_datetime('%Y%m%d%H%M%SZ') + +- name: Copy server certificates to cache if the cache cert expires sooner + ansible.builtin.include_tasks: copy_certificates.yml + vars: + items: + - src: "{{ nginx_ssl_cert_file }}" + dest: "{{ nginx_server_cert_cache }}" + - src: "{{ nginx_ssl_key_file }}" + dest: "{{ nginx_server_key_cache }}" + when: + - current_cert.stat.exists + - cached_cert.stat.exists + - current_cert_info.not_after | to_datetime('%Y%m%d%H%M%SZ') > + cached_cert_info.not_after | to_datetime('%Y%m%d%H%M%SZ') + +- name: + Generate Diffie-Hellman (DH) parameters. Number of {{ + nginx_diffie_helman_size_bits }}. + community.crypto.openssl_dhparam: + path: "{{ nginx_dh_params_file }}" + size: "{{ nginx_diffie_helman_size_bits }}" + notify: Reload nginx diff --git a/roles/ssl_certificates/README.md b/roles/ssl_certificates/README.md index 21a50120..780f0514 100644 --- a/roles/ssl_certificates/README.md +++ b/roles/ssl_certificates/README.md @@ -86,15 +86,16 @@ First define variables for the server: ```yaml # Variables for creating a SSL certificate for a postgresql server ssl_certificate: - owner: "root" - group: "root" - certificate_directory: "/var/lib/pgsql/certs" - privatekey_filename: "/var/lib/pgsql/certs/server.key" + owner: root + group: root + certificate_directory: /var/lib/pgsql/certs + privatekey_filename: /var/lib/pgsql/certs/server.key use_pk8: false - csr_filename: "/var/lib/pgsql/server.csr" - csr_common_name: "db" - certificate_filename: "/var/lib/pgsql/server.crt" - provider: "selfsigned" + csr_filename: /var/lib/pgsql/server.csr + csr_common_name: db + certificate_filename: /var/lib/pgsql/server.crt + provider: selfsigned + selfsigned_not_after: +3650d cache_filename: "{{ lookup('env', 'HOME') }}/ansible_persistent_files/pg_certificates/db.postgresql_server.crt" @@ -108,16 +109,17 @@ client is a tomcat server: ```yaml # Variables for creating a SSL certificate for a postgresql client ssl_certificate: - owner: "root" - group: "root" - certificate_directory: "/usr/share/tomcat/.postgresql" - privatekey_filename: "/usr/share/tomcat/.postgresql/postgresql.key" + owner: root + group: root + certificate_directory: /usr/share/tomcat/.postgresql + privatekey_filename: /usr/share/tomcat/.postgresql/postgresql.key use_pk8: true - pk8_filename: "/usr/share/tomcat/.postgresql/postgresql.pk8" - csr_filename: "/usr/share/tomcat/.postgresql/postgresql.csr" + pk8_filename: /usr/share/tomcat/.postgresql/postgresql.pk8 + csr_filename: /usr/share/tomcat/.postgresql/postgresql.csr csr_common_name: "{{ web_hostname }}" - certificate_filename: "/usr/share/tomcat/.postgresql/postgresql.crt" - provider: "selfsigned" + certificate_filename: /usr/share/tomcat/.postgresql/postgresql.crt + provider: selfsigned + selfsigned_not_after: +3650d cache_filename: "{{ lookup('env', 'HOME') }}/ansible_persistent_files/pg_certificates/db.postgresql_client.crt" diff --git a/roles/ssl_certificates/tasks/main.yml b/roles/ssl_certificates/tasks/main.yml index 636e4fe2..f6cc4884 100644 --- a/roles/ssl_certificates/tasks/main.yml +++ b/roles/ssl_certificates/tasks/main.yml @@ -35,6 +35,7 @@ privatekey_path: "{{ ssl_certificate.privatekey_filename }}" csr_path: "{{ ssl_certificate.csr_filename }}" provider: "{{ ssl_certificate.provider }}" + selfsigned_not_after: "{{ ssl_certificate.selfsigned_not_after }}" mode: "0400" owner: "{{ ssl_certificate.owner }}" group: "{{ ssl_certificate.group }}" diff --git a/roles/tomcat/defaults/main.yml b/roles/tomcat/defaults/main.yml index e31ae382..d9fe1814 100644 --- a/roles/tomcat/defaults/main.yml +++ b/roles/tomcat/defaults/main.yml @@ -7,7 +7,7 @@ java_home: /usr/lib/jvm/jre java_profile_d: /etc/profile.d # mirsg.tomcat -tomcat_version: 9.0.82 +tomcat_version: 9.0.97 tomcat_owner: tomcat tomcat_group: tomcat