Skip to content

Commit

Permalink
cherry pick pingcap#15137 to release-3.1
Browse files Browse the repository at this point in the history
Signed-off-by: sre-bot <[email protected]>
  • Loading branch information
lysu authored and sre-bot committed Mar 5, 2020
1 parent 56ca69a commit 8ec3c75
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 7 deletions.
15 changes: 8 additions & 7 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,14 @@ 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"`
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"`
}

// The ErrConfigValidationFailed error is used so that external callers can do a type assertion
Expand Down
98 changes: 98 additions & 0 deletions server/http_handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ package server

import (
"bytes"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"database/sql"
"encoding/base64"
"encoding/hex"
Expand Down Expand Up @@ -1009,3 +1012,98 @@ func (ts *HTTPHandlerTestSuite) TestAllServerInfo(c *C) {
c.Assert(serverInfo.GitHash, Equals, printer.TiDBGitHash)
c.Assert(serverInfo.ID, Equals, ddl.GetID())
}
<<<<<<< HEAD
=======

func (ts *HTTPHandlerTestSuite) TestHotRegionInfo(c *C) {
ts.startServer(c)
defer ts.stopServer(c)
resp, err := ts.fetchStatus("/regions/hot")
c.Assert(err, IsNil)
defer resp.Body.Close()
c.Assert(resp.StatusCode, Equals, http.StatusBadRequest)
}

func (ts *HTTPHandlerTestSuite) TestDebugZip(c *C) {
ts.startServer(c)
defer ts.stopServer(c)
resp, err := ts.fetchStatus("/debug/zip?seconds=1")
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusOK)
b, err := httputil.DumpResponse(resp, true)
c.Assert(err, IsNil)
c.Assert(len(b), Greater, 0)
c.Assert(resp.Body.Close(), IsNil)
}

func (ts *HTTPHandlerTestSuite) TestCheckCN(c *C) {
s := &Server{cfg: &config.Config{Security: config.Security{ClusterVerifyCN: []string{"a ", "b", "c"}}}}
tlsConfig := &tls.Config{}
s.setCNChecker(tlsConfig)
c.Assert(tlsConfig.VerifyPeerCertificate, NotNil)
err := tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "a"}}}})
c.Assert(err, IsNil)
err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "b"}}}})
c.Assert(err, IsNil)
err = tlsConfig.VerifyPeerCertificate(nil, [][]*x509.Certificate{{{Subject: pkix.Name{CommonName: "d"}}}})
c.Assert(err, NotNil)
}

func (ts *HTTPHandlerTestSuite) TestZipInfoForSQL(c *C) {
ts.startServer(c)
defer ts.stopServer(c)

db, err := sql.Open("mysql", ts.getDSN())
c.Assert(err, IsNil, Commentf("Error connecting"))
defer db.Close()
dbt := &DBTest{c, db}

dbt.mustExec("use test")
dbt.mustExec("create table if not exists t (a int)")

urlValues := url.Values{
"sql": {"select * from t"},
"current_db": {"test"},
}
resp, err := ts.formStatus("/debug/sub-optimal-plan", urlValues)
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusOK)
b, err := httputil.DumpResponse(resp, true)
c.Assert(err, IsNil)
c.Assert(len(b), Greater, 0)
c.Assert(resp.Body.Close(), IsNil)

resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5&timeout=0", urlValues)
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusOK)
b, err = httputil.DumpResponse(resp, true)
c.Assert(err, IsNil)
c.Assert(len(b), Greater, 0)
c.Assert(resp.Body.Close(), IsNil)

resp, err = ts.formStatus("/debug/sub-optimal-plan?pprof_time=5", urlValues)
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusOK)
b, err = httputil.DumpResponse(resp, true)
c.Assert(err, IsNil)
c.Assert(len(b), Greater, 0)
c.Assert(resp.Body.Close(), IsNil)

resp, err = ts.formStatus("/debug/sub-optimal-plan?timeout=1", urlValues)
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusOK)
b, err = httputil.DumpResponse(resp, true)
c.Assert(err, IsNil)
c.Assert(len(b), Greater, 0)
c.Assert(resp.Body.Close(), IsNil)

