Use the same TLS cert for the server and client
This commit is contained in:
parent
af9ff63e9a
commit
2ab159569d
|
@ -51,20 +51,20 @@ type PluginRunner struct {
|
||||||
// plugin.
|
// plugin.
|
||||||
func (r *PluginRunner) Run(wrapper Wrapper, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string) (*plugin.Client, error) {
|
func (r *PluginRunner) Run(wrapper Wrapper, pluginMap map[string]plugin.Plugin, hs plugin.HandshakeConfig, env []string) (*plugin.Client, error) {
|
||||||
// Get a CA TLS Certificate
|
// Get a CA TLS Certificate
|
||||||
CACertBytes, CACert, CAKey, err := GenerateCACert()
|
certBytes, key, err := GenerateCert()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use CA to sign a client cert and return a configured TLS config
|
// Use CA to sign a client cert and return a configured TLS config
|
||||||
clientTLSConfig, err := CreateClientTLSConfig(CACert, CAKey)
|
clientTLSConfig, err := CreateClientTLSConfig(certBytes, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use CA to sign a server cert and wrap the values in a response wrapped
|
// Use CA to sign a server cert and wrap the values in a response wrapped
|
||||||
// token.
|
// token.
|
||||||
wrapToken, err := WrapServerConfig(wrapper, CACertBytes, CACert, CAKey)
|
wrapToken, err := WrapServerConfig(wrapper, certBytes, key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,58 +29,19 @@ var (
|
||||||
PluginUnwrapTokenEnv = "VAULT_UNWRAP_TOKEN"
|
PluginUnwrapTokenEnv = "VAULT_UNWRAP_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)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
host, err := uuid.GenerateUUID()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, err
|
|
||||||
}
|
|
||||||
host = "localhost"
|
|
||||||
template := &x509.Certificate{
|
|
||||||
Subject: pkix.Name{
|
|
||||||
CommonName: host,
|
|
||||||
},
|
|
||||||
DNSNames: []string{host},
|
|
||||||
ExtKeyUsage: []x509.ExtKeyUsage{
|
|
||||||
x509.ExtKeyUsageServerAuth,
|
|
||||||
x509.ExtKeyUsageClientAuth,
|
|
||||||
},
|
|
||||||
KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement | x509.KeyUsageCertSign,
|
|
||||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
|
||||||
NotBefore: time.Now().Add(-30 * time.Second),
|
|
||||||
// 30 years of single-active uptime ought to be enough for anybody
|
|
||||||
NotAfter: time.Now().Add(262980 * time.Hour),
|
|
||||||
BasicConstraintsValid: true,
|
|
||||||
IsCA: true,
|
|
||||||
}
|
|
||||||
|
|
||||||
certBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("unable to generate replicated cluster certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
caCert, err := x509.ParseCertificate(certBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("error parsing generated replication certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return certBytes, caCert, key, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// generateSignedCert is used internally to create certificates for the plugin
|
// generateSignedCert is used internally to create certificates for the plugin
|
||||||
// client and server. These certs are signed by the given CA Cert and Key.
|
// 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) {
|
func GenerateCert() ([]byte, *ecdsa.PrivateKey, error) {
|
||||||
|
key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
host, err := uuid.GenerateUUID()
|
host, err := uuid.GenerateUUID()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
host = "localhost"
|
|
||||||
template := &x509.Certificate{
|
template := &x509.Certificate{
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: host,
|
CommonName: host,
|
||||||
|
@ -94,48 +55,38 @@ func generateSignedCert(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) ([]by
|
||||||
SerialNumber: big.NewInt(mathrand.Int63()),
|
SerialNumber: big.NewInt(mathrand.Int63()),
|
||||||
NotBefore: time.Now().Add(-30 * time.Second),
|
NotBefore: time.Now().Add(-30 * time.Second),
|
||||||
NotAfter: time.Now().Add(262980 * time.Hour),
|
NotAfter: time.Now().Add(262980 * time.Hour),
|
||||||
|
IsCA: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
clientKey, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
certBytes, err := x509.CreateCertificate(rand.Reader, template, template, key.Public(), key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, errwrap.Wrapf("error generating client key: {{err}}", err)
|
return nil, nil, errwrap.Wrapf("unable to generate client certificate: {{err}}", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
certBytes, err := x509.CreateCertificate(rand.Reader, template, CACert, clientKey.Public(), CAKey)
|
return certBytes, key, nil
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, errwrap.Wrapf("unable to generate client certificate: {{err}}", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
clientCert, err := x509.ParseCertificate(certBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, fmt.Errorf("error parsing generated replication certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return certBytes, clientCert, clientKey, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateClientTLSConfig creates a signed certificate and returns a configured
|
// CreateClientTLSConfig creates a signed certificate and returns a configured
|
||||||
// TLS config.
|
// TLS config.
|
||||||
func CreateClientTLSConfig(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) (*tls.Config, error) {
|
func CreateClientTLSConfig(certBytes []byte, key *ecdsa.PrivateKey) (*tls.Config, error) {
|
||||||
clientCertBytes, clientCert, clientKey, err := generateSignedCert(CACert, CAKey)
|
clientCert, err := x509.ParseCertificate(certBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("error parsing generated plugin certificate: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cert := tls.Certificate{
|
cert := tls.Certificate{
|
||||||
Certificate: [][]byte{clientCertBytes},
|
Certificate: [][]byte{certBytes},
|
||||||
PrivateKey: clientKey,
|
PrivateKey: key,
|
||||||
Leaf: clientCert,
|
Leaf: clientCert,
|
||||||
}
|
}
|
||||||
|
|
||||||
clientCertPool := x509.NewCertPool()
|
clientCertPool := x509.NewCertPool()
|
||||||
clientCertPool.AddCert(CACert)
|
clientCertPool.AddCert(clientCert)
|
||||||
|
|
||||||
tlsConfig := &tls.Config{
|
tlsConfig := &tls.Config{
|
||||||
Certificates: []tls.Certificate{cert},
|
Certificates: []tls.Certificate{cert},
|
||||||
RootCAs: clientCertPool,
|
RootCAs: clientCertPool,
|
||||||
ClientCAs: clientCertPool,
|
ServerName: clientCert.Subject.CommonName,
|
||||||
ServerName: CACert.Subject.CommonName,
|
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: tls.VersionTLS12,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,19 +97,14 @@ func CreateClientTLSConfig(CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) (*
|
||||||
|
|
||||||
// WrapServerConfig is used to create a server certificate and private key, then
|
// WrapServerConfig is used to create a server certificate and private key, then
|
||||||
// wrap them in an unwrap token for later retrieval by the plugin.
|
// wrap them in an unwrap token for later retrieval by the plugin.
|
||||||
func WrapServerConfig(sys Wrapper, CACertBytes []byte, CACert *x509.Certificate, CAKey *ecdsa.PrivateKey) (string, error) {
|
func WrapServerConfig(sys Wrapper, certBytes []byte, key *ecdsa.PrivateKey) (string, error) {
|
||||||
serverCertBytes, _, serverKey, err := generateSignedCert(CACert, CAKey)
|
rawKey, err := x509.MarshalECPrivateKey(key)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
rawKey, err := x509.MarshalECPrivateKey(serverKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapToken, err := sys.ResponseWrapData(map[string]interface{}{
|
wrapToken, err := sys.ResponseWrapData(map[string]interface{}{
|
||||||
"CACert": CACertBytes,
|
"ServerCert": certBytes,
|
||||||
"ServerCert": serverCertBytes,
|
|
||||||
"ServerKey": rawKey,
|
"ServerKey": rawKey,
|
||||||
}, time.Second*10, true)
|
}, time.Second*10, true)
|
||||||
|
|
||||||
|
@ -217,22 +163,6 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
return nil, errors.New("error during token unwrap request secret is nil")
|
return nil, errors.New("error during token unwrap request secret is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve and parse the CA Certificate
|
|
||||||
CABytesRaw, ok := secret.Data["CACert"].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, errors.New("error unmarshalling CA certificate")
|
|
||||||
}
|
|
||||||
|
|
||||||
CABytes, err := base64.StdEncoding.DecodeString(CABytesRaw)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
CACert, err := x509.ParseCertificate(CABytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("error parsing certificate: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve and parse the server's certificate
|
// Retrieve and parse the server's certificate
|
||||||
serverCertBytesRaw, ok := secret.Data["ServerCert"].(string)
|
serverCertBytesRaw, ok := secret.Data["ServerCert"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -267,7 +197,7 @@ func VaultPluginTLSProvider() (*tls.Config, error) {
|
||||||
|
|
||||||
// Add CA cert to the cert pool
|
// Add CA cert to the cert pool
|
||||||
caCertPool := x509.NewCertPool()
|
caCertPool := x509.NewCertPool()
|
||||||
caCertPool.AddCert(CACert)
|
caCertPool.AddCert(serverCert)
|
||||||
|
|
||||||
// Build a certificate object out of the server's cert and private key.
|
// Build a certificate object out of the server's cert and private key.
|
||||||
cert := tls.Certificate{
|
cert := tls.Certificate{
|
||||||
|
|
|
@ -29,6 +29,19 @@ func StrListSubset(super, sub []string) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parses a comma separated list of strings into a slice of strings.
|
||||||
|
// The return slice will be sorted and will not contain duplicate or
|
||||||
|
// empty items.
|
||||||
|
func ParseDedupAndSortStrings(input string, sep string) []string {
|
||||||
|
input = strings.TrimSpace(input)
|
||||||
|
parsed := []string{}
|
||||||
|
if input == "" {
|
||||||
|
// Don't return nil
|
||||||
|
return parsed
|
||||||
|
}
|
||||||
|
return RemoveDuplicates(strings.Split(input, sep), false)
|
||||||
|
}
|
||||||
|
|
||||||
// Parses a comma separated list of strings into a slice of strings.
|
// Parses a comma separated list of strings into a slice of strings.
|
||||||
// The return slice will be sorted and will not contain duplicate or
|
// The return slice will be sorted and will not contain duplicate or
|
||||||
// empty items. The values will be converted to lower case.
|
// empty items. The values will be converted to lower case.
|
||||||
|
|
Loading…
Reference in New Issue