feat(KV): support TLS.

This commit is contained in:
Fernandez Ludovic 2019-04-22 14:14:23 +02:00
parent 5639decf82
commit 92ce6d8d03
6 changed files with 155 additions and 4 deletions

129
cmd/kv.go
View File

@ -1,6 +1,11 @@
package cmd
import (
"crypto/tls"
"crypto/x509"
"fmt"
"io/ioutil"
"os"
"time"
"github.com/abronan/valkeyrie/store"
@ -24,10 +29,12 @@ func init() {
kvCmd.PersistentFlags().String("password", "", "Password for connection.")
kvCmd.PersistentFlags().String("username", "", "Username for connection.")
// FIXME review TLS parts
// kvCmd.PersistentFlags().Bool("tls.enable", false, "Enable TLS encryption.")
// kvCmd.PersistentFlags().Bool("tls.insecureskipverify", false, "Trust unverified certificates if TLS is enabled.")
// kvCmd.PersistentFlags().String("tls.ca-cert-file", "", "Root CA file for certificate verification if TLS is enabled.")
kvCmd.PersistentFlags().Bool("tls", false, "Enable TLS encryption.")
kvCmd.PersistentFlags().String("tls.ca", "", "Root CA for certificate verification if TLS is enabled")
kvCmd.PersistentFlags().Bool("tls.ca.optional", false, "")
kvCmd.PersistentFlags().String("tls.cert", "", "TLS cert")
kvCmd.PersistentFlags().String("tls.key", "", "TLS key")
kvCmd.PersistentFlags().Bool("tls.insecureskipverify", false, "Trust unverified certificates if TLS is enabled.")
}
func getKvConfig(cmd *cobra.Command) (*kv.Config, error) {
@ -41,6 +48,11 @@ func getKvConfig(cmd *cobra.Command) (*kv.Config, error) {
return nil, err
}
tlsConfig, err := createTLSConfig(cmd)
if err != nil {
return nil, err
}
return &kv.Config{
Endpoints: endpoints,
Prefix: cmd.Flag("prefix").Value.String(),
@ -48,6 +60,115 @@ func getKvConfig(cmd *cobra.Command) (*kv.Config, error) {
ConnectionTimeout: time.Duration(connectionTimeout) * time.Second,
Username: cmd.Flag("password").Value.String(),
Password: cmd.Flag("username").Value.String(),
TLS: tlsConfig,
},
}, nil
}
func createTLSConfig(cmd *cobra.Command) (*tls.Config, error) {
enable, _ := cmd.Flags().GetBool("tls")
if !enable {
return nil, nil
}
ca := cmd.Flag("tls.ca").Value.String()
caPool, err := getCertPool(ca)
if err != nil {
return nil, err
}
caOptional, _ := cmd.Flags().GetBool("tls.ca.optional")
clientAuth := getClientAuth(ca, caOptional)
insecureSkipVerify, _ := cmd.Flags().GetBool("tls.insecureskipverify")
privateKey := cmd.Flag("tls.key").Value.String()
certContent := cmd.Flag("tls.cert").Value.String()
if !insecureSkipVerify && (len(certContent) == 0 || len(privateKey) == 0) {
return nil, fmt.Errorf("TLS Certificate or Key file must be set when TLS configuration is created")
}
cert, err := getCertificate(privateKey, certContent)
if err != nil {
return nil, fmt.Errorf("failed to load TLS keypair: %s", err)
}
return &tls.Config{
Certificates: []tls.Certificate{cert},
RootCAs: caPool,
InsecureSkipVerify: insecureSkipVerify,
ClientAuth: clientAuth,
}, nil
}
func getCertPool(ca string) (*x509.CertPool, error) {
caPool := x509.NewCertPool()
if ca != "" {
caContent, err := getCAContent(ca)
if err != nil {
return nil, fmt.Errorf("failed to read CA. %s", err)
}
if !caPool.AppendCertsFromPEM(caContent) {
return nil, fmt.Errorf("failed to parse CA")
}
}
return caPool, nil
}
func getCAContent(ca string) ([]byte, error) {
if _, errCA := os.Stat(ca); errCA != nil {
return []byte(ca), nil
}
caContent, err := ioutil.ReadFile(ca)
if err != nil {
return nil, err
}
return caContent, nil
}
func getClientAuth(ca string, caOptional bool) tls.ClientAuthType {
if ca == "" {
return tls.NoClientCert
}
if caOptional {
return tls.VerifyClientCertIfGiven
}
return tls.RequireAndVerifyClientCert
}
func getCertificate(privateKey, certContent string) (tls.Certificate, error) {
if certContent == "" || privateKey == "" {
return tls.Certificate{}, nil
}
_, errKeyIsFile := os.Stat(privateKey)
_, errCertIsFile := os.Stat(certContent)
if errCertIsFile == nil && os.IsNotExist(errKeyIsFile) {
return tls.Certificate{}, fmt.Errorf("tls cert is a file, but tls key is not")
}
if os.IsNotExist(errCertIsFile) && errKeyIsFile == nil {
return tls.Certificate{}, fmt.Errorf("TLS key is a file, but tls cert is not")
}
// string
if os.IsNotExist(errCertIsFile) && os.IsNotExist(errKeyIsFile) {
return tls.X509KeyPair([]byte(certContent), []byte(privateKey))
}
// files
if errCertIsFile == nil && errKeyIsFile == nil {
return tls.LoadX509KeyPair(certContent, privateKey)
}
if errCertIsFile != nil {
return tls.Certificate{}, errCertIsFile
}
return tls.Certificate{}, errKeyIsFile
}

View File

@ -14,6 +14,12 @@ Dump the content of a KV store.
-h, --help help for kv
--password string Password for connection.
--prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled
--tls.ca.optional
--tls.cert string TLS cert
--tls.insecureskipverify Trust unverified certificates if TLS is enabled.
--tls.key string TLS key
--username string Username for connection.
```

View File

@ -33,6 +33,12 @@ traefik-certs-dumper kv boltdb [flags]
--key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection.
--prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled
--tls.ca.optional
--tls.cert string TLS cert
--tls.insecureskipverify Trust unverified certificates if TLS is enabled.
--tls.key string TLS key
--username string Username for connection.
--watch Enable watching changes.
```

View File

@ -32,6 +32,12 @@ traefik-certs-dumper kv consul [flags]
--key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection.
--prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled
--tls.ca.optional
--tls.cert string TLS cert
--tls.insecureskipverify Trust unverified certificates if TLS is enabled.
--tls.key string TLS key
--username string Username for connection.
--watch Enable watching changes.
```

View File

@ -32,6 +32,12 @@ traefik-certs-dumper kv etcd [flags]
--key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection.
--prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled
--tls.ca.optional
--tls.cert string TLS cert
--tls.insecureskipverify Trust unverified certificates if TLS is enabled.
--tls.key string TLS key
--username string Username for connection.
--watch Enable watching changes.
```

View File

@ -31,6 +31,12 @@ traefik-certs-dumper kv zookeeper [flags]
--key-name string The file name (without extension) of the generated private keys. (default "privatekey")
--password string Password for connection.
--prefix string Prefix used for KV store. (default "traefik")
--tls Enable TLS encryption.
--tls.ca string Root CA for certificate verification if TLS is enabled
--tls.ca.optional
--tls.cert string TLS cert
--tls.insecureskipverify Trust unverified certificates if TLS is enabled.
--tls.key string TLS key
--username string Username for connection.
--watch Enable watching changes.
```