Browse Source

etcdmain, pkg: CN based auth for inter peer connection

This commit adds an authentication mechanism to inter peer connection
(rafthttp). If the cert based peer auth is enabled and a new option
`--peer-cert-allowed-cn` is passed, an etcd process denies a peer
connection whose CN doesn't match.
Hitoshi Mitake 8 years ago
parent
commit
70018e9207
3 changed files with 24 additions and 0 deletions
  1. 5 0
      Documentation/op-guide/configuration.md
  2. 1 0
      etcdmain/config.go
  3. 18 0
      pkg/transport/listener.go

+ 5 - 0
Documentation/op-guide/configuration.md

@@ -251,6 +251,11 @@ The security flags help to [build a secure etcd cluster][security].
 + default: false
 + default: false
 + env variable: ETCD_PEER_AUTO_TLS
 + 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
 ## Logging flags
 
 
 ### --debug
 ### --debug

+ 1 - 0
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.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.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.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
 	// logging
 	fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.")
 	fs.BoolVar(&cfg.Debug, "debug", false, "Enable debug-level logging for etcd.")

+ 18 - 0
pkg/transport/listener.go

@@ -22,6 +22,7 @@ import (
 	"crypto/x509"
 	"crypto/x509"
 	"crypto/x509/pkix"
 	"crypto/x509/pkix"
 	"encoding/pem"
 	"encoding/pem"
+	"errors"
 	"fmt"
 	"fmt"
 	"math/big"
 	"math/big"
 	"net"
 	"net"
@@ -76,6 +77,9 @@ type TLSInfo struct {
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// parseFunc exists to simplify testing. Typically, parseFunc
 	// should be left nil. In that case, tls.X509KeyPair will be used.
 	// should be left nil. In that case, tls.X509KeyPair will be used.
 	parseFunc func([]byte, []byte) (tls.Certificate, error)
 	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 {
 func (info TLSInfo) String() string {
@@ -174,6 +178,20 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
 		MinVersion:   tls.VersionTLS12,
 		MinVersion:   tls.VersionTLS12,
 		ServerName:   info.ServerName,
 		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
 	// this only reloads certs when there's a client request
 	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
 	// TODO: support server-side refresh (e.g. inotify, SIGHUP), caching
 	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
 	cfg.GetCertificate = func(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {