Skip to content

Commit

Permalink
server: Add status vars for NotAfter/NotBefore of TLS certs (pingcap#…
Browse files Browse the repository at this point in the history
  • Loading branch information
dveeden authored Jul 21, 2021
1 parent 7ab81f2 commit 16d947d
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 1 deletion.
3 changes: 3 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
60 changes: 60 additions & 0 deletions server/stat.go
Original file line number Diff line number Diff line change
@@ -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
}
21 changes: 20 additions & 1 deletion server/tidb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
Expand Down

0 comments on commit 16d947d

Please sign in to comment.