From 23617f287fbf0903e8979ec4ba5086b032e0bc23 Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Thu, 31 Jan 2019 10:03:48 -0600 Subject: [PATCH 1/9] Add initial support for ssl encryption connections to database servers. - Adding a command line option for users to enforce tls/ssl connections for the applier, inspector, and binlog reader. - The user can optionally request server certificate verification through a command line option to specify the ca cert via a file path. - Fixes an existing bug appending the timeout option to the singleton applier connection. --- go/base/context.go | 9 +++++++ go/binlog/gomysql_reader.go | 1 + go/cmd/gh-ost/main.go | 8 ++++++ go/logic/applier.go | 2 +- go/mysql/connection.go | 51 +++++++++++++++++++++++++++++++++---- go/mysql/connection_test.go | 19 +++++++++++++- 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/go/base/context.go b/go/base/context.go index 0043d07b2..856a29ca3 100644 --- a/go/base/context.go +++ b/go/base/context.go @@ -99,6 +99,8 @@ type MigrationContext struct { ConfigFile string CliUser string CliPassword string + UseTLS bool + TlsCACertificate string CliMasterUser string CliMasterPassword string @@ -695,6 +697,13 @@ func (this *MigrationContext) ApplyCredentials() { } } +func (this *MigrationContext) SetupTLS() error { + if this.UseTLS { + return this.InspectorConnectionConfig.UseTLS(this.TlsCACertificate) + } + return nil +} + // ReadConfigFile attempts to read the config file, if it exists func (this *MigrationContext) ReadConfigFile() error { this.configMutex.Lock() diff --git a/go/binlog/gomysql_reader.go b/go/binlog/gomysql_reader.go index 794d54589..41d1ead92 100644 --- a/go/binlog/gomysql_reader.go +++ b/go/binlog/gomysql_reader.go @@ -46,6 +46,7 @@ func NewGoMySQLReader(migrationContext *base.MigrationContext) (binlogReader *Go Port: uint16(binlogReader.connectionConfig.Key.Port), User: binlogReader.connectionConfig.User, Password: binlogReader.connectionConfig.Password, + TLSConfig: binlogReader.connectionConfig.TLSConfig(), UseDecimal: true, } binlogReader.binlogSyncer = replication.NewBinlogSyncer(binlogSyncerConfig) diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index 302470299..8bd8c78a4 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -14,6 +14,7 @@ import ( "github.com/github/gh-ost/go/base" "github.com/github/gh-ost/go/logic" + _ "github.com/go-sql-driver/mysql" "github.com/outbrain/golib/log" "golang.org/x/crypto/ssh/terminal" @@ -54,6 +55,9 @@ func main() { flag.StringVar(&migrationContext.ConfigFile, "conf", "", "Config file") askPass := flag.Bool("ask-pass", false, "prompt for MySQL password") + flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL") + flag.StringVar(&migrationContext.TlsCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections. Requires --ssl") + flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)") flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)") flag.StringVar(&migrationContext.AlterStatement, "alter", "", "alter statement (mandatory)") @@ -194,6 +198,9 @@ func main() { if migrationContext.CliMasterPassword != "" && migrationContext.AssumeMasterHostname == "" { log.Fatalf("--master-password requires --assume-master-host") } + if migrationContext.TlsCACertificate != "" && !migrationContext.UseTLS { + log.Fatalf("--ssl-ca requires --ssl") + } if *replicationLagQuery != "" { log.Warningf("--replication-lag-query is deprecated") } @@ -238,6 +245,7 @@ func main() { migrationContext.SetThrottleHTTP(*throttleHTTP) migrationContext.SetDefaultNumRetries(*defaultRetries) migrationContext.ApplyCredentials() + migrationContext.SetupTLS() if err := migrationContext.SetCutOverLockTimeoutSeconds(*cutOverLockTimeoutSeconds); err != nil { log.Errore(err) } diff --git a/go/logic/applier.go b/go/logic/applier.go index 140b1a4f5..b3de0e1e4 100644 --- a/go/logic/applier.go +++ b/go/logic/applier.go @@ -73,7 +73,7 @@ func (this *Applier) InitDBConnections() (err error) { if this.db, _, err = mysql.GetDB(this.migrationContext.Uuid, applierUri); err != nil { return err } - singletonApplierUri := fmt.Sprintf("%s?timeout=0", applierUri) + singletonApplierUri := fmt.Sprintf("%s&timeout=0", applierUri) if this.singletonDB, _, err = mysql.GetDB(this.migrationContext.Uuid, singletonApplierUri); err != nil { return err } diff --git a/go/mysql/connection.go b/go/mysql/connection.go index c9c75f2fb..bfb445adf 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -6,8 +6,14 @@ package mysql import ( + "crypto/tls" + "crypto/x509" + "errors" "fmt" + "io/ioutil" "net" + + "github.com/go-sql-driver/mysql" ) // ConnectionConfig is the minimal configuration required to connect to a MySQL server @@ -16,6 +22,7 @@ type ConnectionConfig struct { User string Password string ImpliedKey *InstanceKey + tlsConfig *tls.Config } func NewConnectionConfig() *ConnectionConfig { @@ -29,9 +36,10 @@ func NewConnectionConfig() *ConnectionConfig { // DuplicateCredentials creates a new connection config with given key and with same credentials as this config func (this *ConnectionConfig) DuplicateCredentials(key InstanceKey) *ConnectionConfig { config := &ConnectionConfig{ - Key: key, - User: this.User, - Password: this.Password, + Key: key, + User: this.User, + Password: this.Password, + tlsConfig: this.tlsConfig, } config.ImpliedKey = &config.Key return config @@ -42,13 +50,42 @@ func (this *ConnectionConfig) Duplicate() *ConnectionConfig { } func (this *ConnectionConfig) String() string { - return fmt.Sprintf("%s, user=%s", this.Key.DisplayString(), this.User) + return fmt.Sprintf("%s, user=%s, usingTLS=%t", this.Key.DisplayString(), this.User, this.tlsConfig != nil) } func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool { return this.Key.Equals(&other.Key) || this.ImpliedKey.Equals(other.ImpliedKey) } +func (this *ConnectionConfig) UseTLS(caCertificatePath string) error { + skipVerify := caCertificatePath == "" + var rootCertPool *x509.CertPool + if !skipVerify { + rootCertPool = x509.NewCertPool() + pem, err := ioutil.ReadFile(caCertificatePath) + if err != nil { + return err + } + if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { + return errors.New("could not add ca certificate to cert pool") + } + } + + this.tlsConfig = &tls.Config{ + RootCAs: rootCertPool, + InsecureSkipVerify: skipVerify, + } + + if err := mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig); err != nil { + return err + } + return nil +} + +func (this *ConnectionConfig) TLSConfig() *tls.Config { + return this.tlsConfig +} + func (this *ConnectionConfig) GetDBUri(databaseName string) string { hostname := this.Key.Hostname var ip = net.ParseIP(hostname) @@ -57,5 +94,9 @@ func (this *ConnectionConfig) GetDBUri(databaseName string) string { hostname = fmt.Sprintf("[%s]", hostname) } interpolateParams := true - return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=%t&autocommit=true&charset=utf8mb4,utf8,latin1", this.User, this.Password, hostname, this.Key.Port, databaseName, interpolateParams) + tlsOption := "false" + if this.tlsConfig != nil { + tlsOption = this.Key.StringCode() + } + return fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?interpolateParams=%t&autocommit=true&charset=utf8mb4,utf8,latin1&tls=%s", this.User, this.Password, hostname, this.Key.Port, databaseName, interpolateParams, tlsOption) } diff --git a/go/mysql/connection_test.go b/go/mysql/connection_test.go index 19badf388..3a6cf294a 100644 --- a/go/mysql/connection_test.go +++ b/go/mysql/connection_test.go @@ -6,6 +6,7 @@ package mysql import ( + "crypto/tls" "testing" "github.com/outbrain/golib/log" @@ -31,6 +32,10 @@ func TestDuplicateCredentials(t *testing.T) { c.Key = InstanceKey{Hostname: "myhost", Port: 3306} c.User = "gromit" c.Password = "penguin" + c.tlsConfig = &tls.Config{ + InsecureSkipVerify: true, + ServerName: "feathers", + } dup := c.DuplicateCredentials(InstanceKey{Hostname: "otherhost", Port: 3310}) test.S(t).ExpectEquals(dup.Key.Hostname, "otherhost") @@ -39,6 +44,7 @@ func TestDuplicateCredentials(t *testing.T) { test.S(t).ExpectEquals(dup.ImpliedKey.Port, 3310) test.S(t).ExpectEquals(dup.User, "gromit") test.S(t).ExpectEquals(dup.Password, "penguin") + test.S(t).ExpectEquals(dup.tlsConfig, c.tlsConfig) } func TestDuplicate(t *testing.T) { @@ -63,5 +69,16 @@ func TestGetDBUri(t *testing.T) { c.Password = "penguin" uri := c.GetDBUri("test") - test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1") + test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1&tls=false") +} + +func TestGetDBUriWithTLSSetup(t *testing.T) { + c := NewConnectionConfig() + c.Key = InstanceKey{Hostname: "myhost", Port: 3306} + c.User = "gromit" + c.Password = "penguin" + c.tlsConfig = &tls.Config{} + + uri := c.GetDBUri("test") + test.S(t).ExpectEquals(uri, "gromit:penguin@tcp(myhost:3306)/test?interpolateParams=true&autocommit=true&charset=utf8mb4,utf8,latin1&tls=myhost:3306") } From 4f9367e6909dc93d824cda9f536921e449cf689e Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Thu, 31 Jan 2019 16:59:42 -0600 Subject: [PATCH 2/9] Fix casing for initialism --- go/base/context.go | 4 ++-- go/cmd/gh-ost/main.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go/base/context.go b/go/base/context.go index 856a29ca3..90581e273 100644 --- a/go/base/context.go +++ b/go/base/context.go @@ -100,7 +100,7 @@ type MigrationContext struct { CliUser string CliPassword string UseTLS bool - TlsCACertificate string + TLSCACertificate string CliMasterUser string CliMasterPassword string @@ -699,7 +699,7 @@ func (this *MigrationContext) ApplyCredentials() { func (this *MigrationContext) SetupTLS() error { if this.UseTLS { - return this.InspectorConnectionConfig.UseTLS(this.TlsCACertificate) + return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate) } return nil } diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index 8bd8c78a4..db044f364 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -56,7 +56,7 @@ func main() { askPass := flag.Bool("ask-pass", false, "prompt for MySQL password") flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL") - flag.StringVar(&migrationContext.TlsCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections. Requires --ssl") + flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections. Requires --ssl") flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)") flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)") @@ -198,7 +198,7 @@ func main() { if migrationContext.CliMasterPassword != "" && migrationContext.AssumeMasterHostname == "" { log.Fatalf("--master-password requires --assume-master-host") } - if migrationContext.TlsCACertificate != "" && !migrationContext.UseTLS { + if migrationContext.TLSCACertificate != "" && !migrationContext.UseTLS { log.Fatalf("--ssl-ca requires --ssl") } if *replicationLagQuery != "" { From dc599bb0368f0ccd15a605348a6615cfe8f03faf Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Thu, 31 Jan 2019 17:20:11 -0600 Subject: [PATCH 3/9] Remove unnecessary branching --- go/mysql/connection.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/go/mysql/connection.go b/go/mysql/connection.go index bfb445adf..7fa826859 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -76,10 +76,7 @@ func (this *ConnectionConfig) UseTLS(caCertificatePath string) error { InsecureSkipVerify: skipVerify, } - if err := mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig); err != nil { - return err - } - return nil + return mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig) } func (this *ConnectionConfig) TLSConfig() *tls.Config { From c440112d440112e819d17f8d6997f3b41882edac Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Thu, 31 Jan 2019 17:23:19 -0600 Subject: [PATCH 4/9] Explain default setting for TLS param in DSN --- go/mysql/connection.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/go/mysql/connection.go b/go/mysql/connection.go index 7fa826859..742ca7e0f 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -91,6 +91,8 @@ func (this *ConnectionConfig) GetDBUri(databaseName string) string { hostname = fmt.Sprintf("[%s]", hostname) } interpolateParams := true + // go-mysql-driver defaults to false if tls param is not provided; explicitly setting here to + // simplify construction of the DSN below. tlsOption := "false" if this.tlsConfig != nil { tlsOption = this.Key.StringCode() From f67ec15f2b972fd6b6b5b1892fe9838a3f0c9e34 Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Fri, 1 Feb 2019 13:16:54 -0600 Subject: [PATCH 5/9] Handle returned error --- go/cmd/gh-ost/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index db044f364..9d7d60f0e 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -245,7 +245,9 @@ func main() { migrationContext.SetThrottleHTTP(*throttleHTTP) migrationContext.SetDefaultNumRetries(*defaultRetries) migrationContext.ApplyCredentials() - migrationContext.SetupTLS() + if err := migrationContext.SetupTLS(); err != nil { + log.Fatale(err) + } if err := migrationContext.SetCutOverLockTimeoutSeconds(*cutOverLockTimeoutSeconds); err != nil { log.Errore(err) } From 5319157789e317d296e298c0eb86240d3ef3cd56 Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Fri, 1 Feb 2019 13:20:17 -0600 Subject: [PATCH 6/9] Expand usage statement to indicate setting applies to multiple hosts --- go/cmd/gh-ost/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index 9d7d60f0e..d8add4f1f 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -55,8 +55,8 @@ func main() { flag.StringVar(&migrationContext.ConfigFile, "conf", "", "Config file") askPass := flag.Bool("ask-pass", false, "prompt for MySQL password") - flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL") - flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections. Requires --ssl") + flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL hosts") + flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl") flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)") flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)") From 79df0d1c5de9eec208da73f2657b6ff666af6239 Mon Sep 17 00:00:00 2001 From: Matt Belisle Date: Mon, 4 Feb 2019 14:46:08 -0600 Subject: [PATCH 7/9] Adding --ssl-insecure flag --- go/base/context.go | 19 ++++++++++--------- go/cmd/gh-ost/main.go | 4 ++++ go/mysql/connection.go | 28 ++++++++++++++++++---------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/go/base/context.go b/go/base/context.go index 90581e273..9f9de9b89 100644 --- a/go/base/context.go +++ b/go/base/context.go @@ -94,15 +94,16 @@ type MigrationContext struct { AliyunRDS bool GoogleCloudPlatform bool - config ContextConfig - configMutex *sync.Mutex - ConfigFile string - CliUser string - CliPassword string - UseTLS bool - TLSCACertificate string - CliMasterUser string - CliMasterPassword string + config ContextConfig + configMutex *sync.Mutex + ConfigFile string + CliUser string + CliPassword string + UseTLS bool + TLSInsecureSkipVerify bool + TLSCACertificate string + CliMasterUser string + CliMasterPassword string HeartbeatIntervalMilliseconds int64 defaultNumRetries int64 diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index d8add4f1f..96bd2dcb2 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -57,6 +57,7 @@ func main() { flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL hosts") flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl") + flag.StringVar(&migrationContext.TLSInsecureSkipVerify, "ssl-insecure", false, "Do not verify that the TLS connection is secure. Requires --ssl") flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)") flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)") @@ -201,6 +202,9 @@ func main() { if migrationContext.TLSCACertificate != "" && !migrationContext.UseTLS { log.Fatalf("--ssl-ca requires --ssl") } + if migrationContext.TLSInsecureSkipVerify && !migrationContext.UseTLS { + log.Fatalf("--ssl-insecure requires --ssl") + } if *replicationLagQuery != "" { log.Warningf("--replication-lag-query is deprecated") } diff --git a/go/mysql/connection.go b/go/mysql/connection.go index 742ca7e0f..f0f73ce71 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -58,22 +58,30 @@ func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool { } func (this *ConnectionConfig) UseTLS(caCertificatePath string) error { - skipVerify := caCertificatePath == "" var rootCertPool *x509.CertPool - if !skipVerify { - rootCertPool = x509.NewCertPool() - pem, err := ioutil.ReadFile(caCertificatePath) - if err != nil { - return err - } - if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { - return errors.New("could not add ca certificate to cert pool") + var err error + + if !this.TLSInsecureSkipVerify { + if caCertificatePath == "" { + rootCertPool, err = x509.SystemCertPool() + if err != nil { + return err + } + } else { + rootCertPool = x509.NewCertPool() + pem, err := ioutil.ReadFile(caCertificatePath) + if err != nil { + return err + } + if ok := rootCertPool.AppendCertsFromPEM(pem); !ok { + return errors.New("could not add ca certificate to cert pool") + } } } this.tlsConfig = &tls.Config{ RootCAs: rootCertPool, - InsecureSkipVerify: skipVerify, + InsecureSkipVerify: this.TLSInsecureSkipVerify, } return mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig) From 5b0dfb009c5e0dfb815d125da2faec1f132a4c75 Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Mon, 4 Feb 2019 16:21:25 -0600 Subject: [PATCH 8/9] Wireup allowing insecure ssl --- go/base/context.go | 22 +++++++++++----------- go/cmd/gh-ost/main.go | 6 +++--- go/mysql/connection.go | 6 +++--- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/go/base/context.go b/go/base/context.go index 9f9de9b89..e9991d831 100644 --- a/go/base/context.go +++ b/go/base/context.go @@ -94,16 +94,16 @@ type MigrationContext struct { AliyunRDS bool GoogleCloudPlatform bool - config ContextConfig - configMutex *sync.Mutex - ConfigFile string - CliUser string - CliPassword string - UseTLS bool - TLSInsecureSkipVerify bool - TLSCACertificate string - CliMasterUser string - CliMasterPassword string + config ContextConfig + configMutex *sync.Mutex + ConfigFile string + CliUser string + CliPassword string + UseTLS bool + TLSAllowInsecure bool + TLSCACertificate string + CliMasterUser string + CliMasterPassword string HeartbeatIntervalMilliseconds int64 defaultNumRetries int64 @@ -700,7 +700,7 @@ func (this *MigrationContext) ApplyCredentials() { func (this *MigrationContext) SetupTLS() error { if this.UseTLS { - return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate) + return this.InspectorConnectionConfig.UseTLS(this.TLSCACertificate, this.TLSAllowInsecure) } return nil } diff --git a/go/cmd/gh-ost/main.go b/go/cmd/gh-ost/main.go index 96bd2dcb2..b02d6b7d1 100644 --- a/go/cmd/gh-ost/main.go +++ b/go/cmd/gh-ost/main.go @@ -57,7 +57,7 @@ func main() { flag.BoolVar(&migrationContext.UseTLS, "ssl", false, "Enable SSL encrypted connections to MySQL hosts") flag.StringVar(&migrationContext.TLSCACertificate, "ssl-ca", "", "CA certificate in PEM format for TLS connections to MySQL hosts. Requires --ssl") - flag.StringVar(&migrationContext.TLSInsecureSkipVerify, "ssl-insecure", false, "Do not verify that the TLS connection is secure. Requires --ssl") + flag.BoolVar(&migrationContext.TLSAllowInsecure, "ssl-allow-insecure", false, "Skips verification of MySQL hosts' certificate chain and host name. Requires --ssl") flag.StringVar(&migrationContext.DatabaseName, "database", "", "database name (mandatory)") flag.StringVar(&migrationContext.OriginalTableName, "table", "", "table name (mandatory)") @@ -202,8 +202,8 @@ func main() { if migrationContext.TLSCACertificate != "" && !migrationContext.UseTLS { log.Fatalf("--ssl-ca requires --ssl") } - if migrationContext.TLSInsecureSkipVerify && !migrationContext.UseTLS { - log.Fatalf("--ssl-insecure requires --ssl") + if migrationContext.TLSAllowInsecure && !migrationContext.UseTLS { + log.Fatalf("--ssl-allow-insecure requires --ssl") } if *replicationLagQuery != "" { log.Warningf("--replication-lag-query is deprecated") diff --git a/go/mysql/connection.go b/go/mysql/connection.go index f0f73ce71..d6c721554 100644 --- a/go/mysql/connection.go +++ b/go/mysql/connection.go @@ -57,11 +57,11 @@ func (this *ConnectionConfig) Equals(other *ConnectionConfig) bool { return this.Key.Equals(&other.Key) || this.ImpliedKey.Equals(other.ImpliedKey) } -func (this *ConnectionConfig) UseTLS(caCertificatePath string) error { +func (this *ConnectionConfig) UseTLS(caCertificatePath string, allowInsecure bool) error { var rootCertPool *x509.CertPool var err error - if !this.TLSInsecureSkipVerify { + if !allowInsecure { if caCertificatePath == "" { rootCertPool, err = x509.SystemCertPool() if err != nil { @@ -81,7 +81,7 @@ func (this *ConnectionConfig) UseTLS(caCertificatePath string) error { this.tlsConfig = &tls.Config{ RootCAs: rootCertPool, - InsecureSkipVerify: this.TLSInsecureSkipVerify, + InsecureSkipVerify: allowInsecure, } return mysql.RegisterTLSConfig(this.Key.StringCode(), this.tlsConfig) From 1543098891296e496e16f63b671d6d0ea80342e8 Mon Sep 17 00:00:00 2001 From: Brandon Bodnar <33429657+brandonbodnar-wk@users.noreply.github.com> Date: Tue, 5 Feb 2019 08:02:47 -0600 Subject: [PATCH 9/9] Document ssl-related command line flags. --- doc/command-line-flags.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/command-line-flags.md b/doc/command-line-flags.md index 804ba58ef..c20a5a8d4 100644 --- a/doc/command-line-flags.md +++ b/doc/command-line-flags.md @@ -177,6 +177,18 @@ By default `gh-ost` verifies no foreign keys exist on the migrated table. On ser See [`approve-renamed-columns`](#approve-renamed-columns) +### ssl + +By default `gh-ost` does not use ssl/tls connections to the database servers when performing migrations. This flag instructs `gh-ost` to use encrypted connections. If enabled, `gh-ost` will use the system's ca certificate pool for server certificate verification. If a different certificate is needed for server verification, see `--ssl-ca`. If you wish to skip server verification, but still use encrypted connections, use with `--ssl-allow-insecure`. + +### ssl-allow-insecure + +Allows `gh-ost` to connect to the MySQL servers using encrypted connections, but without verifying the validity of the certificate provided by the server during the connection. Requires `--ssl`. + +### ssl-ca + +`--ssl-ca=/path/to/ca-cert.pem`: ca certificate file (in PEM format) to use for server certificate verification. If specified, the default system ca cert pool will not be used for verification, only the ca cert provided here. Requires `--ssl`. + ### test-on-replica Issue the migration on a replica; do not modify data on master. Useful for validating, testing and benchmarking. See [`testing-on-replica`](testing-on-replica.md)