raft: use file paths for TLS info in the retry_join block (#8894)
* raft: use file paths for TLS info in the retry_join stanza * raft: maintain backward compat for existing tls params * docs: update raft docs with new file-based TLS params * Update godoc comment, fix docs
This commit is contained in:
parent
69fa1965de
commit
e7af25b969
|
@ -118,14 +118,28 @@ type LeaderJoinInfo struct {
|
|||
// LeaderCACert is the CA cert of the leader node
|
||||
LeaderCACert string `json:"leader_ca_cert"`
|
||||
|
||||
// LeaderClientCert is the client certificate for the follower node to establish
|
||||
// client authentication during TLS
|
||||
// LeaderClientCert is the client certificate for the follower node to
|
||||
// establish client authentication during TLS
|
||||
LeaderClientCert string `json:"leader_client_cert"`
|
||||
|
||||
// LeaderClientKey is the client key for the follower node to establish client
|
||||
// authentication during TLS
|
||||
// LeaderClientKey is the client key for the follower node to establish
|
||||
// client authentication during TLS.
|
||||
LeaderClientKey string `json:"leader_client_key"`
|
||||
|
||||
// LeaderCACertFile is the path on disk to the the CA cert file of the
|
||||
// leader node. This should only be provided via Vault's configuration file.
|
||||
LeaderCACertFile string `json:"leader_ca_cert_file"`
|
||||
|
||||
// LeaderClientCertFile is the path on disk to the client certificate file
|
||||
// for the follower node to establish client authentication during TLS. This
|
||||
// should only be provided via Vault's configuration file.
|
||||
LeaderClientCertFile string `json:"leader_client_cert_file"`
|
||||
|
||||
// LeaderClientKeyFile is the path on disk to the client key file for the
|
||||
// follower node to establish client authentication during TLS. This should
|
||||
// only be provided via Vault's configuration file.
|
||||
LeaderClientKeyFile string `json:"leader_client_key_file"`
|
||||
|
||||
// Retry indicates if the join process should automatically be retried
|
||||
Retry bool `json:"-"`
|
||||
|
||||
|
@ -153,20 +167,35 @@ func (b *RaftBackend) JoinConfig() ([]*LeaderJoinInfo, error) {
|
|||
|
||||
for _, info := range leaderInfos {
|
||||
info.Retry = true
|
||||
var tlsConfig *tls.Config
|
||||
var err error
|
||||
if len(info.LeaderCACert) != 0 || len(info.LeaderClientCert) != 0 || len(info.LeaderClientKey) != 0 {
|
||||
tlsConfig, err = tlsutil.ClientTLSConfig([]byte(info.LeaderCACert), []byte(info.LeaderClientCert), []byte(info.LeaderClientKey))
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(fmt.Sprintf("failed to create tls config to communicate with leader node %q: {{err}}", info.LeaderAPIAddr), err)
|
||||
}
|
||||
info.TLSConfig, err = parseTLSInfo(info)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf(fmt.Sprintf("failed to create tls config to communicate with leader node %q: {{err}}", info.LeaderAPIAddr), err)
|
||||
}
|
||||
info.TLSConfig = tlsConfig
|
||||
}
|
||||
|
||||
return leaderInfos, nil
|
||||
}
|
||||
|
||||
// parseTLSInfo is a helper for parses the TLS information, preferring file
|
||||
// paths over raw certificate content.
|
||||
func parseTLSInfo(leaderInfo *LeaderJoinInfo) (*tls.Config, error) {
|
||||
var tlsConfig *tls.Config
|
||||
var err error
|
||||
if len(leaderInfo.LeaderCACertFile) != 0 || len(leaderInfo.LeaderClientCertFile) != 0 || len(leaderInfo.LeaderClientKeyFile) != 0 {
|
||||
tlsConfig, err = tlsutil.LoadClientTLSConfig(leaderInfo.LeaderCACertFile, leaderInfo.LeaderClientCertFile, leaderInfo.LeaderClientKeyFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if len(leaderInfo.LeaderCACert) != 0 || len(leaderInfo.LeaderClientCert) != 0 || len(leaderInfo.LeaderClientKey) != 0 {
|
||||
tlsConfig, err = tlsutil.ClientTLSConfig([]byte(leaderInfo.LeaderCACert), []byte(leaderInfo.LeaderClientCert), []byte(leaderInfo.LeaderClientKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// EnsurePath is used to make sure a path exists
|
||||
func EnsurePath(path string, dir bool) error {
|
||||
if !dir {
|
||||
|
|
|
@ -79,6 +79,8 @@ func GetCipherName(cipher uint16) (string, error) {
|
|||
return "", fmt.Errorf("unsupported cipher %d", cipher)
|
||||
}
|
||||
|
||||
// ClientTLSConfig parses the CA certificate, and optionally a public/private
|
||||
// client certificate key pair. The certificates must be in PEM encoded format.
|
||||
func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.Config, error) {
|
||||
var tlsConfig *tls.Config
|
||||
var pool *x509.CertPool
|
||||
|
@ -117,6 +119,55 @@ func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.C
|
|||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// LoadClientTLSConfig loads and parse the CA certificate, and optionally a
|
||||
// public/private client certificate key pair. The certificates must be in PEM
|
||||
// encoded format.
|
||||
func LoadClientTLSConfig(caCert, clientCert, clientKey string) (*tls.Config, error) {
|
||||
var tlsConfig *tls.Config
|
||||
var pool *x509.CertPool
|
||||
|
||||
switch {
|
||||
case len(caCert) != 0:
|
||||
// Valid
|
||||
case len(clientCert) != 0 && len(clientKey) != 0:
|
||||
// Valid
|
||||
default:
|
||||
return nil, ErrInvalidCertParams
|
||||
}
|
||||
|
||||
if len(caCert) != 0 {
|
||||
pool = x509.NewCertPool()
|
||||
|
||||
data, err := ioutil.ReadFile(caCert)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err)
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(data) {
|
||||
return nil, fmt.Errorf("failed to parse CA certificate")
|
||||
}
|
||||
}
|
||||
|
||||
tlsConfig = &tls.Config{
|
||||
RootCAs: pool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
|
||||
var cert tls.Certificate
|
||||
var err error
|
||||
if len(clientCert) != 0 && len(clientKey) != 0 {
|
||||
cert, err = tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func SetupTLSConfig(conf map[string]string, address string) (*tls.Config, error) {
|
||||
serverName, _, err := net.SplitHostPort(address)
|
||||
switch {
|
||||
|
|
|
@ -79,6 +79,8 @@ func GetCipherName(cipher uint16) (string, error) {
|
|||
return "", fmt.Errorf("unsupported cipher %d", cipher)
|
||||
}
|
||||
|
||||
// ClientTLSConfig parses the CA certificate, and optionally a public/private
|
||||
// client certificate key pair. The certificates must be in PEM encoded format.
|
||||
func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.Config, error) {
|
||||
var tlsConfig *tls.Config
|
||||
var pool *x509.CertPool
|
||||
|
@ -117,6 +119,55 @@ func ClientTLSConfig(caCert []byte, clientCert []byte, clientKey []byte) (*tls.C
|
|||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
// LoadClientTLSConfig loads and parse the CA certificate, and optionally a
|
||||
// public/private client certificate key pair. The certificates must be in PEM
|
||||
// encoded format.
|
||||
func LoadClientTLSConfig(caCert, clientCert, clientKey string) (*tls.Config, error) {
|
||||
var tlsConfig *tls.Config
|
||||
var pool *x509.CertPool
|
||||
|
||||
switch {
|
||||
case len(caCert) != 0:
|
||||
// Valid
|
||||
case len(clientCert) != 0 && len(clientKey) != 0:
|
||||
// Valid
|
||||
default:
|
||||
return nil, ErrInvalidCertParams
|
||||
}
|
||||
|
||||
if len(caCert) != 0 {
|
||||
pool = x509.NewCertPool()
|
||||
|
||||
data, err := ioutil.ReadFile(caCert)
|
||||
if err != nil {
|
||||
return nil, errwrap.Wrapf("failed to read CA file: {{err}}", err)
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(data) {
|
||||
return nil, fmt.Errorf("failed to parse CA certificate")
|
||||
}
|
||||
}
|
||||
|
||||
tlsConfig = &tls.Config{
|
||||
RootCAs: pool,
|
||||
ClientAuth: tls.RequireAndVerifyClientCert,
|
||||
MinVersion: tls.VersionTLS12,
|
||||
}
|
||||
|
||||
var cert tls.Certificate
|
||||
var err error
|
||||
if len(clientCert) != 0 && len(clientKey) != 0 {
|
||||
cert, err = tls.LoadX509KeyPair(clientCert, clientKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
func SetupTLSConfig(conf map[string]string, address string) (*tls.Config, error) {
|
||||
serverName, _, err := net.SplitHostPort(address)
|
||||
switch {
|
||||
|
|
|
@ -96,13 +96,29 @@ time. To use Raft for HA coordination users must also use Raft for storage.
|
|||
|
||||
### `retry_join` stanza
|
||||
|
||||
- `leader_api_addr` `(string: "")` - Address of a possible leader node
|
||||
- `leader_api_addr` `(string: "")` - Address of a possible leader node.
|
||||
|
||||
- `leader_ca_cert` `(string: "")` - CA cert of the possible leader node
|
||||
- `leader_ca_cert_file` `(string: "")` - File path to the CA cert of the
|
||||
possible leader node.
|
||||
|
||||
- `leader_client_cert` `(string: "")` - Client certificate for the follower node to establish client authentication with the possible leader node
|
||||
- `leader_client_cert_file` `(string: "")` - File path to the client certificate
|
||||
for the follower node to establish client authentication with the possible
|
||||
leader node.
|
||||
|
||||
- `leader_client_key` `(string: "")` - Client key for the follower node to establish client authentication with the possible leader node
|
||||
- `leader_client_key_file` `(string: "")` - File path to the client key for the
|
||||
follower node to establish client authentication with the possible leader node.
|
||||
|
||||
- `leader_ca_cert` `(string: "")` - CA cert of the possible leader node.
|
||||
|
||||
- `leader_client_cert` `(string: "")` - Client certificate for the follower node
|
||||
to establish client authentication with the possible leader node.
|
||||
|
||||
- `leader_client_key` `(string: "")` - Client key for the follower node to
|
||||
establish client authentication with the possible leader node.
|
||||
|
||||
Each `retry_join` block may provide TLS certificates via file paths or as a
|
||||
single-line certificate string value with newlines delimited by `\n`, but not a
|
||||
combination of both.
|
||||
|
||||
Example Configuration:
|
||||
```
|
||||
|
@ -111,21 +127,21 @@ storage "raft" {
|
|||
node_id = "node1"
|
||||
retry_join {
|
||||
leader_api_addr = "http://127.0.0.2:8200"
|
||||
leader_ca_cert = "/path/to/ca1"
|
||||
leader_client_cert = "/path/to/client/cert1"
|
||||
leader_client_key = "/path/to/client/key1"
|
||||
leader_ca_cer_file = "/path/to/ca1"
|
||||
leader_client_cert_file = "/path/to/client/cert1"
|
||||
leader_client_key_file = "/path/to/client/key1"
|
||||
}
|
||||
retry_join {
|
||||
leader_api_addr = "http://127.0.0.3:8200"
|
||||
leader_ca_cert = "/path/to/ca2"
|
||||
leader_client_cert = "/path/to/client/cert2"
|
||||
leader_client_key = "/path/to/client/key2"
|
||||
leader_ca_cert_file = "/path/to/ca2"
|
||||
leader_client_cert_file = "/path/to/client/cert2"
|
||||
leader_client_key_file = "/path/to/client/key2"
|
||||
}
|
||||
retry_join {
|
||||
leader_api_addr = "http://127.0.0.4:8200"
|
||||
leader_ca_cert = "/path/to/ca3"
|
||||
leader_client_cert = "/path/to/client/cert3"
|
||||
leader_client_key = "/path/to/client/key3"
|
||||
leader_ca_cert_file = "/path/to/ca3"
|
||||
leader_client_cert_file = "/path/to/client/cert3"
|
||||
leader_client_key_file = "/path/to/client/key3"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue