Fixes #45: Added Support fot Mutual TLS Authentication

This commit is contained in:
Héctor Hurtado
2020-01-23 17:39:58 +01:00
parent 493e6be78c
commit cddc5ff351
3 changed files with 58 additions and 5 deletions
+18 -2
View File
@@ -32,8 +32,8 @@ import (
var ServerCmd = &cobra.Command{ var ServerCmd = &cobra.Command{
Use: "server [optional flags] [optional pow file(s)]", Use: "server [optional flags] [optional pow file(s)]",
Short: "Start a kapow server", Short: "Start a kapow server",
Long: `Start a Kapow server with, by default with client interface, data interface Long: `Start a Kapow server with a client interface, a data interface and an
and admin interface`, admin interface`,
PreRunE: validateServerCommandArguments, PreRunE: validateServerCommandArguments,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
var sConf server.ServerConfig = server.ServerConfig{} var sConf server.ServerConfig = server.ServerConfig{}
@@ -44,6 +44,9 @@ var ServerCmd = &cobra.Command{
sConf.CertFile, _ = cmd.Flags().GetString("certfile") sConf.CertFile, _ = cmd.Flags().GetString("certfile")
sConf.KeyFile, _ = cmd.Flags().GetString("keyfile") sConf.KeyFile, _ = cmd.Flags().GetString("keyfile")
sConf.ClientAuth, _ = cmd.Flags().GetBool("clientauth")
sConf.ClientCaFile, _ = cmd.Flags().GetString("clientcafile")
go server.StartServer(sConf) go server.StartServer(sConf)
// start sub shell + ENV(KAPOW_CONTROL_URL) // start sub shell + ENV(KAPOW_CONTROL_URL)
@@ -78,13 +81,26 @@ func init() {
ServerCmd.Flags().String("certfile", "", "Cert file to serve thru https") ServerCmd.Flags().String("certfile", "", "Cert file to serve thru https")
ServerCmd.Flags().String("keyfile", "", "Key file to serve thru https") ServerCmd.Flags().String("keyfile", "", "Key file to serve thru https")
ServerCmd.Flags().Bool("clientauth", false, "Activate client mutual tls authentication")
ServerCmd.Flags().String("clientcafile", "", "Cert file to validate client certificates")
} }
func validateServerCommandArguments(cmd *cobra.Command, args []string) error { func validateServerCommandArguments(cmd *cobra.Command, args []string) error {
cert, _ := cmd.Flags().GetString("certfile") cert, _ := cmd.Flags().GetString("certfile")
key, _ := cmd.Flags().GetString("keyfile") key, _ := cmd.Flags().GetString("keyfile")
cliAuth, _ := cmd.Flags().GetBool("clientauth")
if (cert == "") != (key == "") { if (cert == "") != (key == "") {
return errors.New("expected both or neither (certfile and keyfile)") return errors.New("expected both or neither (certfile and keyfile)")
} }
if cert == "" {
// If we don't serve thru https client authentication can't be enabled
if cliAuth {
return errors.New("Client authentication can't be active in a non https server")
}
}
return nil return nil
} }
+5 -2
View File
@@ -27,14 +27,17 @@ type ServerConfig struct {
DataBindAddr, DataBindAddr,
UserBindAddr, UserBindAddr,
KeyFile, KeyFile,
CertFile string CertFile,
ClientCaFile string
ClientAuth bool
} }
// StartServer Starts one instance of each server in a goroutine and remains listening on a channel for trace events generated by them // StartServer Starts one instance of each server in a goroutine and remains listening on a channel for trace events generated by them
func StartServer(config ServerConfig) { func StartServer(config ServerConfig) {
go control.Run(config.ControlBindAddr) go control.Run(config.ControlBindAddr)
go data.Run(config.DataBindAddr) go data.Run(config.DataBindAddr)
go user.Run(config.UserBindAddr, config.CertFile, config.KeyFile) go user.Run(config.UserBindAddr, config.CertFile, config.KeyFile, config.ClientCaFile, config.ClientAuth)
// Wait for ever // Wait for ever
select {} select {}
+35 -1
View File
@@ -17,6 +17,9 @@
package user package user
import ( import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log" "log"
"net/http" "net/http"
@@ -29,13 +32,32 @@ var Server = http.Server{
} }
// Run finishes configuring Server and runs ListenAndServe on it // Run finishes configuring Server and runs ListenAndServe on it
func Run(bindAddr, certFile, keyFile string) { func Run(bindAddr, certFile, keyFile, cliCaFile string, cliAuth bool) {
Server = http.Server{ Server = http.Server{
Addr: bindAddr, Addr: bindAddr,
Handler: mux.New(), Handler: mux.New(),
} }
if (certFile != "") && (keyFile != "") { if (certFile != "") && (keyFile != "") {
if cliAuth {
if Server.TLSConfig == nil {
Server.TLSConfig = &tls.Config{}
}
var err error
Server.TLSConfig.ClientCAs, err = loadCertificatesFromFile(cliCaFile)
if err != nil {
log.Printf("UserServer failed to load CA certs: %s\nDefault to system CA store.", err)
} else {
CAStore := "System store"
if Server.TLSConfig.ClientCAs != nil {
CAStore = cliCaFile
}
log.Printf("UserServer using CA certs from %s\n", CAStore)
Server.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
}
}
if err := Server.ListenAndServeTLS(certFile, keyFile); err != http.ErrServerClosed { if err := Server.ListenAndServeTLS(certFile, keyFile); err != http.ErrServerClosed {
log.Fatalf("UserServer failed: %s", err) log.Fatalf("UserServer failed: %s", err)
} }
@@ -45,3 +67,15 @@ func Run(bindAddr, certFile, keyFile string) {
} }
} }
} }
func loadCertificatesFromFile(certFile string) (pool *x509.CertPool, err error) {
if certFile != "" {
caCerts, err := ioutil.ReadFile(certFile)
if err == nil {
pool = x509.NewCertPool()
pool.AppendCertsFromPEM(caCerts)
}
}
return
}