Skip to content

Commit

Permalink
Merge pull request #150 from joewilliams/metrics
Browse files Browse the repository at this point in the history
tlsconfig trace implementation
  • Loading branch information
azdagron committed Sep 17, 2020
2 parents 13cad8a + 0ca6ea6 commit 5bab594
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 49 deletions.
4 changes: 2 additions & 2 deletions v2/spiffetls/dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ func DialWithMode(ctx context.Context, network, addr string, mode DialMode, opti
case tlsClientMode:
tlsconfig.HookTLSClientConfig(tlsConfig, m.bundle, m.authorizer)
case mtlsClientMode:
tlsconfig.HookMTLSClientConfig(tlsConfig, m.svid, m.bundle, m.authorizer)
tlsconfig.HookMTLSClientConfig(tlsConfig, m.svid, m.bundle, m.authorizer, opt.tlsoptions...)
case mtlsWebClientMode:
tlsconfig.HookMTLSWebClientConfig(tlsConfig, m.svid, m.roots)
tlsconfig.HookMTLSWebClientConfig(tlsConfig, m.svid, m.roots, opt.tlsoptions...)
default:
return nil, spiffetlsErr.New("unknown client mode: %v", m.mode)
}
Expand Down
4 changes: 2 additions & 2 deletions v2/spiffetls/listen.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,9 @@ func NewListenerWithMode(ctx context.Context, inner net.Listener, mode ListenMod

switch m.mode {
case tlsServerMode:
tlsconfig.HookTLSServerConfig(tlsConfig, m.svid)
tlsconfig.HookTLSServerConfig(tlsConfig, m.svid, opt.tlsoptions...)
case mtlsServerMode:
tlsconfig.HookMTLSServerConfig(tlsConfig, m.svid, m.bundle, m.authorizer)
tlsconfig.HookMTLSServerConfig(tlsConfig, m.svid, m.bundle, m.authorizer, opt.tlsoptions...)
case mtlsWebServerMode:
tlsconfig.HookMTLSWebServerConfig(tlsConfig, m.cert, m.bundle, m.authorizer)
default:
Expand Down
17 changes: 17 additions & 0 deletions v2/spiffetls/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"crypto/tls"
"net"

"github.com/spiffe/go-spiffe/v2/spiffetls/tlsconfig"
"github.com/zeebo/errs"
)

Expand All @@ -23,12 +24,14 @@ func (fn dialOption) apply(c *dialConfig) {
type dialConfig struct {
baseTLSConf *tls.Config
dialer *net.Dialer
tlsoptions []tlsconfig.Option
}

type listenOption func(*listenConfig)

type listenConfig struct {
baseTLSConf *tls.Config
tlsoptions []tlsconfig.Option
}

func (fn listenOption) apply(c *listenConfig) {
Expand All @@ -44,6 +47,13 @@ func WithDialTLSConfigBase(base *tls.Config) DialOption {
})
}

// WithDialTLSOptions provides options to use for the TLS config.
func WithDialTLSOptions(opts ...tlsconfig.Option) DialOption {
return dialOption(func(c *dialConfig) {
c.tlsoptions = opts
})
}

// WithDialer provides a net dialer to use. If unset, the standard net dialer
// will be used.
func WithDialer(dialer *net.Dialer) DialOption {
Expand All @@ -65,3 +75,10 @@ func WithListenTLSConfigBase(base *tls.Config) ListenOption {
c.baseTLSConf = base
})
}

