diff --git a/cli/config.go b/cli/config.go index 0f72b9ef8..c1ba23798 100644 --- a/cli/config.go +++ b/cli/config.go @@ -21,6 +21,7 @@ type Config struct { TLSKeyFile string MutualTLSCAFile string MutualTLSCNRegex string + MutualTLSSANRegex string TLSRemoteCAs string MutualTLSCertFile string MutualTLSKeyFile string @@ -83,6 +84,7 @@ func registerFlags(c *Config, f *flag.FlagSet) { f.StringVar(&c.TLSKeyFile, "tls-key", "", "Other endpoint CA private key") f.StringVar(&c.MutualTLSCAFile, "mutual-tls-ca", "", "Mutual TLS - require clients be signed by this CA ") f.StringVar(&c.MutualTLSCNRegex, "mutual-tls-cn", "", "Mutual TLS - regex for whitelist of allowed client CNs") + f.StringVar(&c.MutualTLSSANRegex, "mutual-tls-san", "", "Mutual TLS - regex for whitelist of allowed client SANs") f.StringVar(&c.TLSRemoteCAs, "tls-remote-ca", "", "CAs to trust for remote TLS requests") f.StringVar(&c.MutualTLSCertFile, "mutual-tls-client-cert", "", "Mutual TLS - client certificate to call remote instance requiring client certs") f.StringVar(&c.MutualTLSKeyFile, "mutual-tls-client-key", "", "Mutual TLS - client key to call remote instance requiring client certs") diff --git a/cli/serve/serve.go b/cli/serve/serve.go index 57c7ef590..6b1b48e30 100644 --- a/cli/serve/serve.go +++ b/cli/serve/serve.go @@ -51,8 +51,8 @@ Usage of serve: [-metadata file] [-remote remote_host] [-config config] \ [-responder cert] [-responder-key key] \ [-tls-cert cert] [-tls-key key] [-mutual-tls-ca ca] [-mutual-tls-cn regex] \ - [-tls-remote-ca ca] [-mutual-tls-client-cert cert] [-mutual-tls-client-key key] \ - [-db-config db-config] [-disable endpoint[,endpoint]] + [-mutual-tls-san regex] [-tls-remote-ca ca] [-mutual-tls-client-cert cert] \ + [-mutual-tls-client-key key] [-db-config db-config] [-disable endpoint[,endpoint]] Flags: ` @@ -60,7 +60,7 @@ Flags: // Flags used by 'cfssl serve' var serverFlags = []string{"address", "port", "min-tls-version", "ca", "ca-key", "ca-bundle", "int-bundle", "int-dir", "metadata", "remote", "config", "responder", "responder-key", "tls-key", "tls-cert", "mutual-tls-ca", - "mutual-tls-cn", "tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config", "disable"} + "mutual-tls-cn", "mutual-tls-san", "tls-remote-ca", "mutual-tls-client-cert", "mutual-tls-client-key", "db-config", "disable"} var ( conf cli.Config @@ -354,6 +354,31 @@ func serverMain(args []string, c cli.Config) error { http.Error(w, "Invalid CN", http.StatusForbidden) }) } + + if conf.MutualTLSSANRegex != "" { + log.Debugf(`Requiring any SAN matches regex "%s" for client connections`, conf.MutualTLSSANRegex) + re, err := regexp.Compile(conf.MutualTLSSANRegex) + if err != nil { + return fmt.Errorf("malformed SAN regex: %s", err) + } + server.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r != nil && r.TLS != nil && len(r.TLS.PeerCertificates) > 0 { + for _, name := range r.TLS.PeerCertificates[0].DNSNames { + if re.MatchString(name) { + http.DefaultServeMux.ServeHTTP(w, r) + return + } + } + log.Warningf(`Rejected client cert CN "%s", SANs [%s] does not match regex %s`, + r.TLS.PeerCertificates[0].Subject.CommonName, + strings.Join(r.TLS.PeerCertificates[0].DNSNames, ", "), + conf.MutualTLSCNRegex, + ) + } + http.Error(w, "No Valid SAN", http.StatusForbidden) + }) + } + log.Info("Now listening with mutual TLS on https://", addr) return server.ListenAndServeTLS(conf.TLSCertFile, conf.TLSKeyFile) }