diff --git a/server/server.go b/server/server.go index 9b6f6314d2f68..33c2b15d35cde 100644 --- a/server/server.go +++ b/server/server.go @@ -268,6 +268,9 @@ func NewServer(cfg *config.Config, driver IDriver) (*Server, error) { // Init rand seed for randomBuf() rand.Seed(time.Now().UTC().UnixNano()) + + variable.RegisterStatistics(s) + return s, nil } diff --git a/server/stat.go b/server/stat.go new file mode 100644 index 0000000000000..582dc9cb3e8e0 --- /dev/null +++ b/server/stat.go @@ -0,0 +1,60 @@ +// Copyright 2021 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package server + +import ( + "crypto/x509" + + "github.com/pingcap/tidb/sessionctx/variable" + "github.com/pingcap/tidb/util/logutil" + "go.uber.org/zap" +) + +var ( + serverNotAfter = "Ssl_server_not_after" + serverNotBefore = "Ssl_server_not_before" +) + +var defaultStatus = map[string]*variable.StatusVal{ + serverNotAfter: {Scope: variable.ScopeGlobal | variable.ScopeSession, Value: ""}, + serverNotBefore: {Scope: variable.ScopeGlobal | variable.ScopeSession, Value: ""}, +} + +// GetScope gets the status variables scope. +func (s *Server) GetScope(status string) variable.ScopeFlag { + return variable.DefaultStatusVarScopeFlag +} + +// Stats returns the server statistics. +func (s *Server) Stats(vars *variable.SessionVars) (map[string]interface{}, error) { + m := make(map[string]interface{}, len(defaultStatus)) + + for name, v := range defaultStatus { + m[name] = v.Value + } + + tlsConfig := s.getTLSConfig() + if tlsConfig != nil { + if len(tlsConfig.Certificates) == 1 { + pc, err := x509.ParseCertificate(tlsConfig.Certificates[0].Certificate[0]) + if err != nil { + logutil.BgLogger().Error("Failed to parse TLS certficates to get server status", zap.Error(err)) + } else { + m[serverNotAfter] = pc.NotAfter.Format("Jan _2 15:04:05 2006 MST") + m[serverNotBefore] = pc.NotBefore.Format("Jan 2 15:04:05 2006 MST") + } + } + } + return m, nil +} diff --git a/server/tidb_test.go b/server/tidb_test.go index 0fde70331b9ef..ebc56e60e325f 100644 --- a/server/tidb_test.go +++ b/server/tidb_test.go @@ -867,7 +867,7 @@ func (ts *tidbTestSerialSuite) TestTLS(c *C) { // Generate valid TLS certificates. caCert, caKey, err := generateCert(0, "TiDB CA", nil, nil, "/tmp/ca-key.pem", "/tmp/ca-cert.pem") c.Assert(err, IsNil) - _, _, err = generateCert(1, "tidb-server", caCert, caKey, "/tmp/server-key.pem", "/tmp/server-cert.pem") + serverCert, _, err := generateCert(1, "tidb-server", caCert, caKey, "/tmp/server-key.pem", "/tmp/server-cert.pem") c.Assert(err, IsNil) _, _, err = generateCert(2, "SQL Client Certificate", caCert, caKey, "/tmp/client-key.pem", "/tmp/client-cert.pem") c.Assert(err, IsNil) @@ -908,6 +908,16 @@ func (ts *tidbTestSerialSuite) TestTLS(c *C) { err = cli.runTestTLSConnection(c, connOverrider) // We should get ErrNoTLS. c.Assert(err, NotNil) c.Assert(errors.Cause(err).Error(), Equals, mysql.ErrNoTLS.Error()) + + // Test SSL/TLS session vars + var v *variable.SessionVars + stats, err := server.Stats(v) + c.Assert(err, IsNil) + c.Assert(stats, HasKey, "Ssl_server_not_after") + c.Assert(stats, HasKey, "Ssl_server_not_before") + c.Assert(stats["Ssl_server_not_after"], Equals, "") + c.Assert(stats["Ssl_server_not_before"], Equals, "") + server.Close() // Start the server with TLS but without CA, in this case the server will not verify client's certificate. @@ -940,6 +950,15 @@ func (ts *tidbTestSerialSuite) TestTLS(c *C) { err = cli.runTestTLSConnection(c, connOverrider) // We should establish connection successfully. c.Assert(err, IsNil, Commentf("%v", errors.ErrorStack(err))) cli.runTestRegression(c, connOverrider, "TLSRegression") + + // Test SSL/TLS session vars + stats, err = server.Stats(v) + c.Assert(err, IsNil) + c.Assert(stats, HasKey, "Ssl_server_not_after") + c.Assert(stats, HasKey, "Ssl_server_not_before") + c.Assert(stats["Ssl_server_not_after"], Equals, serverCert.NotAfter.Format("Jan _2 15:04:05 2006 MST")) + c.Assert(stats["Ssl_server_not_before"], Equals, serverCert.NotBefore.Format("Jan _2 15:04:05 2006 MST")) + server.Close() // Start the server with TLS & CA, if the client presents its certificate, the certificate will be verified.