Add support for plaintext clients in TLS cluster#8587
Add support for plaintext clients in TLS cluster#8587yossigo merged 5 commits intoredis:unstablefrom
Conversation
53e81f3 to
f4733d0
Compare
|
Open question: In commands like CLUSTER SLOTS, redirects, etc. the plaintext port of a node is reported to clients connected over plaintext if such port exists, otherwise, the TLS port is returned as before. This is backward-compatible, but given that the TLS port can never work for plaintext clients, it may be better to return an error instead of a redirect and exclude nodes without plaintext ports in the result of CLUSTER SLOTS/NODES, when the client is non-TLS. WDYT? |
|
@zuiderkwast The heuristic of returning a TCP or TLS port depending on the client connection has a few other unresolved issues:
The real problem with We plan to anyway extend We could also take a step forward and let clients explicitly specify their preference, which will solve the Unix socket clients issue. BTW personally I find the term "TCP port" more obvious than "plain port", not sure if it's just me though. |
Good question. Perhaps it's safest to return the TLS port to these. (If domain sockets are used by a cluster client, it can only be used for the (first) connected node on the same host as the application. It's possible to use a domain socket for the init node to get slot configuration and then use TLS for the rest of the nodes, although I think it's an unlikely scenario.) Agree? Do you have a different use case?
If any proxy (etc.) speaks non-TLS with one Redis node, it would need the non-TLS port to the other Redis nodes too AFAIK. The only scenario which could break is the TCP version of the unix domain socket example above, a very unlikely scenario I think.
HTTP redirect with relative scheme is a good comparison.
I'm all for this, but our motivation for this PR is to ease transition to TLS by allowing some VMs/containers/etc. or some corner case clients (cron jobs, etc.) to continue running non-TLS during a transition phase, until all parts of a system has switched to TLS. The solution has to work with old clients out of the box to be meaningful. After transitioning to TLS, I don't see much value in using TLS and non-TLS side by side. As for the CLUSTER SLOTS extension: Please consider using URIs to encode hostnames, schemes and other things. Some clients and similar use
Sure, if you think it would be valuable. It sounds like a separate PR to me in that case.
The TLS port is also a TCP port, so I don't think it's a very good term for non-TLS, but I can accept it if it's used in this sense in existing config and docs. Other words for non-TLS are "plaintext" and "cleartext", as what I can think of. Perhaps "clear" is a better short version than "plain" as part of a config field? |
|
We should assume multiple nodes run on the same operating system (VM/instance) as a way to utilize multiple cores, so theoretically we could need to redirect from one Unix socket to another. This is of course not support and already a shortcoming of the protocol. I think we can conclude this --
Regarding terminology, the configuration file and minimal documentation already refer to TCP vs. TLS. Technically it's not a very correct but I think it's common, but would be happy to hear other opinions/preferences. |
Interesting. I can change cluster-announce-plain-port to cluster-announce-tcp-port if you prefer(?). For reference, here's what I've found: TCP vs TLS is used in comments in redis.conf but not in actual config names, so it's not hard-wired. In docs, the closest to this I've found is this: "The One config comment mentions "plain TCP": Additionally, some TCP config probably also affects TLS, e.g. tcp-keepalive and repl-disable-tcp-nodelay(?). |
|
@zuiderkwast Redis is consistently inconsistent when it comes to terminology. I'm OK either way, @redis/core-team any other suggestions? |
|
I think one of our goals is to make it eventually consistent, and we'll get there eventually :) To make it plain, I'd keep it at |
|
regarding terminology, i personally don't like "plain text" (maybe "plain-tcp" is ok, but IMHO the word "text" is unrelated). i would rather use "tcp" or "non-tls" than "plain text". But maybe we can still find a better solution. i'm not sufficiently familiar with that area, so forgive me if my advise makes no sense. so we'll have p.s. putting that config apart, we also have a backwards compatibility issue with the cluster command responses, right? |
|
Nice idea @oranagra! I like the symmetry:
But then it has to be explained that, for historical reasons, cluster-announce-port is the TLS port if cluster-announce-tls-port = 0 and tls-cluster = yes. If that's not too complicated to understand for a user, then I'm fine with this. @yossigo, @itamarhaber Agree on
Note the difference between plain text (e.g. Note also that "cluster-announce-plain-port" doesn't contain "text". :-) I suppose "non-TLS" is indeed a more exact term when encryption is not used. I can totally change all occurrences of "plaintext" to "non-TLS" in the comments and docs. |
arguably, it's not only for historical reasons, it's also possibly slightly easier to use. if you define just one port, and it is used in the context of the other configs.
noted about "plaintext" vs "plain text", but i still think "non-tls" would be better if we are to keep the current approach of the PR. what about the concern about backwards compatibility issue with the cluster command responses? is there any concern here? |
I'll try. "Non-TLS" is already used in docs though, to highlight the absence of TLS. The only way around it would be formulations like "clients connected without TLS"
Not AFAIK. |
Given how port and tls-port are used in non-cluster (you have to zero |
|
Maybe we just need to be more explicit and use Note that we also have some ambiguity about the port usage inside the cluster bus. We assume port is either TLS or non-TLS, and can include an additional non-TLS port; but what if the cluster bus is non-TLS and we want to also expose a TLS port to clients? |
|
@yossigo i'm not sure i'm a fan of concatenation and string manipulation, i think i'd rather configs to be primitives (integers) whenever we can, and avoid additional parsing of compound configs (the places were we have that already are painful) |
I've thought about the possibility. For a cluster running on a single host to utilize multiple cores it could be useful. Unix domain sockets can also be useful for the cluster bus in this case. If we want to support it, I guess we can something similar, e.g. |
yossigo
left a comment
There was a problem hiding this comment.
@zuiderkwast I think we can push this forward, need @redis/core-team approval as it's tagged a major decision.
To summarize our discussions, there is more follow-up work to this PR:
- Fully support the case where we have a non-TLS cluster and we want to advertise TLS ports for TLS clients. This will require another case in the config handling as well as more tests.
- A way for clients to explicitly reference their connection redirection preference.
In the longer term, we need to complete this work by extending CLUSTER SLOTS to support multiple endpoints per node. This can be used not only for TLS/non-TLS but also Unix sockets etc.
oranagra
left a comment
There was a problem hiding this comment.
New config directives LGTM.
I didn't review the code, i imagine the top comment needs some update.
So I'll describe what I understand:
- the nodes used to communicate on the cluster bus either the TLS or non-TLS port depending on the
tls-clusterconfig. and the user was able to override that by definingcluster-announce-port - now the nodes can communicate both ports between them, and the user is able to define an alternative (non-default) announce port for both TLS and non-TLS (with
cluster-announce-tls-port). - CLUSTER SLOTS now report the TLS port if the client connected to the current node on the TLS port, and reports the non-TLS port if the client connected to it by non-TLS.
madolson
left a comment
There was a problem hiding this comment.
Mostly just some high level questions. I'm not a big fan of adding support for this type of configuration since it seems very insecure, but it seems like a stepping stone for having online TLS enabling, so that seems like a win.
|
Bump. Please re-approve if you're happy with the small refactoring commit added. ... or should I rebase first? |
Although Redis can be configured to allow plaintext and TLS clients side by side, (until now) Redis Cluster doesn't. If tls-cluster is set to yes, the cluster bus and the client ports reported by CLUSTER SLOTS, CLUSTER NODES, ASK and MOVED redirects are treated as TLS ports. To support also plaintext clients, commands such as CLUSTER NODES report the plaintext port to clients connected over plaintext and the TLS port to clients connected over TLS. The cluster bus is extended to contain the plaintext port of each node, whenever TLS cluster is enabled. This is fit in unused bits in the cluster bus header structure and the gossip structure. Before this commit, the unused area was memset to zero, which is treated as none, meaning a cluster node with this feature compatible with an older node without the feature.
If a client is connected over plaintext (non-TLS), report the plaintext port to the client in: * CLUSTER NODES * CLUSTER SLAVES * ASK and MOVED redirects Test: * In TCL cluster client, add parameter to specify if TLS should be used, instead of using the global ::tls variable. * In 04-resharding, query with both TLS and plaintext clients, covering redirects and CLUSTER NODES
If tls-cluster is yes and cluster-announce-tls-port is set, it refers to TLS port and cluster-announce-port refers to the non-TLS port. If tls-cluster is yes and cluster-announce-tls-port is zero, then instead cluster-announce-port refers to the TLS port. This logic replaces the cluster-announce-plain-port added in previous commit.
fef221e to
dec4780
Compare
|
Rebased. |
madolson
left a comment
There was a problem hiding this comment.
I'm good with this change. I left a comment about also committing the pport to the nodes conf so we don't show the wrong port transitively, but don't feel like that needs to be solved immediately.
|
A long journey but this is now merged, thank you @zuiderkwast! |
The cluster bus is established over TLS or non-TLS depending on the configuration tls-cluster. The client ports distributed in the cluster and sent to clients are assumed to be TLS or non-TLS also depending on tls-cluster. The cluster bus is now extended to also contain the non-TLS port of clients in a TLS cluster, when available. The non-TLS port of a cluster node, when available, is sent to clients connected without TLS in responses to CLUSTER SLOTS, CLUSTER NODES, CLUSTER SLAVES and MOVED and ASK redirects, instead of the TLS port. The user was able to override the client port by defining cluster-announce-port. Now cluster-announce-tls-port is added, so the user can define an alternative announce port for both TLS and non-TLS clients. Fixes redis#8134
The cluster bus is established over TLS or non-TLS depending on the configuration
tls-cluster. The client ports distributed in the cluster and sent to clients are assumed to be TLS or non-TLS also depending ontls-cluster.The cluster bus is now extended to also contain the non-TLS port of clients in a TLS cluster, when available. The non-TLS port of a cluster node, when available, is sent to clients connected without TLS in responses to CLUSTER SLOTS, CLUSTER NODES, CLUSTER SLAVES and MOVED and ASK redirects, instead of the TLS port.
The user was able to override the client port by defining
cluster-announce-port. Nowcluster-announce-tls-portis added, so the user can define an alternative announce port for both TLS and non-TLS clients.Fixes #8134