2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2019-06-20 19:14:58 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2019-06-24 22:49:28 +00:00
|
|
|
"crypto/tls"
|
2019-10-11 18:56:59 +00:00
|
|
|
"errors"
|
2020-10-23 20:13:09 +00:00
|
|
|
"fmt"
|
2019-06-20 19:14:58 +00:00
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
|
2021-07-16 00:17:31 +00:00
|
|
|
"github.com/hashicorp/go-secure-stdlib/tlsutil"
|
2020-01-28 05:11:00 +00:00
|
|
|
"github.com/hashicorp/vault/physical/raft"
|
2019-06-20 19:14:58 +00:00
|
|
|
"github.com/hashicorp/vault/vault"
|
|
|
|
)
|
|
|
|
|
2020-06-23 19:04:13 +00:00
|
|
|
func handleSysRaftBootstrap(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
switch r.Method {
|
|
|
|
case "POST", "PUT":
|
|
|
|
if core.Sealed() {
|
|
|
|
respondError(w, http.StatusBadRequest, errors.New("node must be unsealed to bootstrap"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := core.RaftBootstrap(context.Background(), false); err != nil {
|
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
respondError(w, http.StatusBadRequest, nil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-06-20 19:14:58 +00:00
|
|
|
func handleSysRaftJoin(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
switch r.Method {
|
|
|
|
case "POST", "PUT":
|
|
|
|
handleSysRaftJoinPost(core, w, r)
|
|
|
|
default:
|
|
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleSysRaftJoinPost(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
|
|
|
// Parse the request
|
|
|
|
var req JoinRequest
|
2020-02-12 22:20:22 +00:00
|
|
|
if _, err := parseJSONRequest(core.PerfStandby(), r, w, &req); err != nil && err != io.EOF {
|
2019-06-20 19:14:58 +00:00
|
|
|
respondError(w, http.StatusBadRequest, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-02-10 21:41:58 +00:00
|
|
|
if req.NonVoter && !nonVotersAllowed {
|
|
|
|
respondError(w, http.StatusBadRequest, errors.New("non-voting nodes not allowed"))
|
2020-04-21 22:30:36 +00:00
|
|
|
return
|
2019-10-11 18:56:59 +00:00
|
|
|
}
|
|
|
|
|
2019-06-24 22:49:28 +00:00
|
|
|
var tlsConfig *tls.Config
|
|
|
|
var err error
|
|
|
|
if len(req.LeaderCACert) != 0 || len(req.LeaderClientCert) != 0 || len(req.LeaderClientKey) != 0 {
|
|
|
|
tlsConfig, err = tlsutil.ClientTLSConfig([]byte(req.LeaderCACert), []byte(req.LeaderClientCert), []byte(req.LeaderClientKey))
|
|
|
|
if err != nil {
|
|
|
|
respondError(w, http.StatusBadRequest, err)
|
|
|
|
return
|
|
|
|
}
|
2021-01-19 22:54:28 +00:00
|
|
|
tlsConfig.ServerName = req.LeaderTLSServerName
|
2019-06-21 21:41:07 +00:00
|
|
|
}
|
|
|
|
|
2020-10-23 20:13:09 +00:00
|
|
|
if req.AutoJoinScheme != "" && (req.AutoJoinScheme != "http" && req.AutoJoinScheme != "https") {
|
2022-08-03 18:32:45 +00:00
|
|
|
respondError(w, http.StatusBadRequest, fmt.Errorf("invalid scheme %q; must either be http or https", req.AutoJoinScheme))
|
2020-10-23 20:13:09 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-01-14 01:02:16 +00:00
|
|
|
leaderInfos := []*raft.LeaderJoinInfo{
|
|
|
|
{
|
2020-10-23 20:13:09 +00:00
|
|
|
AutoJoin: req.AutoJoin,
|
|
|
|
AutoJoinScheme: req.AutoJoinScheme,
|
|
|
|
AutoJoinPort: req.AutoJoinPort,
|
|
|
|
LeaderAPIAddr: req.LeaderAPIAddr,
|
|
|
|
TLSConfig: tlsConfig,
|
|
|
|
Retry: req.Retry,
|
2020-01-14 01:02:16 +00:00
|
|
|
},
|
|
|
|
}
|
2020-06-23 19:04:13 +00:00
|
|
|
|
2021-02-10 21:41:58 +00:00
|
|
|
joined, err := core.JoinRaftCluster(context.Background(), leaderInfos, req.NonVoter)
|
2019-06-20 19:14:58 +00:00
|
|
|
if err != nil {
|
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
resp := JoinResponse{
|
|
|
|
Joined: joined,
|
|
|
|
}
|
|
|
|
respondOk(w, resp)
|
|
|
|
}
|
|
|
|
|
|
|
|
type JoinResponse struct {
|
|
|
|
Joined bool `json:"joined"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type JoinRequest struct {
|
2021-01-19 22:54:28 +00:00
|
|
|
AutoJoin string `json:"auto_join"`
|
|
|
|
AutoJoinScheme string `json:"auto_join_scheme"`
|
|
|
|
AutoJoinPort uint `json:"auto_join_port"`
|
|
|
|
LeaderAPIAddr string `json:"leader_api_addr"`
|
|
|
|
LeaderCACert string `json:"leader_ca_cert"`
|
|
|
|
LeaderClientCert string `json:"leader_client_cert"`
|
|
|
|
LeaderClientKey string `json:"leader_client_key"`
|
|
|
|
LeaderTLSServerName string `json:"leader_tls_servername"`
|
|
|
|
Retry bool `json:"retry"`
|
2021-02-10 21:41:58 +00:00
|
|
|
NonVoter bool `json:"non_voter"`
|
2019-06-20 19:14:58 +00:00
|
|
|
}
|