Matrix synapse

De Wiki doc

Révision datée du 24 mars 2024 à 13:17 par Ycharbi (discussion | contributions) (Ajout de la section "Réinitialisation de mot de passe")
(diff) ← Version précédente | Voir la version actuelle (diff) | Version suivante → (diff)

EN CHANTIER

Article en cours d'écriture et/ou de test. Certains éléments peuvent être incomplets et mener à un résultat non fonctionnel.
Merci de ne pas rager.

Synapse est une implémentation serveur libre (licence Apache 2.0) du protocole Matrix écrit en Python. Le projet, initié en 2014, est maintenu par la fondation Matrix.org et passe en version stable (1.0.0) en 2019. Il est disponible dans les dépôts Bullseye-Backports et Testing de Debian.

Il permet la communication électronique textuelle, orale et vidéo entre plusieurs interlocuteurs au travers de réseaux IP. Il propose en outre la possibilité d'envoyer des fichiers et de partager les écrans des correspondants. Une attention toute particulière est porté sur la sécurité des échanges avec un système de chiffrement de bout en bout obligatoire, tant entre clients (pair à pair) que lors de transactions avec le serveur (client/serveur).

Il est nécessaire de permettre la communication vers les ports suivants :

  • Fédération Synapse : 8448 TCP
  • TURN : 3478 TCP/UDP

Service Synapse

Installation

Ajout des dépôts Backports pour Debian 11

echo "deb http://ftp2.fr.debian.org/debian bullseye-backports main" >> /etc/apt/sources.list
apt update
apt install --no-install-recommends -t bullseye-backports matrix-synapse

La réponse aux questions n'a pas d'importance car les fichiers de configuration seront re-générés plus loin.

Configuration

Le domaine utilisé pour l'exemple est le suivant

export DNS_SYNAPSE=synapse.exemple.fr

Génération des fichiers configuration et de la clé de signature

synapse_generate_config --server-name ${DNS_SYNAPSE} --config-dir /etc/matrix-synapse --data-dir /etc/matrix-synapse/ --report-stats no --generate-secrets -o /etc/matrix-synapse/homeserver.yaml
synapse_generate_log_config -o /etc/matrix-synapse/${DNS_SYNAPSE}.log.config
synapse_generate_signing_key -o /etc/matrix-synapse/${DNS_SYNAPSE}.signing.key

echo 'report_stats: false' > /etc/matrix-synapse/conf.d/report_stats.yaml
echo "server_name: \"${DNS_SYNAPSE}\"" > /etc/matrix-synapse/conf.d/server_name.yaml

Écouter les requêtes clientes sur toutes les adresses IP du serveur

sed -i "s/bind_addresses: \[.*\]/bind_addresses: ['0.0.0.0']/g" /etc/matrix-synapse/homeserver.yaml

Redémarrer le service

systemctl restart matrix-synapse.service

Vous devriez voir un port 8008 TCP en écoute avec un ss -ltn. Celui-ci permet aux outils d'administrations d'utiliser les API de Synapse pour interagir avec lui.

Gestion des utilisateurs

Actuellement, seule la création d'un utilisateur est possible avec les outils fournis. Leur suppression ou modification (ou même leur listage) n'est pas supporté (oui c'est aberrant). Ce sujet est traité dans ce ticket.

La syntaxe d'un utilisateurs dans les différents clients Matrix est @michel:synapse.exemple.fr. Ceci est utile pour en ajouter comme contact depuis un logiciel client (pourquoi faire simple ?).

Création d'un utilisateur

synapse_register_new_matrix_user http://127.0.0.1:8008 -c /etc/matrix-synapse/homeserver.yaml

Source de la section

Service TURN

Dans la mesure où le vrai monde est peuplé de NAT à profusion et qu'aucun protocole de communication en temps réel ne sais gérer cette situation correctement (la raison m'échappe toujours...), il est indispensable d'employer un service mitigeant cette contrainte. Ceci est le rôle des protocoles TURN/STUN implémenté dans le logiciel Coturn.

Installation

Le paquet est disponible dans les dépôts Sable

apt install --no-install-recommends coturn

Configuration