urlValues.Set("current_db", "non_exists_db")
resp, err = ts.formStatus("/debug/sub-optimal-plan", urlValues)
c.Assert(err, IsNil)
c.Assert(resp.StatusCode, Equals, http.StatusInternalServerError)
b, err = ioutil.ReadAll(resp.Body)
c.Assert(err, IsNil)
c.Assert(string(b), Equals, "use database non_exists_db failed, err: [schema:1049]Unknown database 'non_exists_db'\n")
c.Assert(resp.Body.Close(), IsNil)
}
>>>>>>> 92f6f4e... server: support check the "CommanName" of tls-cert for status-port(http/grpc) (#15137)
41 changes: 41 additions & 0 deletions server/http_status.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import (
"archive/zip"
"bytes"
"context"
<<<<<<< HEAD
=======
"crypto/tls"
"crypto/x509"
>>>>>>> 92f6f4e... server: support check the "CommanName" of tls-cert for status-port(http/grpc) (#15137)
"encoding/json"
"fmt"
"net"
Expand Down Expand Up @@ -252,8 +257,22 @@ func (s *Server) startHTTPServer() {
}
})

<<<<<<< HEAD
logutil.Logger(context.Background()).Info("for status and metrics report", zap.String("listening on addr", addr))
s.statusServer = &http.Server{Addr: addr, Handler: CorsHandler{handler: serverMux, cfg: s.cfg}}
=======
logutil.BgLogger().Info("for status and metrics report", zap.String("listening on addr", addr))
s.setupStatusServerAndRPCServer(addr, serverMux)
}

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
}
tlsConfig = s.setCNChecker(tlsConfig)
>>>>>>> 92f6f4e... server: support check the "CommanName" of tls-cert for status-port(http/grpc) (#15137)

if len(s.cfg.Security.ClusterSSLCA) != 0 {
err = s.statusServer.ListenAndServeTLS(s.cfg.Security.ClusterSSLCert, s.cfg.Security.ClusterSSLKey)
Expand All @@ -266,6 +285,28 @@ func (s *Server) startHTTPServer() {
}
}

func (s *Server) setCNChecker(tlsConfig *tls.Config) *tls.Config {
if tlsConfig != nil && len(s.cfg.Security.ClusterVerifyCN) != 0 {
checkCN := make(map[string]struct{})
for _, cn := range s.cfg.Security.ClusterVerifyCN {
cn = strings.TrimSpace(cn)
checkCN[cn] = struct{}{}
}
tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
for _, chain := range verifiedChains {
if len(chain) != 0 {
if _, match := checkCN[chain[0].Subject.CommonName]; match {
return nil
}
}
}
return errors.Errorf("client certificate authentication failed. The Common Name from the client certificate was not found in the configuration cluster-verify-cn with value: %s", s.cfg.Security.ClusterVerifyCN)
}
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
return tlsConfig
}

// status of TiDB.
type status struct {
Connections int `json:"connections"`
Expand Down
56 changes: 56 additions & 0 deletions server/tidb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import (
"encoding/pem"
"io/ioutil"
"math/big"
"net/http"
"os"
"path/filepath"
"time"

"github.com/go-sql-driver/mysql"
Expand Down Expand Up @@ -157,7 +159,61 @@ func (ts *TidbTestSuite) TestStatusAPI(c *C) {
runTestStatusAPI(c)
}

<<<<<<< HEAD
func (ts *TidbTestSuite) TestMultiStatements(c *C) {
=======
func (ts *tidbTestSuite) TestStatusAPIWithTLSCNCheck(c *C) {
c.Skip("need add ca-tidb-test-1.crt to OS")
root := filepath.Join(os.Getenv("GOPATH"), "/src/github.com/pingcap/tidb")
ca := filepath.Join(root, "/tests/cncheckcert/ca-tidb-test-1.crt")

cli := newTestServerClient()
cli.statusScheme = "https"
cfg := config.NewConfig()
cfg.Port = cli.port
cfg.Status.StatusPort = cli.statusPort
cfg.Security.ClusterSSLCA = ca
cfg.Security.ClusterSSLCert = filepath.Join(root, "/tests/cncheckcert/server-cert.pem")
cfg.Security.ClusterSSLKey = filepath.Join(root, "/tests/cncheckcert/server-key.pem")
cfg.Security.ClusterVerifyCN = []string{"tidb-client-2"}
server, err := NewServer(cfg, ts.tidbdrv)
c.Assert(err, IsNil)
go server.Run()
time.Sleep(time.Millisecond * 100)

hc := newTLSHttpClient(c, ca,
filepath.Join(root, "/tests/cncheckcert/client-cert-1.pem"),
filepath.Join(root, "/tests/cncheckcert/client-key-1.pem"),
)
_, err = hc.Get(cli.statusURL("/status"))
c.Assert(err, NotNil)

hc = newTLSHttpClient(c, ca,
filepath.Join(root, "/tests/cncheckcert/client-cert-2.pem"),
filepath.Join(root, "/tests/cncheckcert/client-key-2.pem"),
)
_, err = hc.Get(cli.statusURL("/status"))
c.Assert(err, IsNil)
}

func newTLSHttpClient(c *C, caFile, certFile, keyFile string) *http.Client {
cert, err := tls.LoadX509KeyPair(certFile, keyFile)
c.Assert(err, IsNil)
caCert, err := ioutil.ReadFile(caFile)
c.Assert(err, IsNil)
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caCertPool,
InsecureSkipVerify: true,
}
tlsConfig.BuildNameToCertificate()
return &http.Client{Transport: &http.Transport{TLSClientConfig: tlsConfig}}
}

func (ts *tidbTestSuite) TestMultiStatements(c *C) {
>>>>>>> 92f6f4e... server: support check the "CommanName" of tls-cert for status-port(http/grpc) (#15137)
c.Parallel()
runTestMultiStatements(c)
}
Expand Down
9 changes: 9 additions & 0 deletions tests/cncheckcert/ca-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBQwIBAAJDAL6zaGJBgNTBNhtGTfSXnbzoZa1LlfCpFlIwtXc1YBBtl9IIzRI5
j2Cyd/DTYjO0vniHGIHv7H64336szhSGOcHV5QIDAQABAkIpDH9MnyL3KPvXlSOU
oco/bprsWZfV7N+0I238Ug3ym1QyCK3ue8m/bJveL9AXCwJWMLdvHQoiyCFnaQ6f
Ay2hGYUCIgD4YcAP4aIJL1H9vo0vmXQzFZJzklyOUcmRm00Ulvie5dsCIgDEjMGk
QZoiR9ammPSc1IKF/c6THtd1sA0rW9Vh0sCBXz8CIgCMkq4jjtyo/BoYVRcM4HmO
S+A1/pjZh1pgSRfH1mXhcE8CITRT5Rn9/TMzPQqNnlJCoZ1avSyeAW7ruBXbFSw+
F9JZsQIhMvQjbm0ygrSwOlvRhWOzAtUKSxcs7JKfxgt9/5/XIV4C
-----END RSA PRIVATE KEY-----
10 changes: 10 additions & 0 deletions tests/cncheckcert/ca-tidb-test-1.crt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBXzCCAQegAwIBAgIBADANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUaURC
IENBIDUwHhcNMjAwMzA0MTI0MzIxWhcNMjAwMzA0MTM0MzIxWjAUMRIwEAYDVQQD
EwlUaURCIENBIDUwXjANBgkqhkiG9w0BAQEFAANNADBKAkMAvrNoYkGA1ME2G0ZN
9JedvOhlrUuV8KkWUjC1dzVgEG2X0gjNEjmPYLJ38NNiM7S+eIcYge/sfrjffqzO
FIY5wdXlAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwICpDAdBgNVHSUEFjAUBggrBgEF
BQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAND
AKfu05xLZQ6PVMyYPjpo/RI/WchaLFRbBZKpdu+/QMaxreH7/xAqDfnslTVblWLo
uGxIrIOBL/1jR8CoAhBB1VAoJw==
-----END CERTIFICATE-----
10 changes: 10 additions & 0 deletions tests/cncheckcert/client-cert-1.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBYDCCAQigAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUaURC
IENBIDUwHhcNMjAwMzA0MTI0MzIxWhcNMjAwMzA0MTM0MzIxWjAYMRYwFAYDVQQD
Ew10aWRiLWNsaWVudC0xMF4wDQYJKoZIhvcNAQEBBQADTQAwSgJDAMMfWMiDqdQE
xy0kE/W+V+OmYZGit7iGk+BzMe6G0w9fFmJt8ajwmHp5dMT5AmJpNF/i089Wej3K
SdEkWhWa96BBOwIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
QwAnXNy43kWtlyelP1M5s0h4KNkmYBe6McaGV5nvhD/dwFfviY1dMRQ4ChgBgc5y
vv2r0fnRd2XF+81EmNGQk79Xg9A=
-----END CERTIFICATE-----
10 changes: 10 additions & 0 deletions tests/cncheckcert/client-cert-2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBYDCCAQigAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUaURC
IENBIDUwHhcNMjAwMzA0MTI0MzIxWhcNMjAwMzA0MTM0MzIxWjAYMRYwFAYDVQQD
Ew10aWRiLWNsaWVudC0yMF4wDQYJKoZIhvcNAQEBBQADTQAwSgJDANuIi1RlJKHF
KJg5D/fblj8FfRaay9CLJOhDZkabJTuMHerlpY0vf8wsY15khaJU/dRiJeAT+lvg
V4CluJLSSLuIEQIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
QwABsC2+tggurK8iUDmuaEKOqGnQdHrMMohDnSjmuS+X9xYcLlix7Haf53fBhs8B
kvUiPFk8QEiOi7xttaMHKeDLnRE=
-----END CERTIFICATE-----
9 changes: 9 additions & 0 deletions tests/cncheckcert/client-key-1.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBRQIBAAJDAMMfWMiDqdQExy0kE/W+V+OmYZGit7iGk+BzMe6G0w9fFmJt8ajw
mHp5dMT5AmJpNF/i089Wej3KSdEkWhWa96BBOwIDAQABAkJ4ps1zT1aX70xpsUFW
Vxhpf9wc/Yy04SJXS2O4pk2j15seJ9chhaolp26mVm1w/jyV/k6TwuKo0pM+F4pI
ePJNQQECIgDLWTCV6E1KGmprVnm/WRqUTewcNzfsXFHUlPSuIhTxUZsCIgD1pOfU
DpzwOoZb7XUogqkLKleaWWm22ffHuvuT3+ozGOECIgDDDS9Ea8pPTV1MzmsDtyV+
oevb+L9ksf0wKx00Nq7d9wcCIgCX/++4B0bTW9OSBLCvXZKOpyfICbXhgKTTQX+0
9CRuc+ECIgCqTejjhRnhz3rYD0wWqRRsXT/144RmiIpBslRp+HJ+5dg=
-----END RSA PRIVATE KEY-----
9 changes: 9 additions & 0 deletions tests/cncheckcert/client-key-2.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBQgIBAAJDANuIi1RlJKHFKJg5D/fblj8FfRaay9CLJOhDZkabJTuMHerlpY0v
f8wsY15khaJU/dRiJeAT+lvgV4CluJLSSLuIEQIDAQABAkJw/adQqbof9Pz+1CfO
11tOVoHaV5PdYzB8xuvmHUYdjvCG4WJcfFFkVipqE8VhJsS2Onzb7BFJ7gOqxCV6
9+FoYgECIgD1IP2jXxqOJgI3p78YaCJnBlRUMIu/+g+MmGPcLqg8taECIgDlRPYh
m0kOwtmzTtTI5sOLDgDPew16p8jyBvBPxsk53HECIW6W/rc5DeL5tOBlFqqtOHAg
g+Ujrbjj2SYGDm9kwVP6YQIhPd/xqTo2alRt2nWA+cNFrMaXs2cbSSn1ElSLEIyu
i/4RAiFcI5yrNMt2XwyKo/A+hzFvJeuQ6xTs9I1KMYbsngXJ58k=
-----END RSA PRIVATE KEY-----
10 changes: 10 additions & 0 deletions tests/cncheckcert/server-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
-----BEGIN CERTIFICATE-----
MIIBYDCCAQigAwIBAgIBATANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDEwlUaURC
IENBIDUwHhcNMjAwMzA0MTI0MzIxWhcNMjAwMzA0MTM0MzIxWjAYMRYwFAYDVQQD
Ew10aWRiLXNlcnZlci0zMF4wDQYJKoZIhvcNAQEBBQADTQAwSgJDAM+ez7yZLKp9
spGiUqqInrH8iTZ8JPa3C8K8bYw/Fc/W028sVvf6+VLC1ZP0cJX4Lx3iyyyIfzjG
KV4+MVcBOlfn4wIDAQABoz8wPTAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYI
KwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQAD
QwCUAO+eDYvVXBIqpNWr/h513TTSzZa+ELNOrYNGr2MgQ6j8TW0+J+J4JGgj0Wm7
1haBMbGShAHlXYK81ZShtnbPpFI=
-----END CERTIFICATE-----
9 changes: 9 additions & 0 deletions tests/cncheckcert/server-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-----BEGIN RSA PRIVATE KEY-----
MIIBRAIBAAJDAM+ez7yZLKp9spGiUqqInrH8iTZ8JPa3C8K8bYw/Fc/W028sVvf6
+VLC1ZP0cJX4Lx3iyyyIfzjGKV4+MVcBOlfn4wIDAQABAkJ5hiNh6OZUBK74v2JT
nxQEaiSGV7PrFMk1esVESciilsKsRJLcyzxbpANooQQefOswHzRR/YyMmy2HiW++
H08ENMECIgDR6EfM7CKKJGj2jz3b+2bUoBpdpuPtD9kPo4u6ubVnNz8CIgD9Nfhq
Viiwl2IentOXOWvIasGQdQXz1fWHGLP5nA2Xql0CIgCXcSGUXG2TAy/ja3cy5k/L
afN7y/O3zm5JlTIzttaFMFsCIgC7Io8Eb8bEtCzk+nbgVaStyxBhJcuPaPp7rKse
d9Gn3FUCITGo0wLxVqHmjk2Pe2n9IJK1ooupjGY1unWQ2rM8RDkqfA==
-----END RSA PRIVATE KEY-----

0 comments on commit 8ec3c75

Please sign in to comment.