Skip to content

Commit

Permalink
Fixes #45: Added Support fot Mutual TLS Authentication
Browse files Browse the repository at this point in the history
  • Loading branch information
Héctor Hurtado committed Jan 23, 2020
1 parent 493e6be commit cddc5ff
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 5 deletions.
20 changes: 18 additions & 2 deletions internal/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ import (
var ServerCmd = &cobra.Command{
Use: "server [optional flags] [optional pow file(s)]",
Short: "Start a kapow server",
Long: `Start a Kapow server with, by default with client interface, data interface
and admin interface`,
Long: `Start a Kapow server with a client interface, a data interface and an
admin interface`,
PreRunE: validateServerCommandArguments,
Run: func(cmd *cobra.Command, args []string) {
var sConf server.ServerConfig = server.ServerConfig{}
Expand All @@ -44,6 +44,9 @@ var ServerCmd = &cobra.Command{
sConf.CertFile, _ = cmd.Flags().GetString("certfile")
sConf.KeyFile, _ = cmd.Flags().GetString("keyfile")

sConf.ClientAuth, _ = cmd.Flags().GetBool("clientauth")
sConf.ClientCaFile, _ = cmd.Flags().GetString("clientcafile")

go server.StartServer(sConf)

// start sub shell + ENV(KAPOW_CONTROL_URL)
Expand Down Expand Up @@ -78,13 +81,26 @@ func init() {

ServerCmd.Flags().String("certfile", "", "Cert 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 {
cert, _ := cmd.Flags().GetString("certfile")
key, _ := cmd.Flags().GetString("keyfile")
cliAuth, _ := cmd.Flags().GetBool("clientauth")

if (cert == "") != (key == "") {
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
}
7 changes: 5 additions & 2 deletions internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,17 @@ type ServerConfig struct {
DataBindAddr,
UserBindAddr,
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
func StartServer(config ServerConfig) {
go control.Run(config.ControlBindAddr)
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
select {}
Expand Down
36 changes: 35 additions & 1 deletion internal/server/user/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
package user

import (
"crypto/tls"
"crypto/x509"
"io/ioutil"
"log"
"net/http"

Expand All @@ -29,13 +32,32 @@ var Server = http.Server{
}

// 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{
Addr: bindAddr,
Handler: mux.New(),
}

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 {
log.Fatalf("UserServer failed: %s", err)
}
Expand All @@ -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
}

0 comments on commit cddc5ff

Please sign in to comment.