[WiP] mysql proxy: separate downstream client and upstream server authentication.#15485
[WiP] mysql proxy: separate downstream client and upstream server authentication.#15485qinggniq wants to merge 26 commits intoenvoyproxy:mainfrom
Conversation
Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
…hentication Signed-off-by: qinggniq <livewithblank@gmail.com>
|
@qinggniq I don't understand:
for two reasons:
|
| google.protobuf.UInt32Value max_idle_connections = 2; | ||
|
|
||
| // Connections when envoy setup, default is 0. | ||
| google.protobuf.UInt32Value start_connections = 3; |
There was a problem hiding this comment.
What do these changes have to do with auth?
|
@htuch Hello, I filled up the pr message, just ping me if the message has any confused points. |
Signed-off-by: qinggniq <livewithblank@gmail.com>
| } | ||
|
|
||
| message MySQLProtocolOptions { | ||
| config.core.v3.DataSource auth_password = 1 [(udpa.annotations.sensitive) = true]; |
There was a problem hiding this comment.
Suggest a shared message for username/password.
There was a problem hiding this comment.
Do you mean remove udpa.annotations.sensitive = true? I just found at redis username/password is secret at
envoy/api/envoy/extensions/filters/network/redis_proxy/v3/redis_proxy.proto
Lines 308 to 318 in a240824
There was a problem hiding this comment.
I'm saying grouping username/password with senstitivity options into a single message is good and makes sense als for downstream above; the same username/password message can be reused for both upstream/downstream.
htuch
left a comment
There was a problem hiding this comment.
I still think we need to maintain backwards compatibility. Otherwise, when we ship the next Envoy release, control planes will have their configuration rejected by Envoy.
This is a v3 stable filter (at API level), so we can't just say that certain uses of it are no longer supported. You need to allow the filter to function in the use cases it previously did limit the new capabilities for when it is a terminal filter.
|
|
||
| repeated Route routes = 3; | ||
|
|
||
| ConnectionPoolSettings setting = 4 [(validate.rules).message = {required: true}]; |
There was a problem hiding this comment.
Can you split out the connection pool aspect of this PR from the split in the auth aspect? This is a very large PR and will be hard to review unless that is done IMHO.
|
@rshriram @venilnoronha for high-level API and design input as well. |
|
@htuch I think there are two approaches to make it backward compatible:
|
|
@qinggniq I don't think (2) is great given duplication, so you will need to add an API field to distinguish from existing behaviors like (1). |
|
@htuch Yes, I agree that if (1) and (2) could both work, (1) will be better. I'm trying to find out a way to determine the filter whether is a terminal filter at runtime #15565. And I think the method (2) could be able not to make much duplication, the code base of mysql proxy contains many common files which can be used by two filters like |
Signed-off-by: qinggniq <livewithblank@gmail.com>
…ysql-tool Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
alyssawilk
left a comment
There was a problem hiding this comment.
(adding a drive by comment or two after looking this over from the runtime issue)
| ConnectionPoolSettings config_; | ||
| std::list<ThreadLocalActiveClientPtr> pending_clients_; | ||
| std::list<ThreadLocalActiveClientPtr> active_clients_; | ||
| std::list<ThreadLocalActiveClientPtr> busy_clients_; |
There was a problem hiding this comment.
connection reuse will be awesome! That said, this looks a lot like the legacy TCP connection pool and I don't think we want to reinvent this again, especially as the base pool supports connection reuse.
Can we please inherit from souce/common/conn_pool/conn_pool_base.* and refactor/extend where needed to avoid all the duplicate pending/active/busy work and reuse stats etc?
There was a problem hiding this comment.
Yes, that's better.
| // Configuration for tunneling TCP over other transports or application layers. | ||
| // Tunneling is supported over both HTTP/1.1 and HTTP/2. Upstream protocol is | ||
| // determined by the cluster configuration. | ||
| // Currently, only HTTP/2 is supported. When other options exist, HTTP/2 will |
There was a problem hiding this comment.
Yes, I'll fix those unrelated changes.
|
@venilnoronha @rshriram would one of you be able to provide some MySQL CODEOWNERS input as well into the API discussion? Thanks. |
Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com> format Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
|
|
||
| # We already have absl in the build, define absl=1 to tell googletest to use absl for backtrace. | ||
| build --define absl=1 | ||
| build --//bazel:http3=False |
There was a problem hiding this comment.
I will remove it in the final.
|
|
||
| repeated Route routes = 3; |
There was a problem hiding this comment.
Here I will add a field like bool new_feature_enabled to control after I replace the signature of isTerminalFilter. #15565 (comment)
|
@lizan this was introduced by Tetrate I think; do you folks still consider MySQL something you are supporting? |
htuch
left a comment
There was a problem hiding this comment.
@qinggniq I left some API comments, as long as we resolve this in a way that does not radically break existing users I'm fine with that.
Re: code review, I'm trying to find someone who can take a look. The existing CODEOWNERS appear MIA and this is a large non-trivial change that needs someone with MySQL experience.
We may be able to simply treat this as an external contribution and move it under the new contrib/ directory structure that @mattklein123 is planning on putting in place. I've had a look and your code appears to be localized to just the extension, so it would naturally fit that mold.
| } | ||
|
|
||
| message MySQLProtocolOptions { | ||
| config.core.v3.DataSource auth_password = 1 [(udpa.annotations.sensitive) = true]; |
There was a problem hiding this comment.
I'm saying grouping username/password with senstitivity options into a single message is good and makes sense als for downstream above; the same username/password message can be reused for both upstream/downstream.
|
|
||
| reserved 3; | ||
|
|
||
| reserved "is_termianl"; |
Signed-off-by: qinggniq <livewithblank@gmail.com> fix spell Signed-off-by: qinggniq <livewithblank@gmail.com>
…-tool Signed-off-by: qinggniq <livewithblank@gmail.com>
Signed-off-by: qinggniq <livewithblank@gmail.com>
@htuch Thanks for review, I am a little confused of above message.
|
| // If the access log field is empty, access logs will not be written. | ||
| string access_log = 2; | ||
|
|
||
| // [#not-implemented-hide:] enable feature of separate authentication of downstream clients and upstream server. When feature_enable is true, the filter is a terminal filter, it's config should put at the last of filter chain, when feature_enable is false, the filter is not a terminal filter, it's config can not put at the last of filter chain. Default is false. |
There was a problem hiding this comment.
Needs to be wrapped and have a better name than "feature_enable"; maybe enable_protocol_management or something like that to indicate you're now basically the equivalent of HCM.
| // - database: "database_b" | ||
| // cluster: "cluster_b" | ||
| // | ||
| // When using the above routes, the following connect dsn would be sent to: |
There was a problem hiding this comment.
| // * If username is empty but password is not, then proxy will only auth password. | ||
| // * If password is empty but username is not, then proxy will only auth username/ | ||
| // * If the username is not match, then ER_ACCESS_DENIED_ERROR will return; | ||
| // * If connect db name is not found in envoy.extensions.filters.network.mysql_proxy.v3.MySQLProxy.routes, then ER_ER_BAD_DB_ERROR will return. |
There was a problem hiding this comment.
What does the last bullet point have to do with auth?
|
|
||
| // Downstream client username/password. | ||
| // * If username and password is empty, then authentication will always pass. | ||
| // * If username is empty but password is not, then proxy will only auth password. |
There was a problem hiding this comment.
| // * If username is empty but password is not, then proxy will only auth password. | |
| // * If username is empty but password is not, then proxy will only match the auth password. |
There was a problem hiding this comment.
Also, what's the point of wildcard username/passwords? Why not have exact match semantics, expecting an empty string when there is an empty username specified?
There was a problem hiding this comment.
Yeah, it's weird not using exact match semantics for username/password. fixed.
| // Downstream client username/password. | ||
| // * If username and password is empty, then authentication will always pass. | ||
| // * If username is empty but password is not, then proxy will only auth password. | ||
| // * If password is empty but username is not, then proxy will only auth username/ |
There was a problem hiding this comment.
| // * If password is empty but username is not, then proxy will only auth username/ | |
| // * If password is empty but username is not, then proxy will only match the auth username. |
|
|
||
| // Auth information of MySQL. | ||
| message AuthInfo { | ||
| config.core.v3.DataSource auth_username = 1; |
There was a problem hiding this comment.
Probably just put the sensitive annotations on the fields in here directly to factor them out.
Signed-off-by: qinggniq <livewithblank@gmail.com> fix typo Signed-off-by: qinggniq <livewithblank@gmail.com> fix typo Signed-off-by: qinggniq <livewithblank@gmail.com>
lizan
left a comment
There was a problem hiding this comment.
In general I think the direction is fine, but this PR is too large. Is it possible to split out a couple things out of this PR such: a) adding routing/conn pool support and b) authentication support?
| config.core.v3.DataSource auth_username = 1 [(udpa.annotations.sensitive) = true]; | ||
|
|
||
| config.core.v3.DataSource auth_password = 2 [(udpa.annotations.sensitive) = true]; |
There was a problem hiding this comment.
can be just username/password (without auth_ prefix).
| // [#not-implemented-hide:] enable manage MySQL protocol at proxy. Default is false. | ||
| // * When enable_manage_protocol is true, MySQL filter is a terminal filter, it's config should put at the last of filter chain, in the same time, MySQLProtocolOptions should be set at corresponding config of cluster for connecting to upstream database. | ||
| // * When enable_manage_protocol is false, MySQL filter is not a terminal filter, it's config can not put at the last of filter chain. | ||
| bool enable_manage_protocol = 3; |
There was a problem hiding this comment.
Isn't this implied by whether routes has element or not? Existing behavior delegate route select to tcp_proxy so in that case route shouldn't have anything.
There was a problem hiding this comment.
Yes, when enable_manage_protocol is false, route and auth_info should not set value.
|
@lizan ok, I'll try to do it. |
This pull request is the part of #15485, help reduce the work of review. - refactor the BUILD struct of mysql proxy - replace auth related fields of message from `string` to `vector`, avoid `\0` character leading message to be partial. Commit Message: refactor BUILD struct of mysql proxy Additional Description: Risk Level: Low Testing: N/A Docs Changes: N/A Release Notes: N/A Signed-off-by: qinggniq <livewithblank@gmail.com>
This pull request is the part of envoyproxy#15485, help reduce the work of review. - refactor the BUILD struct of mysql proxy - replace auth related fields of message from `string` to `vector`, avoid `\0` character leading message to be partial. Commit Message: refactor BUILD struct of mysql proxy Additional Description: Risk Level: Low Testing: N/A Docs Changes: N/A Release Notes: N/A Signed-off-by: qinggniq <livewithblank@gmail.com>
|
This pull request has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in 7 days if no further activity occurs. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
|
This pull request has been automatically closed because it has not had activity in the last 37 days. Please feel free to give a status update now, ping for review, or re-open when it's ready. Thank you for your contributions! |
Signed-off-by: qinggniq livewithblank@gmail.com
For an explanation of how to fill out the fields, please see the relevant section
in PULL_REQUESTS.md
This pr implements the separate downstream client and upstream server authentication in mysql proxy.
How it works?
mysql client poolper thread, establish a valid mysql client is expensive, it need one tcp handshake and at least 1.5 round trip server greet -> client auth -> server response, if server need client switch auth plugin, it need additional 1 round trip. So I decide to maintain amysql client poolfor each cluster, once mysql client is released, it will be put back into pool.greetmessage to client, wait for clientauthmessage, then verify the auth message bydownstream_auth_username, downstream_auth_password. Once client pass the authentication, base on thedbinauthmessage, proxy will find corresponding cluster, and get a client frommysql client pool.mysql client poolfirst check whether there are anyidleclients, if not it will use underlayingTcp::ConnectionPool::Instanceto acquire a connection, when success, it will mmic as a mysql client, deal withgreetmessage, sendauthmessage, when receivedokmessage which means it pass the connection phase, the pool will put this connection intoactive clientslist.What will it affect?
Now mysql proxy needs to maintain connections of upstream like.tcp proxyorredis proxy, so it become a terminal filter. In current mysql proxy documentation, it mentions that it's Dynamic Metadata could combine withrbac filterto control accesses to individual tables in a databasebut now mysql proxy becomes a terminal filter, so this feature is no longer support, but when mysql proxy maintain the connections of upstream, it becomes possible to support more features likemirror, fault, read load balance.Commit Message: separate downstream client and upstream server authentication.
Additional Description:
Risk Level: medium
Testing: TBD
Docs Changes: TBD
Release Notes: support separate downstream client and upstream server authentication.
Platform Specific Features: N/A
[Optional Runtime guard:]
[Optional Fixes #Issue] #14697
[Optional Deprecated:]
[Optional API Considerations:]