serve TLS: validate client CNs against whitelist in config file

This commit is contained in:
Christian Schwarz 2018-09-06 13:34:39 -07:00
parent 1edf020ce7
commit 7836ea36fc

View File

@ -3,6 +3,7 @@ package serve
import ( import (
"crypto/tls" "crypto/tls"
"crypto/x509" "crypto/x509"
"fmt"
"github.com/pkg/errors" "github.com/pkg/errors"
"github.com/zrepl/zrepl/config" "github.com/zrepl/zrepl/config"
"github.com/zrepl/zrepl/tlsconf" "github.com/zrepl/zrepl/tlsconf"
@ -16,6 +17,7 @@ type TLSListenerFactory struct {
clientCA *x509.CertPool clientCA *x509.CertPool
serverCert tls.Certificate serverCert tls.Certificate
handshakeTimeout time.Duration handshakeTimeout time.Duration
clientCNs map[string]struct{}
} }
func TLSListenerFactoryFromConfig(c *config.Global, in *config.TLSServe) (lf *TLSListenerFactory, err error) { func TLSListenerFactoryFromConfig(c *config.Global, in *config.TLSServe) (lf *TLSListenerFactory, err error) {
@ -38,6 +40,15 @@ func TLSListenerFactoryFromConfig(c *config.Global, in *config.TLSServe) (lf *TL
return nil, errors.Wrap(err, "cannot parse cer/key pair") return nil, errors.Wrap(err, "cannot parse cer/key pair")
} }
lf.clientCNs = make(map[string]struct{}, len(in.ClientCNs))
for i, cn := range in.ClientCNs {
if err := ValidateClientIdentity(cn); err != nil {
return nil, errors.Wrapf(err, "unsuitable client_cn #%d %q", i, cn)
}
// dupes are ok fr now
lf.clientCNs[cn] = struct{}{}
}
return lf, nil return lf, nil
} }
@ -47,11 +58,12 @@ func (f *TLSListenerFactory) Listen() (AuthenticatedListener, error) {
return nil, err return nil, err
} }
tl := tlsconf.NewClientAuthListener(l, f.clientCA, f.serverCert, f.handshakeTimeout) tl := tlsconf.NewClientAuthListener(l, f.clientCA, f.serverCert, f.handshakeTimeout)
return tlsAuthListener{tl}, nil return tlsAuthListener{tl, f.clientCNs}, nil
} }
type tlsAuthListener struct { type tlsAuthListener struct {
*tlsconf.ClientAuthListener *tlsconf.ClientAuthListener
clientCNs map[string]struct{}
} }
func (l tlsAuthListener) Accept(ctx context.Context) (AuthenticatedConn, error) { func (l tlsAuthListener) Accept(ctx context.Context) (AuthenticatedConn, error) {
@ -59,6 +71,12 @@ func (l tlsAuthListener) Accept(ctx context.Context) (AuthenticatedConn, error)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if _, ok := l.clientCNs[cn]; !ok {
if err := c.Close(); err != nil {
getLogger(ctx).WithError(err).Error("error closing connection with unauthorized common name")
}
return nil, fmt.Errorf("unauthorized client common name %q from %s", cn, c.RemoteAddr())
}
return authConn{c, cn}, nil return authConn{c, cn}, nil
} }