feat: Implement in-protocol TLS handling in proxy instead of parsers#3743
feat: Implement in-protocol TLS handling in proxy instead of parsers#3743Sarthak160 wants to merge 10 commits intomainfrom
Conversation
…the proxy to enable transparent recording.
|
|
||
| // Upgrade server connection (act as TLS client to the real server) | ||
| tlsConfig := &tls.Config{ | ||
| InsecureSkipVerify: true, |
Check failure
Code scanning / CodeQL
Disabled TLS certificate check High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 7 days ago
In general, the fix is to stop disabling TLS verification and instead configure tls.Config so that the client validates the server certificate and hostname. If custom CAs or self‑signed certs are needed, they should be added to a RootCAs pool instead of using InsecureSkipVerify.
In this specific file, there are two tls.Config literals that set InsecureSkipVerify: true when upgrading the PostgreSQL and MySQL server connections. We should remove InsecureSkipVerify: true from both while preserving ServerName, which allows the default verification logic to validate the certificate’s DNS name. No other behavior needs to change: the connections should still be upgraded to TLS using tls.Client and Handshake() exactly as before. Because we are simply changing TLS options, and crypto/tls is already imported, no new imports or helper methods are required. The edits are localized to the tlsConfig initializations around lines 103–107 and 155–159 in pkg/agent/proxy/tls/proto_tls.go.
| @@ -102,8 +102,7 @@ | ||
|
|
||
| // Upgrade server connection (act as TLS client to the real server) | ||
| tlsConfig := &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
| ServerName: dstURL, | ||
| ServerName: dstURL, | ||
| } | ||
| tlsServerConn := tls.Client(serverConn, tlsConfig) | ||
| if err := tlsServerConn.Handshake(); err != nil { | ||
| @@ -154,8 +153,7 @@ | ||
|
|
||
| // Upgrade server connection (act as TLS client to the real server) | ||
| tlsConfig := &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
| ServerName: serverName, | ||
| ServerName: serverName, | ||
| } | ||
| tlsServerConn := tls.Client(serverConn, tlsConfig) | ||
| if err := tlsServerConn.Handshake(); err != nil { |
pkg/agent/proxy/tls/proto_tls.go
Outdated
|
|
||
| // Upgrade server connection (act as TLS client to the real server) | ||
| tlsConfig := &tls.Config{ | ||
| InsecureSkipVerify: true, |
Check failure
Code scanning / CodeQL
Disabled TLS certificate check High
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 7 days ago
In general, the fix is to stop disabling certificate verification and instead configure the TLS client with proper trust roots and hostname verification. That means removing InsecureSkipVerify: true and letting Go’s default verification run, or—if non‑public CAs or self‑signed certs are used—supplying an appropriate RootCAs pool or a VerifyConnection callback that performs strict checks.
Within UpgradeMySQLServerToTLS in pkg/agent/proxy/tls/proto_tls.go, the minimal, behavior‑preserving but secure change is:
- Remove
InsecureSkipVerify: truefrom thetls.Config. - Keep
ServerName: serverNameso hostname verification will be performed using that value. - Rely on the process’ default root CAs (
tls.Config{}with noRootCAsset usesx509.SystemCertPool()by default) so that standard CA‑signed upstream certificates work. If the deployment uses private CAs, that configuration must occur elsewhere (we cannot invent it here).
Concretely, we only need to change the tlsConfig initialization block to stop setting InsecureSkipVerify, leaving everything else intact.
| @@ -154,8 +154,7 @@ | ||
|
|
||
| // Upgrade server connection (act as TLS client to the real server) | ||
| tlsConfig := &tls.Config{ | ||
| InsecureSkipVerify: true, | ||
| ServerName: serverName, | ||
| ServerName: serverName, | ||
| } | ||
| tlsServerConn := tls.Client(serverConn, tlsConfig) | ||
| if err := tlsServerConn.Handshake(); err != nil { |
There was a problem hiding this comment.
Pull request overview
Adds proxy-level handling for database protocols that negotiate TLS in-protocol (not via an immediate TLS ClientHello), with the goal of letting downstream parsers operate on plaintext streams while still supporting TLS to/from the real DB.
Changes:
- Introduces PostgreSQL SSLRequest detection + proxy-side TLS upgrade helper(s) (and shared MySQL helpers) in
pkg/agent/proxy/tls/. - Updates the main proxy connection flow to intercept PostgreSQL SSLRequest in record mode and perform the SSL/TLS upgrade before invoking parsers.
- Refactors MySQL recorder TLS upgrade to use a centralized TLS upgrade helper; adds explanatory comments in MySQL replayer.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/agent/proxy/tls/proto_tls.go | Adds protocol-specific SSL/TLS negotiation helpers for PostgreSQL/MySQL (in-protocol upgrades). |
| pkg/agent/proxy/proxy.go | Detects PostgreSQL SSLRequest (record mode) and attempts proxy-level SSL/TLS upgrade before parsing. |
| pkg/agent/proxy/integrations/mysql/replayer/conn.go | Clarifies replay-mode TLS handling behavior via comments. |
| pkg/agent/proxy/integrations/mysql/recorder/conn.go | Switches MySQL TLS upgrade logic to centralized helper(s). |
| pkg/agent/proxy/integrations/integrations.go | Adds StreamConn wrapper type and expands interface documentation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Dial the destination server first | ||
| dstConn, err = net.Dial("tcp", dstAddr) | ||
| if err != nil { | ||
| utils.LogError(logger, err, "failed to dial PostgreSQL server for SSL negotiation") | ||
| return err |
There was a problem hiding this comment.
HandlePostgresSSL can return an already dialed and TLS-upgraded dstConn, but later in handleConnection the normal non-TLS path still re-dials dstConn because isTLS remains false. That will overwrite the negotiated connection and break Postgres-over-TLS. Consider setting a flag (or updating isTLS) to skip the later dial and reuse the dstConn returned here.
Signed-off-by: Sarthak160 <rocksarthak45@gmail.com>
… Docker build, and remove the `StreamConn` type.
…ly parsers and a PostgreSQL adapter.
…us and asynchronous WriteFuncs, removing the PostgreSQL adapter.
…, tune read buffer parameters, and remove debugging print statements.
This pull request introduces a significant refactor to how in-protocol TLS (SSL) negotiation is handled for database protocols (PostgreSQL and MySQL) in the proxy. The main improvement is centralizing the SSL/TLS upgrade logic at the proxy layer, so protocol parsers always receive plaintext byte streams, simplifying their implementation and improving maintainability.
Centralization of in-protocol TLS handling:
pkg/agent/proxy/tls/proto_tls.gofile with helpers for detecting and handling PostgreSQL and MySQL SSL negotiation at the proxy level, including functions likeIsPostgresSSLRequest,HandlePostgresSSL,UpgradeMySQLConnections, and more. This ensures that both client and server connections are upgraded to TLS before passing them to protocol parsers.pkg/agent/proxy/proxy.go) to detect PostgreSQL SSLRequest packets and perform the SSL negotiation and connection upgrades at the proxy layer. After negotiation, the parser receives the next protocol packet as plaintext.Abstraction and interface improvements:
StreamConnstruct inpkg/agent/proxy/integrations/integrations.go, which wraps a network connection with a custom reader. This allows the proxy to prepend already-read bytes (such as after SSL negotiation) so parsers always see the full protocol stream. TheIntegrationsinterface and its documentation were updated to clarify that parsers receiveStreamConnobjects with plaintext streams.MySQL protocol handling enhancements:
UpgradeMySQLConnections). This removes the previous in-parser TLS logic and ensures consistent handling with the proxy-level approach.These changes make the proxy more robust, easier to maintain, and ensure all protocol parsers work with plaintext streams regardless of whether the underlying protocol uses in-band SSL/TLS negotiation.
Describe the changes that are made
Links & References
Closes: #[issue number that will be closed through this PR]
🔗 Related PRs
🐞 Related Issues
📄 Related Documents
What type of PR is this? (check all applicable)
Added e2e test pipeline?
Added comments for hard-to-understand areas?
Added to documentation?
Are there any sample code or steps to test the changes?
Self Review done?
Any relevant screenshots, recordings or logs?
🧠 Semantics for PR Title & Branch Name
Please ensure your PR title and branch name follow the Keploy semantics:
📌 PR Semantics Guide
📌 Branch Semantics Guide
Examples:
fix: patch MongoDB document update bugfeat/#1-login-flow(You may skip mentioning the issue number in the branch name if the change is small and the PR description clearly explains it.)Additional checklist: