Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TLS for Raft Join #6932

Merged
merged 2 commits into from
Jun 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions api/sys_raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 25 additions & 7 deletions command/operator_raft_join.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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))
Expand Down
47 changes: 43 additions & 4 deletions http/sys_raft.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package http

import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"io"
"net/http"

Expand All @@ -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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I approved this but if you can move this section to sdk/helper/tlsutil we can reuse it elsewhere pretty quickly...

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this in a separate PR.

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
Expand All @@ -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"`
}