From e7cfc4bf3a8da322c1990c83d34f0ed1962afcc2 Mon Sep 17 00:00:00 2001 From: yucun <87208113+db-will@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:06:03 -0500 Subject: [PATCH 01/11] Add tls support for mysql client --- cmd/go-tpc/main.go | 73 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 4b4134b..bd0a523 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -3,6 +3,8 @@ package main import ( "context" "crypto/sha1" + "crypto/tls" + "crypto/x509" "database/sql" sqldrv "database/sql/driver" "encoding/hex" @@ -18,6 +20,7 @@ import ( "github.com/pingcap/go-tpc/pkg/util" "github.com/spf13/cobra" _ "go.uber.org/automaxprocs" + // mysql package "github.com/go-sql-driver/mysql" // pg @@ -47,15 +50,19 @@ var ( connParams string outputStyle string targets []string + sslCA string + sslCert string + sslKey string globalDB *sql.DB globalCtx context.Context ) const ( - createDBDDL = "CREATE DATABASE " - mysqlDriver = "mysql" - pgDriver = "postgres" + createDBDDL = "CREATE DATABASE " + mysqlDriver = "mysql" + pgDriver = "postgres" + customTlsName = "custom" ) type MuxDriver struct { @@ -93,18 +100,31 @@ func newDB(targets []string, driver string, user string, password string, dbName hash.Write([]byte(password)) hash.Write([]byte(dbName)) hash.Write([]byte(connParams)) + + if driver == mysqlDriver && len(sslCA) > 0 { + registerMysqlTLSConfig() + } + for i, addr := range targets { hash.Write([]byte(addr)) switch driver { case mysqlDriver: + var tlsName string = "preferred" + if len(sslCA) > 0 { + tlsName = customTlsName + } // allow multiple statements in one query to allow q15 on the TPC-H - dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?multiStatements=true&tls=preferred", user, password, addr, dbName) + dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?multiStatements=true&tls=%s", user, password, addr, dbName, tlsName) if len(connParams) > 0 { dsn = dsn + "&" + connParams } names[i] = dsn drv = &mysql.MySQLDriver{} case pgDriver: + if len(sslCA) > 0 { + panic("postgres driver doesn't support tls yet") + } + dsn := fmt.Sprintf("postgres://%s:%s@%s/%s", user, password, addr, dbName) if len(connParams) > 0 { dsn = dsn + "?" + connParams @@ -150,9 +170,10 @@ func openDB() { tmpDB, _ = newDB(targets, driver, user, password, "", connParams) defer tmpDB.Close() if _, err := tmpDB.Exec(createDBDDL + dbName); err != nil { - panic(fmt.Errorf("failed to create database, err %v\n", err)) + panic(fmt.Errorf("failed to create database, err %v", err)) } } else { + fmt.Printf("failed to ping db, err %v\n", err) globalDB = nil } } else { @@ -209,6 +230,9 @@ func main() { rootCmd.PersistentFlags().StringVar(&outputStyle, "output", util.OutputStylePlain, "output style, valid values can be { plain | table | json }") rootCmd.PersistentFlags().StringSliceVar(&targets, "targets", nil, "Target database addresses") rootCmd.PersistentFlags().MarkHidden("targets") + rootCmd.PersistentFlags().StringVar(&sslCA, "ssl-ca", "", "Path of file that contains list of trusted SSL CAs for connection") + rootCmd.PersistentFlags().StringVar(&sslCert, "ssl-cert", "", "Path of file that contains X509 certificate in PEM format for connection") + rootCmd.PersistentFlags().StringVar(&sslKey, "ssl-key", "", "Path of file that contains X509 key in PEM format for connection") cobra.EnablePrefixMatching = true @@ -251,3 +275,42 @@ func main() { cancel() } + +// registerMysqlTLSConfig constructs a `*tls.Config` from the CA, certification and key +// paths, and register to mysql client. +func registerMysqlTLSConfig() { + // Load the client certificates from disk + var certificates []tls.Certificate + if len(sslCert) != 0 && len(sslKey) != 0 { + cert, err := tls.LoadX509KeyPair(sslCert, sslKey) + if err != nil { + panic(fmt.Errorf("could not load client key pair, err %v", err)) + } + certificates = []tls.Certificate{cert} + } + + // Create a certificate pool from CA + certPool := x509.NewCertPool() + ca, err := os.ReadFile(sslCA) + if err != nil { + panic(fmt.Errorf("could not read ca certificate, err %v", err)) + } + + // Append the certificates from the CA + if !certPool.AppendCertsFromPEM(ca) { + panic(fmt.Errorf("failed to append ca certs")) + } + + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS10, + Certificates: certificates, + RootCAs: certPool, + ClientCAs: certPool, + NextProtos: []string{"h2", "http/1.1"}, // specify `h2` to let Go use HTTP/2. + } + + err = mysql.RegisterTLSConfig(customTlsName, tlsConfig) + if err != nil { + panic(fmt.Errorf("failed to register ssl configs, err %v", err)) + } +} From 52095d4de43542b82e18d9480768084068143a9f Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:32:00 -0500 Subject: [PATCH 02/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index bd0a523..abcf11c 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -302,7 +302,7 @@ func registerMysqlTLSConfig() { } tlsConfig := &tls.Config{ - MinVersion: tls.VersionTLS10, + MinVersion: tls.VersionTLS12, Certificates: certificates, RootCAs: certPool, ClientCAs: certPool, From 0c2b45d0a2d941010013a4a26b4756c2e0d697fb Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:32:16 -0500 Subject: [PATCH 03/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index abcf11c..28ccd51 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -311,6 +311,6 @@ func registerMysqlTLSConfig() { err = mysql.RegisterTLSConfig(customTlsName, tlsConfig) if err != nil { - panic(fmt.Errorf("failed to register ssl configs, err %v", err)) + panic(fmt.Errorf("failed to register TLS configs, err %v", err)) } } From c8dffdfc1c5c1c330963b3e93844b885d8e504a0 Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:32:25 -0500 Subject: [PATCH 04/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 28ccd51..010b75e 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -122,7 +122,7 @@ func newDB(targets []string, driver string, user string, password string, dbName drv = &mysql.MySQLDriver{} case pgDriver: if len(sslCA) > 0 { - panic("postgres driver doesn't support tls yet") + panic("postgresql driver doesn't support TLS yet") } dsn := fmt.Sprintf("postgres://%s:%s@%s/%s", user, password, addr, dbName) From a7957cb36aa897319823fb3f6f220678fced6a68 Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:54:13 -0500 Subject: [PATCH 05/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 010b75e..852e9ac 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -293,7 +293,7 @@ func registerMysqlTLSConfig() { certPool := x509.NewCertPool() ca, err := os.ReadFile(sslCA) if err != nil { - panic(fmt.Errorf("could not read ca certificate, err %v", err)) + panic(fmt.Errorf("could not read CA certificate, err %v", err)) } // Append the certificates from the CA From 4b2c7db2e3f46b7a6718604118b0ab13e270b2e3 Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:54:30 -0500 Subject: [PATCH 06/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 852e9ac..d008646 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -298,7 +298,7 @@ func registerMysqlTLSConfig() { // Append the certificates from the CA if !certPool.AppendCertsFromPEM(ca) { - panic(fmt.Errorf("failed to append ca certs")) + panic(fmt.Errorf("failed to append CA certs")) } tlsConfig := &tls.Config{ From 9ad25f97c48c1bb9017e22ccda935fb04aca943e Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:54:38 -0500 Subject: [PATCH 07/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index d008646..585a9b8 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -311,6 +311,6 @@ func registerMysqlTLSConfig() { err = mysql.RegisterTLSConfig(customTlsName, tlsConfig) if err != nil { - panic(fmt.Errorf("failed to register TLS configs, err %v", err)) + panic(fmt.Errorf("failed to register TLS config, err %v", err)) } } From 41368bb15264cfbf3ff029fc42cdab35f58484c7 Mon Sep 17 00:00:00 2001 From: yucun <87208113+db-will@users.noreply.github.com> Date: Sat, 4 Jan 2025 00:18:29 -0500 Subject: [PATCH 08/11] Adjust code based on reviews --- cmd/go-tpc/main.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 585a9b8..975d1d6 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -306,7 +306,6 @@ func registerMysqlTLSConfig() { Certificates: certificates, RootCAs: certPool, ClientCAs: certPool, - NextProtos: []string{"h2", "http/1.1"}, // specify `h2` to let Go use HTTP/2. } err = mysql.RegisterTLSConfig(customTlsName, tlsConfig) From 56b6a649e5ce23fcf45c388af2256bef2099cd1a Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Sun, 5 Jan 2025 20:41:23 -0500 Subject: [PATCH 09/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 975d1d6..16faeaa 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -121,7 +121,7 @@ func newDB(targets []string, driver string, user string, password string, dbName names[i] = dsn drv = &mysql.MySQLDriver{} case pgDriver: - if len(sslCA) > 0 { + if len(sslCA) > 0 || len(sslKey) > 0 || len(sslCert) > 0 { panic("postgresql driver doesn't support TLS yet") } From 7f4316bbeedb4716042d076f2b533a52e921a31c Mon Sep 17 00:00:00 2001 From: will <87208113+db-will@users.noreply.github.com> Date: Sun, 5 Jan 2025 21:45:55 -0500 Subject: [PATCH 10/11] Update cmd/go-tpc/main.go MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Daniël van Eeden --- cmd/go-tpc/main.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 16faeaa..50c7977 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -287,6 +287,8 @@ func registerMysqlTLSConfig() { panic(fmt.Errorf("could not load client key pair, err %v", err)) } certificates = []tls.Certificate{cert} + } else if len(sslCert) > 0 || len(sslKey) > 0 { + panic(errors.New("incomplete key pair configuration")) } // Create a certificate pool from CA From 3b8119aaf3c7006c7ff06a814c3afee15b228a16 Mon Sep 17 00:00:00 2001 From: yucun <87208113+db-will@users.noreply.github.com> Date: Sun, 5 Jan 2025 21:54:40 -0500 Subject: [PATCH 11/11] Update error message --- cmd/go-tpc/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/go-tpc/main.go b/cmd/go-tpc/main.go index 50c7977..dfdf1f8 100644 --- a/cmd/go-tpc/main.go +++ b/cmd/go-tpc/main.go @@ -288,7 +288,7 @@ func registerMysqlTLSConfig() { } certificates = []tls.Certificate{cert} } else if len(sslCert) > 0 || len(sslKey) > 0 { - panic(errors.New("incomplete key pair configuration")) + panic("incomplete key pair configuration") } // Create a certificate pool from CA @@ -300,7 +300,7 @@ func registerMysqlTLSConfig() { // Append the certificates from the CA if !certPool.AppendCertsFromPEM(ca) { - panic(fmt.Errorf("failed to append CA certs")) + panic("failed to append CA certs") } tlsConfig := &tls.Config{