agent/consul: test for ConnectCA.Sign
This commit is contained in:
parent
a360c5cca4
commit
9a8653f45e
|
@ -17,6 +17,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/go-uuid"
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
|
@ -32,14 +33,15 @@ const testClusterID = "11111111-2222-3333-4444-555555555555"
|
|||
var testCACounter uint64 = 0
|
||||
|
||||
// TestCA creates a test CA certificate and signing key and returns it
|
||||
// in the CARoot structure format. The CARoot returned will NOT have an ID
|
||||
// set.
|
||||
// in the CARoot structure format. The returned CA will be set as Active = true.
|
||||
//
|
||||
// If xc is non-nil, then the returned certificate will have a signing cert
|
||||
// that is cross-signed with the previous cert, and this will be set as
|
||||
// SigningCert.
|
||||
func TestCA(t testing.T, xc *structs.CARoot) *structs.CARoot {
|
||||
var result structs.CARoot
|
||||
result.ID = testUUID(t)
|
||||
result.Active = true
|
||||
result.Name = fmt.Sprintf("Test CA %d", atomic.AddUint64(&testCACounter, 1))
|
||||
|
||||
// Create the private key we'll use for this CA cert.
|
||||
|
@ -276,3 +278,13 @@ func testPrivateKey(t testing.T, ca *structs.CARoot) crypto.Signer {
|
|||
func testSerialNumber() (*big.Int, error) {
|
||||
return rand.Int(rand.Reader, (&big.Int{}).Exp(big.NewInt(2), big.NewInt(159), nil))
|
||||
}
|
||||
|
||||
// testUUID generates a UUID for testing.
|
||||
func testUUID(t testing.T) string {
|
||||
ret, err := uuid.GenerateUUID()
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to generate a UUID, %s", err)
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package connect
|
||||
|
||||
import (
|
||||
"github.com/mitchellh/go-testing-interface"
|
||||
)
|
||||
|
||||
// TestSpiffeIDService returns a SPIFFE ID representing a service.
|
||||
func TestSpiffeIDService(t testing.T, service string) *SpiffeIDService {
|
||||
return &SpiffeIDService{
|
||||
Host: testClusterID + ".consul",
|
||||
Namespace: "default",
|
||||
Datacenter: "dc01",
|
||||
Service: service,
|
||||
}
|
||||
}
|
|
@ -88,7 +88,12 @@ func (s *ConnectCA) Sign(
|
|||
return fmt.Errorf("SPIFFE ID in CSR must be a service ID")
|
||||
}
|
||||
|
||||
var root *structs.CARoot
|
||||
// Get the currently active root
|
||||
state := s.srv.fsm.State()
|
||||
_, root, err := state.CARootActive(nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Determine the signing certificate. It is the set signing cert
|
||||
// unless that is empty, in which case it is identically to the public
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
package consul
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/consul/agent/connect"
|
||||
"github.com/hashicorp/consul/agent/structs"
|
||||
"github.com/hashicorp/consul/testrpc"
|
||||
"github.com/hashicorp/net-rpc-msgpackrpc"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
// Test CA signing
|
||||
//
|
||||
// NOTE(mitchellh): Just testing the happy path and not all the other validation
|
||||
// issues because the internals of this method will probably be gutted for the
|
||||
// CA plugins then we can just test mocks.
|
||||
func TestConnectCASign(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
assert := assert.New(t)
|
||||
dir1, s1 := testServer(t)
|
||||
defer os.RemoveAll(dir1)
|
||||
defer s1.Shutdown()
|
||||
codec := rpcClient(t, s1)
|
||||
defer codec.Close()
|
||||
|
||||
testrpc.WaitForLeader(t, s1.RPC, "dc1")
|
||||
|
||||
// Insert a CA
|
||||
state := s1.fsm.State()
|
||||
assert.Nil(state.CARootSet(1, connect.TestCA(t, nil)))
|
||||
|
||||
// Generate a CSR and request signing
|
||||
args := &structs.CASignRequest{
|
||||
Datacenter: "dc01",
|
||||
CSR: connect.TestCSR(t, connect.TestSpiffeIDService(t, "web")),
|
||||
}
|
||||
var reply interface{}
|
||||
assert.Nil(msgpackrpc.CallWithCodec(codec, "ConnectCA.Sign", args, &reply))
|
||||
}
|
|
@ -55,6 +55,24 @@ func (s *Store) CARoots(ws memdb.WatchSet) (uint64, structs.CARoots, error) {
|
|||
return idx, results, nil
|
||||
}
|
||||
|
||||
// CARootActive returns the currently active CARoot.
|
||||
func (s *Store) CARootActive(ws memdb.WatchSet) (uint64, *structs.CARoot, error) {
|
||||
// Get all the roots since there should never be that many and just
|
||||
// do the filtering in this method.
|
||||
var result *structs.CARoot
|
||||
idx, roots, err := s.CARoots(ws)
|
||||
if err == nil {
|
||||
for _, r := range roots {
|
||||
if r.Active {
|
||||
result = r
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return idx, result, err
|
||||
}
|
||||
|
||||
// CARootSet creates or updates a CA root.
|
||||
//
|
||||
// NOTE(mitchellh): I have a feeling we'll want a CARootMultiSetCAS to
|
||||
|
|
|
@ -33,6 +33,12 @@ type CARoot struct {
|
|||
SigningCert string
|
||||
SigningKey string
|
||||
|
||||
// Active is true if this is the current active CA. This must only
|
||||
// be true for exactly one CA. For any method that modifies roots in the
|
||||
// state store, tests should be written to verify that multiple roots
|
||||
// cannot be active.
|
||||
Active bool
|
||||
|
||||
RaftIndex
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue