connect/ca: add URI SAN support to the Vault provider
This commit is contained in:
parent
7b0845ccde
commit
a97c44c1ba
|
@ -113,6 +113,7 @@ func DevSource() Source {
|
|||
|
||||
connect = {
|
||||
enabled = true
|
||||
ca_provider = "consul"
|
||||
}
|
||||
performance = {
|
||||
raft_multiplier = 1
|
||||
|
|
|
@ -163,8 +163,9 @@ func (v *VaultProvider) GenerateIntermediate() (string, error) {
|
|||
spiffeID := connect.SpiffeIDSigning{ClusterID: v.clusterId, Domain: "consul"}
|
||||
if role == nil {
|
||||
_, err := v.client.Logical().Write(rolePath, map[string]interface{}{
|
||||
"allowed_domains": spiffeID.Host(),
|
||||
"allow_any_name": true,
|
||||
"allowed_uri_sans": "spiffe://*",
|
||||
"key_type": "any",
|
||||
"max_ttl": "72h",
|
||||
})
|
||||
if err != nil {
|
||||
|
@ -218,11 +219,10 @@ func (v *VaultProvider) Sign(csr *x509.CertificateRequest) (string, error) {
|
|||
|
||||
// Use the leaf cert role to sign a new cert for this CSR.
|
||||
response, err := v.client.Logical().Write(v.config.IntermediatePKIPath+"sign/"+VaultCALeafCertRole, map[string]interface{}{
|
||||
"csr": pemBuf.String(),
|
||||
"common_name": csr.Subject.CommonName,
|
||||
"csr": pemBuf.String(),
|
||||
})
|
||||
if err != nil {
|
||||
return "", nil
|
||||
return "", fmt.Errorf("error issuing cert: %v", err)
|
||||
}
|
||||
if response == nil || response.Data["certificate"] == "" || response.Data["issuing_ca"] == "" {
|
||||
return "", fmt.Errorf("certificate info returned from Vault was blank")
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package ca
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/connect"
|
||||
vaultapi "github.com/hashicorp/vault/api"
|
||||
|
@ -76,5 +78,73 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
|||
parsed, err := connect.ParseCert(cert)
|
||||
require.NoError(err)
|
||||
require.True(parsed.IsCA)
|
||||
require.Len(parsed.URIs, 1)
|
||||
require.Equal(parsed.URIs[0].String(), fmt.Sprintf("spiffe://%s.consul", provider.clusterId))
|
||||
}
|
||||
}
|
||||
|
||||
func TestVaultCAProvider_SignLeaf(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
require := require.New(t)
|
||||
provider, core, listener := testVaultCluster(t)
|
||||
defer core.Shutdown()
|
||||
defer listener.Close()
|
||||
client, err := vaultapi.NewClient(&vaultapi.Config{
|
||||
Address: "http://" + listener.Addr().String(),
|
||||
})
|
||||
require.NoError(err)
|
||||
client.SetToken(provider.config.Token)
|
||||
|
||||
spiffeService := &connect.SpiffeIDService{
|
||||
Host: "node1",
|
||||
Namespace: "default",
|
||||
Datacenter: "dc1",
|
||||
Service: "foo",
|
||||
}
|
||||
|
||||
// Generate a leaf cert for the service.
|
||||
var firstSerial uint64
|
||||
{
|
||||
raw, _ := connect.TestCSR(t, spiffeService)
|
||||
|
||||
csr, err := connect.ParseCSR(raw)
|
||||
require.NoError(err)
|
||||
|
||||
cert, err := provider.Sign(csr)
|
||||
require.NoError(err)
|
||||
|
||||
parsed, err := connect.ParseCert(cert)
|
||||
require.NoError(err)
|
||||
require.Equal(parsed.URIs[0], spiffeService.URI())
|
||||
require.Equal(parsed.Subject.CommonName, "foo")
|
||||
firstSerial = parsed.SerialNumber.Uint64()
|
||||
|
||||
// Ensure the cert is valid now and expires within the correct limit.
|
||||
require.True(parsed.NotAfter.Sub(time.Now()) < 3*24*time.Hour)
|
||||
require.True(parsed.NotBefore.Before(time.Now()))
|
||||
}
|
||||
|
||||
// Generate a new cert for another service and make sure
|
||||
// the serial number is unique.
|
||||
spiffeService.Service = "bar"
|
||||
{
|
||||
raw, _ := connect.TestCSR(t, spiffeService)
|
||||
|
||||
csr, err := connect.ParseCSR(raw)
|
||||
require.NoError(err)
|
||||
|
||||
cert, err := provider.Sign(csr)
|
||||
require.NoError(err)
|
||||
|
||||
parsed, err := connect.ParseCert(cert)
|
||||
require.NoError(err)
|
||||
require.Equal(parsed.URIs[0], spiffeService.URI())
|
||||
require.Equal(parsed.Subject.CommonName, "bar")
|
||||
require.NotEqual(firstSerial, parsed.SerialNumber.Uint64())
|
||||
|
||||
// Ensure the cert is valid now and expires within the correct limit.
|
||||
require.True(parsed.NotAfter.Sub(time.Now()) < 3*24*time.Hour)
|
||||
require.True(parsed.NotBefore.Before(time.Now()))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,16 +5,24 @@ import (
|
|||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
// CreateCSR returns a CSR to sign the given service along with the PEM-encoded
|
||||
// private key for this certificate.
|
||||
func CreateCSR(uri CertURI, privateKey crypto.Signer) (string, error) {
|
||||
serviceId, ok := uri.(*SpiffeIDService)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("SPIFFE ID in CSR must be a service ID")
|
||||
}
|
||||
|
||||
template := &x509.CertificateRequest{
|
||||
URIs: []*url.URL{uri.URI()},
|
||||
SignatureAlgorithm: x509.ECDSAWithSHA256,
|
||||
Subject: pkix.Name{CommonName: serviceId.Service},
|
||||
}
|
||||
|
||||
// Create the CSR itself
|
||||
|
|
|
@ -201,9 +201,15 @@ func TestLeaf(t testing.T, service string, root *structs.CARoot) (string, string
|
|||
// TestCSR returns a CSR to sign the given service along with the PEM-encoded
|
||||
// private key for this certificate.
|
||||
func TestCSR(t testing.T, uri CertURI) (string, string) {
|
||||
serviceId, ok := uri.(*SpiffeIDService)
|
||||
if !ok {
|
||||
t.Fatalf("SPIFFE ID in CSR must be a service ID")
|
||||
}
|
||||
|
||||
template := &x509.CertificateRequest{
|
||||
URIs: []*url.URL{uri.URI()},
|
||||
SignatureAlgorithm: x509.ECDSAWithSHA256,
|
||||
Subject: pkix.Name{CommonName: serviceId.Service},
|
||||
}
|
||||
|
||||
// Create the private key we'll use
|
||||
|
|
Loading…
Reference in New Issue