diff --git a/docs/releasenotes.rst b/docs/releasenotes.rst index ad4f5db43c2305571222d49f3c9c329ef7469fa3..f621c899fbb5697eeabd6c8c2ff710fc9be4a662 100644 --- a/docs/releasenotes.rst +++ b/docs/releasenotes.rst @@ -159,6 +159,11 @@ upgrade to Python 3.x, dropping support for Python 2.7. * Server now supports blocking users via `XEP-0191: Blocking Command `_. + * XMPP server certificate is checked on daily basis using the + ``prosodyctl check certs`` command. This helps catch issues where + issued certificate does not include all the necessary subject + alternative names (this has also been documented in the role + reference documentation). **Deprecations:** diff --git a/docs/rolereference.rst b/docs/rolereference.rst index 17e662b562a68ad5cf09b4877063eecc36a6e77b..fef670df547d172480d0c4d8b6debcc7cbf3312c 100644 --- a/docs/rolereference.rst +++ b/docs/rolereference.rst @@ -834,6 +834,18 @@ The role implements the following: * Sets-up the Debian backports repository and pins the ``lua-ldap`` package to it (needed for Lua 5.2 support with Prosody 0.11). * Deploys XMPP TLS private key and certificate. + + .. warning:: + The issued certificate must have multiple FQDNs listed as subject + alternative names (DNS names) for each configured domain: + + - domain itself + - ``conference.DOMAIN`` + - ``proxy.DOMAIN`` + + A daily cron job is run to validate that all certificates have + been configured and issued correctly. + * Installs Prosody. * Configures Prosody. * Configures firewall to allow incoming connections to the XMPP server. diff --git a/roles/xmpp_server/files/check_prosody_certificate.sh b/roles/xmpp_server/files/check_prosody_certificate.sh new file mode 100644 index 0000000000000000000000000000000000000000..25e73d6328d7ba90647628740641e27895ae714d --- /dev/null +++ b/roles/xmpp_server/files/check_prosody_certificate.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +if ! output=$(prosodyctl check certs); then + echo "$output" >&2 + echo + echo "[ERROR] Prosody certificate check has failed. See above for details." >&2 + echo "[INFO] To manually perform the check, run the command: prosodyctl check certs" + exit 1 +else + exit 0 +fi diff --git a/roles/xmpp_server/files/cron_check_prosody_certificate b/roles/xmpp_server/files/cron_check_prosody_certificate new file mode 100644 index 0000000000000000000000000000000000000000..57b1ea9d365330309bff248f61d73552e38b5061 --- /dev/null +++ b/roles/xmpp_server/files/cron_check_prosody_certificate @@ -0,0 +1,2 @@ +MAILTO=root +0 0 * * * prosody /usr/local/bin/check_prosody_certificate.sh diff --git a/roles/xmpp_server/molecule/default/prepare.yml b/roles/xmpp_server/molecule/default/prepare.yml index 684bfa9dcb79cb6d9562fe1d1622214a29ce0edf..f03bc08a42d34dbdb15aec37c3419fa445871850 100644 --- a/roles/xmpp_server/molecule/default/prepare.yml +++ b/roles/xmpp_server/molecule/default/prepare.yml @@ -26,11 +26,17 @@ fqdn: - parameters-mandatory - domain1 + - proxy.domain1 + - conference.domain1 - name: parameters-optional-stretch64_xmpp fqdn: - parameters-optional - domain2 + - proxy.domain2 + - conference.domain2 - domain3 + - proxy.domain3 + - conference.domain3 - name: Set-up link to generated X.509 material file: diff --git a/roles/xmpp_server/molecule/default/tests/test_default.py b/roles/xmpp_server/molecule/default/tests/test_default.py index 7d13bcf0a6fd046c18e52ed97d93cb106ad58444..7b3762b6cb4f4fd1f4367ddfc49d207c6283d949 100644 --- a/roles/xmpp_server/molecule/default/tests/test_default.py +++ b/roles/xmpp_server/molecule/default/tests/test_default.py @@ -318,6 +318,50 @@ def test_enabled_modules(host): assert enabled_modules == expected_modules +def test_certificate_configuration(host): + """ + Tests if certificates have been issued and configured correctly + for use with Prosody. Relies on Prosody's own internal check + command. + """ + + with host.sudo(): + check_certs = host.run("prosodyctl check certs") + + assert check_certs.rc == 0, check_certs.stdout + + +def test_prosody_certificate_checker_script(host): + """ + Tests if Prosody certificate checker script has been correctly + deployed. + """ + + with host.sudo(): + script = host.file("/usr/local/bin/check_prosody_certificate.sh") + + assert script.is_file + assert script.user == 'root' + assert script.group == 'root' + assert script.mode == 0o755 + + +def test_prosody_certificate_checker_crontab(host): + """ + Tests if crontab entry has been deployed for running the Prosody + certificate checker script. + """ + + crontab = host.file('/etc/cron.d/check_prosody_certificate') + + assert crontab.is_file + assert crontab.user == 'root' + assert crontab.group == 'root' + assert crontab.mode == 0o644 + assert "MAILTO=root" in crontab.content_string + assert "/usr/local/bin/check_prosody_certificate.sh" in crontab.content_string + + # @TODO: Tests which were not implemented due to lack of out-of-box tools: # # - Proxy capability. diff --git a/roles/xmpp_server/tasks/main.yml b/roles/xmpp_server/tasks/main.yml index 3d9530728e052b1c23cf9c0cb826b0fc3f2a786b..fe06afbcb612502808e474ed62403373364ecb25 100644 --- a/roles/xmpp_server/tasks/main.yml +++ b/roles/xmpp_server/tasks/main.yml @@ -95,6 +95,22 @@ group: root mode: 0644 +- name: Deploy script for validating Prosody certificate + copy: + src: "check_prosody_certificate.sh" + dest: "/usr/local/bin/check_prosody_certificate.sh" + owner: root + group: root + mode: 0755 + +- name: Set-up crontab task that runs the Prosody certificate checker script once a day + copy: + src: "cron_check_prosody_certificate" + dest: "/etc/cron.d/check_prosody_certificate" + owner: root + group: root + mode: 0644 + - name: Set-up directory for storing additional Prosody modules file: path: "/usr/local/lib/prosody/modules/" diff --git a/roles/xmpp_server/templates/prosody.cfg.lua.j2 b/roles/xmpp_server/templates/prosody.cfg.lua.j2 index 029b32dc9e0e7c53dcd7df5a6b9eaf8cf2985c47..8a2863c73e0b3e7d3d9b3e4fb6790b9cda2d0f16 100644 --- a/roles/xmpp_server/templates/prosody.cfg.lua.j2 +++ b/roles/xmpp_server/templates/prosody.cfg.lua.j2 @@ -40,26 +40,23 @@ modules_enabled = { -- For more information see http://prosody.im/doc/creating_accounts allow_registration = false; --- These are the SSL/TLS-related settings. If you don't want --- to use SSL/TLS, you may comment or remove this -s2s_ssl = { +-- Set global settings for SSL/TLS. +ssl = { key = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.key"; certificate = "/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem"; dhparam = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.dh.pem"; } +-- Configure TLS protocol and ciphers for client-to-server +-- connections (STARTTLS). c2s_ssl = { - key = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.key"; - certificate = "/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem"; - dhparam = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.dh.pem"; protocol = "{{ xmpp_server_tls_protocol }}"; ciphers = "{{ xmpp_server_tls_ciphers }}"; } +-- Configure TLS protocol and ciphers for client-to-server +-- connections (direct TLS). legacy_ssl_ssl = { - key = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.key"; - certificate = "/etc/ssl/certs/{{ ansible_fqdn }}_xmpp.pem"; - dhparam = "/etc/ssl/private/{{ ansible_fqdn }}_xmpp.dh.pem"; protocol = "{{ xmpp_server_tls_protocol }}"; ciphers = "{{ xmpp_server_tls_ciphers }}"; }