From 2cfd40ed26c5990c08fa06069a22d0d1125214fd Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Wed, 22 Mar 2023 19:54:06 +0100 Subject: [PATCH 1/8] Add SSL options to redis config --- synapse/config/redis.py | 6 +++++ synapse/replication/tcp/handler.py | 29 +++++++++++++++----- synapse/replication/tcp/redis.py | 43 +++++++++++++++++++++++++----- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/synapse/config/redis.py b/synapse/config/redis.py index e6a75be43429..41f73be2c804 100644 --- a/synapse/config/redis.py +++ b/synapse/config/redis.py @@ -35,3 +35,9 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.redis_port = redis_config.get("port", 6379) self.redis_dbid = redis_config.get("dbid", None) self.redis_password = redis_config.get("password") + + self.redis_use_ssl = redis_config.get('use_ssl', False) + self.redis_certificate = redis_config.get("certificate_file", None) + self.redis_private_key = redis_config.get("private_key_file", None) + self.redis_ca_file = redis_config.get("ca_file", None) + self.redis_ca_path = redis_config.get("ca_path", None) \ No newline at end of file diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py index 2290b3e6fe7d..230f53d321ea 100644 --- a/synapse/replication/tcp/handler.py +++ b/synapse/replication/tcp/handler.py @@ -47,6 +47,7 @@ UserSyncCommand, ) from synapse.replication.tcp.protocol import IReplicationConnection +from synapse.replication.tcp.redis import ClientContextFactory from synapse.replication.tcp.streams import ( STREAMS_MAP, AccountDataStream, @@ -348,13 +349,27 @@ def start_replication(self, hs: "HomeServer") -> None: outbound_redis_connection, channel_names=self._channels_to_subscribe_to, ) - hs.get_reactor().connectTCP( - hs.config.redis.redis_host, - hs.config.redis.redis_port, - self._factory, - timeout=30, - bindAddress=None, - ) + + reactor = hs.get_reactor() + redis_config = hs.config.redis + if (hs.config.redis.redis_use_ssl): + ssl_context_factory = ClientContextFactory(hs.config.redis) + reactor.connectSSL( + redis_config.redis_host, + redis_config.redis_port, + self._factory, + ssl_context_factory, + timeout=30, + bindAddress=None, + ) + else: + reactor.connectTCP( + redis_config.redis_host, + redis_config.redis_port, + self._factory, + timeout=30, + bindAddress=None, + ) def get_streams(self) -> Dict[str, Stream]: """Get a map from stream name to all streams.""" diff --git a/synapse/replication/tcp/redis.py b/synapse/replication/tcp/redis.py index dfc061eb5e38..2bd88c5ea10b 100644 --- a/synapse/replication/tcp/redis.py +++ b/synapse/replication/tcp/redis.py @@ -20,6 +20,7 @@ import txredisapi from zope.interface import implementer +from twisted.internet import ssl from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.interfaces import IAddress, IConnector from twisted.python.failure import Failure @@ -386,12 +387,40 @@ def lazyConnection( factory.continueTrying = reconnect reactor = hs.get_reactor() - reactor.connectTCP( - host, - port, - factory, - timeout=30, - bindAddress=None, - ) + + if (hs.config.redis.redis_use_ssl): + ssl_context_factory = ClientContextFactory(hs.config.redis) + reactor.connectSSL( + host, + port, + factory, + ssl_context_factory, + timeout=30, + bindAddress=None, + ) + else: + reactor.connectTCP( + host, + port, + factory, + timeout=30, + bindAddress=None, + ) return factory.handler + +class ClientContextFactory(ssl.ClientContextFactory): + def __init__(self, redis_config): + self.redis_config = redis_config + + def getContext(self): + ctx = ssl.ClientContextFactory.getContext(self) + if (self.redis_config.redis_certificate): + ctx.use_certificate_file(self.redis_config.redis_certificate)) + if (self.redis_config.private_key): + ctx.use_privatekey_file(self.redis_config.private_key) + if (self.redis_config.ca_file): + ctx.load_verify_locations(cafile=self.redis_config.ca_file) + elif (self.redis_config.ca_path): + ctx.load_verify_locationa(capath=self.redis_config.ca_path) + return ctx \ No newline at end of file From 401af4e830f6ba3ed64e51a29261dccadfcf32db Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Thu, 23 Mar 2023 11:57:09 +0100 Subject: [PATCH 2/8] fix lint issues --- synapse/config/redis.py | 6 +++--- synapse/replication/tcp/handler.py | 2 +- synapse/replication/tcp/redis.py | 27 +++++++++++++++------------ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/synapse/config/redis.py b/synapse/config/redis.py index 41f73be2c804..bae73d2f9407 100644 --- a/synapse/config/redis.py +++ b/synapse/config/redis.py @@ -36,8 +36,8 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.redis_dbid = redis_config.get("dbid", None) self.redis_password = redis_config.get("password") - self.redis_use_ssl = redis_config.get('use_ssl', False) + self.redis_use_ssl = redis_config.get("use_ssl", False) self.redis_certificate = redis_config.get("certificate_file", None) self.redis_private_key = redis_config.get("private_key_file", None) - self.redis_ca_file = redis_config.get("ca_file", None) - self.redis_ca_path = redis_config.get("ca_path", None) \ No newline at end of file + self.redis_ca_file = redis_config.get("ca_file", None) + self.redis_ca_path = redis_config.get("ca_path", None) diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py index 230f53d321ea..5d10aa9d3cb9 100644 --- a/synapse/replication/tcp/handler.py +++ b/synapse/replication/tcp/handler.py @@ -352,7 +352,7 @@ def start_replication(self, hs: "HomeServer") -> None: reactor = hs.get_reactor() redis_config = hs.config.redis - if (hs.config.redis.redis_use_ssl): + if hs.config.redis.redis_use_ssl: ssl_context_factory = ClientContextFactory(hs.config.redis) reactor.connectSSL( redis_config.redis_host, diff --git a/synapse/replication/tcp/redis.py b/synapse/replication/tcp/redis.py index 2bd88c5ea10b..f46eb3b1db42 100644 --- a/synapse/replication/tcp/redis.py +++ b/synapse/replication/tcp/redis.py @@ -20,11 +20,13 @@ import txredisapi from zope.interface import implementer +from OpenSSL.SSL import Context from twisted.internet import ssl from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.interfaces import IAddress, IConnector from twisted.python.failure import Failure +from synapse.config.redis import RedisConfig from synapse.logging.context import PreserveLoggingContext, make_deferred_yieldable from synapse.metrics.background_process_metrics import ( BackgroundProcessLoggingContext, @@ -388,7 +390,7 @@ def lazyConnection( reactor = hs.get_reactor() - if (hs.config.redis.redis_use_ssl): + if hs.config.redis.redis_use_ssl: ssl_context_factory = ClientContextFactory(hs.config.redis) reactor.connectSSL( host, @@ -409,18 +411,19 @@ def lazyConnection( return factory.handler + class ClientContextFactory(ssl.ClientContextFactory): - def __init__(self, redis_config): + def __init__(self, redis_config: RedisConfig): self.redis_config = redis_config - def getContext(self): + def getContext(self) -> Context: ctx = ssl.ClientContextFactory.getContext(self) - if (self.redis_config.redis_certificate): - ctx.use_certificate_file(self.redis_config.redis_certificate)) - if (self.redis_config.private_key): - ctx.use_privatekey_file(self.redis_config.private_key) - if (self.redis_config.ca_file): - ctx.load_verify_locations(cafile=self.redis_config.ca_file) - elif (self.redis_config.ca_path): - ctx.load_verify_locationa(capath=self.redis_config.ca_path) - return ctx \ No newline at end of file + if self.redis_config.redis_certificate: + ctx.use_certificate_file(self.redis_config.redis_certificate) + if self.redis_config.redis_private_key: + ctx.use_privatekey_file(self.redis_config.redis_private_key) + if self.redis_config.redis_ca_file: + ctx.load_verify_locations(cafile=self.redis_config.redis_ca_file) + elif self.redis_config.redis_ca_path: + ctx.load_verify_locationa(capath=self.redis_config.redis_ca_path) + return ctx From 29bc3405faee7ff3de225cdf1fd75ad41a3270df Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Thu, 23 Mar 2023 12:06:57 +0100 Subject: [PATCH 3/8] Add documentation and changelog file --- changelog.d/15312.feature | 1 + contrib/docker_compose_workers/README.md | 4 ++++ docs/usage/configuration/config_documentation.md | 9 +++++++++ 3 files changed, 14 insertions(+) create mode 100644 changelog.d/15312.feature diff --git a/changelog.d/15312.feature b/changelog.d/15312.feature new file mode 100644 index 000000000000..7bf63b30ab82 --- /dev/null +++ b/changelog.d/15312.feature @@ -0,0 +1 @@ +Add redis SSL configuration options \ No newline at end of file diff --git a/contrib/docker_compose_workers/README.md b/contrib/docker_compose_workers/README.md index d3cdfe5614bb..6c9f0ab4cc5c 100644 --- a/contrib/docker_compose_workers/README.md +++ b/contrib/docker_compose_workers/README.md @@ -70,6 +70,10 @@ redis: port: 6379 # dbid: # password: + # use_ssl: True + # certificate_file: + # private_key_file: + # ca_file: ``` This assumes that your Redis service is called `redis` in your Docker Compose file. diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 015855ee7ef4..02f95f2cfbe2 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3928,6 +3928,11 @@ This setting has the following sub-options: localhost and 6379 * `password`: Optional password if configured on the Redis instance. * `dbid`: Optional redis dbid if needs to connect to specific redis logical db. +* `use_ssl`: Whether to use ssl connection. Defaults to false. +* `certificate_file`: Optional path to the certificate file +* `private_key_file`: Optional path to the private key file +* `ca_file`: Optional path to the CA certificate file. Use this one or: +* `ca_path`: Optional path to the folder containing the CA certificate file _Added in Synapse 1.78.0._ @@ -3939,6 +3944,10 @@ redis: port: 6379 password: dbid: + #use_ssl: True + #certificate_file: + #private_key_file: + #ca_file: ``` --- ## Individual worker configuration From 66f9b8f371e0f31fdbbf1861924763c40b464847 Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Thu, 23 Mar 2023 12:55:46 +0100 Subject: [PATCH 4/8] add missing . at the end of the changelog --- changelog.d/15312.feature | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/15312.feature b/changelog.d/15312.feature index 7bf63b30ab82..4483b06dae28 100644 --- a/changelog.d/15312.feature +++ b/changelog.d/15312.feature @@ -1 +1 @@ -Add redis SSL configuration options \ No newline at end of file +Add redis SSL configuration options. \ No newline at end of file From 3e4faf2473e4111cf45c4b710dfa5596d20669dc Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Thu, 23 Mar 2023 16:53:44 +0100 Subject: [PATCH 5/8] Move client context factory to new file --- synapse/replication/tcp/context.py | 34 ++++++++++++++++++++++++++++++ synapse/replication/tcp/handler.py | 2 +- synapse/replication/tcp/redis.py | 21 +----------------- 3 files changed, 36 insertions(+), 21 deletions(-) create mode 100644 synapse/replication/tcp/context.py diff --git a/synapse/replication/tcp/context.py b/synapse/replication/tcp/context.py new file mode 100644 index 000000000000..22f43af25d7d --- /dev/null +++ b/synapse/replication/tcp/context.py @@ -0,0 +1,34 @@ +# Copyright 2023 The Matrix.org Foundation C.I.C. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from OpenSSL.SSL import Context +from twisted.internet import ssl + +from synapse.config.redis import RedisConfig + + +class ClientContextFactory(ssl.ClientContextFactory): + def __init__(self, redis_config: RedisConfig): + self.redis_config = redis_config + + def getContext(self) -> Context: + ctx = ssl.ClientContextFactory.getContext(self) + if self.redis_config.redis_certificate: + ctx.use_certificate_file(self.redis_config.redis_certificate) + if self.redis_config.redis_private_key: + ctx.use_privatekey_file(self.redis_config.redis_private_key) + if self.redis_config.redis_ca_file: + ctx.load_verify_locations(cafile=self.redis_config.redis_ca_file) + elif self.redis_config.redis_ca_path: + ctx.load_verify_locationa(capath=self.redis_config.redis_ca_path) + return ctx diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py index 5d10aa9d3cb9..2843b087fdf5 100644 --- a/synapse/replication/tcp/handler.py +++ b/synapse/replication/tcp/handler.py @@ -46,8 +46,8 @@ UserIpCommand, UserSyncCommand, ) +from synapse.replication.tcp.context import ClientContextFactory from synapse.replication.tcp.protocol import IReplicationConnection -from synapse.replication.tcp.redis import ClientContextFactory from synapse.replication.tcp.streams import ( STREAMS_MAP, AccountDataStream, diff --git a/synapse/replication/tcp/redis.py b/synapse/replication/tcp/redis.py index f46eb3b1db42..f334d49254a1 100644 --- a/synapse/replication/tcp/redis.py +++ b/synapse/replication/tcp/redis.py @@ -20,13 +20,10 @@ import txredisapi from zope.interface import implementer -from OpenSSL.SSL import Context -from twisted.internet import ssl from twisted.internet.address import IPv4Address, IPv6Address from twisted.internet.interfaces import IAddress, IConnector from twisted.python.failure import Failure -from synapse.config.redis import RedisConfig from synapse.logging.context import PreserveLoggingContext, make_deferred_yieldable from synapse.metrics.background_process_metrics import ( BackgroundProcessLoggingContext, @@ -38,6 +35,7 @@ ReplicateCommand, parse_command_from_line, ) +from synapse.replication.tcp.context import ClientContextFactory from synapse.replication.tcp.protocol import ( IReplicationConnection, tcp_inbound_commands_counter, @@ -410,20 +408,3 @@ def lazyConnection( ) return factory.handler - - -class ClientContextFactory(ssl.ClientContextFactory): - def __init__(self, redis_config: RedisConfig): - self.redis_config = redis_config - - def getContext(self) -> Context: - ctx = ssl.ClientContextFactory.getContext(self) - if self.redis_config.redis_certificate: - ctx.use_certificate_file(self.redis_config.redis_certificate) - if self.redis_config.redis_private_key: - ctx.use_privatekey_file(self.redis_config.redis_private_key) - if self.redis_config.redis_ca_file: - ctx.load_verify_locations(cafile=self.redis_config.redis_ca_file) - elif self.redis_config.redis_ca_path: - ctx.load_verify_locationa(capath=self.redis_config.redis_ca_path) - return ctx From 9deb4105e9ed4c147b1054e8cadac27cf945184d Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Tue, 4 Apr 2023 11:20:58 +0200 Subject: [PATCH 6/8] Rename ssl to tls and fix typo --- changelog.d/15312.feature | 2 +- contrib/docker_compose_workers/README.md | 2 +- docs/usage/configuration/config_documentation.md | 4 ++-- synapse/config/redis.py | 2 +- synapse/replication/tcp/context.py | 4 ++-- synapse/replication/tcp/handler.py | 2 +- synapse/replication/tcp/redis.py | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/changelog.d/15312.feature b/changelog.d/15312.feature index 4483b06dae28..e4e972cfeb88 100644 --- a/changelog.d/15312.feature +++ b/changelog.d/15312.feature @@ -1 +1 @@ -Add redis SSL configuration options. \ No newline at end of file +Add redis TLS configuration options. \ No newline at end of file diff --git a/contrib/docker_compose_workers/README.md b/contrib/docker_compose_workers/README.md index 6c9f0ab4cc5c..ebb225fba6dd 100644 --- a/contrib/docker_compose_workers/README.md +++ b/contrib/docker_compose_workers/README.md @@ -70,7 +70,7 @@ redis: port: 6379 # dbid: # password: - # use_ssl: True + # use_tls: True # certificate_file: # private_key_file: # ca_file: diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 02f95f2cfbe2..f2876a977edd 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3928,7 +3928,7 @@ This setting has the following sub-options: localhost and 6379 * `password`: Optional password if configured on the Redis instance. * `dbid`: Optional redis dbid if needs to connect to specific redis logical db. -* `use_ssl`: Whether to use ssl connection. Defaults to false. +* `use_tls`: Whether to use tls connection. Defaults to false. * `certificate_file`: Optional path to the certificate file * `private_key_file`: Optional path to the private key file * `ca_file`: Optional path to the CA certificate file. Use this one or: @@ -3944,7 +3944,7 @@ redis: port: 6379 password: dbid: - #use_ssl: True + #use_tls: True #certificate_file: #private_key_file: #ca_file: diff --git a/synapse/config/redis.py b/synapse/config/redis.py index bae73d2f9407..636cb450b8b5 100644 --- a/synapse/config/redis.py +++ b/synapse/config/redis.py @@ -36,7 +36,7 @@ def read_config(self, config: JsonDict, **kwargs: Any) -> None: self.redis_dbid = redis_config.get("dbid", None) self.redis_password = redis_config.get("password") - self.redis_use_ssl = redis_config.get("use_ssl", False) + self.redis_use_tls = redis_config.get("use_tls", False) self.redis_certificate = redis_config.get("certificate_file", None) self.redis_private_key = redis_config.get("private_key_file", None) self.redis_ca_file = redis_config.get("ca_file", None) diff --git a/synapse/replication/tcp/context.py b/synapse/replication/tcp/context.py index 22f43af25d7d..cf45950088c1 100644 --- a/synapse/replication/tcp/context.py +++ b/synapse/replication/tcp/context.py @@ -22,7 +22,7 @@ def __init__(self, redis_config: RedisConfig): self.redis_config = redis_config def getContext(self) -> Context: - ctx = ssl.ClientContextFactory.getContext(self) + ctx = super().getContext(self) if self.redis_config.redis_certificate: ctx.use_certificate_file(self.redis_config.redis_certificate) if self.redis_config.redis_private_key: @@ -30,5 +30,5 @@ def getContext(self) -> Context: if self.redis_config.redis_ca_file: ctx.load_verify_locations(cafile=self.redis_config.redis_ca_file) elif self.redis_config.redis_ca_path: - ctx.load_verify_locationa(capath=self.redis_config.redis_ca_path) + ctx.load_verify_locations(capath=self.redis_config.redis_ca_path) return ctx diff --git a/synapse/replication/tcp/handler.py b/synapse/replication/tcp/handler.py index 2843b087fdf5..233ad61d4930 100644 --- a/synapse/replication/tcp/handler.py +++ b/synapse/replication/tcp/handler.py @@ -352,7 +352,7 @@ def start_replication(self, hs: "HomeServer") -> None: reactor = hs.get_reactor() redis_config = hs.config.redis - if hs.config.redis.redis_use_ssl: + if hs.config.redis.redis_use_tls: ssl_context_factory = ClientContextFactory(hs.config.redis) reactor.connectSSL( redis_config.redis_host, diff --git a/synapse/replication/tcp/redis.py b/synapse/replication/tcp/redis.py index f334d49254a1..c8f4bf8b27c2 100644 --- a/synapse/replication/tcp/redis.py +++ b/synapse/replication/tcp/redis.py @@ -388,7 +388,7 @@ def lazyConnection( reactor = hs.get_reactor() - if hs.config.redis.redis_use_ssl: + if hs.config.redis.redis_use_tls: ssl_context_factory = ClientContextFactory(hs.config.redis) reactor.connectSSL( host, From 4411ee3cf2aa5036b1a803183c5c341f1eeee44d Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Wed, 5 Apr 2023 09:48:33 +0200 Subject: [PATCH 7/8] fix lint issues --- synapse/replication/tcp/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synapse/replication/tcp/context.py b/synapse/replication/tcp/context.py index cf45950088c1..4688b2200b40 100644 --- a/synapse/replication/tcp/context.py +++ b/synapse/replication/tcp/context.py @@ -22,7 +22,7 @@ def __init__(self, redis_config: RedisConfig): self.redis_config = redis_config def getContext(self) -> Context: - ctx = super().getContext(self) + ctx = super().getContext() if self.redis_config.redis_certificate: ctx.use_certificate_file(self.redis_config.redis_certificate) if self.redis_config.redis_private_key: From a4c82c4b1d6f964cc066e0e219ed194d76db801d Mon Sep 17 00:00:00 2001 From: Roel ter Maat Date: Tue, 9 May 2023 10:07:52 +0200 Subject: [PATCH 8/8] Added when redis attributes were added --- docs/usage/configuration/config_documentation.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/usage/configuration/config_documentation.md b/docs/usage/configuration/config_documentation.md index 5f75944bdc9a..b3a51ec2c370 100644 --- a/docs/usage/configuration/config_documentation.md +++ b/docs/usage/configuration/config_documentation.md @@ -3960,6 +3960,8 @@ This setting has the following sub-options: _Added in Synapse 1.78.0._ + _Changed in Synapse 1.84.0: Added use\_tls, certificate\_file, private\_key\_file, ca\_file and ca\_path attributes_ + Example configuration: ```yaml redis: