Skip to content

Commit

Permalink
tweak: allows custom names to pass tls verification
Browse files Browse the repository at this point in the history
Signed-off-by: mornyx <mornyx.z@gmail.com>
  • Loading branch information
mornyx committed Jul 25, 2023
1 parent fe7f01f commit bb8dea0
Showing 1 changed file with 55 additions and 3 deletions.
58 changes: 55 additions & 3 deletions cmd/tidb-dashboard/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package main
import (
"context"
"crypto/tls"
"crypto/x509"
"fmt"
"net"
"net/http"
Expand Down Expand Up @@ -72,10 +73,12 @@ func NewCLIConfig() *DashboardCLIConfig {
clusterCaPath := flag.String("cluster-ca", "", "(TLS between components of the TiDB cluster) path of file that contains list of trusted SSL CAs")
clusterCertPath := flag.String("cluster-cert", "", "(TLS between components of the TiDB cluster) path of file that contains X509 certificate in PEM format")
clusterKeyPath := flag.String("cluster-key", "", "(TLS between components of the TiDB cluster) path of file that contains X509 key in PEM format")
clusterAllowedNames := flag.String("cluster-allowed-names", "", "comma-delimited list of acceptable peer certificate SAN identities")

tidbCaPath := flag.String("tidb-ca", "", "(TLS for MySQL client) path of file that contains list of trusted SSL CAs")
tidbCertPath := flag.String("tidb-cert", "", "(TLS for MySQL client) path of file that contains X509 certificate in PEM format")
tidbKeyPath := flag.String("tidb-key", "", "(TLS for MySQL client) path of file that contains X509 key in PEM format")
tidbAllowedNames := flag.String("tidb-allowed-names", "", "comma-delimited list of acceptable peer certificate SAN identities")

// debug for keyvisual,hide help information
flag.Int64Var(&cfg.KVFileStartTime, "keyviz-file-start", 0, "(debug) start time for file range in file mode")
Expand All @@ -94,13 +97,13 @@ func NewCLIConfig() *DashboardCLIConfig {

// setup TLS config for TiDB components
if len(*clusterCaPath) != 0 && len(*clusterCertPath) != 0 && len(*clusterKeyPath) != 0 {
cfg.CoreConfig.ClusterTLSConfig = buildTLSConfig(clusterCaPath, clusterKeyPath, clusterCertPath)
cfg.CoreConfig.ClusterTLSConfig = buildTLSConfig(clusterCaPath, clusterKeyPath, clusterCertPath, clusterAllowedNames)
}

// setup TLS config for MySQL client
// See https://github.com/pingcap/docs/blob/7a62321b3ce9318cbda8697503c920b2a01aeb3d/how-to/secure/enable-tls-clients.md#enable-authentication
if (len(*tidbCertPath) != 0 && len(*tidbKeyPath) != 0) || len(*tidbCaPath) != 0 {
cfg.CoreConfig.TiDBTLSConfig = buildTLSConfig(tidbCaPath, tidbKeyPath, tidbCertPath)
cfg.CoreConfig.TiDBTLSConfig = buildTLSConfig(tidbCaPath, tidbKeyPath, tidbCertPath, tidbAllowedNames)
}

if err := cfg.CoreConfig.NormalizePDEndPoint(); err != nil {
Expand Down Expand Up @@ -135,16 +138,65 @@ func getContext() context.Context {
return ctx
}

func buildTLSConfig(caPath, keyPath, certPath *string) *tls.Config {
func buildTLSConfig(caPath, keyPath, certPath, allowedNames *string) *tls.Config {
tlsInfo := transport.TLSInfo{
TrustedCAFile: *caPath,
KeyFile: *keyPath,
CertFile: *certPath,
}

tlsConfig, err := tlsInfo.ClientConfig()
if err != nil {
log.Fatal("Failed to load certificates", zap.Error(err))
}

// Disable the default server verification routine in favor of a manually defined connection
// verification callback. The custom verification process verifies that the server
// certificate is issued by a trusted root CA, and that the peer certificate identities
// matches at least one entry specified in verifyNames (if specified). This is required
// because tidb-dashboard directs requests to a loopback-bound forwarding proxy, which would
// otherwise cause server hostname verification to fail.
tlsConfig.InsecureSkipVerify = true
tlsConfig.VerifyConnection = func(state tls.ConnectionState) error {
opts := x509.VerifyOptions{
Intermediates: x509.NewCertPool(),
Roots: tlsConfig.RootCAs,
}

for _, cert := range state.PeerCertificates[1:] {
opts.Intermediates.AddCert(cert)
}

_, err := state.PeerCertificates[0].Verify(opts)

// Optionally verify the peer SANs when available. If no peer identities are
// provided, simply reuse the verification result of the CA verification.
if err != nil || *allowedNames == "" {
return err
}

for _, name := range strings.Split(*allowedNames, ",") {
for _, dns := range state.PeerCertificates[0].DNSNames {
if name == dns {
return nil
}
}

for _, uri := range state.PeerCertificates[0].URIs {
if name == uri.String() {
return nil
}
}
}

return fmt.Errorf(
"no SANs in server certificate (%v, %v) match allowed names %v",
state.PeerCertificates[0].DNSNames,
state.PeerCertificates[0].URIs,
strings.Split(*allowedNames, ","),
)
}

return tlsConfig
}

Expand Down

0 comments on commit bb8dea0

Please sign in to comment.