add support for client cert auth for mysql protocol connections

Signed-off-by: tpetr <tpetr@hubspot.com>
This commit is contained in:
tpetr 2019-01-07 12:54:49 -05:00
Родитель 42f5c760cc
Коммит a5304daa02
3 изменённых файлов: 94 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,12 @@
package main
// This plugin imports clientcert to register the client certificate implementation of AuthServer.
import (
"vitess.io/vitess/go/mysql/clientcert"
"vitess.io/vitess/go/vt/vtgate"
)
func init() {
vtgate.RegisterPluginInitializer(func() { clientcert.Init() })
}

Просмотреть файл

@ -0,0 +1,73 @@
package clientcert
import (
"flag"
"fmt"
"net"
"vitess.io/vitess/go/mysql"
"vitess.io/vitess/go/vt/log"
querypb "vitess.io/vitess/go/vt/proto/query"
)
var clientcertAuthMethod = flag.String("mysql_clientcert_auth_method", mysql.MysqlClearPassword, "client-side authentication method to use. Supported values: mysql_clear_password, dialog.")
type AuthServerClientCert struct {
Method string
}
type UserData struct {
querypb.VTGateCallerID
}
// Init is public so it can be called from plugin_auth_ldap.go (go/cmd/vtgate)
func Init() {
if *clientcertAuthMethod != mysql.MysqlClearPassword && *clientcertAuthMethod != mysql.MysqlDialog {
log.Exitf("Invalid mysql_clientcert_auth_method value: only support mysql_clear_password or dialog")
}
ascc := &AuthServerClientCert{
Method: *clientcertAuthMethod,
}
mysql.RegisterAuthServerImpl("clientcert", ascc)
}
// AuthMethod is part of the AuthServer interface.
func (ascc *AuthServerClientCert) AuthMethod(user string) (string, error) {
return ascc.Method, nil
}
// Salt is not used for this plugin.
func (ascc *AuthServerClientCert) Salt() ([]byte, error) {
return mysql.NewSalt()
}
// ValidateHash is unimplemented.
func (ascc *AuthServerClientCert) ValidateHash(salt []byte, user string, authResponse []byte, remoteAddr net.Addr) (mysql.Getter, error) {
panic("unimplemented")
}
// Negotiate is part of the AuthServer interface.
func (ascc *AuthServerClientCert) Negotiate(c *mysql.Conn, user string, remoteAddr net.Addr) (mysql.Getter, error) {
// This code depends on the fact that golang's tls server enforces client cert verification.
// Note that the -mysql_server_ssl_ca flag must be set in order for the vtgate to accept client certs.
// If not set, the vtgate will effectively deny all incoming mysql connections, since they will all lack certificates.
// For more info, check out go/vt/vtttls/vttls.go
certs := c.GetTLSClientCerts()
if certs == nil || len(certs) == 0 {
return nil, fmt.Errorf("no client certs for connection ID %v", c.ConnectionID)
}
if _, err := mysql.AuthServerReadPacketString(c); err != nil {
return nil, err
}
return &UserData{
VTGateCallerID: querypb.VTGateCallerID{
Username: certs[0].Subject.CommonName,
Groups: certs[0].DNSNames,
},
}, nil
}
func (ud *UserData) Get() *querypb.VTGateCallerID {
return &ud.VTGateCallerID
}

Просмотреть файл

@ -18,6 +18,8 @@ package mysql
import (
"bufio"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
@ -982,3 +984,10 @@ func ParseErrorPacket(data []byte) error {
return NewSQLError(int(code), string(sqlState), "%v", msg)
}
func (conn *Conn) GetTLSClientCerts() []*x509.Certificate {
if tlsConn, ok := conn.conn.(*tls.Conn); ok {
return tlsConn.ConnectionState().PeerCertificates
}
return nil
}