Add auth over ALPN (#5)
This commit is contained in:
1 parent
5acda6a0b1
commit
cad3c24f54
11 files changed
+278
-234
No files matched your search
@@ -93,15 +93,26 @@ func (c *Controller) startListeners() error {
|
||||
}
|
||||
|
||||
configureForCluster := func(ln *base.ServerListener) error {
|
||||
l, err := ln.Mux.RegisterProto("watchtower-worker-v1", &tls.Config{
|
||||
l, err := ln.Mux.RegisterProto(alpnmux.DefaultProto, &tls.Config{
|
||||
GetConfigForClient: c.validateWorkerTLS,
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting sub-listener for worker proto: %w", err)
|
||||
}
|
||||
ln.ALPNListener = l
|
||||
|
||||
// TODO: Pass this to a handler, e.g. a grpc server
|
||||
_ = l
|
||||
// TODO: Pass this to a handler, e.g. a grpc server, in the mean time
|
||||
// just accepting what comes
|
||||
go func() {
|
||||
for {
|
||||
conn, err := ln.ALPNListener.Accept()
|
||||
if err != nil {
|
||||
c.conf.Logger.Info("default alpn listener errored, exiting")
|
||||
return
|
||||
}
|
||||
conn.Close()
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,77 @@
|
||||
package controller
|
||||
|
||||
import "crypto/tls"
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
wrapping "github.com/hashicorp/go-kms-wrapping"
|
||||
"github.com/hashicorp/watchtower/internal/cmd/base"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func (c Controller) validateWorkerTLS(hello *tls.ClientHelloInfo) (*tls.Config, error) {
|
||||
for _, p := range hello.SupportedProtos {
|
||||
switch {
|
||||
case strings.HasPrefix(p, "v1workerauth-"):
|
||||
return c.v1WorkerAuthConfig(hello.SupportedProtos)
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (c Controller) v1WorkerAuthConfig(protos []string) (*tls.Config, error) {
|
||||
var firstMatchProto string
|
||||
var encString string
|
||||
for _, p := range protos {
|
||||
if strings.HasPrefix(p, "v1workerauth-") {
|
||||
// Strip that and the number
|
||||
encString += strings.TrimPrefix(p, "v1workerauth-")[3:]
|
||||
if firstMatchProto == "" {
|
||||
firstMatchProto = p
|
||||
}
|
||||
}
|
||||
}
|
||||
if firstMatchProto == "" {
|
||||
return nil, errors.New("no matching proto found")
|
||||
}
|
||||
marshaledEncInfo, err := base64.RawStdEncoding.DecodeString(encString)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
encInfo := new(wrapping.EncryptedBlobInfo)
|
||||
if err := proto.Unmarshal(marshaledEncInfo, encInfo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
marshaledInfo, err := c.conf.WorkerAuthKMS.Decrypt(context.Background(), encInfo, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
info := new(base.WorkerAuthCertInfo)
|
||||
if err := json.Unmarshal(marshaledInfo, info); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rootCAs := x509.NewCertPool()
|
||||
if ok := rootCAs.AppendCertsFromPEM(info.CACertPEM); !ok {
|
||||
return nil, errors.New("unable to add ca cert to cert pool")
|
||||
}
|
||||
tlsCert, err := tls.X509KeyPair(info.CertPEM, info.KeyPEM)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
Certificates: []tls.Certificate{tlsCert},
|
||||
ClientCAs: rootCAs,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
NextProtos: []string{firstMatchProto},
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
Reference in new issue
Block a user