aboutsummaryrefslogtreecommitdiffstats
path: root/roles/prosody
diff options
context:
space:
mode:
authorStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:23:43 -0500
committerStonewall Jackson <stonewall@sacredheartsc.com>2023-02-04 01:52:13 -0500
commit0261e875679f1bf63c8d689da7fc7e014597885d (patch)
tree3f19cd74a0c1070944f75437f30b098d6ef2ffcb /roles/prosody
downloadselfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.tar.gz
selfhosted-0261e875679f1bf63c8d689da7fc7e014597885d.zip
initial commit
Diffstat (limited to 'roles/prosody')
-rw-r--r--roles/prosody/defaults/main.yml21
-rw-r--r--roles/prosody/files/etc/systemd/system/prosody.service.d/override.conf6
-rw-r--r--roles/prosody/handlers/main.yml4
-rw-r--r--roles/prosody/meta/main.yml16
-rw-r--r--roles/prosody/tasks/database.yml17
-rw-r--r--roles/prosody/tasks/freeipa.yml64
-rw-r--r--roles/prosody/tasks/main.yml97
-rw-r--r--roles/prosody/templates/etc/prosody/prosody.cfg.lua.j2119
-rw-r--r--roles/prosody/templates/usr/local/bin/prosody-update-roster.j256
-rw-r--r--roles/prosody/vars/main.yml38
10 files changed, 438 insertions, 0 deletions
diff --git a/roles/prosody/defaults/main.yml b/roles/prosody/defaults/main.yml
new file mode 100644
index 0000000..df7ac3b
--- /dev/null
+++ b/roles/prosody/defaults/main.yml
@@ -0,0 +1,21 @@
+prosody_admins: []
+prosody_vhosts: ['{{ email_domain }}']
+prosody_conference_vhosts: "{{ ['conference.'] | product(prosody_vhosts) | map('join') | list }}"
+prosody_user: s-prosody
+prosody_db_name: prosody
+prosody_db_host: '{{ postgresql_host }}'
+prosody_archive_expires_after: 4w
+prosody_http_port: 5280
+prosody_http_host: '{{ ansible_fqdn }}'
+prosody_sysaccount_username: prosody
+
+prosody_ldap_hosts: '{{ freeipa_hosts }}'
+prosody_access_group: role-xmpp-access
+
+prosody_upload_file_size_limit: 52428800 # 50 MB
+prosody_upload_expire_after: 604800 # 1 week
+prosody_upload_quota: 10737418240 # 10 GiB
+
+prosody_turn_secret: '{{ coturn_auth_secret }}'
+prosody_turn_host: '{{ coturn_realm }}'
+prosody_turn_port: 3478
diff --git a/roles/prosody/files/etc/systemd/system/prosody.service.d/override.conf b/roles/prosody/files/etc/systemd/system/prosody.service.d/override.conf
new file mode 100644
index 0000000..8ac7456
--- /dev/null
+++ b/roles/prosody/files/etc/systemd/system/prosody.service.d/override.conf
@@ -0,0 +1,6 @@
+[Unit]
+Wants=gssproxy.service
+After=network-online.target gssproxy.service
+
+[Service]
+Environment=GSS_USE_PROXY=yes
diff --git a/roles/prosody/handlers/main.yml b/roles/prosody/handlers/main.yml
new file mode 100644
index 0000000..3d3cbf4
--- /dev/null
+++ b/roles/prosody/handlers/main.yml
@@ -0,0 +1,4 @@
+- name: restart prosody
+ systemd:
+ name: prosody
+ state: restarted
diff --git a/roles/prosody/meta/main.yml b/roles/prosody/meta/main.yml
new file mode 100644
index 0000000..8f5b990
--- /dev/null
+++ b/roles/prosody/meta/main.yml
@@ -0,0 +1,16 @@
+dependencies:
+ - role: yum
+ yum_repositories: epel
+ tags: yum
+
+ - role: prosody_letsencrypt_proxy
+
+ - role: freeipa_system_account
+ system_account_username: '{{ prosody_sysaccount_username }}'
+ system_account_password: '{{ prosody_sysaccount_password }}'
+
+ - role: apache_vhost
+ apache_server_name: '{{ prosody_http_host }}'
+ apache_server_aliases: []
+ apache_letsencrypt: yes
+ apache_config: '{{ prosody_apache_config }}'
diff --git a/roles/prosody/tasks/database.yml b/roles/prosody/tasks/database.yml
new file mode 100644
index 0000000..675ab11
--- /dev/null
+++ b/roles/prosody/tasks/database.yml
@@ -0,0 +1,17 @@
+- name: create database
+ postgresql_db:
+ name: '{{ prosody_db_name }}'
+ state: present
+ delegate_to: '{{ postgresql_inventory_host }}'
+ become: yes
+ become_user: postgres
+
+- name: create database user
+ postgresql_user:
+ name: '{{ prosody_user }}'
+ db: '{{ prosody_db_name }}'
+ priv: ALL
+ state: present
+ delegate_to: '{{ postgresql_inventory_host }}'
+ become: yes
+ become_user: postgres
diff --git a/roles/prosody/tasks/freeipa.yml b/roles/prosody/tasks/freeipa.yml
new file mode 100644
index 0000000..caff62a
--- /dev/null
+++ b/roles/prosody/tasks/freeipa.yml
@@ -0,0 +1,64 @@
+- name: create user
+ ipauser:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ prosody_user }}'
+ loginshell: /sbin/nologin
+ homedir: '{{ prosody_data_dir }}'
+ givenname: Prosody
+ sn: Service Account
+ state: present
+ run_once: yes
+
+- name: retrieve user keytab
+ include_role:
+ name: freeipa_keytab
+ vars:
+ keytab_principal: '{{ prosody_user }}'
+ keytab_path: '{{ prosody_keytab }}'
+
+- name: configure gssproxy for kerberized postgres
+ include_role:
+ name: gssproxy_client
+ vars:
+ gssproxy_name: prosody
+ gssproxy_section: service/prosody
+ gssproxy_client_keytab: '{{ prosody_keytab }}'
+ gssproxy_cred_usage: initiate
+ gssproxy_euid: prosody
+
+- name: create systemd override directory
+ file:
+ path: /etc/systemd/system/prosody.service.d
+ state: directory
+
+- name: create systemd override file
+ copy:
+ src: etc/systemd/system/prosody.service.d/override.conf
+ dest: /etc/systemd/system/prosody.service.d/override.conf
+ register: prosody_systemd_unit
+ notify: restart prosody
+
+- name: reload systemd units
+ systemd:
+ daemon_reload: yes
+ when: prosody_systemd_unit.changed
+
+- name: create SELinux policy for prosody to access gssproxy
+ include_role:
+ name: selinux_policy
+ apply:
+ tags: selinux
+ vars:
+ selinux_policy_name: prosody_gssproxy
+ selinux_policy_te: '{{ prosody_selinux_policy_te }}'
+ tags: selinux
+
+- name: create access group
+ ipagroup:
+ ipaadmin_principal: '{{ ipa_user }}'
+ ipaadmin_password: '{{ ipa_pass }}'
+ name: '{{ prosody_access_group }}'
+ nonposix: yes
+ state: present
+ run_once: yes
diff --git a/roles/prosody/tasks/main.yml b/roles/prosody/tasks/main.yml
new file mode 100644
index 0000000..c29dd38
--- /dev/null
+++ b/roles/prosody/tasks/main.yml
@@ -0,0 +1,97 @@
+- name: install prosody
+ dnf:
+ name: '{{ prosody_packages }}'
+ state: present
+
+- name: request conference vhost certificates
+ include_role:
+ name: certbot
+ vars:
+ certificate_sans: ['{{ item }}']
+ certificate_path: '{{ prosody_certificate_dir }}/{{ item }}.crt'
+ certificate_key_path: '{{ prosody_certificate_dir }}/{{ item }}.key'
+ certificate_owner: prosody
+ certificate_hook: systemctl reload prosody
+ certificate_use_apache: yes
+ loop: '{{ prosody_conference_vhosts }}'
+
+- import_tasks: freeipa.yml
+ tags: freeipa
+
+- import_tasks: database.yml
+ tags: database
+
+- name: create module directory
+ file:
+ path: '{{ prosody_module_dir }}'
+ state: directory
+
+- name: clone module repository
+ hg:
+ repo: '{{ prosody_module_repo }}'
+ dest: '{{ prosody_module_dir }}'
+
+- name: generate configuration
+ template:
+ src: etc/prosody/prosody.cfg.lua.j2
+ dest: /etc/prosody/prosody.cfg.lua
+ owner: root
+ group: prosody
+ mode: 0640
+ notify: restart prosody
+
+- name: open firewall ports
+ firewalld:
+ permanent: yes
+ immediate: yes
+ service: '{{ item }}'
+ state: enabled
+ loop:
+ - xmpp-client
+ - xmpp-server
+ tags: firewalld
+
+- name: enable httpd_can_network_connect SELinux boolean
+ seboolean:
+ name: httpd_can_network_connect
+ state: yes
+ persistent: yes
+ tags: selinux
+
+- name: create roster file with correct permissions
+ copy:
+ content: ''
+ dest: '{{ prosody_groups_file }}'
+ owner: prosody
+ group: prosody
+ mode: 0640
+ force: no
+
+- name: generate roster script
+ template:
+ src: usr/local/bin/prosody-update-roster.j2
+ dest: /usr/local/bin/prosody-update-roster
+ mode: 0555
+
+- name: create prosody-update-roster timer
+ include_role:
+ name: systemd_timer
+ vars:
+ timer_name: prosody-update-roster
+ timer_description: Update prosody shared roster
+ timer_after: network.target
+ timer_on_calendar: daily
+ timer_exec: /usr/local/bin/prosody-update-roster
+ timer_user: prosody
+
+- name: generate shared roster
+ systemd:
+ name: prosody-update-roster.service
+ state: started
+ changed_when: no
+
+- name: start prosody
+ systemd:
+ name: prosody
+ enabled: yes
+ state: started
diff --git a/roles/prosody/templates/etc/prosody/prosody.cfg.lua.j2 b/roles/prosody/templates/etc/prosody/prosody.cfg.lua.j2
new file mode 100644
index 0000000..9a07f8e
--- /dev/null
+++ b/roles/prosody/templates/etc/prosody/prosody.cfg.lua.j2
@@ -0,0 +1,119 @@
+admins = { {% for admin in prosody_admins %}"{{ admin }}"{% if loop.last %},{% endif %}{% endfor %} }
+
+network_backend = "event"
+
+plugin_paths = { "{{ prosody_module_dir }}" }
+
+modules_enabled = {
+ -- required modules
+ "roster"; -- Allow users to have a roster. Recommended ;)
+ "saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
+ "tls"; -- Add support for secure TLS on c2s/s2s connections
+ "dialback"; -- s2s dialback support
+ "disco"; -- Service discovery
+
+ -- optional modules
+ "csi"; -- Client state indication
+ "carbons"; -- Keep multiple clients in sync
+ "pep"; -- Enables users to publish their avatar, mood, activity, playing music and more
+ "private"; -- Private XML storage (for room bookmarks, etc.)
+ "blocklist"; -- Allow users to block communications with other users
+ "vcard4"; -- User profiles (stored in PEP)
+ "vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard
+ "limits"; -- Enable bandwidth limiting for XMPP connections
+
+ "version"; -- Replies to server version requests
+ "uptime"; -- Report how long server has been running
+ "time"; -- Let others know the time here on this server
+ "ping"; -- Replies to XMPP pings with pongs
+ "mam"; -- Store messages in an archive and allow users to access it
+ "admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
+ "groups"; -- Shared roster support
+
+ -- community modules
+ "smacks"; -- Stream management / fast reconnects
+ "csi_battery_saver"; -- Mobile optimizations
+ "turn_external"; -- STUN/TURN server
+ "reload_modules"; -- Reload modules on config reload
+}
+
+reload_modules = { "groups", "tls" }
+pidfile = "/run/prosody/prosody.pid";
+
+allow_registration = false
+groups_file = "{{ prosody_groups_file }}"
+
+c2s_require_encryption = true
+s2s_require_encryption = true
+s2s_secure_auth = false
+
+-- Enable rate limits for incoming client and server connections
+limits = {
+ c2s = {
+ rate = "10kb/s";
+ };
+ s2sin = {
+ rate = "30kb/s";
+ };
+}
+
+-- Authentication
+authentication = "ldap"
+ldap_server = "{{ prosody_ldap_hosts | join(' ') }}"
+ldap_rootdn = "uid={{ prosody_sysaccount_username }},{{ freeipa_sysaccount_basedn }}"
+ldap_password = "{{ prosody_sysaccount_password }}"
+ldap_base = "{{ freeipa_user_basedn }}"
+ldap_filter = "(&(jid=$user@$host)(memberOf=cn={{ prosody_access_group }},{{ freeipa_group_basedn }}))"
+ldap_tls = true
+
+-- Storage
+storage = "sql"
+sql = {
+ driver = "PostgreSQL",
+ database = "{{ prosody_db_name }}",
+ username = "{{ prosody_user }}",
+ host = "{{ prosody_db_host }}"
+}
+
+archive_expires_after = "{{ prosody_archive_expires_after }}"
+
+-- Logging
+log = {
+ info = "*console";
+}
+
+-- Certificates
+certificates = "/etc/pki/prosody"
+
+-- HTTP
+http_ports = { {{ prosody_http_port }} }
+http_interfaces = { "127.0.0.1", "::1" }
+https_interfaces = { }
+https_ports = { }
+http_external_url = "https://{{ prosody_http_host }}/"
+https_external_url = "https://{{ prosody_http_host }}/"
+http_max_content_size = {{ prosody_upload_file_size_limit }}
+trusted_proxies = { "127.0.0.1", "::1" }
+
+Component "{{ prosody_http_host }}" "http_upload"
+
+http_upload_file_size_limit = {{ prosody_upload_file_size_limit }}
+http_upload_expire_after = {{ prosody_upload_expire_after }}
+http_upload_quota = {{ prosody_upload_quota }}
+
+-- Virtual hosts
+{% for vhost in prosody_vhosts %}
+VirtualHost "{{ vhost }}"
+disco_items = {
+ { "{{ prosody_http_host }}" },
+}
+turn_external_host = "{{ prosody_turn_host }}"
+turn_external_port = {{ prosody_turn_port }}
+turn_external_secret = "{{ prosody_turn_secret }}"
+
+{% endfor %}
+
+{% for vhost in prosody_conference_vhosts %}
+Component "{{ vhost }}" "muc"
+ modules_enabled = { "muc_mam" }
+{% endfor %}
diff --git a/roles/prosody/templates/usr/local/bin/prosody-update-roster.j2 b/roles/prosody/templates/usr/local/bin/prosody-update-roster.j2
new file mode 100644
index 0000000..680ab91
--- /dev/null
+++ b/roles/prosody/templates/usr/local/bin/prosody-update-roster.j2
@@ -0,0 +1,56 @@
+#!/usr/libexec/platform-python
+
+# Copyright (c) 2023 stonewall@sacredheartsc.com
+# MIT License https://opensource.org/licenses/MIT
+#
+# Generates a shared roster file for Prosody from the given IPA group.
+
+import os
+import sys
+import ldap
+import ldap.sasl
+import ldap.filter
+import hashlib
+import subprocess
+
+LDAP_URI = '{{ freeipa_ldap_uri }}'
+USER_BASEDN = '{{ freeipa_user_basedn }}'
+GROUP_BASEDN = '{{ freeipa_group_basedn }}'
+
+PROSODY_GROUPS_FILE = '{{ prosody_groups_file }}'
+PROSODY_ACCESS_GROUP = '{{ prosody_access_group }}'
+
+ROSTER_GROUP_NAME = 'Internal'
+
+os.environ['GSS_USE_PROXY'] = 'yes'
+conn = ldap.initialize(LDAP_URI)
+conn.protocol_version = ldap.VERSION3
+conn.sasl_interactive_bind_s('', ldap.sasl.sasl({}, 'GSSAPI'))
+
+users = conn.search_s(
+ USER_BASEDN,
+ ldap.SCOPE_SUBTREE,
+ ldap.filter.filter_format('memberOf=cn=%s,%s', [PROSODY_ACCESS_GROUP, GROUP_BASEDN]),
+ ['jid', 'displayName'])
+
+if not users:
+ exit(1)
+
+with open(PROSODY_GROUPS_FILE, 'rb') as f:
+ hash_before = hashlib.md5(f.read()).hexdigest()
+ f.close()
+
+with open(PROSODY_GROUPS_FILE, 'w') as f:
+ print(f'[{ROSTER_GROUP_NAME}]', file=f)
+ for user in users:
+ jid = user[1]['jid'][0].decode('utf-8')
+ displayName = user[1]['displayName'][0].decode('utf-8')
+ print(f'{jid}={displayName}', file=f)
+ f.close()
+
+with open(PROSODY_GROUPS_FILE, 'rb') as f:
+ hash_after = hashlib.md5(f.read()).hexdigest()
+ f.close()
+
+if hash_before != hash_after:
+ subprocess.run(['prosodyctl', 'reload'])
diff --git a/roles/prosody/vars/main.yml b/roles/prosody/vars/main.yml
new file mode 100644
index 0000000..d971fb7
--- /dev/null
+++ b/roles/prosody/vars/main.yml
@@ -0,0 +1,38 @@
+prosody_certificate_dir: /etc/pki/prosody
+prosody_module_dir: /usr/local/lib64/prosody/modules
+prosody_data_dir: /var/lib/prosody
+prosody_keytab: /var/lib/gssproxy/clients/{{ prosody_user }}.keytab
+prosody_groups_file: /etc/prosody/groups.ini
+
+prosody_module_repo: https://hg.prosody.im/prosody-modules/
+
+prosody_packages:
+ - prosody
+ - lua-dbi
+ - lua-event
+ - lua-ldap
+ - lua-sec
+ - mercurial
+
+prosody_apache_config: |
+ {{ apache_proxy_config }}
+ ProxyPass / http://127.0.0.1:{{ prosody_http_port }}/
+ ProxyPassReverse / http://127.0.0.1:{{ prosody_http_port }}/
+
+prosody_selinux_policy_te: |
+ require {
+ type prosody_t;
+ type gssproxy_t;
+ type gssproxy_var_lib_t;
+ type ldap_port_t;
+ class dir search;
+ class sock_file write;
+ class unix_stream_socket connectto;
+ class tcp_socket name_connect;
+ }
+
+ #============= prosody_t ==============
+ allow prosody_t gssproxy_var_lib_t:dir search;
+ allow prosody_t gssproxy_var_lib_t:sock_file write;
+ allow prosody_t gssproxy_t:unix_stream_socket connectto;
+ allow prosody_t ldap_port_t:tcp_socket name_connect;