diff --git a/Documentation/op-guide/configuration.md b/Documentation/op-guide/configuration.md index 8dadd317917..f8a231443ba 100644 --- a/Documentation/op-guide/configuration.md +++ b/Documentation/op-guide/configuration.md @@ -251,6 +251,11 @@ The security flags help to [build a secure etcd cluster][security]. + default: false + env variable: ETCD_PEER_AUTO_TLS +### --peer-cert-allowed-cn ++ Allowed CommonName for inter peer authentication. ++ default: none ++ env variable: ETCD_PEER_CERT_ALLOWED_CN + ## Logging flags ### --debug diff --git a/etcdmain/config.go b/etcdmain/config.go index 61411292363..f98c8ac1b73 100644 --- a/etcdmain/config.go +++ b/etcdmain/config.go @@ -184,6 +184,7 @@ func newConfig() *config { fs.StringVar(&cfg.PeerTLSInfo.TrustedCAFile, "peer-trusted-ca-file", "", "Path to the peer server TLS trusted CA file.") fs.BoolVar(&cfg.PeerAutoTLS, "peer-auto-tls", false, "Peer TLS using generated certificates") fs.StringVar(&cfg.PeerTLSInfo.CRLFile, "peer-crl-file", "", "Path to the peer certificate revocation list file.") + fs.StringVar(&cfg.PeerTLSInfo.AllowedCN, "peer-cert-allowed-cn", "", "Allowed CN for inter peer authentication.") // logging fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.") diff --git a/pkg/transport/listener.go b/pkg/transport/listener.go index 33ba17fe12d..38737e3e45f 100644 --- a/pkg/transport/listener.go +++ b/pkg/transport/listener.go @@ -22,6 +22,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/pem" + "errors" "fmt" "math/big" "net" @@ -76,6 +77,9 @@ type TLSInfo struct { // parseFunc exists to simplify testing. Typically, parseFunc // should be left nil. In that case, tls.X509KeyPair will be used. parseFunc func([]byte, []byte) (tls.Certificate, error) + + // AllowedCN is a CN which must be provided by a client. + AllowedCN string } func (info TLSInfo) String() string { @@ -174,6 +178,20 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) { MinVersion: tls.VersionTLS12, ServerName: info.ServerName, } + + if info.AllowedCN != "" { + cfg.VerifyPeerCertificate = func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + for _, chains := range verifiedChains { + if len(chains) != 0 { + if info.AllowedCN == chains[0].Subject.CommonName { + return nil + } + } + } + return errors.New("CommonName authentication failed") + } + } + // this only reloads certs when there's a client request // TODO: support server-side refresh (e.g. inotify, SIGHUP), caching cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {