mirror of https://github.com/status-im/consul.git
Return TrustDomain from CARoots RPC
This commit is contained in:
parent
e00088e8ee
commit
c1f2025d96
|
@ -346,7 +346,7 @@ func (c *ConsulProvider) generateCA(privateKey string, sn uint64) (string, error
|
||||||
name := fmt.Sprintf("Consul CA %d", sn)
|
name := fmt.Sprintf("Consul CA %d", sn)
|
||||||
|
|
||||||
// The URI (SPIFFE compatible) for the cert
|
// The URI (SPIFFE compatible) for the cert
|
||||||
id := &connect.SpiffeIDSigning{ClusterID: config.ClusterID, Domain: "consul"}
|
id := connect.SpiffeIDSigningForCluster(config)
|
||||||
keyId, err := connect.KeyId(privKey.Public())
|
keyId, err := connect.KeyId(privKey.Public())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
|
|
@ -27,3 +27,15 @@ func (id *SpiffeIDSigning) Authorize(ixn *structs.Intention) (bool, bool) {
|
||||||
// Never authorize as a client.
|
// Never authorize as a client.
|
||||||
return false, true
|
return false, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SpiffeIDSigningForCluster returns the SPIFFE signing identifier (trust
|
||||||
|
// domain) representation of the given CA config.
|
||||||
|
//
|
||||||
|
// NOTE(banks): we intentionally fix the tld `.consul` for now rather than tie
|
||||||
|
// this to the `domain` config used for DNS because changing DNS domain can't
|
||||||
|
// break all certificate validation. That does mean that DNS prefix might not
|
||||||
|
// match the identity URIs and so the trust domain might not actually resolve
|
||||||
|
// which we would like but don't actually need.
|
||||||
|
func SpiffeIDSigningForCluster(config *structs.CAConfiguration) *SpiffeIDSigning {
|
||||||
|
return &SpiffeIDSigning{ClusterID: config.ClusterID, Domain: "consul"}
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package connect
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -13,3 +15,12 @@ func TestSpiffeIDSigningAuthorize(t *testing.T) {
|
||||||
assert.False(t, auth)
|
assert.False(t, auth)
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSpiffeIDSigningForCluster(t *testing.T) {
|
||||||
|
// For now it should just append .consul to the ID.
|
||||||
|
config := &structs.CAConfiguration{
|
||||||
|
ClusterID: testClusterID,
|
||||||
|
}
|
||||||
|
id := SpiffeIDSigningForCluster(config)
|
||||||
|
assert.Equal(t, id.URI().String(), "spiffe://"+testClusterID+".consul")
|
||||||
|
}
|
||||||
|
|
|
@ -211,6 +211,29 @@ func (s *ConnectCA) Roots(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load the ClusterID to generate TrustDomain. We do this outside the loop
|
||||||
|
// since by definition this value should be immutable once set for lifetime of
|
||||||
|
// the cluster so we don't need to look it up more than once. We also don't
|
||||||
|
// have to worry about non-atomicity between the config fetch transaction and
|
||||||
|
// the CARoots transaction below since this field must remain immutable. Do
|
||||||
|
// not re-use this state/config for other logic that might care about changes
|
||||||
|
// of config during the blocking query below.
|
||||||
|
{
|
||||||
|
state := s.srv.fsm.State()
|
||||||
|
_, config, err := state.CAConfig()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
// Build TrustDomain based on the ClusterID stored.
|
||||||
|
spiffeID := connect.SpiffeIDSigningForCluster(config)
|
||||||
|
uri := spiffeID.URI()
|
||||||
|
if uri == nil {
|
||||||
|
// Impossible(tm) but let's not panic
|
||||||
|
return errors.New("no trust domain found")
|
||||||
|
}
|
||||||
|
reply.TrustDomain = uri.Host
|
||||||
|
}
|
||||||
|
|
||||||
return s.srv.blockingQuery(
|
return s.srv.blockingQuery(
|
||||||
&args.QueryOptions, &reply.QueryMeta,
|
&args.QueryOptions, &reply.QueryMeta,
|
||||||
func(ws memdb.WatchSet, state *state.Store) error {
|
func(ws memdb.WatchSet, state *state.Store) error {
|
||||||
|
|
|
@ -2,10 +2,13 @@ package consul
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/connect"
|
"github.com/hashicorp/consul/agent/connect"
|
||||||
ca "github.com/hashicorp/consul/agent/connect/ca"
|
ca "github.com/hashicorp/consul/agent/connect/ca"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
@ -27,6 +30,7 @@ func TestConnectCARoots(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
require := require.New(t)
|
||||||
dir1, s1 := testServer(t)
|
dir1, s1 := testServer(t)
|
||||||
defer os.RemoveAll(dir1)
|
defer os.RemoveAll(dir1)
|
||||||
defer s1.Shutdown()
|
defer s1.Shutdown()
|
||||||
|
@ -41,17 +45,19 @@ func TestConnectCARoots(t *testing.T) {
|
||||||
ca2 := connect.TestCA(t, nil)
|
ca2 := connect.TestCA(t, nil)
|
||||||
ca2.Active = false
|
ca2.Active = false
|
||||||
idx, _, err := state.CARoots(nil)
|
idx, _, err := state.CARoots(nil)
|
||||||
assert.NoError(err)
|
require.NoError(err)
|
||||||
ok, err := state.CARootSetCAS(idx, idx, []*structs.CARoot{ca1, ca2})
|
ok, err := state.CARootSetCAS(idx, idx, []*structs.CARoot{ca1, ca2})
|
||||||
assert.True(ok)
|
assert.True(ok)
|
||||||
assert.NoError(err)
|
require.NoError(err)
|
||||||
|
_, caCfg, err := state.CAConfig()
|
||||||
|
require.NoError(err)
|
||||||
|
|
||||||
// Request
|
// Request
|
||||||
args := &structs.DCSpecificRequest{
|
args := &structs.DCSpecificRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
}
|
}
|
||||||
var reply structs.IndexedCARoots
|
var reply structs.IndexedCARoots
|
||||||
assert.NoError(msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", args, &reply))
|
require.NoError(msgpackrpc.CallWithCodec(codec, "ConnectCA.Roots", args, &reply))
|
||||||
|
|
||||||
// Verify
|
// Verify
|
||||||
assert.Equal(ca1.ID, reply.ActiveRootID)
|
assert.Equal(ca1.ID, reply.ActiveRootID)
|
||||||
|
@ -61,6 +67,7 @@ func TestConnectCARoots(t *testing.T) {
|
||||||
assert.Equal("", r.SigningCert)
|
assert.Equal("", r.SigningCert)
|
||||||
assert.Equal("", r.SigningKey)
|
assert.Equal("", r.SigningKey)
|
||||||
}
|
}
|
||||||
|
assert.Equal(fmt.Sprintf("%s.consul", caCfg.ClusterID), reply.TrustDomain)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestConnectCAConfig_GetSet(t *testing.T) {
|
func TestConnectCAConfig_GetSet(t *testing.T) {
|
||||||
|
|
|
@ -11,6 +11,21 @@ type IndexedCARoots struct {
|
||||||
// the process of being rotated out.
|
// the process of being rotated out.
|
||||||
ActiveRootID string
|
ActiveRootID string
|
||||||
|
|
||||||
|
// TrustDomain is the identification root for this Consul cluster. All
|
||||||
|
// certificates signed by the cluster's CA must have their identifying URI in
|
||||||
|
// this domain.
|
||||||
|
//
|
||||||
|
// This does not include the protocol (currently spiffe://) since we may
|
||||||
|
// implement other protocols in future with equivalent semantics. It should be
|
||||||
|
// compared against the "authority" section of a URI (i.e. host:port).
|
||||||
|
//
|
||||||
|
// NOTE(banks): Later we may support explicitly trusting external domains
|
||||||
|
// which may be encoded into the CARoot struct or a separate list but this
|
||||||
|
// domain identifier should be immutable and cluster-wide so deserves to be at
|
||||||
|
// the root of this response rather than duplicated through all CARoots that
|
||||||
|
// are not externally trusted entities.
|
||||||
|
TrustDomain string
|
||||||
|
|
||||||
// Roots is a list of root CA certs to trust.
|
// Roots is a list of root CA certs to trust.
|
||||||
Roots []*CARoot
|
Roots []*CARoot
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue