Comment and slight refactor of the TLS plugin helper
This commit is contained in:
parent
0a52ea5c69
commit
f2df4ef0e7
|
@ -1,8 +1,6 @@
|
||||||
package dbs
|
package dbs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/tls"
|
|
||||||
"crypto/x509"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/rpc"
|
"net/rpc"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
@ -56,57 +54,34 @@ func newPluginClient(sys logical.SystemView, command, checksum string) (Database
|
||||||
"database": new(DatabasePlugin),
|
"database": new(DatabasePlugin),
|
||||||
}
|
}
|
||||||
|
|
||||||
CACertBytes, CACert, CAKey, err := pluginutil.GenerateX509Cert()
|
// Get a CA TLS Certificate
|
||||||
|
CACertBytes, CACert, CAKey, err := pluginutil.GenerateCACert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCertBytes, clientCert, clientKey, err := pluginutil.GenerateClientCert(CACert, CAKey)
|
// Use CA to sign a client cert and return a configured TLS config
|
||||||
|
clientTLSConfig, err := pluginutil.CreateClientTLSConfig(CACert, CAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
/* serverCert, serverKey, err := generateClientCert(CACert, CAKey)
|
// Use CA to sign a server cert and wrap the values in a response wrapped
|
||||||
if err != nil {
|
// token.
|
||||||
return nil, err
|
wrapToken, err := pluginutil.WrapServerConfig(sys, CACertBytes, CACert, CAKey)
|
||||||
}*/
|
|
||||||
serverKey, err := x509.MarshalECPrivateKey(CAKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
cert := tls.Certificate{
|
|
||||||
Certificate: [][]byte{clientCertBytes, CACertBytes},
|
|
||||||
PrivateKey: clientKey,
|
|
||||||
Leaf: clientCert,
|
|
||||||
}
|
|
||||||
|
|
||||||
clientCertPool := x509.NewCertPool()
|
|
||||||
clientCertPool.AddCert(CACert)
|
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{cert},
|
|
||||||
RootCAs: clientCertPool,
|
|
||||||
ClientCAs: clientCertPool,
|
|
||||||
ServerName: CACert.Subject.CommonName,
|
|
||||||
MinVersion: tls.VersionTLS12,
|
|
||||||
}
|
|
||||||
|
|
||||||
tlsConfig.BuildNameToCertificate()
|
|
||||||
|
|
||||||
wrapToken, err := sys.ResponseWrapData(map[string]interface{}{
|
|
||||||
"CACert": CACertBytes,
|
|
||||||
"ServerCert": CACertBytes,
|
|
||||||
"ServerKey": serverKey,
|
|
||||||
}, time.Second*10, true)
|
|
||||||
|
|
||||||
|
// Add the response wrap token to the ENV of the plugin
|
||||||
cmd := exec.Command(command)
|
cmd := exec.Command(command)
|
||||||
cmd.Env = append(cmd.Env, fmt.Sprintf("VAULT_WRAP_TOKEN=%s", wrapToken))
|
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", pluginutil.PluginUnwrapTokenEnv, wrapToken))
|
||||||
|
|
||||||
client := plugin.NewClient(&plugin.ClientConfig{
|
client := plugin.NewClient(&plugin.ClientConfig{
|
||||||
HandshakeConfig: handshakeConfig,
|
HandshakeConfig: handshakeConfig,
|
||||||
Plugins: pluginMap,
|
Plugins: pluginMap,
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
TLSConfig: tlsConfig,
|
TLSConfig: clientTLSConfig,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Connect via RPC
|
// Connect via RPC
|
||||||
|
|
|
@ -21,9 +21,16 @@ import (
|
||||||
"github.com/hashicorp/errwrap"
|
"github.com/hashicorp/errwrap"
|
||||||
uuid "github.com/hashicorp/go-uuid"
|
uuid "github.com/hashicorp/go-uuid"
|
||||||
"github.com/hashicorp/vault/api"
|
"github.com/hashicorp/vault/api"
|
||||||
|
"github.com/hashicorp/vault/logical"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GenerateX509Cert() ([]byte, *x509.Certificate, *ecdsa.PrivateKey, error) {
|
var (
|
||||||
|
PluginUnwrapTokenEnv = "VAULT_WRAP_TOKEN"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GenerateCACert returns a CA cert used to later sign the certificates for the
|
||||||
|
// plugin client and server.
|
||||||
|
func GenerateCACert() ([]byte, *x509.Certificate, *ecdsa.PrivateKey, error) {
|
||||||
key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
|
@ -65,7 +72,9 @@ func GenerateX509Cert() ([]byte, *x509.Certificate, *ecdsa.PrivateKey, error) {
|
||||||
return certBytes, caCert, key, nil
|
return certBytes, caCert, key, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateClientCert(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) ([]byte, *x509.Certificate, []byte, error) {
|
// generateSignedCert is used internally to create certificates for the plugin
|
||||||
|
// client and server. These certs are signed by the given CA Cert and Key.
|
||||||
|
func generateSignedCert(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) ([]byte, *x509.Certificate, *ecdsa.PrivateKey, error) {
|
||||||
host, err := uuid.GenerateUUID()
|
host, err := uuid.GenerateUUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, nil, err
|
||||||
|
@ -101,22 +110,71 @@ func GenerateClientCert(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) ([]by
|
||||||
return nil, nil, nil, fmt.Errorf("error parsing generated replication certificate: %v", err)
|
return nil, nil, nil, fmt.Errorf("error parsing generated replication certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
keyBytes, err := x509.MarshalECPrivateKey(clientKey)
|
return certBytes, clientCert, clientKey, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateClientTLSConfig creates a signed certificate and returns a configured
|
||||||
|
// TLS config.
|
||||||
|
func CreateClientTLSConfig(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) (*tls.Config, error) {
|
||||||
|
clientCertBytes, clientCert, clientKey, err := generateSignedCert(CACert, CAKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return certBytes, clientCert, keyBytes, nil
|
cert := tls.Certificate{
|
||||||
|
Certificate: [][]byte{clientCertBytes},
|
||||||
|
PrivateKey: clientKey,
|
||||||
|
Leaf: clientCert,
|
||||||
|
}
|
||||||
|
|
||||||
|
clientCertPool := x509.NewCertPool()
|
||||||
|
clientCertPool.AddCert(CACert)
|
||||||
|
|
||||||
|
tlsConfig := &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
RootCAs: clientCertPool,
|
||||||
|
ClientCAs: clientCertPool,
|
||||||
|
ServerName: CACert.Subject.CommonName,
|
||||||
|
MinVersion: tls.VersionTLS12,
|
||||||
|
}
|
||||||
|
|
||||||
|
tlsConfig.BuildNameToCertificate()
|
||||||
|
|
||||||
|
return tlsConfig, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// WrapServerConfig is used to create a server certificate and private key, then
|
||||||
|
// wrap them in an unwrap token for later retrieval by the plugin.
|
||||||
|
func WrapServerConfig(sys logical.SystemView, CACertBytes []byte, CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) (string, error) {
|
||||||
|
serverCertBytes, _, serverKey, err := generateSignedCert(CACert, CAKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
rawKey, err := x509.MarshalECPrivateKey(serverKey)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapToken, err := sys.ResponseWrapData(map[string]interface{}{
|
||||||
|
"CACert": CACertBytes,
|
||||||
|
"ServerCert": serverCertBytes,
|
||||||
|
"ServerKey": rawKey,
|
||||||
|
}, time.Second*10, true)
|
||||||
|
|
||||||
|
return wrapToken, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// VaultPluginTLSProvider is run inside a plugin and retrives the response
|
// VaultPluginTLSProvider is run inside a plugin and retrives the response
|
||||||
// wrapped TLS certificate from vault. It returns a configured tlsConfig.
|
// wrapped TLS certificate from vault. It returns a configured TLS Config.
|
||||||
func VaultPluginTLSProvider() (*tls.Config, error) {
|
func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
unwrapToken := os.Getenv("VAULT_WRAP_TOKEN")
|
unwrapToken := os.Getenv(PluginUnwrapTokenEnv)
|
||||||
|
|
||||||
|
// Ensure unwrap token is a JWT
|
||||||
if strings.Count(unwrapToken, ".") != 2 {
|
if strings.Count(unwrapToken, ".") != 2 {
|
||||||
return nil, errors.New("Could not parse unwraptoken")
|
return nil, errors.New("Could not parse unwraptoken")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse the JWT and retrieve the vault address
|
||||||
wt, err := jws.ParseJWT([]byte(unwrapToken))
|
wt, err := jws.ParseJWT([]byte(unwrapToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.New(fmt.Sprintf("error decoding token: %s", err))
|
return nil, errors.New(fmt.Sprintf("error decoding token: %s", err))
|
||||||
|
@ -142,6 +200,7 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
return nil, errors.New(fmt.Sprintf("error parsing the vault address: %s", err))
|
return nil, errors.New(fmt.Sprintf("error parsing the vault address: %s", err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unwrap the token
|
||||||
clientConf := api.DefaultConfig()
|
clientConf := api.DefaultConfig()
|
||||||
clientConf.Address = vaultAddr
|
clientConf.Address = vaultAddr
|
||||||
client, err := api.NewClient(clientConf)
|
client, err := api.NewClient(clientConf)
|
||||||
|
@ -154,9 +213,10 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err)
|
return nil, errwrap.Wrapf("error during token unwrap request: {{err}}", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve and parse the CA Certificate
|
||||||
CABytesRaw, ok := secret.Data["CACert"].(string)
|
CABytesRaw, ok := secret.Data["CACert"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("error unmarshalling certificate")
|
return nil, errors.New("error unmarshalling CA certificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
CABytes, err := base64.StdEncoding.DecodeString(CABytesRaw)
|
CABytes, err := base64.StdEncoding.DecodeString(CABytesRaw)
|
||||||
|
@ -169,6 +229,7 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retrieve and parse the server's certificate
|
||||||
serverCertBytesRaw, ok := secret.Data["ServerCert"].(string)
|
serverCertBytesRaw, ok := secret.Data["ServerCert"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("error unmarshalling certificate")
|
return nil, errors.New("error unmarshalling certificate")
|
||||||
|
@ -184,19 +245,27 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
serverKeyRaw, ok := secret.Data["ServerKey"].(string)
|
// Retrieve and parse the server's private key
|
||||||
|
serverKeyB64, ok := secret.Data["ServerKey"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("error unmarshalling certificate")
|
return nil, errors.New("error unmarshalling certificate")
|
||||||
}
|
}
|
||||||
|
|
||||||
serverKey, err := base64.StdEncoding.DecodeString(serverKeyRaw)
|
serverKeyRaw, err := base64.StdEncoding.DecodeString(serverKeyB64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverKey, err := x509.ParseECPrivateKey(serverKeyRaw)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add CA cert to the cert pool
|
||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
caCertPool.AddCert(CACert)
|
caCertPool.AddCert(CACert)
|
||||||
|
|
||||||
|
// Build a certificate object out of the server's cert and private key.
|
||||||
cert := tls.Certificate{
|
cert := tls.Certificate{
|
||||||
Certificate: [][]byte{serverCertBytes},
|
Certificate: [][]byte{serverCertBytes},
|
||||||
PrivateKey: serverKey,
|
PrivateKey: serverKey,
|
||||||
|
|
Loading…
Reference in a new issue