From 30eb256da2a96dd8fbdbac385da84accf13c74d1 Mon Sep 17 00:00:00 2001 From: pingcap-github-bot Date: Wed, 18 Mar 2020 11:02:44 +0800 Subject: [PATCH 1/3] cherry pick #15415 to release-3.1 Signed-off-by: sre-bot --- config/config.go | 17 +++++++------- executor/simple.go | 2 +- server/conn.go | 3 +++ server/server.go | 31 ++++++++++++++----------- server/tidb_test.go | 9 ++++++++ tidb-server/main.go | 56 ++++++++++++++++++++++++--------------------- util/misc.go | 11 ++++++++- 7 files changed, 80 insertions(+), 49 deletions(-) diff --git a/config/config.go b/config/config.go index 2f923b823140b..bf100437683eb 100644 --- a/config/config.go +++ b/config/config.go @@ -131,14 +131,15 @@ type Log struct { // Security is the security section of the config. type Security struct { - SkipGrantTable bool `toml:"skip-grant-table" json:"skip-grant-table"` - SSLCA string `toml:"ssl-ca" json:"ssl-ca"` - SSLCert string `toml:"ssl-cert" json:"ssl-cert"` - SSLKey string `toml:"ssl-key" json:"ssl-key"` - ClusterSSLCA string `toml:"cluster-ssl-ca" json:"cluster-ssl-ca"` - ClusterSSLCert string `toml:"cluster-ssl-cert" json:"cluster-ssl-cert"` - ClusterSSLKey string `toml:"cluster-ssl-key" json:"cluster-ssl-key"` - ClusterVerifyCN []string `toml:"cluster-verify-cn" json:"cluster-verify-cn"` + SkipGrantTable bool `toml:"skip-grant-table" json:"skip-grant-table"` + SSLCA string `toml:"ssl-ca" json:"ssl-ca"` + SSLCert string `toml:"ssl-cert" json:"ssl-cert"` + SSLKey string `toml:"ssl-key" json:"ssl-key"` + RequireSecureTransport bool `toml:"require-secure-transport" json:"require-secure-transport"` + ClusterSSLCA string `toml:"cluster-ssl-ca" json:"cluster-ssl-ca"` + ClusterSSLCert string `toml:"cluster-ssl-cert" json:"cluster-ssl-cert"` + ClusterSSLKey string `toml:"cluster-ssl-key" json:"cluster-ssl-key"` + ClusterVerifyCN []string `toml:"cluster-verify-cn" json:"cluster-verify-cn"` } // The ErrConfigValidationFailed error is used so that external callers can do a type assertion diff --git a/executor/simple.go b/executor/simple.go index b690c4a694b7f..b3d9fc2f5b62e 100644 --- a/executor/simple.go +++ b/executor/simple.go @@ -1106,7 +1106,7 @@ func (e *SimpleExec) executeAlterInstance(s *ast.AlterInstanceStmt) error { variable.SysVars["ssl_cert"].Value, ) if err != nil { - if !s.NoRollbackOnError { + if !s.NoRollbackOnError || config.GetGlobalConfig().Security.RequireSecureTransport { return err } logutil.Logger(context.Background()).Warn("reload TLS fail but keep working without TLS due to 'no rollback on error'") diff --git a/server/conn.go b/server/conn.go index 75ddf5285f65b..a71c2fb62c67c 100644 --- a/server/conn.go +++ b/server/conn.go @@ -56,6 +56,7 @@ import ( "github.com/pingcap/parser/auth" "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/executor" "github.com/pingcap/tidb/kv" "github.com/pingcap/tidb/metrics" @@ -516,6 +517,8 @@ func (cc *clientConn) readOptionalSSLRequestAndHandshakeResponse(ctx context.Con return err } } + } else if config.GetGlobalConfig().Security.RequireSecureTransport { + return errSecureTransportRequired.FastGenByArgs() } // Read the remaining part of the packet. diff --git a/server/server.go b/server/server.go index 97d7819db38f6..145ab54b16bb3 100644 --- a/server/server.go +++ b/server/server.go @@ -83,13 +83,14 @@ func init() { } var ( - errUnknownFieldType = terror.ClassServer.New(codeUnknownFieldType, "unknown field type") - errInvalidPayloadLen = terror.ClassServer.New(codeInvalidPayloadLen, "invalid payload length") - errInvalidSequence = terror.ClassServer.New(codeInvalidSequence, "invalid sequence") - errInvalidType = terror.ClassServer.New(codeInvalidType, "invalid type") - errNotAllowedCommand = terror.ClassServer.New(codeNotAllowedCommand, "the used command is not allowed with this TiDB version") - errAccessDenied = terror.ClassServer.New(codeAccessDenied, mysql.MySQLErrName[mysql.ErrAccessDenied]) - errMaxExecTimeExceeded = terror.ClassServer.New(codeMaxExecTimeExceeded, mysql.MySQLErrName[mysql.ErrMaxExecTimeExceeded]) + errUnknownFieldType = terror.ClassServer.New(codeUnknownFieldType, "unknown field type") + errInvalidPayloadLen = terror.ClassServer.New(codeInvalidPayloadLen, "invalid payload length") + errInvalidSequence = terror.ClassServer.New(codeInvalidSequence, "invalid sequence") + errInvalidType = terror.ClassServer.New(codeInvalidType, "invalid type") + errNotAllowedCommand = terror.ClassServer.New(codeNotAllowedCommand, "the used command is not allowed with this TiDB version") + errAccessDenied = terror.ClassServer.New(codeAccessDenied, mysql.MySQLErrName[mysql.ErrAccessDenied]) + errMaxExecTimeExceeded = terror.ClassServer.New(codeMaxExecTimeExceeded, mysql.MySQLErrName[mysql.ErrMaxExecTimeExceeded]) + errSecureTransportRequired = terror.ClassServer.New(codeSecureTransportRequired, mysql.MySQLErrName[mysql.ErrSecureTransportRequired]) ) // DefaultCapability is the capability of the server when it is created using the default configuration. @@ -205,6 +206,8 @@ func NewServer(cfg *config.Config, driver IDriver) (*Server, error) { setSSLVariable(s.cfg.Security.SSLCA, s.cfg.Security.SSLKey, s.cfg.Security.SSLCert) atomic.StorePointer(&s.tlsConfig, unsafe.Pointer(tlsConfig)) logutil.Logger(context.Background()).Info("mysql protocol server secure connection is enabled", zap.Bool("client verification enabled", len(variable.SysVars["ssl_ca"].Value) > 0)) + } else if cfg.Security.RequireSecureTransport { + return nil, errSecureTransportRequired.FastGenByArgs() } setSystemTimeZoneVariable() @@ -595,16 +598,18 @@ const ( codeInvalidSequence = 3 codeInvalidType = 4 - codeNotAllowedCommand = 1148 - codeAccessDenied = mysql.ErrAccessDenied - codeMaxExecTimeExceeded = mysql.ErrMaxExecTimeExceeded + codeNotAllowedCommand = 1148 + codeAccessDenied = mysql.ErrAccessDenied + codeMaxExecTimeExceeded = mysql.ErrMaxExecTimeExceeded + codeSecureTransportRequired = mysql.ErrSecureTransportRequired ) func init() { serverMySQLErrCodes := map[terror.ErrCode]uint16{ - codeNotAllowedCommand: mysql.ErrNotAllowedCommand, - codeAccessDenied: mysql.ErrAccessDenied, - codeMaxExecTimeExceeded: mysql.ErrMaxExecTimeExceeded, + codeNotAllowedCommand: mysql.ErrNotAllowedCommand, + codeAccessDenied: mysql.ErrAccessDenied, + codeMaxExecTimeExceeded: mysql.ErrMaxExecTimeExceeded, + codeSecureTransportRequired: mysql.ErrSecureTransportRequired, } terror.ErrClassToMySQLCodes[terror.ClassServer] = serverMySQLErrCodes } diff --git a/server/tidb_test.go b/server/tidb_test.go index d80e8f202378c..2441bab9dfd02 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -609,6 +609,15 @@ func (ts *TidbTestSuite) TestErrorNoRollback(c *C) { cfg.Port = 4006 cfg.Status.ReportStatus = false + cfg.Security = config.Security{ + RequireSecureTransport: true, + SSLCA: "wrong path", + SSLCert: "wrong path", + SSLKey: "wrong path", + } + _, err = NewServer(cfg, ts.tidbdrv) + c.Assert(err, NotNil) + // test reload tls fail with/without "error no rollback option" cfg.Security = config.Security{ SSLCA: "/tmp/ca-cert-rollback.pem", diff --git a/tidb-server/main.go b/tidb-server/main.go index 2a141db5070a2..4ab5680c2b3e2 100644 --- a/tidb-server/main.go +++ b/tidb-server/main.go @@ -63,31 +63,32 @@ import ( // Flag Names const ( - nmVersion = "V" - nmConfig = "config" - nmConfigCheck = "config-check" - nmConfigStrict = "config-strict" - nmStore = "store" - nmStorePath = "path" - nmHost = "host" - nmAdvertiseAddress = "advertise-address" - nmPort = "P" - nmCors = "cors" - nmSocket = "socket" - nmEnableBinlog = "enable-binlog" - nmRunDDL = "run-ddl" - nmLogLevel = "L" - nmLogFile = "log-file" - nmLogSlowQuery = "log-slow-query" - nmReportStatus = "report-status" - nmStatusHost = "status-host" - nmStatusPort = "status" - nmMetricsAddr = "metrics-addr" - nmMetricsInterval = "metrics-interval" - nmDdlLease = "lease" - nmTokenLimit = "token-limit" - nmPluginDir = "plugin-dir" - nmPluginLoad = "plugin-load" + nmVersion = "V" + nmConfig = "config" + nmConfigCheck = "config-check" + nmConfigStrict = "config-strict" + nmStore = "store" + nmStorePath = "path" + nmHost = "host" + nmAdvertiseAddress = "advertise-address" + nmPort = "P" + nmCors = "cors" + nmSocket = "socket" + nmEnableBinlog = "enable-binlog" + nmRunDDL = "run-ddl" + nmLogLevel = "L" + nmLogFile = "log-file" + nmLogSlowQuery = "log-slow-query" + nmReportStatus = "report-status" + nmStatusHost = "status-host" + nmStatusPort = "status" + nmMetricsAddr = "metrics-addr" + nmMetricsInterval = "metrics-interval" + nmDdlLease = "lease" + nmTokenLimit = "token-limit" + nmPluginDir = "plugin-dir" + nmPluginLoad = "plugin-load" + nmRequireSecureTransport = "require-secure-transport" nmProxyProtocolNetworks = "proxy-protocol-networks" nmProxyProtocolHeaderTimeout = "proxy-protocol-header-timeout" @@ -113,6 +114,7 @@ var ( tokenLimit = flag.Int(nmTokenLimit, 1000, "the limit of concurrent executed sessions") pluginDir = flag.String(nmPluginDir, "/data/deploy/plugin", "the folder that hold plugin") pluginLoad = flag.String(nmPluginLoad, "", "wait load plugin name(separated by comma)") + requireTLS = flag.Bool(nmRequireSecureTransport, false, "require client use secure transport") // Log logLevel = flag.String(nmLogLevel, "info", "log level: info, debug, warn, error, fatal") @@ -439,7 +441,9 @@ func overrideConfig() { if actualFlags[nmPluginDir] { cfg.Plugin.Dir = *pluginDir } - + if actualFlags[nmRequireSecureTransport] { + cfg.Security.RequireSecureTransport = *requireTLS + } // Log if actualFlags[nmLogLevel] { cfg.Log.Level = *logLevel diff --git a/util/misc.go b/util/misc.go index 743b58fa24a58..b45df9a9c9fc8 100644 --- a/util/misc.go +++ b/util/misc.go @@ -317,8 +317,13 @@ func LoadTLSCertificates(ca, key, cert string) (tlsConfig *tls.Config, err error return } + requireTLS := config.GetGlobalConfig().Security.RequireSecureTransport + // Try loading CA cert. clientAuthPolicy := tls.NoClientCert + if requireTLS { + clientAuthPolicy = tls.RequestClientCert + } var certPool *x509.CertPool if len(ca) > 0 { var caCert []byte @@ -330,7 +335,11 @@ func LoadTLSCertificates(ca, key, cert string) (tlsConfig *tls.Config, err error } certPool = x509.NewCertPool() if certPool.AppendCertsFromPEM(caCert) { - clientAuthPolicy = tls.VerifyClientCertIfGiven + if requireTLS { + clientAuthPolicy = tls.RequireAndVerifyClientCert + } else { + clientAuthPolicy = tls.VerifyClientCertIfGiven + } } } tlsConfig = &tls.Config{ From 74d30198f3eefc2443c0e3ca566dc5cb1a7231dc Mon Sep 17 00:00:00 2001 From: lysu Date: Wed, 18 Mar 2020 11:46:43 +0800 Subject: [PATCH 2/3] fix after rebase --- util/misc.go | 1 + 1 file changed, 1 insertion(+) diff --git a/util/misc.go b/util/misc.go index b45df9a9c9fc8..9a5977ac8c2f4 100644 --- a/util/misc.go +++ b/util/misc.go @@ -30,6 +30,7 @@ import ( "github.com/pingcap/parser/model" "github.com/pingcap/parser/mysql" "github.com/pingcap/parser/terror" + "github.com/pingcap/tidb/config" "github.com/pingcap/tidb/util/logutil" "go.uber.org/zap" ) From 86919a195b044db511b773a502812b8da7c3eeb9 Mon Sep 17 00:00:00 2001 From: lysu Date: Wed, 18 Mar 2020 15:18:50 +0800 Subject: [PATCH 3/3] fix after rebase --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index aef71b8386f58..208c969814e3c 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/pingcap/goleveldb v0.0.0-20171020122428-b9ff6c35079e github.com/pingcap/kvproto v0.0.0-20200317043902-2838e21ca222 github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd - github.com/pingcap/parser v3.1.0-beta.1.0.20200317043536-9ebea32e03a6+incompatible + github.com/pingcap/parser v3.1.0-beta.1.0.20200318061433-f0b8f6cdca0d+incompatible github.com/pingcap/pd/v3 v3.1.0-beta.2.0.20200312100832-1206736bd050 github.com/pingcap/tidb-tools v4.0.0-beta.1.0.20200317092225-ed6b2a87af54+incompatible github.com/pingcap/tipb v0.0.0-20191126033718-169898888b24 diff --git a/go.sum b/go.sum index 55e1ad0088263..9d72d3773b71d 100644 --- a/go.sum +++ b/go.sum @@ -248,8 +248,8 @@ github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9 h1:AJD9pZYm72vMgPcQDww github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd h1:CV3VsP3Z02MVtdpTMfEgRJ4T9NGgGTxdHpJerent7rM= github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/parser v3.1.0-beta.1.0.20200317043536-9ebea32e03a6+incompatible h1:LXg9RBvy+a6odBikQF0IcITVFYYDCgbVf5YPhM+AIIU= -github.com/pingcap/parser v3.1.0-beta.1.0.20200317043536-9ebea32e03a6+incompatible/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= +github.com/pingcap/parser v3.1.0-beta.1.0.20200318061433-f0b8f6cdca0d+incompatible h1:+Jibmc9uklKz9/prpBggFyjZpqRM8phc1AOOJGxkP48= +github.com/pingcap/parser v3.1.0-beta.1.0.20200318061433-f0b8f6cdca0d+incompatible/go.mod h1:1FNvfp9+J0wvc4kl8eGNh7Rqrxveg15jJoWo/a0uHwA= github.com/pingcap/pd/v3 v3.1.0-beta.2.0.20200312100832-1206736bd050 h1:mxPdR0pxnUcRfRGX2JnaLyAd9SZWeR42SzvMp4Zv3YI= github.com/pingcap/pd/v3 v3.1.0-beta.2.0.20200312100832-1206736bd050/go.mod h1:0HfF1LfWLMuGpui0PKhGvkXxfjv1JslMRY6B+cae3dg= github.com/pingcap/tidb-tools v4.0.0-beta.1.0.20200317092225-ed6b2a87af54+incompatible h1:tYADqdmWwgDOwf/qEN0trJAy6H3c3Tt/QZx1z4qVrRQ=