diff --git a/cmd/drainer/drainer.toml b/cmd/drainer/drainer.toml index c0da90a3e..bbda1f26b 100644 --- a/cmd/drainer/drainer.toml +++ b/cmd/drainer/drainer.toml @@ -118,6 +118,8 @@ port = 3306 # ssl-cert = "/path/to/drainer.pem" # Path of file that contains X509 key in PEM format. # ssl-key = "/path/to/drainer-key.pem" +# The common name which is allowed to connection with cluster components. +# cert-allowed-cn = ["binlog"] [syncer.to.checkpoint] # only support mysql or tidb now, you can uncomment this to control where the checkpoint is saved. diff --git a/cmd/pump/pump.toml b/cmd/pump/pump.toml index 28ffa75ea..def9ffbe9 100644 --- a/cmd/pump/pump.toml +++ b/cmd/pump/pump.toml @@ -26,6 +26,8 @@ pd-urls = "http://127.0.0.1:2379" # ssl-cert = "/path/to/drainer.pem" # Path of file that contains X509 key in PEM format for connection with cluster components. # ssl-key = "/path/to/drainer-key.pem" +# The common name which is allowed to connection with cluster components. +# cert-allowed-cn = ["binlog"] # # [storage] # Set to `true` (default) for best reliability, which prevents data loss when there is a power failure. diff --git a/pkg/security/security.go b/pkg/security/security.go index 7be3d6f1c..08f25e302 100644 --- a/pkg/security/security.go +++ b/pkg/security/security.go @@ -17,6 +17,7 @@ import ( "crypto/tls" "crypto/x509" "io/ioutil" + "strings" "github.com/pingcap/errors" "github.com/pingcap/tidb/config" @@ -24,9 +25,10 @@ import ( // Config is security config type Config struct { - SSLCA string `toml:"ssl-ca" json:"ssl-ca"` - SSLCert string `toml:"ssl-cert" json:"ssl-cert"` - SSLKey string `toml:"ssl-key" json:"ssl-key"` + SSLCA string `toml:"ssl-ca" json:"ssl-ca"` + SSLCert string `toml:"ssl-cert" json:"ssl-cert"` + SSLKey string `toml:"ssl-key" json:"ssl-key"` + CertAllowedCN []string `toml:"cert-allowed-cn" json:"cert-allowed-cn"` } // ToTLSConfig generates tls's config based on security section of the config. @@ -49,7 +51,8 @@ func (c *Config) ToTLSConfig() (tlsConfig *tls.Config, err error) { } tlsConfig = &tls.Config{ - RootCAs: certPool, + RootCAs: certPool, + ClientCAs: certPool, } if len(c.SSLCert) != 0 && len(c.SSLKey) != 0 { @@ -75,6 +78,29 @@ func (c *Config) ToTLSConfig() (tlsConfig *tls.Config, err error) { } } + if len(c.CertAllowedCN) != 0 { + checkCN := make(map[string]struct{}) + for _, cn := range c.CertAllowedCN { + cn = strings.TrimSpace(cn) + checkCN[cn] = struct{}{} + } + + tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert + + tlsConfig.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + cns := make([]string, 0, len(verifiedChains)) + for _, chains := range verifiedChains { + for _, chain := range chains { + cns = append(cns, chain.Subject.CommonName) + if _, match := checkCN[chain.Subject.CommonName]; match { + return nil + } + } + } + return errors.Errorf("client certificate authentication failed. The Common Name from the client certificate %v was not found in the configuration cluster-verify-cn with value: %s", cns, c.CertAllowedCN) + } + } + return } diff --git a/tests/_utils/run_drainer b/tests/_utils/run_drainer index 33f73ab26..c8aa8de66 100755 --- a/tests/_utils/run_drainer +++ b/tests/_utils/run_drainer @@ -32,6 +32,8 @@ fi ssl-ca = "$OUT_DIR/cert/ca.pem" ssl-cert = "$OUT_DIR/cert/drainer.pem" ssl-key = "$OUT_DIR/cert/drainer.key" +cert-allowed-cn = ["binlog"] + EOF drainer -log-file $OUT_DIR/drainer.log -config "$OUT_DIR/drainer-config-tmp.toml" -pd-urls https://127.0.0.1:2379 -addr 0.0.0.0:8249 -advertise-addr 127.0.0.1:8249 -node-id drainer-id $* >> $OUT_DIR/drainer.log 2>&1 diff --git a/tests/_utils/run_pump b/tests/_utils/run_pump index ccd3e7262..53cc2ccb1 100755 --- a/tests/_utils/run_pump +++ b/tests/_utils/run_pump @@ -29,6 +29,7 @@ cat - > "$OUT_DIR/pump-config.toml" < /dev/null for name in tidb pd tikv pump drainer client; do openssl ecparam -out "$TT/$name.key" -name prime256v1 -genkey - openssl req -new -batch -sha256 -subj '/CN=localhost' -key "$TT/$name.key" -out "$TT/$name.csr" + openssl req -new -batch -sha256 -subj '/CN=binlog' -key "$TT/$name.key" -out "$TT/$name.csr" openssl x509 -req -sha256 -days 1 -extensions EXT -extfile "$TT/ipsan.cnf" -in "$TT/$name.csr" -CA "$TT/ca.pem" -CAkey "$TT/ca.key" -CAcreateserial -out "$TT/$name.pem" 2> /dev/null done }