feat: switch to mas for matrix
This commit is contained in:
parent
3cdc76bc10
commit
0ae91ee62f
4 changed files with 226 additions and 73 deletions
|
|
@ -3,42 +3,178 @@ let
|
|||
hostname = "matrix";
|
||||
fqdn = "${hostname}.cloonar.com";
|
||||
baseUrl = "https://${fqdn}";
|
||||
clientConfig."m.homeserver".base_url = baseUrl;
|
||||
clientConfig = {
|
||||
"m.homeserver".base_url = baseUrl;
|
||||
# MAS auth issuer discovery (MSC2965)
|
||||
"org.matrix.msc2965.authentication" = {
|
||||
issuer = baseUrl + "/";
|
||||
account = baseUrl + "/account";
|
||||
};
|
||||
};
|
||||
serverConfig."m.server" = "${fqdn}:443";
|
||||
mkWellKnown = data: ''
|
||||
default_type application/json;
|
||||
add_header Access-Control-Allow-Origin *;
|
||||
return 200 '${builtins.toJSON data}';
|
||||
'';
|
||||
|
||||
masUpstreamId = "01KJPRKN397E5N8D0CA2Z3TJ7Y";
|
||||
elementWebClientId = "01KJPVT5D54NRAY7AJY6PZEN0D";
|
||||
masPackage = pkgs.matrix-authentication-service;
|
||||
in {
|
||||
# Secrets for Synapse
|
||||
sops.secrets.synapse-oidc-client-secret = {
|
||||
owner = "matrix-synapse";
|
||||
};
|
||||
# Secrets for MAS
|
||||
sops.secrets.mas-encryption-key = { owner = "mas"; };
|
||||
sops.secrets.mas-matrix-secret = { owner = "mas"; };
|
||||
sops.secrets.mas-authelia-client-secret = { owner = "mas"; };
|
||||
sops.secrets.mas-rsa-key = { owner = "mas"; };
|
||||
|
||||
sops.secrets.mautrix-whatsapp-env = { };
|
||||
sops.secrets.mautrix-signal-env = { };
|
||||
sops.secrets.mautrix-discord-env = { };
|
||||
|
||||
# PostgreSQL database for Synapse
|
||||
# MAS system user
|
||||
users.users.mas = {
|
||||
isSystemUser = true;
|
||||
group = "mas";
|
||||
home = "/var/lib/mas";
|
||||
};
|
||||
users.groups.mas = { };
|
||||
|
||||
# PostgreSQL databases for Synapse and MAS
|
||||
services.postgresql = {
|
||||
enable = true;
|
||||
# Synapse requires C locale for correct collation behavior
|
||||
initdbArgs = [ "--lc-collate=C" "--lc-ctype=C" ];
|
||||
ensureDatabases = [ "matrix-synapse" ];
|
||||
ensureDatabases = [ "matrix-synapse" "mas" ];
|
||||
ensureUsers = [
|
||||
{
|
||||
name = "matrix-synapse";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
{
|
||||
name = "mas";
|
||||
ensureDBOwnership = true;
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
services.postgresqlBackup.enable = true;
|
||||
services.postgresqlBackup.databases = [ "matrix-synapse" ];
|
||||
services.postgresqlBackup.databases = [ "matrix-synapse" "mas" ];
|
||||
|
||||
# Matrix Authentication Service (MAS)
|
||||
systemd.services.matrix-authentication-service = {
|
||||
description = "Matrix Authentication Service";
|
||||
after = [ "postgresql.service" "network.target" ];
|
||||
before = [ "matrix-synapse.service" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "simple";
|
||||
User = "mas";
|
||||
Group = "mas";
|
||||
RuntimeDirectory = "mas";
|
||||
RuntimeDirectoryMode = "0755";
|
||||
StateDirectory = "mas";
|
||||
StateDirectoryMode = "0750";
|
||||
ExecStart = "${masPackage}/bin/mas-cli server --config /run/mas/config.yaml";
|
||||
Restart = "on-failure";
|
||||
RestartSec = "5s";
|
||||
};
|
||||
|
||||
preStart = ''
|
||||
# Read secrets from SOPS-managed files
|
||||
ENCRYPTION_KEY=$(cat ${config.sops.secrets.mas-encryption-key.path})
|
||||
MATRIX_SECRET=$(cat ${config.sops.secrets.mas-matrix-secret.path})
|
||||
CLIENT_SECRET=$(cat ${config.sops.secrets.mas-authelia-client-secret.path})
|
||||
|
||||
# Write Synapse MAS config fragment with inline secret
|
||||
# (secret_path is not supported in all Synapse versions)
|
||||
cat > /run/mas/synapse-mas-config.yaml <<SYNEOF
|
||||
matrix_authentication_service:
|
||||
enabled: true
|
||||
endpoint: "http://127.0.0.1:8081"
|
||||
secret: "$MATRIX_SECRET"
|
||||
SYNEOF
|
||||
chmod 644 /run/mas/synapse-mas-config.yaml
|
||||
|
||||
# Write MAS config with secrets interpolated
|
||||
cat > /run/mas/config.yaml <<MASEOF
|
||||
http:
|
||||
public_base: ${baseUrl}/
|
||||
listeners:
|
||||
- name: web
|
||||
resources:
|
||||
- name: discovery
|
||||
- name: human
|
||||
- name: oauth
|
||||
- name: compat
|
||||
- name: graphql
|
||||
- name: assets
|
||||
binds:
|
||||
- address: "127.0.0.1:8081"
|
||||
|
||||
database:
|
||||
uri: postgresql:///mas?host=/run/postgresql
|
||||
|
||||
matrix:
|
||||
homeserver: cloonar.com
|
||||
endpoint: "http://[::1]:8008"
|
||||
secret: "$MATRIX_SECRET"
|
||||
|
||||
upstream_oauth2:
|
||||
providers:
|
||||
- id: ${masUpstreamId}
|
||||
synapse_idp_id: oidc-authelia
|
||||
human_name: Authelia
|
||||
issuer: https://auth.cloonar.com
|
||||
client_id: synapse
|
||||
client_secret: "$CLIENT_SECRET"
|
||||
token_endpoint_auth_method: client_secret_post
|
||||
scope: "openid email profile"
|
||||
claims_imports:
|
||||
localpart:
|
||||
action: force
|
||||
template: "{{ user.email | split('@') | first }}"
|
||||
displayname:
|
||||
action: suggest
|
||||
template: "{{ user.name }}"
|
||||
email:
|
||||
action: force
|
||||
template: "{{ user.email }}"
|
||||
set_email_verification: always
|
||||
|
||||
clients:
|
||||
- client_id: ${elementWebClientId}
|
||||
client_auth_method: none
|
||||
redirect_uris:
|
||||
- https://element.cloonar.com/
|
||||
- https://element.cloonar.com/?no_universal_links=true
|
||||
|
||||
passwords:
|
||||
enabled: true
|
||||
schemes:
|
||||
- version: 1
|
||||
algorithm: bcrypt
|
||||
|
||||
secrets:
|
||||
encryption: "$ENCRYPTION_KEY"
|
||||
keys:
|
||||
- kid: mas-rsa-key
|
||||
key_file: ${config.sops.secrets.mas-rsa-key.path}
|
||||
|
||||
telemetry:
|
||||
tracing:
|
||||
exporter: none
|
||||
metrics:
|
||||
exporter: none
|
||||
MASEOF
|
||||
'';
|
||||
};
|
||||
|
||||
# Synapse homeserver
|
||||
services.matrix-synapse = {
|
||||
enable = true;
|
||||
extraConfigFiles = [ "/run/mas/synapse-mas-config.yaml" ];
|
||||
settings = {
|
||||
server_name = "cloonar.com";
|
||||
public_baseurl = baseUrl;
|
||||
|
|
@ -68,37 +204,16 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
# Disable registration - users created via OIDC
|
||||
enable_registration = false;
|
||||
allow_guest_access = false;
|
||||
|
||||
# OIDC SSO via Authelia
|
||||
oidc_providers = [
|
||||
{
|
||||
idp_id = "authelia";
|
||||
idp_name = "Authelia";
|
||||
discover = true;
|
||||
issuer = "https://auth.cloonar.com";
|
||||
user_profile_method = "userinfo_endpoint";
|
||||
client_id = "synapse";
|
||||
client_secret_path = config.sops.secrets.synapse-oidc-client-secret.path;
|
||||
scopes = [ "openid" "profile" "email" ];
|
||||
allow_existing_users = true;
|
||||
user_mapping_provider.config = {
|
||||
subject_claim = "sub";
|
||||
localpart_template = "{{ user.email | localpart_from_email }}";
|
||||
display_name_template = "{{ user.name }}";
|
||||
email_template = "{{ user.email }}";
|
||||
};
|
||||
}
|
||||
];
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
# Synapse runs inside an isolated microVM, so PrivateUsers provides minimal
|
||||
# additional security. Disabling it allows Synapse to read bridge registration
|
||||
# files via SupplementaryGroups (user namespace blocks mapped GIDs otherwise).
|
||||
# Synapse depends on MAS for auth delegation
|
||||
systemd.services.matrix-synapse.after = [ "matrix-authentication-service.service" ];
|
||||
systemd.services.matrix-synapse.wants = [ "matrix-authentication-service.service" ];
|
||||
systemd.services.matrix-synapse.serviceConfig.PrivateUsers = lib.mkForce false;
|
||||
|
||||
# Element Web client
|
||||
|
|
@ -114,6 +229,15 @@ in {
|
|||
base_url = "https://matrix.cloonar.com";
|
||||
server_name = "cloonar.com";
|
||||
};
|
||||
"org.matrix.msc2965.authentication" = {
|
||||
issuer = "https://matrix.cloonar.com/";
|
||||
account = "https://matrix.cloonar.com/account";
|
||||
};
|
||||
};
|
||||
oidc_static_clients = {
|
||||
"https://matrix.cloonar.com/" = {
|
||||
client_id = elementWebClientId;
|
||||
};
|
||||
};
|
||||
disable_custom_urls = true;
|
||||
disable_3pid_login = true;
|
||||
|
|
@ -122,7 +246,7 @@ in {
|
|||
};
|
||||
};
|
||||
|
||||
# Synapse nginx reverse proxy
|
||||
# Synapse + MAS nginx reverse proxy
|
||||
services.nginx.virtualHosts."${fqdn}" = {
|
||||
forceSSL = true;
|
||||
enableACME = true;
|
||||
|
|
@ -132,6 +256,28 @@ in {
|
|||
'';
|
||||
locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
|
||||
locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
|
||||
|
||||
# MAS compatibility endpoints (must be before /_matrix catch-all)
|
||||
locations."~ ^/_matrix/client/(r0|v3)/login$".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."~ ^/_matrix/client/(r0|v3)/logout$".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."~ ^/_matrix/client/(r0|v3)/refresh$".proxyPass = "http://127.0.0.1:8081";
|
||||
|
||||
# MAS own endpoints
|
||||
locations."/authorize".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/oauth2".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/.well-known/openid-configuration".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/.well-known/webfinger".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/assets".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/graphql".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/account".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/upstream".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/register".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/consent".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/recovery".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/login".proxyPass = "http://127.0.0.1:8081";
|
||||
locations."/change-password".proxyPass = "http://127.0.0.1:8081";
|
||||
|
||||
# Synapse endpoints
|
||||
locations."/_matrix".proxyPass = "http://[::1]:8008";
|
||||
locations."/_synapse/client".proxyPass = "http://[::1]:8008";
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue