Skip to content

Commit

Permalink
server: properly support status port over TLS (pingcap#14785)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennytm authored Feb 14, 2020
1 parent d7fd38e commit c6e4325
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 30 deletions.
35 changes: 21 additions & 14 deletions server/http_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"archive/zip"
"bytes"
"context"
"crypto/tls"
"encoding/json"
"fmt"
"net"
Expand Down Expand Up @@ -264,11 +265,23 @@ func (s *Server) startHTTPServer() {
})

logutil.BgLogger().Info("for status and metrics report", zap.String("listening on addr", addr))
s.setupStatuServerAndRPCServer(addr, serverMux)
s.setupStatusServerAndRPCServer(addr, serverMux)
}

func (s *Server) setupStatuServerAndRPCServer(addr string, serverMux *http.ServeMux) {
l, err := net.Listen("tcp", addr)
func (s *Server) setupStatusServerAndRPCServer(addr string, serverMux *http.ServeMux) {
tlsConfig, err := s.cfg.Security.ToTLSConfig()
if err != nil {
logutil.BgLogger().Error("invalid TLS config", zap.Error(err))
return
}

var l net.Listener
if tlsConfig != nil {
// we need to manage TLS here for cmux to distinguish between HTTP and gRPC.
l, err = tls.Listen("tcp", addr, tlsConfig)
} else {
l, err = net.Listen("tcp", addr)
}
if err != nil {
logutil.BgLogger().Info("listen failed", zap.Error(err))
return
Expand All @@ -287,17 +300,11 @@ func (s *Server) setupStatuServerAndRPCServer(addr string, serverMux *http.Serve
logutil.BgLogger().Error("grpc server error", zap.Error(err))
}, nil)

if len(s.cfg.Security.ClusterSSLCA) != 0 {
go util.WithRecovery(func() {
err := s.statusServer.ServeTLS(httpL, s.cfg.Security.ClusterSSLCert, s.cfg.Security.ClusterSSLKey)
logutil.BgLogger().Error("http server error", zap.Error(err))
}, nil)
} else {
go util.WithRecovery(func() {
err := s.statusServer.Serve(httpL)
logutil.BgLogger().Error("http server error", zap.Error(err))
}, nil)
}
go util.WithRecovery(func() {
err := s.statusServer.Serve(httpL)
logutil.BgLogger().Error("http server error", zap.Error(err))
}, nil)

err = m.Serve()
if err != nil {
logutil.BgLogger().Error("start status/rpc server error", zap.Error(err))
Expand Down
12 changes: 1 addition & 11 deletions server/rpc_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import (
"github.com/pingcap/tidb/util/stringutil"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)

// NewRPCServer creates a new rpc server.
Expand All @@ -46,16 +45,7 @@ func NewRPCServer(config *config.Config, dom *domain.Domain, sm util.SessionMana
}
}()

var s *grpc.Server
if len(config.Security.ClusterSSLCA) != 0 {
tlsConfig, err := config.Security.ToTLSConfig()
if err == nil {
s = grpc.NewServer(grpc.Creds(credentials.NewTLS(tlsConfig)))
}
}
if s == nil {
s = grpc.NewServer()
}
s := grpc.NewServer()
rpcSrv := &rpcServer{
DiagnosticsServer: sysutil.NewDiagnosticsServer(config.Log.File.Filename),
dom: dom,
Expand Down
12 changes: 7 additions & 5 deletions server/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,21 +65,23 @@ type configOverrider func(*mysql.Config)
// testServerClient config server connect parameters and provider several
// method to communicate with server and run tests
type testServerClient struct {
port uint
statusPort uint
port uint
statusPort uint
statusScheme string
}

// newTestServerClient return a testServerClient with unique address
func newTestServerClient() *testServerClient {
return &testServerClient{
port: genPort(),
statusPort: genStatusPort(),
port: genPort(),
statusPort: genStatusPort(),
statusScheme: "http",
}
}

// statusURL return the full URL of a status path
func (cli *testServerClient) statusURL(path string) string {
return fmt.Sprintf("http://localhost:%d%s", cli.statusPort, path)
return fmt.Sprintf("%s://localhost:%d%s", cli.statusScheme, cli.statusPort, path)
}

// fetchStatus exec http.Get to server status port
Expand Down
37 changes: 37 additions & 0 deletions server/tidb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,43 @@ func (ts *tidbTestSuite) TestStatusAPI(c *C) {
ts.runTestStatusAPI(c)
}

func (ts *tidbTestSuite) TestStatusAPIWithTLS(c *C) {
caCert, caKey, err := generateCert(0, "TiDB CA 2", nil, nil, "/tmp/ca-key-2.pem", "/tmp/ca-cert-2.pem")
c.Assert(err, IsNil)
_, _, err = generateCert(1, "tidb-server-2", caCert, caKey, "/tmp/server-key-2.pem", "/tmp/server-cert-2.pem")
c.Assert(err, IsNil)

defer func() {
os.Remove("/tmp/ca-key-2.pem")
os.Remove("/tmp/ca-cert-2.pem")
os.Remove("/tmp/server-key-2.pem")
os.Remove("/tmp/server-cert-2.pem")
}()

cli := newTestServerClient()
cli.statusScheme = "https"
cfg := config.NewConfig()
cfg.Port = cli.port
cfg.Status.StatusPort = cli.statusPort
cfg.Security.ClusterSSLCA = "/tmp/ca-cert-2.pem"
cfg.Security.ClusterSSLCert = "/tmp/server-cert-2.pem"
cfg.Security.ClusterSSLKey = "/tmp/server-key-2.pem"
server, err := NewServer(cfg, ts.tidbdrv)
c.Assert(err, IsNil)
go server.Run()
time.Sleep(time.Millisecond * 100)

// https connection should work.
ts.runTestStatusAPI(c)

// but plain http connection should fail.
cli.statusScheme = "http"
_, err = cli.fetchStatus("/status")
c.Assert(err, NotNil)

server.Close()
}

func (ts *tidbTestSuite) TestMultiStatements(c *C) {
c.Parallel()
ts.runTestMultiStatements(c)
Expand Down

0 comments on commit c6e4325

Please sign in to comment.