Les informations spécifiques à l'instance de cette documentations seront les suivantes

export DNS_COTURN=turn.exemple.fr
export SECRET_COTURN=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1)
export IP_EXTERNE=$(wget -qO - ifconfig.co)
export IP_INTERNE=192.168.0.100

Le fichier de configuration du service se composera comme suit

cat << _EOF_ > /etc/turnserver.conf
use-auth-secret
static-auth-secret=${SECRET_COTURN}
realm=${DNS_COTURN}

# Le trafic VoIP est entièrement UDP. Il n'y a aucune raison de laisser les utilisateurs se connecter à des points d'extrémité TCP arbitraires via le relais
no-tcp-relay

# Ne laissez pas le relais essayer de se connecter à des plages d'adresses IP privées au sein de votre réseau (s'il y en a)
# Étant donné que le serveur tournant est probablement derrière votre pare-feu, n'oubliez pas d'inclure également toutes les adresses IP publiques privilégiées
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=172.16.0.0-172.31.255.255

# À recommandé, blocage de pairs locaux supplémentaires, afin de limiter l'accès externe aux services internes
# https://www.rtcsec.com/article/slack-webrtc-turn-compromise-and-bug-bounty/#how-to-fix-an-open-turn-relay-to-address-this-vulnerability
no-multicast-peers
denied-peer-ip=0.0.0.0-0.255.255.255
denied-peer-ip=100.64.0.0-100.127.255.255
denied-peer-ip=127.0.0.0-127.255.255.255
denied-peer-ip=169.254.0.0-169.254.255.255
denied-peer-ip=192.0.0.0-192.0.0.255
denied-peer-ip=192.0.2.0-192.0.2.255
denied-peer-ip=192.88.99.0-192.88.99.255
denied-peer-ip=198.18.0.0-198.19.255.255
denied-peer-ip=198.51.100.0-198.51.100.255
denied-peer-ip=203.0.113.0-203.0.113.255
denied-peer-ip=240.0.0.0-255.255.255.255

# Cas particulier : le serveur TURN lui-même pour que les flux client->TURN->TURN->client fonctionnent
# Il doit s'agir de l'une des adresses IP d'écoute du serveur TURN
allowed-peer-ip=${IP_INTERNE}

# Examinez si vous souhaitez limiter le quota de flux relayés par utilisateur (ou total) pour éviter les risques de DoS
user-quota=12 # 4 flux par appel vidéo, donc 12 flux = 3 appels relayés simultanés par utilisateur
total-quota=1200

# Certificats TLS, y compris les certificats intermédiaires
# Pour les certificats Let's Encrypt, utilisez 'fullchain.pem' ici
cert=/srv/tls/corturn.pem

# Fichier TLS de clé privée
pkey=/srv/tls/corturn.key

# Assurez-vous que les lignes de configuration qui désactivent TLS/DTLS sont commentées ou supprimées.
#no-tls
#no-dtls

external-ip=${IP_EXTERNE}
listening-ip=${IP_INTERNE}
_EOF_

Support du TLS

Créer le répertoire d'accueil des éléments de chiffrement

mkdir /srv/tls

Ces éléments peuvent être issus d'une autorité de certification publique comme Letsencrypt (mettre la clé et le certificat chaînés) ou privée, via OpenSSL par exemple.