// WithListenTLSOptions provides options to use when doing Server mTLS.
func WithListenTLSOptions(opts ...tlsconfig.Option) ListenOption {
return listenOption(func(c *listenConfig) {
c.tlsoptions = opts
})
}
113 changes: 78 additions & 35 deletions v2/spiffetls/tlsconfig/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,79 +10,108 @@ import (

// TLSClientConfig returns a TLS configuration which verifies and authorizes
// the server X509-SVID.
func TLSClientConfig(bundle x509bundle.Source, authorizer Authorizer) *tls.Config {
func TLSClientConfig(bundle x509bundle.Source, authorizer Authorizer, opts ...Option) *tls.Config {
config := new(tls.Config)
HookTLSClientConfig(config, bundle, authorizer)
HookTLSClientConfig(config, bundle, authorizer, opts...)
return config
}

// HookTLSClientConfig sets up the TLS configuration to verify and authorize
// the server X509-SVID. If there is an existing callback set for
// VerifyPeerCertificate it will be wrapped by by this package and invoked
// after SPIFFE authentication has completed.
func HookTLSClientConfig(config *tls.Config, bundle x509bundle.Source, authorizer Authorizer) {
func HookTLSClientConfig(config *tls.Config, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) {
resetAuthFields(config)
config.InsecureSkipVerify = true
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
}

// A Option changes the defaults used to by mTLS ClientConfig functions.
type Option interface {
apply(*options)
}

type option func(*options)

func (fn option) apply(o *options) { fn(o) }

type options struct {
trace Trace
}

func newOptions(opts []Option) *options {
out := &options{}
for _, opt := range opts {
opt.apply(out)
}
return out
}

// WithTrace will use the provided tracing callbacks
// when various TLS config functions gets invoked.
func WithTrace(trace Trace) Option {
return option(func(opts *options) {
opts.trace = trace
})
}

// MTLSClientConfig returns a TLS configuration which presents an X509-SVID
// to the server and verifies and authorizes the server X509-SVID.
func MTLSClientConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer) *tls.Config {
func MTLSClientConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) *tls.Config {
config := new(tls.Config)
HookMTLSClientConfig(config, svid, bundle, authorizer)
HookMTLSClientConfig(config, svid, bundle, authorizer, opts...)
return config
}

// HookMTLSClientConfig sets up the TLS configuration to present an X509-SVID
// to the server and verify and authorize the server X509-SVID. If there is an
// existing callback set for VerifyPeerCertificate it will be wrapped by by
// this package and invoked after SPIFFE authentication has completed.
func HookMTLSClientConfig(config *tls.Config, svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer) {
func HookMTLSClientConfig(config *tls.Config, svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) {
resetAuthFields(config)
config.GetClientCertificate = GetClientCertificate(svid)
config.GetClientCertificate = GetClientCertificate(svid, opts...)
config.InsecureSkipVerify = true
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
}

// MTLSWebClientConfig returns a TLS configuration which presents an X509-SVID
// to the server and verifies the server certificate using provided roots (or
// the system roots if nil).
func MTLSWebClientConfig(svid x509svid.Source, roots *x509.CertPool) *tls.Config {
func MTLSWebClientConfig(svid x509svid.Source, roots *x509.CertPool, opts ...Option) *tls.Config {
config := new(tls.Config)
HookMTLSWebClientConfig(config, svid, roots)
HookMTLSWebClientConfig(config, svid, roots, opts...)
return config
}

// HookMTLSWebClientConfig sets up the TLS configuration to present an
// X509-SVID to the server and verifies the server certificate using the
// provided roots (or the system roots if nil).
func HookMTLSWebClientConfig(config *tls.Config, svid x509svid.Source, roots *x509.CertPool) {
func HookMTLSWebClientConfig(config *tls.Config, svid x509svid.Source, roots *x509.CertPool, opts ...Option) {
resetAuthFields(config)
config.GetClientCertificate = GetClientCertificate(svid)
config.GetClientCertificate = GetClientCertificate(svid, opts...)
config.RootCAs = roots
}

// TLSServerConfig returns a TLS configuration which presents an X509-SVID
// to the client and does not require or verify client certificates.
func TLSServerConfig(svid x509svid.Source) *tls.Config {
func TLSServerConfig(svid x509svid.Source, opts ...Option) *tls.Config {
config := new(tls.Config)
HookTLSServerConfig(config, svid)
HookTLSServerConfig(config, svid, opts...)
return config
}

// HookTLSServerConfig sets up the TLS configuration to present an X509-SVID
// to the client and to not require or verify client certificates.
func HookTLSServerConfig(config *tls.Config, svid x509svid.Source) {
func HookTLSServerConfig(config *tls.Config, svid x509svid.Source, opts ...Option) {
resetAuthFields(config)
config.GetCertificate = GetCertificate(svid)
config.GetCertificate = GetCertificate(svid, opts...)
}

// MTLSServerConfig returns a TLS configuration which presents an X509-SVID
// to the client and requires, verifies, and authorizes client X509-SVIDs.
func MTLSServerConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer) *tls.Config {
func MTLSServerConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) *tls.Config {
config := new(tls.Config)
HookMTLSServerConfig(config, svid, bundle, authorizer)
HookMTLSServerConfig(config, svid, bundle, authorizer, opts...)
return config
}

Expand All @@ -91,19 +120,19 @@ func MTLSServerConfig(svid x509svid.Source, bundle x509bundle.Source, authorizer
// there is an existing callback set for VerifyPeerCertificate it will be
// wrapped by by this package and invoked after SPIFFE authentication has
// completed.
func HookMTLSServerConfig(config *tls.Config, svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer) {
func HookMTLSServerConfig(config *tls.Config, svid x509svid.Source, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) {
resetAuthFields(config)
config.ClientAuth = tls.RequireAnyClientCert
config.GetCertificate = GetCertificate(svid)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer)
config.GetCertificate = GetCertificate(svid, opts...)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
}

// MTLSWebServerConfig returns a TLS configuration which presents a web
// server certificate to the client and requires, verifies, and authorizes
// client X509-SVIDs.
func MTLSWebServerConfig(cert *tls.Certificate, bundle x509bundle.Source, authorizer Authorizer) *tls.Config {
func MTLSWebServerConfig(cert *tls.Certificate, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) *tls.Config {
config := new(tls.Config)
HookMTLSWebServerConfig(config, cert, bundle, authorizer)
HookMTLSWebServerConfig(config, cert, bundle, authorizer, opts...)
return config
}

Expand All @@ -112,34 +141,36 @@ func MTLSWebServerConfig(cert *tls.Certificate, bundle x509bundle.Source, author
// X509-SVIDs. If there is an existing callback set for VerifyPeerCertificate
// it will be wrapped by by this package and invoked after SPIFFE
// authentication has completed.
func HookMTLSWebServerConfig(config *tls.Config, cert *tls.Certificate, bundle x509bundle.Source, authorizer Authorizer) {
func HookMTLSWebServerConfig(config *tls.Config, cert *tls.Certificate, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) {
resetAuthFields(config)
config.ClientAuth = tls.RequireAnyClientCert
config.Certificates = []tls.Certificate{*cert}
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer)
config.VerifyPeerCertificate = WrapVerifyPeerCertificate(config.VerifyPeerCertificate, bundle, authorizer, opts...)
}

// GetCertificate returns a GetCertificate callback for tls.Config. It uses the
// given X509-SVID getter to obtain a server X509-SVID for the TLS handshake.
func GetCertificate(svid x509svid.Source) func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
func GetCertificate(svid x509svid.Source, opts ...Option) func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
opt := newOptions(opts)
return func(*tls.ClientHelloInfo) (*tls.Certificate, error) {
return getTLSCertificate(svid)
return getTLSCertificate(svid, opt.trace)
}
}

// GetClientCertificate returns a GetClientCertificate callback for tls.Config.
// It uses the given X509-SVID getter to obtain a client X509-SVID for the TLS
// handshake.
func GetClientCertificate(svid x509svid.Source) func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
func GetClientCertificate(svid x509svid.Source, opts ...Option) func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
opt := newOptions(opts)
return func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
return getTLSCertificate(svid)
return getTLSCertificate(svid, opt.trace)
}
}

// VerifyPeerCertificate returns a VerifyPeerCertificate callback for
// tls.Config. It uses the given bundle source and authorizer to verify and
// authorize X509-SVIDs provided by peers during the TLS handshake.
func VerifyPeerCertificate(bundle x509bundle.Source, authorizer Authorizer) func([][]byte, [][]*x509.Certificate) error {
func VerifyPeerCertificate(bundle x509bundle.Source, authorizer Authorizer, opts ...Option) func([][]byte, [][]*x509.Certificate) error {
return func(raw [][]byte, _ [][]*x509.Certificate) error {
id, certs, err := x509svid.ParseAndVerify(raw, bundle)
if err != nil {
Expand All @@ -154,9 +185,9 @@ func VerifyPeerCertificate(bundle x509bundle.Source, authorizer Authorizer) func
// SPIFFE authentication against the peer certificates using the given bundle and
// authorizer. The wrapped callback will be passed the verified chains.
// Note: TLS clients must set `InsecureSkipVerify` when doing SPIFFE authentication to disable hostname verification.
func WrapVerifyPeerCertificate(wrapped func([][]byte, [][]*x509.Certificate) error, bundle x509bundle.Source, authorizer Authorizer) func([][]byte, [][]*x509.Certificate) error {
func WrapVerifyPeerCertificate(wrapped func([][]byte, [][]*x509.Certificate) error, bundle x509bundle.Source, authorizer Authorizer, opts ...Option) func([][]byte, [][]*x509.Certificate) error {
if wrapped == nil {
return VerifyPeerCertificate(bundle, authorizer)
return VerifyPeerCertificate(bundle, authorizer, opts...)
}

return func(raw [][]byte, _ [][]*x509.Certificate) error {
Expand All @@ -173,10 +204,18 @@ func WrapVerifyPeerCertificate(wrapped func([][]byte, [][]*x509.Certificate) err
}
}

func getTLSCertificate(svid x509svid.Source) (*tls.Certificate, error) {
func getTLSCertificate(svid x509svid.Source, trace Trace) (*tls.Certificate, error) {
var traceVal interface{}
if trace.GetCertificate != nil {
traceVal = trace.GetCertificate()
}

s, err := svid.GetX509SVID()
if err != nil {
return nil, err
if trace.GotCertificate != nil {
trace.GotCertificate(traceVal, GotCertificateInfo{Err: err})
return nil, err
}
}

cert := &tls.Certificate{
Expand All @@ -188,6 +227,10 @@ func getTLSCertificate(svid x509svid.Source) (*tls.Certificate, error) {
cert.Certificate = append(cert.Certificate, svidCert.Raw)
}

if trace.GotCertificate != nil {
trace.GotCertificate(traceVal, GotCertificateInfo{Cert: cert})
}

return cert, nil
}

Expand Down
Loading

0 comments on commit 5bab594

Please sign in to comment.