mirror of https://github.com/status-im/consul.git
connect/ca: fix vault provider URI SANs and test
This commit is contained in:
parent
1a8ac686b2
commit
226a59215d
|
@ -9,6 +9,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
vaultapi "github.com/hashicorp/vault/api"
|
vaultapi "github.com/hashicorp/vault/api"
|
||||||
"github.com/mitchellh/mapstructure"
|
"github.com/mitchellh/mapstructure"
|
||||||
|
@ -29,24 +30,22 @@ type VaultProvider struct {
|
||||||
// backends mounted and initialized. If the root backend is not set up already,
|
// backends mounted and initialized. If the root backend is not set up already,
|
||||||
// it will be mounted/generated as needed, but any existing state will not be
|
// it will be mounted/generated as needed, but any existing state will not be
|
||||||
// overwritten.
|
// overwritten.
|
||||||
func NewVaultProvider(rawConfig map[string]interface{}, clusterId string, client *vaultapi.Client) (*VaultProvider, error) {
|
func NewVaultProvider(rawConfig map[string]interface{}, clusterId string) (*VaultProvider, error) {
|
||||||
conf, err := ParseVaultCAConfig(rawConfig)
|
conf, err := ParseVaultCAConfig(rawConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo(kyhavlov): figure out the right way to pass the TLS config
|
// todo(kyhavlov): figure out the right way to pass the TLS config
|
||||||
if client == nil {
|
clientConf := &vaultapi.Config{
|
||||||
clientConf := &vaultapi.Config{
|
Address: conf.Address,
|
||||||
Address: conf.Address,
|
|
||||||
}
|
|
||||||
client, err = vaultapi.NewClient(clientConf)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
client.SetToken(conf.Token)
|
|
||||||
}
|
}
|
||||||
|
client, err := vaultapi.NewClient(clientConf)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
client.SetToken(conf.Token)
|
||||||
|
|
||||||
provider := &VaultProvider{
|
provider := &VaultProvider{
|
||||||
config: conf,
|
config: conf,
|
||||||
|
@ -72,8 +71,9 @@ func NewVaultProvider(rawConfig map[string]interface{}, clusterId string, client
|
||||||
|
|
||||||
fallthrough
|
fallthrough
|
||||||
case ErrBackendNotInitialized:
|
case ErrBackendNotInitialized:
|
||||||
|
spiffeID := connect.SpiffeIDSigning{ClusterID: clusterId, Domain: "consul"}
|
||||||
_, err := client.Logical().Write(conf.RootPKIPath+"root/generate/internal", map[string]interface{}{
|
_, err := client.Logical().Write(conf.RootPKIPath+"root/generate/internal", map[string]interface{}{
|
||||||
"alt_names": fmt.Sprintf("URI:spiffe://%s.consul", clusterId),
|
"uri_sans": spiffeID.URI().String(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -160,10 +160,12 @@ func (v *VaultProvider) GenerateIntermediate() (string, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
spiffeID := connect.SpiffeIDSigning{ClusterID: v.clusterId, Domain: "consul"}
|
||||||
if role == nil {
|
if role == nil {
|
||||||
_, err := v.client.Logical().Write(rolePath, map[string]interface{}{
|
_, err := v.client.Logical().Write(rolePath, map[string]interface{}{
|
||||||
"allowed_domains": fmt.Sprintf("%s.consul", v.clusterId),
|
"allowed_domains": spiffeID.Host(),
|
||||||
"max_ttl": "72h",
|
"allowed_uri_sans": "spiffe://*",
|
||||||
|
"max_ttl": "72h",
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -173,7 +175,7 @@ func (v *VaultProvider) GenerateIntermediate() (string, error) {
|
||||||
// Generate a new intermediate CSR for the root to sign.
|
// Generate a new intermediate CSR for the root to sign.
|
||||||
csr, err := v.client.Logical().Write(v.config.IntermediatePKIPath+"intermediate/generate/internal", map[string]interface{}{
|
csr, err := v.client.Logical().Write(v.config.IntermediatePKIPath+"intermediate/generate/internal", map[string]interface{}{
|
||||||
"common_name": "Vault CA Intermediate Authority",
|
"common_name": "Vault CA Intermediate Authority",
|
||||||
"alt_names": fmt.Sprintf("URI:spiffe://%s.consul", v.clusterId),
|
"uri_sans": spiffeID.URI().String(),
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -1,52 +1,51 @@
|
||||||
package ca
|
package ca
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
|
vaultapi "github.com/hashicorp/vault/api"
|
||||||
"github.com/hashicorp/vault/builtin/logical/pki"
|
"github.com/hashicorp/vault/builtin/logical/pki"
|
||||||
vaulthttp "github.com/hashicorp/vault/http"
|
vaulthttp "github.com/hashicorp/vault/http"
|
||||||
"github.com/hashicorp/vault/logical"
|
|
||||||
"github.com/hashicorp/vault/vault"
|
"github.com/hashicorp/vault/vault"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
func testVaultCluster(t *testing.T) (*VaultProvider, *vault.TestCluster) {
|
func testVaultCluster(t *testing.T) (*VaultProvider, *vault.Core, net.Listener) {
|
||||||
coreConfig := &vault.CoreConfig{
|
if err := vault.AddTestLogicalBackend("pki", pki.Factory); err != nil {
|
||||||
LogicalBackends: map[string]logical.Factory{
|
t.Fatal(err)
|
||||||
"pki": pki.Factory,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
cluster := vault.NewTestCluster(t, coreConfig, &vault.TestClusterOptions{
|
core, _, token := vault.TestCoreUnsealedRaw(t)
|
||||||
HandlerFunc: vaulthttp.Handler,
|
|
||||||
NumCores: 1,
|
|
||||||
})
|
|
||||||
cluster.Start()
|
|
||||||
|
|
||||||
client := cluster.Cores[0].Client
|
ln, addr := vaulthttp.TestServer(t, core)
|
||||||
|
|
||||||
provider, err := NewVaultProvider(map[string]interface{}{
|
provider, err := NewVaultProvider(map[string]interface{}{
|
||||||
"Address": client.Address(),
|
"Address": addr,
|
||||||
"Token": cluster.RootToken,
|
"Token": token,
|
||||||
"RootPKIPath": "pki-root/",
|
"RootPKIPath": "pki-root/",
|
||||||
"IntermediatePKIPath": "pki-intermediate/",
|
"IntermediatePKIPath": "pki-intermediate/",
|
||||||
}, "asdf", client)
|
}, "asdf")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return provider, cluster
|
return provider, core, ln
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
provider, vaultCluster := testVaultCluster(t)
|
provider, core, listener := testVaultCluster(t)
|
||||||
defer vaultCluster.Cleanup()
|
defer core.Shutdown()
|
||||||
client := vaultCluster.Cores[0].Client
|
defer listener.Close()
|
||||||
|
client, err := vaultapi.NewClient(&vaultapi.Config{
|
||||||
|
Address: "http://" + listener.Addr().String(),
|
||||||
|
})
|
||||||
|
require.NoError(err)
|
||||||
|
client.SetToken(provider.config.Token)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
certFunc func() (string, error)
|
certFunc func() (string, error)
|
||||||
|
@ -66,16 +65,16 @@ func TestVaultCAProvider_Bootstrap(t *testing.T) {
|
||||||
for _, tc := range cases {
|
for _, tc := range cases {
|
||||||
cert, err := tc.certFunc()
|
cert, err := tc.certFunc()
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
req := client.NewRequest("GET", "v1/"+tc.backendPath+"ca/pem")
|
req := client.NewRequest("GET", "/v1/"+tc.backendPath+"ca/pem")
|
||||||
resp, err := client.RawRequest(req)
|
resp, err := client.RawRequest(req)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
bytes, err := ioutil.ReadAll(resp.Body)
|
bytes, err := ioutil.ReadAll(resp.Body)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.Equal(cert, string(bytes))
|
require.Equal(cert, string(bytes))
|
||||||
|
|
||||||
// Should be a valid cert
|
// Should be a valid CA cert
|
||||||
parsed, err := connect.ParseCert(cert)
|
parsed, err := connect.ParseCert(cert)
|
||||||
require.NoError(err)
|
require.NoError(err)
|
||||||
require.Equal(parsed.URIs[0].String(), fmt.Sprintf("spiffe://%s.consul", provider.clusterId))
|
require.True(parsed.IsCA)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,11 +83,15 @@ func fixupConfig(conf *structs.CAConfiguration) {
|
||||||
if raw, ok := v.([]uint8); ok {
|
if raw, ok := v.([]uint8); ok {
|
||||||
conf.Config[k] = ca.Uint8ToString(raw)
|
conf.Config[k] = ca.Uint8ToString(raw)
|
||||||
}
|
}
|
||||||
// todo(kyhavlov): should we be hiding this and the vault token?
|
switch conf.Provider {
|
||||||
if conf.Provider == structs.ConsulCAProvider {
|
case structs.ConsulCAProvider:
|
||||||
if v, ok := conf.Config["PrivateKey"]; ok && v != "" {
|
if v, ok := conf.Config["PrivateKey"]; ok && v != "" {
|
||||||
conf.Config["PrivateKey"] = "hidden"
|
conf.Config["PrivateKey"] = "hidden"
|
||||||
}
|
}
|
||||||
|
case structs.VaultCAProvider:
|
||||||
|
if v, ok := conf.Config["Token"]; ok && v != "" {
|
||||||
|
conf.Config["Token"] = "hidden"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -512,7 +512,7 @@ func (s *Server) createCAProvider(conf *structs.CAConfiguration) (ca.Provider, e
|
||||||
case structs.ConsulCAProvider:
|
case structs.ConsulCAProvider:
|
||||||
return ca.NewConsulProvider(conf.Config, &consulCADelegate{s})
|
return ca.NewConsulProvider(conf.Config, &consulCADelegate{s})
|
||||||
case structs.VaultCAProvider:
|
case structs.VaultCAProvider:
|
||||||
return ca.NewVaultProvider(conf.Config, conf.ClusterID, nil)
|
return ca.NewVaultProvider(conf.Config, conf.ClusterID)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown CA provider %q", conf.Provider)
|
return nil, fmt.Errorf("unknown CA provider %q", conf.Provider)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue