From 9e8ab73c48dc353d74572f2b5b594a22a04cab06 Mon Sep 17 00:00:00 2001 From: Jakub D Date: Thu, 31 Mar 2022 15:14:16 +0200 Subject: [PATCH] Start Feature-Conduit PR --- roles/matrix-conduit/defaults/main.yml | 175 ++++++++ roles/matrix-conduit/tasks/dendrite/setup.yml | 7 + .../tasks/dendrite/setup_install.yml | 81 ++++ .../tasks/dendrite/setup_uninstall.yml | 30 ++ roles/matrix-conduit/tasks/init.yml | 5 + roles/matrix-conduit/tasks/main.yml | 42 ++ roles/matrix-conduit/tasks/register_user.yml | 25 ++ .../tasks/self_check_client_api.yml | 18 + .../tasks/self_check_federation_api.yml | 24 ++ roles/matrix-conduit/tasks/setup_dendrite.yml | 14 + .../matrix-conduit/tasks/validate_config.yml | 16 + .../templates/dendrite/dendrite.yaml.j2 | 390 ++++++++++++++++++ .../systemd/matrix-dendrite.service.j2 | 64 +++ .../matrix-dendrite-create-account.j2 | 12 + roles/matrix-conduit/vars/main.yml | 11 + 15 files changed, 914 insertions(+) create mode 100644 roles/matrix-conduit/defaults/main.yml create mode 100644 roles/matrix-conduit/tasks/dendrite/setup.yml create mode 100644 roles/matrix-conduit/tasks/dendrite/setup_install.yml create mode 100644 roles/matrix-conduit/tasks/dendrite/setup_uninstall.yml create mode 100644 roles/matrix-conduit/tasks/init.yml create mode 100644 roles/matrix-conduit/tasks/main.yml create mode 100644 roles/matrix-conduit/tasks/register_user.yml create mode 100644 roles/matrix-conduit/tasks/self_check_client_api.yml create mode 100644 roles/matrix-conduit/tasks/self_check_federation_api.yml create mode 100644 roles/matrix-conduit/tasks/setup_dendrite.yml create mode 100644 roles/matrix-conduit/tasks/validate_config.yml create mode 100644 roles/matrix-conduit/templates/dendrite/dendrite.yaml.j2 create mode 100644 roles/matrix-conduit/templates/dendrite/systemd/matrix-dendrite.service.j2 create mode 100644 roles/matrix-conduit/templates/dendrite/usr-local-bin/matrix-dendrite-create-account.j2 create mode 100644 roles/matrix-conduit/vars/main.yml diff --git a/roles/matrix-conduit/defaults/main.yml b/roles/matrix-conduit/defaults/main.yml new file mode 100644 index 000000000..19c3603f3 --- /dev/null +++ b/roles/matrix-conduit/defaults/main.yml @@ -0,0 +1,175 @@ +--- +# Dendrite is a second-generation Matrix homeserver currently in Beta +# See: https://github.com/matrix-org/dendrite + +matrix_conduit_enabled: true + +matrix_conduit_docker_image: "{{ matrix_conduit_docker_image_name_prefix }}matrixconduit/matrix-conduit:{{ matrix_conduit_docker_image_tag }}" +matrix_conduit_docker_image_name_prefix: "docker.io/" +matrix_conduit_docker_image_tag: "v0.5.1" +matrix_conduit_docker_image_force_pull: "{{ matrix_conduit_docker_image.endswith(':latest') }}" + +matrix_conduit_base_path: "{{ matrix_base_data_path }}/dendrite" +matrix_conduit_config_dir_path: "{{ matrix_conduit_base_path }}/config" +matrix_conduit_storage_path: "{{ matrix_conduit_base_path }}/storage" +matrix_conduit_media_store_path: "{{ matrix_conduit_storage_path }}/media-store" +matrix_conduit_ext_path: "{{ matrix_conduit_base_path }}/ext" + +# By default, we make Dendrite only serve HTTP (not HTTPS). +# HTTPS is usually served at the reverse-proxy side (usually via `matrix-nginx-proxy`). +# +# To enable HTTPS serving by Dendrite (directly): +# - `matrix_conduit_https_bind_port` must be set +# - `-tls-cert` and `-tls-key` must be passed to Dendrite via `matrix_conduit_process_extra_arguments` +# - the TLS certificate files must be mounted into the container using `matrix_conduit_container_additional_volumes` +matrix_conduit_http_bind_port: 8008 +matrix_conduit_https_bind_port: ~ + +# This is passed as an `-http-bind-address` flag to the Dendrite server in the container +matrix_conduit_http_bind_address: "{{ (':' + matrix_conduit_http_bind_port|string) if matrix_conduit_http_bind_port else '' }}" + +# This is passed as an `-https-bind-address` flag to the Dendrite server in the container +matrix_conduit_https_bind_address: "{{ (':' + matrix_conduit_https_bind_port|string) if matrix_conduit_https_bind_port else '' }}" + +# Controls whether the matrix-dendrite container exposes the HTTP port (tcp/{{ matrix_conduit_http_bind_port }} in the container). +# +# Takes an ":" or "" value (e.g. "127.0.0.1:8008"), or empty string to not expose. +matrix_conduit_container_http_host_bind_address: "" + +# Controls whether the matrix-dendrite container exposes the HTTPS port (tcp/{{ matrix_conduit_https_bind_port }} in the container). +# +# Takes an ":" or "" value (e.g. "127.0.0.1:8448"), or empty string to not expose. +matrix_conduit_container_https_host_bind_address: "" + +# A list of extra arguments to pass to the container (`docker run` command) +matrix_conduit_container_extra_arguments: [] + +# A list of extra arguments to pass to the container process (`dendrite-monolith` command) +# Example: +# matrix_conduit_process_extra_arguments: +# - "-tls-cert /some/path.crt" +# - "-tls-key /some/path.pem" +matrix_conduit_process_extra_arguments: [] + +# List of systemd services that matrix-dendrite.service depends on +matrix_conduit_systemd_required_services_list: ["docker.service"] + +# List of systemd services that matrix-dendrite.service wants +matrix_conduit_systemd_wanted_services_list: [] + +# Specifies which template files to use when configuring Dendrite. +# If you'd like to have your own different configuration, feel free to copy and paste +# the original files into your inventory (e.g. in `inventory/host_vars//`) +# and then change the specific host's `vars.yaml` file like this: +# matrix_conduit_template_conduit_config: "{{ playbook_dir }}/inventory/host_vars//dendrite.yaml.j2" +matrix_conduit_template_conduit_config: "{{ role_path }}/templates/dendrite/dendrite.yaml.j2" + +matrix_conduit_registration_shared_secret: '' +matrix_conduit_allow_guest_access: false + +matrix_conduit_max_file_size_bytes: 10485760 + +# Controls which HTTP header (e.g. 'X-Forwarded-For', 'X-Real-IP') to inspect to find the real remote IP address of the client. +# This is likely required if Dendrite is running behind a reverse proxy server. +matrix_conduit_sync_api_real_ip_header: '' + +# The tmpfs at /tmp needs to be large enough to handle multiple concurrent file uploads. +matrix_conduit_tmp_directory_size_mb: 500 + +# Rate limits +matrix_conduit_rate_limiting_enabled: true +matrix_conduit_rate_limiting_threshold: 5 +matrix_conduit_rate_limiting_cooloff_ms: 500 + +# Controls whether people with access to the homeserver can register by themselves. +matrix_conduit_registration_disabled: false + +# reCAPTCHA API for validating registration attempts +matrix_conduit_enable_registration_captcha: false +matrix_conduit_recaptcha_public_key: "" +matrix_conduit_recaptcha_private_key: "" + +# A list of additional "volumes" to mount in the container. +# This list gets populated dynamically based on Dendrite extensions that have been enabled. +# Contains definition objects like this: `{"src": "/outside", "dst": "/inside", "options": "rw|ro|slave|.."} +# +# Note: internally, this uses the `-v` flag for mounting the specified volumes. +# It's better (safer) to use the `--mount` flag for mounting volumes. +# To use `--mount`, specify it in `matrix_conduit_container_extra_arguments`. +# Example: `matrix_conduit_container_extra_arguments: ['--mount type=bind,src=/outside,dst=/inside,ro'] +matrix_conduit_container_additional_volumes: [] + +# A list of appservice config files (in-container filesystem paths). +# This list gets populated dynamically based on Dendrite extensions that have been enabled. +# You may wish to use this together with `matrix_conduit_container_additional_volumes` or `matrix_conduit_container_extra_arguments`. +matrix_conduit_app_service_config_files: [] + +# Enable exposure of metrics +matrix_conduit_metrics_enabled: false +matrix_conduit_metrics_username: "metrics" +matrix_conduit_metrics_password: "metrics" + +# Postgres database information +matrix_conduit_database_str: "postgresql://{{ matrix_conduit_database_user }}:{{ matrix_conduit_database_password }}@{{ matrix_conduit_database_hostname }}" +matrix_conduit_database_hostname: "matrix-postgres" +matrix_conduit_database_user: "dendrite" +matrix_conduit_database_password: "itsasecret" +matrix_conduit_naffka_database: "dendrite_naffka" +matrix_conduit_appservice_database: "dendrite_appservice" +matrix_conduit_federationsender_database: "dendrite_federationsender" +matrix_conduit_keyserver_database: "dendrite_keyserver" +matrix_conduit_mediaapi_database: "dendrite_mediaapi" +matrix_conduit_room_database: "dendrite_room" +matrix_conduit_singingkeyserver_database: "dendrite_sigingkeyserver" +matrix_conduit_syncapi_database: "dendrite_syncapi" +matrix_conduit_account_database: "dendrite_account" +matrix_conduit_device_database: "dendrite_device" +matrix_conduit_mscs_database: "dendrite_mscs" + +matrix_conduit_turn_uris: [] +matrix_conduit_turn_shared_secret: "" +matrix_conduit_turn_allow_guests: false + +# Controls whether the self-check feature should validate TLS certificates. +matrix_conduit_disable_tls_validation: false + +matrix_conduit_trusted_id_servers: + - "matrix.org" + - "vector.im" + +# Controls whether Dendrite will federate at all. +# Disable this to completely isolate your server from the rest of the Matrix network. +matrix_conduit_federation_enabled: true + +# Controls whether the self-check feature should validate SSL certificates. +matrix_conduit_self_check_validate_certificates: true + +# Default Dendrite configuration template which covers the generic use case. +# You can customize it by controlling the various variables inside it. +# +# For a more advanced customization, you can extend the default (see `matrix_conduit_configuration_extension_yaml`) +# or completely replace this variable with your own template. +matrix_conduit_configuration_yaml: "{{ lookup('template', 'templates/dendrite/dendrite.yaml.j2') }}" + +matrix_conduit_configuration_extension_yaml: | + # Your custom YAML configuration for Dendrite goes here. + # This configuration extends the default starting configuration (`matrix_conduit_configuration_yaml`). + # + # You can override individual variables from the default configuration, or introduce new ones. + # + # If you need something more special, you can take full control by + # completely redefining `matrix_conduit_configuration_yaml`. + # + # Example configuration extension follows: + # + # server_notices: + # system_mxid_localpart: notices + # system_mxid_display_name: "Server Notices" + # system_mxid_avatar_url: "mxc://server.com/oumMVlgDnLYFaPVkExemNVVZ" + # room_name: "Server Notices" + +matrix_conduit_configuration_extension: "{{ matrix_conduit_configuration_extension_yaml|from_yaml if matrix_conduit_configuration_extension_yaml|from_yaml is mapping else {} }}" + +# Holds the final Dendrite configuration (a combination of the default and its extension). +# You most likely don't need to touch this variable. Instead, see `matrix_conduit_configuration_yaml`. +matrix_conduit_configuration: "{{ matrix_conduit_configuration_yaml|from_yaml|combine(matrix_conduit_configuration_extension, recursive=True) }}" diff --git a/roles/matrix-conduit/tasks/dendrite/setup.yml b/roles/matrix-conduit/tasks/dendrite/setup.yml new file mode 100644 index 000000000..4e556cefb --- /dev/null +++ b/roles/matrix-conduit/tasks/dendrite/setup.yml @@ -0,0 +1,7 @@ +--- + +- import_tasks: "{{ role_path }}/tasks/dendrite/setup_install.yml" + when: matrix_conduit_enabled|bool + +- import_tasks: "{{ role_path }}/tasks/dendrite/setup_uninstall.yml" + when: "not matrix_conduit_enabled|bool" diff --git a/roles/matrix-conduit/tasks/dendrite/setup_install.yml b/roles/matrix-conduit/tasks/dendrite/setup_install.yml new file mode 100644 index 000000000..ba9edd28f --- /dev/null +++ b/roles/matrix-conduit/tasks/dendrite/setup_install.yml @@ -0,0 +1,81 @@ +--- +# This will throw a Permission Denied error if already mounted using fuse +- name: Check Dendrite media store path + stat: + path: "{{ matrix_conduit_media_store_path }}" + register: local_path_media_store_stat + ignore_errors: true + +# This is separate and conditional, to ensure we don't execute it +# if the path already exists or we failed to check, because it's mounted using fuse. +- name: Ensure Dendrite media store path exists + file: + path: "{{ matrix_conduit_media_store_path }}" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + when: "not local_path_media_store_stat.failed and not local_path_media_store_stat.stat.exists" + +- name: Ensure Dendrite Docker image is pulled + docker_image: + name: "{{ matrix_conduit_docker_image }}" + source: "{{ 'pull' if ansible_version.major > 2 or ansible_version.minor > 7 else omit }}" + force_source: "{{ matrix_conduit_docker_image_force_pull if ansible_version.major > 2 or ansible_version.minor >= 8 else omit }}" + force: "{{ omit if ansible_version.major > 2 or ansible_version.minor >= 8 else matrix_conduit_docker_image_force_pull }}" + register: result + retries: "{{ matrix_container_retries_count }}" + delay: "{{ matrix_container_retries_delay }}" + until: result is not failed + +- name: Check if a Dendrite signing key exists + stat: + path: "{{ matrix_conduit_config_dir_path }}/{{ matrix_server_fqn_matrix }}.signing.pem" + register: matrix_conduit_signing_key_stat + +# We do this so that the signing key would get generated. +# We don't use the `docker_container` module, because using it with `cap_drop` requires +# a very recent version, which is not available for a lot of people yet. +- name: Generate Dendrite signing key + command: | + docker run + --rm + --name=matrix-dendrite-config + --entrypoint=generate-keys + --mount type=bind,src={{ matrix_conduit_config_dir_path }},dst=/data + {{ matrix_conduit_docker_image }} --private-key=/data/{{ matrix_server_fqn_matrix }}.signing.pem + generate + when: "not matrix_conduit_signing_key_stat.stat.exists" + +- name: Ensure Dendrite server key exists + file: + path: "{{ matrix_conduit_config_dir_path }}/{{ matrix_server_fqn_matrix }}.signing.pem" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure Dendrite configuration installed + copy: + content: "{{ matrix_conduit_configuration|to_nice_yaml(indent=2, width=999999) }}" + dest: "{{ matrix_conduit_config_dir_path }}/dendrite.yaml" + mode: 0644 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + +- name: Ensure matrix-dendrite.service installed + template: + src: "{{ role_path }}/templates/dendrite/systemd/matrix-dendrite.service.j2" + dest: "{{ matrix_systemd_path }}/matrix-dendrite.service" + mode: 0644 + register: matrix_conduit_systemd_service_result + +- name: Ensure systemd reloaded after matrix-dendrite.service installation + service: + daemon_reload: true + when: "matrix_conduit_systemd_service_result.changed|bool" + +- name: Ensure matrix-dendrite-create-account script created + template: + src: "{{ role_path }}/templates/dendrite/usr-local-bin/matrix-dendrite-create-account.j2" + dest: "{{ matrix_local_bin_path }}/matrix-dendrite-create-account" + mode: 0750 diff --git a/roles/matrix-conduit/tasks/dendrite/setup_uninstall.yml b/roles/matrix-conduit/tasks/dendrite/setup_uninstall.yml new file mode 100644 index 000000000..991da5b80 --- /dev/null +++ b/roles/matrix-conduit/tasks/dendrite/setup_uninstall.yml @@ -0,0 +1,30 @@ +--- + +- name: Check existence of matrix-dendrite service + stat: + path: "{{ matrix_systemd_path }}/matrix-dendrite.service" + register: matrix_conduit_service_stat + +- name: Ensure matrix-dendrite is stopped + service: + name: matrix-dendrite + state: stopped + daemon_reload: true + register: stopping_result + when: "matrix_conduit_service_stat.stat.exists" + +- name: Ensure matrix-dendrite.service doesn't exist + file: + path: "{{ matrix_systemd_path }}/matrix-dendrite.service" + state: absent + when: "matrix_conduit_service_stat.stat.exists" + +- name: Ensure systemd reloaded after matrix-dendrite.service removal + service: + daemon_reload: true + when: "matrix_conduit_service_stat.stat.exists" + +- name: Ensure Dendrite Docker image doesn't exist + docker_image: + name: "{{ matrix_conduit_docker_image }}" + state: absent diff --git a/roles/matrix-conduit/tasks/init.yml b/roles/matrix-conduit/tasks/init.yml new file mode 100644 index 000000000..0c298962d --- /dev/null +++ b/roles/matrix-conduit/tasks/init.yml @@ -0,0 +1,5 @@ +--- + +- set_fact: + matrix_systemd_services_list: "{{ matrix_systemd_services_list + ['matrix-dendrite.service'] }}" + when: matrix_conduit_enabled|bool diff --git a/roles/matrix-conduit/tasks/main.yml b/roles/matrix-conduit/tasks/main.yml new file mode 100644 index 000000000..9885b1262 --- /dev/null +++ b/roles/matrix-conduit/tasks/main.yml @@ -0,0 +1,42 @@ +--- + +- import_tasks: "{{ role_path }}/tasks/init.yml" + tags: + - always + +- import_tasks: "{{ role_path }}/tasks/validate_config.yml" + when: run_setup|bool + tags: + - setup-all + - setup-dendrite + +- import_tasks: "{{ role_path }}/tasks/setup_dendrite.yml" + when: run_setup|bool + tags: + - setup-all + - setup-dendrite + +- import_tasks: "{{ role_path }}/tasks/register_user.yml" + when: run_conduit_register_user|bool and matrix_conduit_enabled|bool + tags: + - register-user + +- import_tasks: "{{ role_path }}/tasks/self_check_client_api.yml" + delegate_to: 127.0.0.1 + become: false + when: run_self_check|bool and matrix_conduit_enabled|bool + tags: + - self-check + +- import_tasks: "{{ role_path }}/tasks/self_check_federation_api.yml" + delegate_to: 127.0.0.1 + become: false + when: run_self_check|bool and matrix_conduit_enabled|bool + tags: + - self-check + +- name: Mark matrix-dendrite role as executed + set_fact: + matrix_conduit_role_executed: true + tags: + - always diff --git a/roles/matrix-conduit/tasks/register_user.yml b/roles/matrix-conduit/tasks/register_user.yml new file mode 100644 index 000000000..b8e3ae5eb --- /dev/null +++ b/roles/matrix-conduit/tasks/register_user.yml @@ -0,0 +1,25 @@ +--- +- name: Fail if playbook called incorrectly + fail: + msg: "The `username` variable needs to be provided to this playbook, via --extra-vars" + when: "username is not defined or username == ''" + +- name: Fail if playbook called incorrectly + fail: + msg: "The `password` variable needs to be provided to this playbook, via --extra-vars" + when: "password is not defined or password == ''" + +- name: Ensure matrix-dendrite is started + service: + name: matrix-dendrite + state: started + daemon_reload: true + register: start_result + +- name: Wait a while, so that Dendrite can manage to start + pause: + seconds: 7 + when: "start_result.changed" + +- name: Register user + command: "{{ matrix_local_bin_path }}/matrix-dendrite-create-account {{ username|quote }} {{ password|quote }}" diff --git a/roles/matrix-conduit/tasks/self_check_client_api.yml b/roles/matrix-conduit/tasks/self_check_client_api.yml new file mode 100644 index 000000000..07e7969c0 --- /dev/null +++ b/roles/matrix-conduit/tasks/self_check_client_api.yml @@ -0,0 +1,18 @@ +--- +- name: Check Matrix Client API + uri: + url: "{{ matrix_conduit_client_api_url_endpoint_public }}" + follow_redirects: none + validate_certs: "{{ matrix_conduit_self_check_validate_certificates }}" + register: result_matrix_conduit_client_api + ignore_errors: true + check_mode: false + +- name: Fail if Matrix Client API not working + fail: + msg: "Failed checking Matrix Client API is up at `{{ matrix_server_fqn_matrix }}` (checked endpoint: `{{ matrix_conduit_client_api_url_endpoint_public }}`). Is Dendrite running? Is port 443 open in your firewall? Full error: {{ result_matrix_conduit_client_api }}" + when: "(result_matrix_conduit_client_api.failed or 'json' not in result_matrix_conduit_client_api)" + +- name: Report working Matrix Client API + debug: + msg: "The Matrix Client API at `{{ matrix_server_fqn_matrix }}` (checked endpoint: `{{ matrix_conduit_client_api_url_endpoint_public }}`) is working" diff --git a/roles/matrix-conduit/tasks/self_check_federation_api.yml b/roles/matrix-conduit/tasks/self_check_federation_api.yml new file mode 100644 index 000000000..f88148763 --- /dev/null +++ b/roles/matrix-conduit/tasks/self_check_federation_api.yml @@ -0,0 +1,24 @@ +--- +- name: Check Matrix Federation API + uri: + url: "{{ matrix_conduit_federation_api_url_endpoint_public }}" + follow_redirects: none + validate_certs: "{{ matrix_conduit_self_check_validate_certificates }}" + register: result_matrix_conduit_federation_api + ignore_errors: true + check_mode: false + +- name: Fail if Matrix Federation API not working + fail: + msg: "Failed checking Matrix Federation API is up at `{{ matrix_server_fqn_matrix }}` (checked endpoint: `{{ matrix_conduit_federation_api_url_endpoint_public }}`). Is Dendrite running? Is port {{ matrix_federation_public_port }} open in your firewall? Full error: {{ result_matrix_conduit_federation_api }}" + when: "matrix_conduit_federation_enabled|bool and (result_matrix_conduit_federation_api.failed or 'json' not in result_matrix_conduit_federation_api)" + +- name: Fail if Matrix Federation API unexpectedly enabled + fail: + msg: "Matrix Federation API is up at `{{ matrix_server_fqn_matrix }}` (checked endpoint: `{{ matrix_conduit_federation_api_url_endpoint_public }}`) despite being disabled." + when: "not matrix_conduit_federation_enabled|bool and not result_matrix_conduit_federation_api.failed" + +- name: Report working Matrix Federation API + debug: + msg: "The Matrix Federation API at `{{ matrix_server_fqn_matrix }}` (checked endpoint: `{{ matrix_conduit_federation_api_url_endpoint_public }}`) is working" + when: "matrix_conduit_federation_enabled|bool" diff --git a/roles/matrix-conduit/tasks/setup_dendrite.yml b/roles/matrix-conduit/tasks/setup_dendrite.yml new file mode 100644 index 000000000..6559bbe7a --- /dev/null +++ b/roles/matrix-conduit/tasks/setup_dendrite.yml @@ -0,0 +1,14 @@ +--- +- name: Ensure Dendrite paths exist + file: + path: "{{ item.path }}" + state: directory + mode: 0750 + owner: "{{ matrix_user_username }}" + group: "{{ matrix_user_groupname }}" + with_items: + - {path: "{{ matrix_conduit_config_dir_path }}", when: true} + - {path: "{{ matrix_conduit_ext_path }}", when: true} + when: "matrix_conduit_enabled|bool and item.when" + +- import_tasks: "{{ role_path }}/tasks/dendrite/setup.yml" diff --git a/roles/matrix-conduit/tasks/validate_config.yml b/roles/matrix-conduit/tasks/validate_config.yml new file mode 100644 index 000000000..150a44f15 --- /dev/null +++ b/roles/matrix-conduit/tasks/validate_config.yml @@ -0,0 +1,16 @@ +--- +- name: Fail if required Dendrite settings not defined + fail: + msg: >- + You need to define a required configuration setting (`{{ item }}`) for using Dendrite. + when: "vars[item] == ''" + with_items: + - "matrix_conduit_registration_shared_secret" + +- name: (Deprecation) Catch and report renamed settings + fail: + msg: >- + Your configuration contains a variable, which now has a different name. + Please change your configuration to rename the variable (`{{ item.old }}` -> `{{ item.new }}`). + when: "item.old in vars" + with_items: [] diff --git a/roles/matrix-conduit/templates/dendrite/dendrite.yaml.j2 b/roles/matrix-conduit/templates/dendrite/dendrite.yaml.j2 new file mode 100644 index 000000000..78c88721c --- /dev/null +++ b/roles/matrix-conduit/templates/dendrite/dendrite.yaml.j2 @@ -0,0 +1,390 @@ +# This is the Dendrite configuration file. +# +# The configuration is split up into sections - each Dendrite component has a +# configuration section, in addition to the "global" section which applies to +# all components. +# +# At a minimum, to get started, you will need to update the settings in the +# "global" section for your deployment, and you will need to check that the +# database "connection_string" line in each component section is correct. +# +# Each component with a "database" section can accept the following formats +# for "connection_string": +# SQLite: file:filename.db +# file:///path/to/filename.db +# PostgreSQL: postgresql://user:pass@hostname/database?params=... +# +# SQLite is embedded into Dendrite and therefore no further prerequisites are +# needed for the database when using SQLite mode. However, performance with +# PostgreSQL is significantly better and recommended for multi-user deployments. +# SQLite is typically around 20-30% slower than PostgreSQL when tested with a +# small number of users and likely will perform worse still with a higher volume +# of users. +# +# The "max_open_conns" and "max_idle_conns" settings configure the maximum +# number of open/idle database connections. The value 0 will use the database +# engine default, and a negative value will use unlimited connections. The +# "conn_max_lifetime" option controls the maximum length of time a database +# connection can be idle in seconds - a negative value is unlimited. + +# The version of the configuration file. +version: 1 + +# Global Matrix configuration. This configuration applies to all components. +global: + # The domain name of this homeserver. + server_name: {{ matrix_domain|to_json }} + + # The path to the signing private key file, used to sign requests and events. + # Note that this is NOT the same private key as used for TLS! To generate a + # signing key, use "./bin/generate-keys --private-key matrix_key.pem". + private_key: "/data/{{ matrix_server_fqn_matrix }}.signing.pem" + + # The paths and expiry timestamps (as a UNIX timestamp in millisecond precision) + # to old signing private keys that were formerly in use on this domain. These + # keys will not be used for federation request or event signing, but will be + # provided to any other homeserver that asks when trying to verify old events. + # old_private_keys: + # - private_key: old_matrix_key.pem + # expired_at: 1601024554498 + + # How long a remote server can cache our server signing key before requesting it + # again. Increasing this number will reduce the number of requests made by other + # servers for our key but increases the period that a compromised key will be + # considered valid by other homeservers. + key_validity_period: 168h0m0s + + # The server name to delegate server-server communications to, with optional port + # e.g. localhost:443 + well_known_server_name: "" + + # Lists of domains that the server will trust as identity servers to verify third + # party identifiers such as phone numbers and email addresses. + trusted_third_party_id_servers: {{ matrix_conduit_trusted_id_servers|to_json }} + + # Disables federation. Dendrite will not be able to make any outbound HTTP requests + # to other servers and the federation API will not be exposed. + disable_federation: {{ (not matrix_conduit_federation_enabled)|to_json }} + + # Configuration for Kafka/Naffka. + kafka: + # List of Kafka broker addresses to connect to. This is not needed if using + # Naffka in monolith mode. + addresses: [] + + # The prefix to use for Kafka topic names for this homeserver. Change this only if + # you are running more than one Dendrite homeserver on the same Kafka deployment. + topic_prefix: Dendrite + + # Whether to use Naffka instead of Kafka. This is only available in monolith + # mode, but means that you can run a single-process server without requiring + # Kafka. + use_naffka: true + + # The max size a Kafka message is allowed to use. + # You only need to change this value, if you encounter issues with too large messages. + # Must be less than/equal to "max.message.bytes" configured in Kafka. + # Defaults to 8388608 bytes. + # max_message_bytes: 8388608 + + # Naffka database options. Not required when using Kafka. + naffka_database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_naffka_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # Configuration for Prometheus metric collection. + metrics: + # Whether or not Prometheus metrics are enabled. + enabled: {{ matrix_conduit_metrics_enabled|to_json }} + + # HTTP basic authentication to protect access to monitoring. + basic_auth: + username: {{ matrix_conduit_metrics_username|to_json }} + password: {{ matrix_conduit_metrics_password|to_json }} + + # DNS cache options. The DNS cache may reduce the load on DNS servers + # if there is no local caching resolver available for use. + dns_cache: + # Whether or not the DNS cache is enabled. + enabled: false + + # Maximum number of entries to hold in the DNS cache, and + # for how long those items should be considered valid in seconds. + cache_size: 256 + cache_lifetime: "5m" # 5minutes; see https://pkg.go.dev/time@master#ParseDuration for more + +# Configuration for the Appservice API. +app_service_api: + internal_api: + listen: http://0.0.0.0:7777 + connect: http://appservice_api:7777 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_appservice_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # Disable the validation of TLS certificates of appservices. This is + # not recommended in production since it may allow appservice traffic + # to be sent to an unverified endpoint. + disable_tls_validation: false + + # Appservice configuration files to load into this homeserver. + config_files: {{ matrix_conduit_app_service_config_files|to_json }} + +# Configuration for the Client API. +client_api: + internal_api: + listen: http://0.0.0.0:7771 + connect: http://client_api:7771 + external_api: + listen: http://0.0.0.0:8071 + + # Prevents new users from being able to register on this homeserver, except when + # using the registration shared secret below. + registration_disabled: {{ matrix_conduit_registration_disabled|to_json }} + + # If set, allows registration by anyone who knows the shared secret, regardless of + # whether registration is otherwise disabled. + registration_shared_secret: {{ matrix_conduit_registration_shared_secret|string|to_json }} + + # Whether to require reCAPTCHA for registration. + enable_registration_captcha: {{ matrix_conduit_enable_registration_captcha|to_json }} + + # Settings for ReCAPTCHA. + recaptcha_public_key: {{ matrix_conduit_recaptcha_public_key|to_json }} + recaptcha_private_key: {{ matrix_conduit_recaptcha_private_key|to_json }} + recaptcha_bypass_secret: "" + recaptcha_siteverify_api: "" + + # TURN server information that this homeserver should send to clients. + turn: + turn_user_lifetime: "" + turn_uris: {{ matrix_conduit_turn_uris|to_json }} + turn_shared_secret: {{ matrix_conduit_turn_shared_secret|to_json }} + turn_username: "" + turn_password: "" + + # Settings for rate-limited endpoints. Rate limiting will kick in after the + # threshold number of "slots" have been taken by requests from a specific + # host. Each "slot" will be released after the cooloff time in milliseconds. + rate_limiting: + enabled: {{ matrix_conduit_rate_limiting_enabled|to_json }} + threshold: {{ matrix_conduit_rate_limiting_threshold|to_json }} + cooloff_ms: {{ matrix_conduit_rate_limiting_cooloff_ms|to_json }} + +# Configuration for the EDU server. +edu_server: + internal_api: + listen: http://0.0.0.0:7778 + connect: http://edu_server:7778 + +# Configuration for the Federation API. +federation_api: + internal_api: + listen: http://0.0.0.0:7772 + connect: http://federation_api:7772 + external_api: + listen: http://0.0.0.0:8072 + + # List of paths to X.509 certificates to be used by the external federation listeners. + # These certificates will be used to calculate the TLS fingerprints and other servers + # will expect the certificate to match these fingerprints. Certificates must be in PEM + # format. + federation_certificates: [] + +# Configuration for the Federation Sender. +federation_sender: + internal_api: + listen: http://0.0.0.0:7775 + connect: http://federation_sender:7775 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_federationsender_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # How many times we will try to resend a failed transaction to a specific server. The + # backoff is 2**x seconds, so 1 = 2 seconds, 2 = 4 seconds, 3 = 8 seconds etc. + send_max_retries: 16 + + # Disable the validation of TLS certificates of remote federated homeservers. Do not + # enable this option in production as it presents a security risk! + disable_tls_validation: {{ matrix_conduit_disable_tls_validation|to_json }} + + # Use the following proxy server for outbound federation traffic. + proxy_outbound: + enabled: false + protocol: http + host: localhost + port: 8080 + +# Configuration for the Key Server (for end-to-end encryption). +key_server: + internal_api: + listen: http://0.0.0.0:7779 + connect: http://key_server:7779 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_keyserver_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + +# Configuration for the Media API. +media_api: + internal_api: + listen: http://0.0.0.0:7774 + connect: http://media_api:7774 + external_api: + listen: http://0.0.0.0:8074 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_mediaapi_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # Storage path for uploaded media. May be relative or absolute. + base_path: "/matrix-media-store-parent/{{ matrix_conduit_media_store_directory_name }}" + + # The maximum allowed file size (in bytes) for media uploads to this homeserver + # (0 = unlimited). If using a reverse proxy, ensure it allows requests at + # least this large (e.g. client_max_body_size in nginx.) + max_file_size_bytes: {{ matrix_conduit_max_file_size_bytes|to_json }} + + # Whether to dynamically generate thumbnails if needed. + dynamic_thumbnails: false + + # The maximum number of simultaneous thumbnail generators to run. + max_thumbnail_generators: 10 + + # A list of thumbnail sizes to be generated for media content. + thumbnail_sizes: + - width: 32 + height: 32 + method: crop + - width: 96 + height: 96 + method: crop + - width: 640 + height: 480 + method: scale + +# Configuration for experimental MSC's +mscs: + # A list of enabled MSC's + # Currently valid values are: + # - msc2836 (Threading, see https://github.com/matrix-org/matrix-doc/pull/2836) + # - msc2946 (Spaces Summary, see https://github.com/matrix-org/matrix-doc/pull/2946) + mscs: [] + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_mscs_database }}?sslmode=disable + max_open_conns: 5 + max_idle_conns: 2 + conn_max_lifetime: -1 + +# Configuration for the Room Server. +room_server: + internal_api: + listen: http://0.0.0.0:7770 + connect: http://room_server:7770 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_room_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + +# Configuration for the Signing Key Server (for server signing keys). +signing_key_server: + internal_api: + listen: http://0.0.0.0:7780 + connect: http://signing_key_server:7780 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_singingkeyserver_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # Perspective keyservers to use as a backup when direct key fetches fail. This may + # be required to satisfy key requests for servers that are no longer online when + # joining some rooms. + key_perspectives: + - server_name: matrix.org + keys: + - key_id: ed25519:auto + public_key: Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw + - key_id: ed25519:a_RXGa + public_key: l8Hft5qXKn1vfHrg3p4+W8gELQVo8N13JkluMfmn2sQ + + # This option will control whether Dendrite will prefer to look up keys directly + # or whether it should try perspective servers first, using direct fetches as a + # last resort. + prefer_direct_fetch: false + +# Configuration for the Sync API. +sync_api: + internal_api: + listen: http://0.0.0.0:7773 + connect: http://sync_api:7773 + external_api: + listen: http://0.0.0.0:8073 + database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_syncapi_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + + # This option controls which HTTP header to inspect to find the real remote IP + # address of the client. This is likely required if Dendrite is running behind + # a reverse proxy server. + # real_ip_header: X-Real-IP + real_ip_header: {{ matrix_conduit_sync_api_real_ip_header|to_json }} + +# Configuration for the User API. +user_api: + # The cost when hashing passwords on registration/login. Default: 10. Min: 4, Max: 31 + # See https://pkg.go.dev/golang.org/x/crypto/bcrypt for more information. + # Setting this lower makes registration/login consume less CPU resources at the cost of security + # should the database be compromised. Setting this higher makes registration/login consume more + # CPU resources but makes it harder to brute force password hashes. + # This value can be low if performing tests or on embedded Dendrite instances (e.g WASM builds) + # bcrypt_cost: 10 + internal_api: + listen: http://0.0.0.0:7781 + connect: http://user_api:7781 + account_database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_account_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + device_database: + connection_string: {{ matrix_conduit_database_str }}/{{ matrix_conduit_device_database }}?sslmode=disable + max_open_conns: 10 + max_idle_conns: 2 + conn_max_lifetime: -1 + # The length of time that a token issued for a relying party from + # /_matrix/client/r0/user/{userId}/openid/request_token endpoint + # is considered to be valid in milliseconds. + # The default lifetime is 3600000ms (60 minutes). + # openid_token_lifetime_ms: 3600000 + +# Configuration for Opentracing. +# See https://github.com/matrix-org/dendrite/tree/master/docs/tracing for information on +# how this works and how to set it up. +tracing: + enabled: false + jaeger: + serviceName: "" + disabled: false + rpc_metrics: false + tags: [] + sampler: null + reporter: null + headers: null + baggage_restrictions: null + throttler: null + +# Logging configuration, in addition to the standard logging that is sent to +# stdout by Dendrite. +logging: [] diff --git a/roles/matrix-conduit/templates/dendrite/systemd/matrix-dendrite.service.j2 b/roles/matrix-conduit/templates/dendrite/systemd/matrix-dendrite.service.j2 new file mode 100644 index 000000000..368150071 --- /dev/null +++ b/roles/matrix-conduit/templates/dendrite/systemd/matrix-dendrite.service.j2 @@ -0,0 +1,64 @@ +#jinja2: lstrip_blocks: "True" +[Unit] +Description=Dendrite server +{% for service in matrix_conduit_systemd_required_services_list %} +Requires={{ service }} +After={{ service }} +{% endfor %} +{% for service in matrix_conduit_systemd_wanted_services_list %} +Wants={{ service }} +{% endfor %} +DefaultDependencies=no + +[Service] +Type=simple +Environment="HOME={{ matrix_systemd_unit_home_path }}" +ExecStartPre=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} kill matrix-dendrite 2>/dev/null' +ExecStartPre=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} rm matrix-dendrite 2>/dev/null' + +{% if 'matrix-postgres.service' in matrix_conduit_systemd_required_services_list %} +# Dendrite is too quick to start in relation to its matrix-postgres dependency. +# Delay Dendrite startup to avoid failing with: "failed to connect to accounts db" ("pq: the database system is starting up"). +ExecStartPre={{ matrix_host_command_sleep }} 5 +{% endif %} + +ExecStart={{ matrix_host_command_docker }} run --rm --name matrix-dendrite \ + --log-driver=none \ + --user={{ matrix_user_uid }}:{{ matrix_user_gid }} \ + --cap-drop=ALL \ + --read-only \ + --tmpfs=/tmp:rw,noexec,nosuid,size={{ matrix_conduit_tmp_directory_size_mb }}m \ + --network={{ matrix_docker_network }} \ + {% if matrix_conduit_container_http_host_bind_address and matrix_conduit_http_bind_port %} + -p {{ matrix_conduit_container_http_host_bind_address }}:{{ matrix_conduit_http_bind_port }} \ + {% endif %} + {% if matrix_conduit_container_https_host_bind_address and matrix_conduit_https_bind_port %} + -p {{ matrix_conduit_container_https_host_bind_address }}:{{ matrix_conduit_https_bind_port }} \ + {% endif %} + --mount type=bind,src={{ matrix_conduit_config_dir_path }},dst=/data,ro \ + --mount type=bind,src={{ matrix_conduit_storage_path }},dst=/matrix-media-store-parent,bind-propagation=slave \ + {% for volume in matrix_conduit_container_additional_volumes %} + -v {{ volume.src }}:{{ volume.dst }}:{{ volume.options }} \ + {% endfor %} + {% for arg in matrix_conduit_container_extra_arguments %} + {{ arg }} \ + {% endfor %} + {{ matrix_conduit_docker_image }} \ + -config /data/dendrite.yaml \ + {% if matrix_conduit_http_bind_address %} + -http-bind-address {{ matrix_conduit_http_bind_address }} + {% endif %} + {% if matrix_conduit_https_bind_address %} + -https-bind-address {{ matrix_conduit_https_bind_address }} + {% endif %} + {{ matrix_conduit_process_extra_arguments|join(' ') }} + +ExecStop=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} kill matrix-dendrite 2>/dev/null' +ExecStop=-{{ matrix_host_command_sh }} -c '{{ matrix_host_command_docker }} rm matrix-dendrite 2>/dev/null' +ExecReload={{ matrix_host_command_docker }} exec matrix-dendrite /bin/sh -c 'kill -HUP 1' +Restart=always +RestartSec=30 +SyslogIdentifier=matrix-dendrite + +[Install] +WantedBy=multi-user.target diff --git a/roles/matrix-conduit/templates/dendrite/usr-local-bin/matrix-dendrite-create-account.j2 b/roles/matrix-conduit/templates/dendrite/usr-local-bin/matrix-dendrite-create-account.j2 new file mode 100644 index 000000000..5332b964d --- /dev/null +++ b/roles/matrix-conduit/templates/dendrite/usr-local-bin/matrix-dendrite-create-account.j2 @@ -0,0 +1,12 @@ +#jinja2: lstrip_blocks: "True" +#!/bin/bash + +if [ $# -ne 2 ]; then + echo "Usage: "$0" " + exit 1 +fi + +user=$1 +password=$2 + +docker exec matrix-dendrite create-account -config /data/dendrite.yaml -username "$user" -password "$password" diff --git a/roles/matrix-conduit/vars/main.yml b/roles/matrix-conduit/vars/main.yml new file mode 100644 index 000000000..f140d4b75 --- /dev/null +++ b/roles/matrix-conduit/vars/main.yml @@ -0,0 +1,11 @@ +--- +matrix_conduit_client_api_url_endpoint_public: "https://{{ matrix_server_fqn_matrix }}/_matrix/client/versions" +matrix_conduit_federation_api_url_endpoint_public: "https://{{ matrix_server_fqn_matrix }}:{{ matrix_federation_public_port }}/_matrix/federation/v1/version" + +# Tells whether this role had executed or not. Toggled to `true` during runtime. +matrix_conduit_role_executed: false + +matrix_conduit_media_store_parent_path: "{{ matrix_conduit_media_store_path|dirname }}" +matrix_conduit_media_store_directory_name: "{{ matrix_conduit_media_store_path|basename }}" + +matrix_conduit_signing_key_file_name: "{{ matrix_conduit_signing_key|basename }}"