blob: 976b8b592c4e833e0c7be4232c286475bd307c64 [file] [log] [blame]
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +01001# Matrix server (synapse).
2# This needs a secret provisioned, create with:
3# ns=matrix
4#
5# SIGNING_KEY="$(kubectl run -n $ns -i --quiet --restart=Never --rm synapse-generate-config --image=matrixdotorg/synapse:v1.19.2 --env SYNAPSE_SERVER_NAME=dummy --env SYNAPSE_REPORT_STATS=no -o yaml --command -- sh -c '/start.py generate >/dev/null && cat /data/*.signing.key')"
6# kubectl -n $ns create secret generic synapse --from-literal=postgres_password=$(pwgen 24 1) --from-literal=macaroon_secret_key=$(pwgen 32 1) --from-literal=registration_shared_secret=$(pwgen 32 1) --from-literal=homeserver_signing_key="$SIGNING_KEY" --from-literal=redis_password=$(pwgen 32 1) --from-literal=worker_replication_secret=$(pwgen 32 1)
7# kubectl -n $ns create secret generic oauth2-cas-proxy --from-literal=oauth2_secret=...
8#
9# When migrating from matrix.libsonnet, instance signing key, redis passwsord
10# and worker replication secret need to be added to existing synapse secret:
11#
12# echo "homeserver_signing_key: $(kubectl -n $ns exec deploy/synapse -- sh -c 'cat /data/*.signing.key' | base64 -w0)"
13# echo "redis_password: $(pwgen 32 1 | tr -d '\n' | base64 -w0)"
14# echo "worker_replication_secret: $(pwgen 32 1 | tr -d '\n' | base64 -w0)"
15# kubectl -n $ns edit secret synapse
16# # ...add homeserver_signing_key, redis_password and worker_replication_secret keys
17#
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +010018# Additionally some resources need to be explicitly removed due to
19# label/annotations changes:
20# kubectl -n $ns delete deployment riot-web oauth2-cas-proxy wellknown synapse
21#
22# Some service configuration customization fields have been renamed:
23# .riotConfig → .riot.config
24# .synapseConfig → .synapse.config
25#
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +010026# Sequencing appservices is fun. The appservice needs to run first (for
27# instance, via a bootstrap job), and on startup it will spit out a
28# registration file. This registration file then needs to be fed to synapse -
29# this is done via specialy named secrets (appservice-X-registration, for X key
30# in the appservices object).
31#
32# For appservice-irc instances, you can use this oneliner magic to get the
33# registration YAML from logs.
34# kubectl -n matrix create secret generic appservice-irc-freenode-registration --from-file=registration.yaml=<(kubectl -n matrix logs job/appservice-irc-freenode-bootstrap | tail -n +4 | sed -r 's/(.*aliases:.*)/ group_id: "+freenode:hackerspace.pl"\n\1/')
35#
36# For appservice-telegram instances, you can use this oneliner magic:
37# kubectl -n matrix create secret generic appservice-telegram-prod-registration --from-file=registration.yaml=<(kubectl -n matrix logs job/appservice-telegram-prod-bootstrap | grep -A 100 SNIPSNIP | grep -v SNIPSNIP)
38
39local kube = import "../../../kube/kube.libsonnet";
40local postgres = import "../../../kube/postgres.libsonnet";
41local redis = import "../../../kube/redis.libsonnet";
42
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +010043local riot = import "./riot.libsonnet";
44local cas = import "./cas.libsonnet";
45local wellKnown = import "./wellknown.libsonnet";
46local synapse = import "./synapse.libsonnet";
47
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +010048{
49 local app = self,
50 local cfg = app.cfg,
51 cfg:: {
52 namespace: error "cfg.namespace must be set",
53 # webDomain is the domain name at which element will run
54 webDomain: error "cfg.webDomain must be set",
55 # serverName is the server part of the MXID this homeserver will cover
56 serverName: error "cfg.serverName must be set",
57 storageClassName: "waw-hdd-redundant-3",
58
59 images: {
60 synapse: "matrixdotorg/synapse:v1.25.0",
61 riot: "vectorim/riot-web:v1.7.18",
62 casProxy: "registry.k0.hswaw.net/q3k/oauth2-cas-proxy:0.1.4",
63 appserviceIRC: "matrixdotorg/matrix-appservice-irc:release-0.17.1",
64 # That's v0.8.2 - we just don't trust that host to not re-tag images.
65 appserviceTelegram: "dock.mau.dev/tulir/mautrix-telegram@sha256:9e68eaa80c9e4a75d9a09ec92dc4898b12d48390e01efa4de40ce882a6f7e330",
66 wellKnown: "registry.k0.hswaw.net/q3k/wellknown:1611960794-adbf560851a46ad0e58b42f0daad7ef19535687c",
67 },
68
69 # OpenID Connect provider configuration.
70 # Currently only client_secret can be provided as a secretKeyRef.
71 #
72 # https://${cfg.webDomain}/_synapse/oidc/callback needs to be set as
73 # allowed OAuth2/OpenID Connect callback URL
74 #
75 # See: https://github.com/matrix-org/synapse/blob/v1.25.0/docs/openid.md
76 oidc: {
77 enable: false,
78 config: {
79 issuer: error "oidc.config.issuer must be set",
80 client_id: error "oidc.config.client_id must be set",
81 client_secret: error "oidc.config.client_secret must be set",
82
83 # Set this to true when migrating from existing CAS deployment
84 allow_existing_users: false,
85 user_mapping_provider: {
86 config: {
87 localpart_template: '{{ user.sub }}',
88 display_name_template: '{{ user.sub }}',
89 },
90 },
91
92 # Extra configuration required when migrating from
93 # oauth2-cas-proxy bound to https://sso.hackerspace.pl
94 # user_profile_method: "userinfo_endpoint",
95 # client_auth_method: "client_secret_post",
96 },
97 },
98
99 # Central Authentication Scheme, a single-sign-on system. Note: this flow is now called 'SSO' in Matrix, we keep this name for legacy reasons.
100 # Refer to https://matrix.org/docs/spec/client_server/r0.6.1#sso-client-login
101 cas: {
102 # whether to enable the CAS proxy (ie. connect to hswaw sso via OAuth)
103 enable: false,
104 # generate client ID and secret in with your OAuth2 provider, refer to https://www.oauth.com/oauth2-servers/client-registration/client-id-secret/
105 oauth2: {
106 clientID: error "cas.oauth2.clientID must be set",
107 clientSecret: error "cas.oauth2.clientSecret must be set",
108 scope: error "cas.oauth2.scope must be set",
109 authorizeURL: error "cas.oauth2.authorizeURL must be set",
110 tokenURL: error "cas.oauth2.tokenURL must be set",
111 userinfoURL: error "cas.oauth2.userinfoURL must be set",
112 },
113 },
114
115 # Serve /.well-known/matrix configuration endpoints required when using
116 # cfg.webDomain directly as mxid.
117 wellKnown: false,
118 },
119
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100120 namespace: kube.Namespace(cfg.namespace),
121
122 postgres3: postgres {
123 cfg+: {
124 namespace: cfg.namespace,
125 appName: "synapse",
126 database: "synapse",
127 username: "synapse",
128 prefix: "waw3-",
129 password: { secretKeyRef: { name: "synapse", key: "postgres_password" } },
130 storageClassName: cfg.storageClassName,
131 storageSize: "100Gi",
132 initdbArgs: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'",
133 },
134 },
135
136 redis: redis {
137 cfg+: {
138 namespace: cfg.namespace,
139 appName: "synapse",
140 storageClassName: cfg.storageClassName,
141 password: { secretKeyRef: { name: "synapse", key: "redis_password" } },
142 },
143 },
144
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100145 riot: riot {
146 ns: app.namespace,
147 cfg+: {
148 webDomain: cfg.webDomain,
149 serverName: cfg.serverName,
150 image: cfg.images.riot,
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100151 },
152 },
153
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100154 cas: if cfg.cas.enable && cfg.oidc.enable then error "cfg.cas.enable and cfg.oidc.enable options are exclusive"
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100155 else if cfg.cas.enable then cas {
156 ns: app.namespace,
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100157 cfg+: {
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100158 image: cfg.images.casProxy,
159 webDomain: cfg.webDomain,
160 oauth2: cfg.cas.oauth2,
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100161 },
162 },
163
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100164 wellKnown: if cfg.wellKnown then wellKnown {
165 ns: app.namespace,
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100166 cfg+: {
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100167 image: cfg.images.wellKnown,
168 webDomain: cfg.webDomain,
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100169 },
170 } else {},
171
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100172 synapse: synapse {
173 ns: app.namespace,
174 postgres: app.postgres3,
175 redis: app.redis,
176 appservices: app.appservices,
177 cfg+: app.cfg {
178 image: app.cfg.images.synapse,
179
180 macaroonSecretKey: { secretKeyRef: { name: "synapse", key: "macaroon_secret_key" } },
181 registrationSharedSecret: { secretKeyRef: { name: "synapse", key: "registration_shared_secret" } },
182 workerReplicationSecret: { secretKeyRef: { name: "synapse", key: "worker_replication_secret" } },
183 },
184 },
185
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100186 // Any appservice you add here will require an appservice-X-registration
187 // secret containing a registration.yaml file. Adding something to this
188 // dictionary will cause Synapse to not start until that secret is
189 // available - so change things carefully!
190 // If bootstrapping a new appservice, just keep it out of this dictionary
191 // until it spits you a registration YAML and you feed that to a secret.
192 appservices: {},
193
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100194 ingress: app.namespace.Contain(kube.Ingress("matrix")) {
195 metadata+: {
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100196 annotations+: {
197 "kubernetes.io/tls-acme": "true",
198 "certmanager.k8s.io/cluster-issuer": "letsencrypt-prod",
199 "nginx.ingress.kubernetes.io/proxy-body-size": "0",
200 "nginx.ingress.kubernetes.io/use-regex": "true",
201 },
202 },
203 spec+: {
204 tls: [
205 {
206 hosts: [cfg.webDomain],
207 secretName: "synapse-tls",
208 },
209 ],
210 rules: [
211 {
212 host: cfg.webDomain,
213 http: {
214 paths: [
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100215 { path: path, backend: app.synapse.genericWorker.svc.name_port }
216 for path in app.synapse.genericWorker.paths
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100217 ] + [
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100218 { path: "/", backend: app.riot.svc.name_port },
219 { path: "/_matrix/media/", backend: app.synapse.mediaWorker.svc.name_port },
220 { path: "/_matrix/", backend: app.synapse.main.svc.name_port },
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100221
222 # Used by OpenID Connect login flow
Piotr Dobrowolskib67ae482021-01-31 10:35:38 +0100223 { path: "/_synapse/", backend: app.synapse.main.svc.name_port },
Piotr Dobrowolski8ec86572021-01-30 13:06:07 +0100224 ] + (if cfg.cas.enable then [
225 { path: "/_cas", backend: app.cas.svc.name_port },
226 ] else []) + (if cfg.wellKnown then [
227 { path: "/.well-known/matrix", backend: app.wellKnown.svc.name_port },
228 ] else [])
229 },
230 }
231 ],
232 },
233 },
234}