chown -R root:root /srv/tls
chmod 500 /srv/tls
chmod 400 /srv/tls/*

Redémarrer le service

systemctl restart coturn.service

Le service écoute sur le port 3478 TCP/UDP.

Il est à présent possible de configurer Synapse afin qu'il informe les clients d'utiliser notre service TURN lors de l'établissement des communications pair à pair entre eux.

cat << _EOF_ >> /etc/matrix-synapse/homeserver.yaml

turn_uris: [ "turn:${DNS_COTURN}?transport=udp", "turn:${DNS_COTURN}?transport=tcp" ]
turn_shared_secret: "${SECRET_COTURN}"
turn_user_lifetime: 86400000
turn_allow_guests: True
_EOF_
systemctl restart matrix-synapse.service

Enregistrement DNS

Cette section est totalement facultative et n'apporte rien. Il existe peut-être une configuration de Synapse permettant de trouver automatiquement le serveur TURN via DNS...

Enregistrements DNS SRV (à ajouter dans la configuration de votre zone)

_stun._udp 10800 IN SRV 0 5 3478 exemple.fr.
_turn._udp 10800 IN SRV 0 5 3478 exemple.fr.

Il est possible de requêter le serveur de noms sur ces champs précis via les commandes suivantes

dig +short _stun._udp._tcp 10800 IN SRV 0 5 3478 exemple.fr.
dig +short _turn._udp._tcp 10800 IN SRV 0 5 3478 exemple.fr.

Test de fonctionnement

Voici une méthode permettant de tester le fonctionnement du service en ligne de commande. Elle peut aider à deceler des problèmes simplement.

turnutils_uclient -p 3478 -W <CLÉ_SERVEUR_TURN> -v -y turn.exemple.fr

Source de la section

Client WEB Element

Element est un client WEB pour Matrix. Anciennement connu sous le nom de Riot, il existe aussi sous forme d'application IOS et Android.

Installation

N'étant pas dans les dépôts Debian, nous utiliserons la version Git

apt install --no-install-recommends apache2

wget https://github.com/vector-im/element-web/releases/download/v1.10.14/element-v1.10.14.tar.gz -P /tmp

tar xf /tmp/element-v1.10.14.tar.gz -C /var/www/
ln -s /var/www/element-v1.10.14/ /var/www/element
chown -R www-data: /var/www/element*

Configuration

L'hôte virtuel d'Apache doit pointer vers le programme

cat << '_EOF_' > /etc/apache2/sites-available/element.conf
<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/element
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
_EOF_

Désactivation de l'hôte virtuel par défaut et activation du nouveau

a2dissite 000-default.conf
a2ensite element.conf

Le domaine utilisé sera le suivant

export DNS_ELEMENT=element.exemple.fr

La configuration de notre instance sera celle-ci

cat << _EOF_ > /var/www/element/config.json
{
    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://${DNS_SYNAPSE}",
            "server_name": "${DNS_SYNAPSE}"
        },
        "m.identity_server": {
            "base_url": "https://vector.im"
        }
    },
    "disable_custom_urls": false,
    "disable_guests": false,
    "disable_login_language_selector": false,
    "disable_3pid_login": false,
    "brand": "Element",
    "bug_report_endpoint_url": "https://element.io/bugreports/submit",
    "uisi_autorageshake_app": "element-auto-uisi",
    "default_country_code": "FR",
    "show_labs_settings": false,
    "features": { },
    "default_federate": false,
    "default_theme": "light",
    "enable_presence_by_hs_url": {
        "https://matrix.org": false,
        "https://matrix-client.matrix.org": false
    },
    "setting_defaults": {
        "breadcrumbs": true
    },
   "features": {
      "feature_you_want_to_turn_on": true,
      "feature_you_want_to_keep_off": false
   }
}
_EOF_

Redémarrer Apache

systemctl restart apache2.service

Source

Fédération

Un des atouts de cette solution est la décentralisation. En effet, il est possible d'interconnecter plusieurs serveurs afin de permettre la communication d'utilisateurs enregistrés sur des instances différentes. Ces interconnexions doivent êtres explicitement spécifiées dans la configuration de Synapse.

Le domaine du serveur distant sera le suivant

export DNS_SRV_DISTANT_SYNAPSE=synapse.toto.fr

Ajout de celui-ci dans la configuration de Synapse (ceci doit être fait des deux côtés)

sed -i "s/^trusted_key_servers:/trusted_key_servers:\n  - server_name: \"${DNS_SRV_DISTANT_SYNAPSE}\"/g" /etc/matrix-synapse/homeserver.yaml
sed -i "s/^#federation_domain_whitelist:/federation_domain_whitelist:\n  - ${DNS_SRV_DISTANT_SYNAPSE}/g" /etc/matrix-synapse/homeserver.yaml
systemctl restart matrix-synapse.service

Cas d'une connexion mandaté

Dans la mesure où il est courant qu'un serveur ne soit jamais relié directement à Internet (comprendre par la qu'il ne dispose pas d'IP publique), le cas d'un mandataire inverse officiant entre les clients du WAN et le serveur Element du LAN est le plus probable. Ce point complique la transparence des échanges entre les machines et doit être géré au niveau de cet intermédiaire. Deux services ont étés testés en production avec succès. Leur configuration est donnée ci-après.

Traefik

Ajout d'un point d'entrer dans Traefik pour le port 8448

cat << _EOF_ >> /etc/traefik/config/vhosts/matrix.toml
[http]
  [http.routers]
     [http.routers.synapse]
      entryPoints = ["websecure"]
      rule = "Host(\`${DNS_SYNAPSE}\`)"
      service = "synapse"
      [http.routers.synapse.tls]
        certResolver = "myresolver"

     [http.routers.element]
      entryPoints = ["websecure"]
      rule = "Host(\`${DNS_ELEMENT}\`)"
      service = "element"
      [http.routers.element.tls]
        certResolver = "myresolver"

     [http.routers.synapsefed]
      entryPoints = ["synapsefed"]
      rule = "Host(\`${DNS_SYNAPSE}\`)"
      service = "synapse"
      [http.routers.synapsefed.tls]
        certResolver = "myresolver"

  [http.services]
    [http.services.synapse.loadBalancer]
      [[http.services.synapse.loadBalancer.servers]]
        url = "http://${IP_INTERNE}:8008"
    [http.services.element.loadBalancer]
      [[http.services.element.loadBalancer.servers]]
        url = "http://${IP_INTERNE}:80"
_EOF_

HAProxy

cat << _EOF_ >> /etc/haproxy/haproxy.cfg
frontend matrix-federation
    bind *:8448,[::]:8448 ssl crt /etc/haproxy/tls/ alpn h2,http/1.1
    http-request set-header X-Forwarded-Proto https if { ssl_fc }
    http-request set-header X-Forwarded-Proto http if !{ ssl_fc }
    http-request set-header X-Forwarded-For %[src]
    default_backend synapse

frontend https
    http-response add-header X-Frame-Options SAMEORIGIN

    bind :443 ssl crt /etc/haproxy/tls/ alpn h2,http/1.1

    acl host_synapse hdr(host) -i synapse.exemple.fr

    use_backend synapse if host_synapse

    <backend synapse
    option forwardfor except 127.0.0.1
    option http-server-close
    server synapse 192.168.170.178:8008 check maxconn 32
_EOF_

Débogage

La configuration de Synapse est quelque peu imbuvable et les problèmes, difficiles à corriger. Il est possible de s'appuyer sur les journaux du service afin de cibler l'origine des disfonctionnements.

tail -f /var/log/matrix-synapse/homeserver.log

Un outil permettant de determiner les caractéristiques du serveur est disponible à l'adresse https://federationtester.matrix.org/. Il peut s'avérer d'une aide précisieuse (surtout le rapport Json).

Réinitialisation de mot de passe

Aussi étrange que cela puisse parraitre, il n'existe pas de fonction pour réinitialiser le mot de passe d'un utilisateur (incroyable) ! Les développeurs de cette solution doivent ignorer que ces derniers perdent régulièrement leur mot de passe et qu'il s'agit donc d'une fonctionnalité indispensable en production. Heureusement, la structure de l'authentification étant très simple, il est triviale de réaliser cette opération soit-même dans la base de données après génération d'un mot de passe haché .

# Génération du mot de passe haché
su - matrix-synapse -s /bin/sh -c 'python3 /usr/libexec/matrix-synapse/hash_password -c /etc/matrix-synapse/homeserver.yaml'
# connexion à la base de donnée de Synapse
su - matrix-synapse -s /bin/sh -c 'sqlite3 /etc/matrix-synapse/homeserver.db'

Après avoir identifié l'utilisateur dont le mot de passe doit être réinitialisé ("michel" pour l'exemple), utiliser le hachi généré pour remplacer l'ancien

SELECT * FROM users;
UPDATE users SET password_hash='$2b$12$OkrnSR1hOCj0xjb7mDnvf.OXVQ0P/EU8u4lUpMuU5YepvHXpv3sxm' WHERE name='@michel:synapse.exemple.fr';

Le changement est instantané.