Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit b5ab2c4

Browse files
Tuomas Ojamiestojamiesclokepreivilibre
authored
Support using SSL on worker endpoints. (#14128)
* Fix missing SSL support in worker endpoints. * Add changelog * SSL for Replication endpoint * Remove unit test change * Refactor listener creation to reduce duplicated code * Fix the logger message * Update synapse/app/_base.py Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> * Update synapse/app/_base.py Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> * Update synapse/app/_base.py Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> * Add config documentation for new TLS option Co-authored-by: Tuomas Ojamies <tojamies@palantir.com> Co-authored-by: Patrick Cloke <clokep@users.noreply.github.com> Co-authored-by: Olivier Wilkinson (reivilibre) <oliverw@matrix.org>
1 parent 634359b commit b5ab2c4

7 files changed

Lines changed: 100 additions & 53 deletions

File tree

changelog.d/14128.misc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add TLS support for generic worker endpoints.

docs/usage/configuration/config_documentation.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3893,6 +3893,26 @@ Example configuration:
38933893
worker_replication_http_port: 9093
38943894
```
38953895
---
3896+
### `worker_replication_http_tls`
3897+
3898+
Whether TLS should be used for talking to the HTTP replication port on the main
3899+
Synapse process.
3900+
The main Synapse process defines this with the `tls` option on its [listener](#listeners) that
3901+
has the `replication` resource enabled.
3902+
3903+
**Please note:** by default, it is not safe to expose replication ports to the
3904+
public Internet, even with TLS enabled.
3905+
See [`worker_replication_secret`](#worker_replication_secret).
3906+
3907+
Defaults to `false`.
3908+
3909+
*Added in Synapse 1.72.0.*
3910+
3911+
Example configuration:
3912+
```yaml
3913+
worker_replication_http_tls: true
3914+
```
3915+
---
38963916
### `worker_listeners`
38973917

38983918
A worker can handle HTTP requests. To do so, a `worker_listeners` option

synapse/app/_base.py

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
from twisted.logger import LoggingFile, LogLevel
4848
from twisted.protocols.tls import TLSMemoryBIOFactory
4949
from twisted.python.threadpool import ThreadPool
50+
from twisted.web.resource import Resource
5051

5152
import synapse.util.caches
5253
from synapse.api.constants import MAX_PDU_SIZE
@@ -55,12 +56,13 @@
5556
from synapse.config import ConfigError
5657
from synapse.config._base import format_config_error
5758
from synapse.config.homeserver import HomeServerConfig
58-
from synapse.config.server import ManholeConfig
59+
from synapse.config.server import ListenerConfig, ManholeConfig
5960
from synapse.crypto import context_factory
6061
from synapse.events.presence_router import load_legacy_presence_router
6162
from synapse.events.spamcheck import load_legacy_spam_checkers
6263
from synapse.events.third_party_rules import load_legacy_third_party_event_rules
6364
from synapse.handlers.auth import load_legacy_password_auth_providers
65+
from synapse.http.site import SynapseSite
6466
from synapse.logging.context import PreserveLoggingContext
6567
from synapse.logging.opentracing import init_tracer
6668
from synapse.metrics import install_gc_manager, register_threadpool
@@ -357,6 +359,55 @@ def listen_tcp(
357359
return r # type: ignore[return-value]
358360

359361

362+
def listen_http(
363+
listener_config: ListenerConfig,
364+
root_resource: Resource,
365+
version_string: str,
366+
max_request_body_size: int,
367+
context_factory: IOpenSSLContextFactory,
368+
reactor: IReactorSSL = reactor,
369+
) -> List[Port]:
370+
port = listener_config.port
371+
bind_addresses = listener_config.bind_addresses
372+
tls = listener_config.tls
373+
374+
assert listener_config.http_options is not None
375+
376+
site_tag = listener_config.http_options.tag
377+
if site_tag is None:
378+
site_tag = str(port)
379+
380+
site = SynapseSite(
381+
"synapse.access.%s.%s" % ("https" if tls else "http", site_tag),
382+
site_tag,
383+
listener_config,
384+
root_resource,
385+
version_string,
386+
max_request_body_size=max_request_body_size,
387+
reactor=reactor,
388+
)
389+
if tls:
390+
# refresh_certificate should have been called before this.
391+
assert context_factory is not None
392+
ports = listen_ssl(
393+
bind_addresses,
394+
port,
395+
site,
396+
context_factory,
397+
reactor=reactor,
398+
)
399+
logger.info("Synapse now listening on TCP port %d (TLS)", port)
400+
else:
401+
ports = listen_tcp(
402+
bind_addresses,
403+
port,
404+
site,
405+
reactor=reactor,
406+
)
407+
logger.info("Synapse now listening on TCP port %d", port)
408+
return ports
409+
410+
360411
def listen_ssl(
361412
bind_addresses: Collection[str],
362413
port: int,

synapse/app/generic_worker.py

Lines changed: 7 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
from synapse.federation.transport.server import TransportLayerServer
4545
from synapse.http.server import JsonResource, OptionsResource
4646
from synapse.http.servlet import RestServlet, parse_json_object_from_request
47-
from synapse.http.site import SynapseRequest, SynapseSite
47+
from synapse.http.site import SynapseRequest
4848
from synapse.logging.context import LoggingContext
4949
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
5050
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
@@ -288,15 +288,9 @@ class GenericWorkerServer(HomeServer):
288288
DATASTORE_CLASS = GenericWorkerSlavedStore # type: ignore
289289

290290
def _listen_http(self, listener_config: ListenerConfig) -> None:
291-
port = listener_config.port
292-
bind_addresses = listener_config.bind_addresses
293291

294292
assert listener_config.http_options is not None
295293

296-
site_tag = listener_config.http_options.tag
297-
if site_tag is None:
298-
site_tag = str(port)
299-
300294
# We always include a health resource.
301295
resources: Dict[str, Resource] = {"/health": HealthResource()}
302296

@@ -395,23 +389,15 @@ def _listen_http(self, listener_config: ListenerConfig) -> None:
395389

396390
root_resource = create_resource_tree(resources, OptionsResource())
397391

398-
_base.listen_tcp(
399-
bind_addresses,
400-
port,
401-
SynapseSite(
402-
"synapse.access.http.%s" % (site_tag,),
403-
site_tag,
404-
listener_config,
405-
root_resource,
406-
self.version_string,
407-
max_request_body_size=max_request_body_size(self.config),
408-
reactor=self.get_reactor(),
409-
),
392+
_base.listen_http(
393+
listener_config,
394+
root_resource,
395+
self.version_string,
396+
max_request_body_size(self.config),
397+
self.tls_server_context_factory,
410398
reactor=self.get_reactor(),
411399
)
412400

413-
logger.info("Synapse worker now listening on port %d", port)
414-
415401
def start_listening(self) -> None:
416402
for listener in self.config.worker.worker_listeners:
417403
if listener.type == "http":

synapse/app/homeserver.py

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,7 @@
3737
from synapse.app import _base
3838
from synapse.app._base import (
3939
handle_startup_exception,
40-
listen_ssl,
41-
listen_tcp,
40+
listen_http,
4241
max_request_body_size,
4342
redirect_stdio_to_logs,
4443
register_start,
@@ -53,7 +52,6 @@
5352
RootOptionsRedirectResource,
5453
StaticResource,
5554
)
56-
from synapse.http.site import SynapseSite
5755
from synapse.logging.context import LoggingContext
5856
from synapse.metrics import METRICS_PREFIX, MetricsResource, RegistryProxy
5957
from synapse.replication.http import REPLICATION_PREFIX, ReplicationRestResource
@@ -83,8 +81,6 @@ def _listener_http(
8381
self, config: HomeServerConfig, listener_config: ListenerConfig
8482
) -> Iterable[Port]:
8583
port = listener_config.port
86-
bind_addresses = listener_config.bind_addresses
87-
tls = listener_config.tls
8884
# Must exist since this is an HTTP listener.
8985
assert listener_config.http_options is not None
9086
site_tag = listener_config.http_options.tag
@@ -140,37 +136,15 @@ def _listener_http(
140136
else:
141137
root_resource = OptionsResource()
142138

143-
site = SynapseSite(
144-
"synapse.access.%s.%s" % ("https" if tls else "http", site_tag),
145-
site_tag,
139+
ports = listen_http(
146140
listener_config,
147141
create_resource_tree(resources, root_resource),
148142
self.version_string,
149-
max_request_body_size=max_request_body_size(self.config),
143+
max_request_body_size(self.config),
144+
self.tls_server_context_factory,
150145
reactor=self.get_reactor(),
151146
)
152147

153-
if tls:
154-
# refresh_certificate should have been called before this.
155-
assert self.tls_server_context_factory is not None
156-
ports = listen_ssl(
157-
bind_addresses,
158-
port,
159-
site,
160-
self.tls_server_context_factory,
161-
reactor=self.get_reactor(),
162-
)
163-
logger.info("Synapse now listening on TCP port %d (TLS)", port)
164-
165-
else:
166-
ports = listen_tcp(
167-
bind_addresses,
168-
port,
169-
site,
170-
reactor=self.get_reactor(),
171-
)
172-
logger.info("Synapse now listening on TCP port %d", port)
173-
174148
return ports
175149

176150
def _configure_named_resource(

synapse/config/workers.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ class InstanceLocationConfig:
6767

6868
host: str
6969
port: int
70+
tls: bool = False
7071

7172

7273
@attr.s
@@ -149,6 +150,12 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None:
149150
# The port on the main synapse for HTTP replication endpoint
150151
self.worker_replication_http_port = config.get("worker_replication_http_port")
151152

153+
# The tls mode on the main synapse for HTTP replication endpoint.
154+
# For backward compatibility this defaults to False.
155+
self.worker_replication_http_tls = config.get(
156+
"worker_replication_http_tls", False
157+
)
158+
152159
# The shared secret used for authentication when connecting to the main synapse.
153160
self.worker_replication_secret = config.get("worker_replication_secret", None)
154161

synapse/replication/http/_base.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,10 @@ def make_client(cls, hs: "HomeServer") -> Callable:
184184
client = hs.get_simple_http_client()
185185
local_instance_name = hs.get_instance_name()
186186

187+
# The value of these option should match the replication listener settings
187188
master_host = hs.config.worker.worker_replication_host
188189
master_port = hs.config.worker.worker_replication_http_port
190+
master_tls = hs.config.worker.worker_replication_http_tls
189191

190192
instance_map = hs.config.worker.instance_map
191193

@@ -205,9 +207,11 @@ async def send_request(*, instance_name: str = "master", **kwargs: Any) -> Any:
205207
if instance_name == "master":
206208
host = master_host
207209
port = master_port
210+
tls = master_tls
208211
elif instance_name in instance_map:
209212
host = instance_map[instance_name].host
210213
port = instance_map[instance_name].port
214+
tls = instance_map[instance_name].tls
211215
else:
212216
raise Exception(
213217
"Instance %r not in 'instance_map' config" % (instance_name,)
@@ -238,7 +242,11 @@ async def send_request(*, instance_name: str = "master", **kwargs: Any) -> Any:
238242
"Unknown METHOD on %s replication endpoint" % (cls.NAME,)
239243
)
240244

241-
uri = "http://%s:%s/_synapse/replication/%s/%s" % (
245+
# Here the protocol is hard coded to be http by default or https in case the replication
246+
# port is set to have tls true.
247+
scheme = "https" if tls else "http"
248+
uri = "%s://%s:%s/_synapse/replication/%s/%s" % (
249+
scheme,
242250
host,
243251
port,
244252
cls.NAME,

0 commit comments

Comments
 (0)