From b0cd36dbfdb18506bdc78b53fc60776a9a08c28c Mon Sep 17 00:00:00 2001 From: Vishal Nayak Date: Fri, 21 Jun 2019 15:16:18 -0400 Subject: [PATCH] raft join tls --- api/sys_raft.go | 8 +++--- command/operator_raft_join.go | 32 ++++++++++++++++++------ http/sys_raft.go | 47 ++++++++++++++++++++++++++++++++--- 3 files changed, 73 insertions(+), 14 deletions(-) diff --git a/api/sys_raft.go b/api/sys_raft.go index a9342a8f3598..6897dc0a7eb2 100644 --- a/api/sys_raft.go +++ b/api/sys_raft.go @@ -15,9 +15,11 @@ type RaftJoinResponse struct { // RaftJoinRequest represents the parameters consumed by the raft join API type RaftJoinRequest struct { - LeaderAddr string `json:"leader_api_addr"` - CACert string `json:"ca_cert":` - Retry bool `json:"retry"` + LeaderAPIAddr string `json:"leader_api_addr"` + LeaderCACert string `json:"leader_ca_cert":` + LeaderClientCert string `json:"leader_client_cert"` + LeaderClientKey string `json:"leader_client_key"` + Retry bool `json:"retry"` } // RaftJoin adds the node from which this call is invoked from to the raft diff --git a/command/operator_raft_join.go b/command/operator_raft_join.go index 30d31a45d7b1..528007c66fa4 100644 --- a/command/operator_raft_join.go +++ b/command/operator_raft_join.go @@ -13,8 +13,10 @@ var _ cli.Command = (*OperatorRaftJoinCommand)(nil) var _ cli.CommandAutocomplete = (*OperatorRaftJoinCommand)(nil) type OperatorRaftJoinCommand struct { - flagRaftRetry bool - flagRaftCACert string + flagRaftRetry bool + flagLeaderCACert string + flagLeaderClientCert string + flagLeaderClientKey string *BaseCommand } @@ -42,12 +44,26 @@ func (c *OperatorRaftJoinCommand) Flags() *FlagSets { f := set.NewFlagSet("Command Options") f.StringVar(&StringVar{ - Name: "raft-ca-cert", - Target: &c.flagRaftCACert, + Name: "leader-ca-cert", + Target: &c.flagLeaderCACert, Completion: complete.PredictNothing, Usage: "CA cert to communicate with raft leader.", }) + f.StringVar(&StringVar{ + Name: "leader-client-cert", + Target: &c.flagLeaderClientCert, + Completion: complete.PredictNothing, + Usage: "Client cert to to authenticate to raft leader.", + }) + + f.StringVar(&StringVar{ + Name: "leader-client-key", + Target: &c.flagLeaderClientKey, + Completion: complete.PredictNothing, + Usage: "Client key to to authenticate to raft leader.", + }) + f.BoolVar(&BoolVar{ Name: "retry", Target: &c.flagRaftRetry, @@ -97,9 +113,11 @@ func (c *OperatorRaftJoinCommand) Run(args []string) int { } resp, err := client.Sys().RaftJoin(&api.RaftJoinRequest{ - LeaderAddr: leaderAPIAddr, - Retry: c.flagRaftRetry, - CACert: c.flagRaftCACert, + LeaderAPIAddr: leaderAPIAddr, + LeaderCACert: c.flagLeaderCACert, + LeaderClientCert: c.flagLeaderClientCert, + LeaderClientKey: c.flagLeaderClientKey, + Retry: c.flagRaftRetry, }) if err != nil { c.UI.Error(fmt.Sprintf("Error joining the node to the raft cluster: %s", err)) diff --git a/http/sys_raft.go b/http/sys_raft.go index 2533307b26fa..f9c4d43b0ba1 100644 --- a/http/sys_raft.go +++ b/http/sys_raft.go @@ -2,6 +2,10 @@ package http import ( "context" + "crypto/tls" + "crypto/x509" + "errors" + "fmt" "io" "net/http" @@ -27,7 +31,40 @@ func handleSysRaftJoinPost(core *vault.Core, w http.ResponseWriter, r *http.Requ return } - joined, err := core.JoinRaftCluster(context.Background(), req.LeaderAddr, nil, req.Retry) + var tlsConfig *tls.Config + switch { + case req.LeaderCACert != "" && req.LeaderClientCert != "" && req.LeaderClientKey != "": + // Create TLS Config + pool := x509.NewCertPool() + pool.AppendCertsFromPEM([]byte(req.LeaderCACert)) + + cert, err := tls.X509KeyPair([]byte(req.LeaderClientCert), []byte(req.LeaderClientKey)) + if err != nil { + respondError(w, http.StatusBadRequest, fmt.Errorf("invalid key pair: %v", err)) + return + } + + tlsConfig = &tls.Config{ + Certificates: []tls.Certificate{cert}, + RootCAs: pool, + ClientAuth: tls.RequireAndVerifyClientCert, + MinVersion: tls.VersionTLS12, + } + + tlsConfig.BuildNameToCertificate() + + case req.LeaderCACert != "": + respondError(w, http.StatusBadRequest, errors.New("ca_cert, client_key, client_cert must all be set; or none should be set")) + return + case req.LeaderClientCert != "": + respondError(w, http.StatusBadRequest, errors.New("ca_cert, client_key, client_cert must all be set; or none should be set")) + return + case req.LeaderClientKey != "": + respondError(w, http.StatusBadRequest, errors.New("ca_cert, client_key, client_cert must all be set; or none should be set")) + return + } + + joined, err := core.JoinRaftCluster(context.Background(), req.LeaderAPIAddr, tlsConfig, req.Retry) if err != nil { respondError(w, http.StatusInternalServerError, err) return @@ -44,7 +81,9 @@ type JoinResponse struct { } type JoinRequest struct { - LeaderAddr string `json:"leader_api_addr"` - CACert string `json:"ca_cert":` - Retry bool `json:"retry"` + LeaderAPIAddr string `json:"leader_api_addr"` + LeaderCACert string `json:"leader_ca_cert":` + LeaderClientCert string `json:"leader_client_cert"` + LeaderClientKey string `json:"leader_client_key"` + Retry bool `json:"retry"` }